diff --git a/.editorconfig b/.editorconfig index 6c8560aa1f54..d2d788d2172f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,9 @@ trim_trailing_whitespace = true indent_style = space indent_size = 4 +[*.css] +indent_style = tab + # some tests need trailing whitespace in output snapshots [tests/**] trim_trailing_whitespace = false diff --git a/.mailmap b/.mailmap index c0333b49f53b..17232083679c 100644 --- a/.mailmap +++ b/.mailmap @@ -262,6 +262,7 @@ Guillaume Gomez Guillaume Gomez ggomez Guillaume Gomez Guillaume Gomez Guillaume Gomez Guillaume Gomez +Guillaume Gomez Guillaume Gomez gnzlbg hamidreza kalbasi Hanna Kruppe diff --git a/Cargo.lock b/Cargo.lock index 1e6d8f682d04..8b3792cef61b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -376,12 +376,41 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "bytecheck" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "bytecount" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + [[package]] name = "camino" version = "1.2.1" @@ -1111,9 +1140,9 @@ version = "0.1.96" [[package]] name = "derive-where" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" +checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" dependencies = [ "proc-macro2", "quote", @@ -2146,9 +2175,9 @@ checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libdbus-sys" @@ -2425,11 +2454,12 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", + "log", "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.61.2", ] @@ -2461,6 +2491,7 @@ dependencies = [ "libffi", "libloading 0.9.0", "measureme", + "mio", "nix", "rand 0.9.2", "regex", @@ -2476,6 +2507,26 @@ dependencies = [ name = "miropt-test-tools" version = "0.1.0" +[[package]] +name = "munge" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -2622,9 +2673,9 @@ dependencies = [ [[package]] name = "objc2-core-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags", ] @@ -2637,9 +2688,9 @@ checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "objc2-io-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ "libc", "objc2-core-foundation", @@ -3047,6 +3098,26 @@ dependencies = [ "cc", ] +[[package]] +name = "ptr_meta" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "pulldown-cmark" version = "0.11.3" @@ -3092,6 +3163,15 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rancor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" +dependencies = [ + "ptr_meta", +] + [[package]] name = "rand" version = "0.8.5" @@ -3275,6 +3355,15 @@ dependencies = [ name = "remote-test-server" version = "0.1.0" +[[package]] +name = "rend" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" +dependencies = [ + "bytecheck", +] + [[package]] name = "replace-version-placeholder" version = "0.1.0" @@ -3283,6 +3372,36 @@ dependencies = [ "walkdir", ] +[[package]] +name = "rkyv" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a30e631b7f4a03dee9056b8ef6982e8ba371dd5bedb74d3ec86df4499132c70" +dependencies = [ + "bytecheck", + "bytes", + "hashbrown 0.16.1", + "indexmap", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "run_make_support" version = "0.0.0" @@ -3302,14 +3421,14 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b881c015c729b43105bbd3702a9bdecee28fafaa21126d1d62e454ec011a4b7" +checksum = "eec3905e8201688412f6f4b1f6c86d38b3ee6578f59ba85f41330a3af61e8365" dependencies = [ "anyhow", "rustc_version", "tempfile", - "toml 0.8.23", + "toml 1.1.0+spec-1.1.0", "walkdir", ] @@ -3902,7 +4021,6 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", - "rustc_lint", "rustc_lint_defs", "rustc_macros", "rustc_middle", @@ -4227,7 +4345,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", - "rustc_lint", + "rustc_lint_defs", "rustc_macros", "rustc_middle", "rustc_pattern_analysis", @@ -4454,11 +4572,9 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_hir", - "rustc_index", "rustc_macros", "rustc_middle", "rustc_serialize", - "rustc_session", "rustc_span", "rustc_thread_pool", "tracing", @@ -4790,6 +4906,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", + "rkyv", "rustc-hash 2.1.1", "serde", "serde_derive", @@ -5078,9 +5195,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" dependencies = [ "serde_core", ] @@ -5128,6 +5245,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "similar" version = "2.7.0" @@ -5248,9 +5371,9 @@ dependencies = [ [[package]] name = "stringdex" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ab85c3f308f022ce6861ab57576b5b6ebc4835f9577e67e0f35f6c351e3f0a" +checksum = "155cb460a7ede06f71ac9961e28d3ba4b3408355e233f8edd158b957ceba3950" dependencies = [ "stacker", ] @@ -5315,9 +5438,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.38.2" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efc19935b4b66baa6f654ac7924c192f55b175c00a7ab72410fc24284dacda8" +checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" dependencies = [ "libc", "objc2-core-foundation", @@ -5337,9 +5460,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" dependencies = [ "filetime", "libc", @@ -5570,7 +5693,6 @@ version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ - "indexmap", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -5585,13 +5707,28 @@ checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "indexmap", "serde_core", - "serde_spanned 1.0.3", + "serde_spanned 1.1.0", "toml_datetime 0.7.3", "toml_parser", "toml_writer", "winnow 0.7.13", ] +[[package]] +name = "toml" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.0", + "toml_datetime 1.1.0+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.0", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -5610,6 +5747,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_datetime" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" @@ -5639,11 +5785,11 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" dependencies = [ - "winnow 0.7.13", + "winnow 1.0.0", ] [[package]] @@ -5654,9 +5800,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.0.4" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" +checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" [[package]] name = "tracing" @@ -6642,6 +6788,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" + [[package]] name = "winsplit" version = "0.1.0" diff --git a/RELEASES.md b/RELEASES.md index f180d740a3d1..c396cd8069d6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,17 @@ +Version 1.94.1 (2026-03-26) +=========================== + + + +* [Fix `std::thread::spawn` on wasm32-wasip1-threads](https://github.com/rust-lang/rust/pull/153634) +* [Remove new methods added to `std::os::windows::fs::OpenOptionsExt`](https://github.com/rust-lang/rust/pull/153491) + The new methods were unstable, but the trait itself is not sealed and so + cannot be extended with non-default methods. +* [Clippy: fix ICE in `match_same_arms`](https://github.com/rust-lang/rust-clippy/pull/16685) +* [Cargo: update tar to 0.4.45](https://github.com/rust-lang/cargo/pull/16769) + This resolves CVE-2026-33055 and CVE-2026-33056. Users of crates.io are not affected. + See [blog](https://blog.rust-lang.org/2026/03/21/cve-2026-33056/) for more details. + Version 1.94.0 (2026-03-05) ========================== diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 662bcc5d61e7..25e2ca5948bf 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -826,7 +826,8 @@ # in the sysroot. It is required for running nvptx tests. #rust.llvm-bitcode-linker = false -# Whether to deny warnings in crates +# Whether to deny warnings in crates. Set to `false` to avoid +# error: warnings are denied by `build.warnings` configuration #rust.deny-warnings = true # Print backtrace on internal compiler errors during bootstrap @@ -1013,9 +1014,10 @@ # its historical default, but when compiling the compiler itself, we skip it by # default since we know it's safe to do so in that case. # -# On Windows platforms, packed debuginfo is the only supported option, -# producing a `.pdb` file. -#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked } +# On Windows MSVC platforms, packed debuginfo is the only supported option, +# producing a `.pdb` file. On Windows GNU rustc doesn't support splitting debuginfo, +# and enabling it causes issues. +#split-debuginfo = if linux || windows-gnu { off } else if windows-msvc { packed } else if apple { unpacked } # Path to the `llvm-config` binary of the installation of a custom LLVM to link # against. Note that if this is specified we don't compile LLVM at all for this diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index 5b43a6c5881d..7ad7088b3089 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -83,7 +83,7 @@ pub fn homogeneous_aggregate(&self, cx: &C) -> Result { + BackendRepr::SimdScalableVector { .. } => { unreachable!("`homogeneous_aggregate` should not be called for scalable vectors") } diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 2351d58d8e82..ca6128b6f1be 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -45,7 +45,7 @@ /// `b` is `FieldIdx(1)` in `VariantIdx(0)`, /// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and /// `f` is `FieldIdx(1)` in `VariantIdx(0)`. - #[cfg_attr(feature = "nightly", derive(rustc_macros::HashStable_Generic))] + #[stable_hash_generic] #[encodable] #[orderable] #[gate_rustc_only] @@ -70,7 +70,7 @@ impl FieldIdx { /// /// `struct`s, `tuples`, and `unions`s are considered to have a single variant /// with variant index zero, aka [`FIRST_VARIANT`]. - #[cfg_attr(feature = "nightly", derive(rustc_macros::HashStable_Generic))] + #[stable_hash_generic] #[encodable] #[orderable] #[gate_rustc_only] @@ -210,7 +210,7 @@ pub fn scalable_vector_type( VariantIdx: Idx, F: AsRef> + fmt::Debug, { - vector_type_layout(VectorKind::Scalable, self.cx.data_layout(), element, count) + vector_type_layout(SimdVectorKind::Scalable, self.cx.data_layout(), element, count) } pub fn simd_type( @@ -224,7 +224,7 @@ pub fn simd_type( VariantIdx: Idx, F: AsRef> + fmt::Debug, { - let kind = if repr_packed { VectorKind::PackedFixed } else { VectorKind::Fixed }; + let kind = if repr_packed { SimdVectorKind::PackedFixed } else { SimdVectorKind::Fixed }; vector_type_layout(kind, self.cx.data_layout(), element, count) } @@ -484,7 +484,7 @@ pub fn layout_of_union< BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) | BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::Memory { .. } => repr, }, }; @@ -557,7 +557,7 @@ fn layout_of_struct< hide_niches(b); } BackendRepr::SimdVector { element, .. } - | BackendRepr::ScalableVector { element, .. } => hide_niches(element), + | BackendRepr::SimdScalableVector { element, .. } => hide_niches(element), BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; @@ -1524,7 +1524,7 @@ fn format_field_niches< } } -enum VectorKind { +enum SimdVectorKind { /// `#[rustc_scalable_vector]` Scalable, /// `#[repr(simd, packed)]` @@ -1534,7 +1534,7 @@ enum VectorKind { } fn vector_type_layout( - kind: VectorKind, + kind: SimdVectorKind, dl: &TargetDataLayout, element: F, count: u64, @@ -1559,16 +1559,16 @@ fn vector_type_layout( let size = elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; let (repr, align) = match kind { - VectorKind::Scalable => { - (BackendRepr::ScalableVector { element, count }, dl.llvmlike_vector_align(size)) + SimdVectorKind::Scalable => { + (BackendRepr::SimdScalableVector { element, count }, dl.llvmlike_vector_align(size)) } // Non-power-of-two vectors have padding up to the next power-of-two. // If we're a packed repr, remove the padding while keeping the alignment as close // to a vector as possible. - VectorKind::PackedFixed if !count.is_power_of_two() => { + SimdVectorKind::PackedFixed if !count.is_power_of_two() => { (BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size)) } - VectorKind::PackedFixed | VectorKind::Fixed => { + SimdVectorKind::PackedFixed | SimdVectorKind::Fixed => { (BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size)) } }; diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index ce5f257abae9..253dff6f8e75 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1000,20 +1000,6 @@ pub enum AlignFromBytesError { TooLarge(u64), } -impl AlignFromBytesError { - pub fn diag_ident(self) -> &'static str { - match self { - Self::NotPowerOfTwo(_) => "not_power_of_two", - Self::TooLarge(_) => "too_large", - } - } - - pub fn align(self) -> u64 { - let (Self::NotPowerOfTwo(align) | Self::TooLarge(align)) = self; - align - } -} - impl fmt::Debug for AlignFromBytesError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) @@ -1023,8 +1009,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl fmt::Display for AlignFromBytesError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - AlignFromBytesError::NotPowerOfTwo(align) => write!(f, "`{align}` is not a power of 2"), - AlignFromBytesError::TooLarge(align) => write!(f, "`{align}` is too large"), + AlignFromBytesError::NotPowerOfTwo(align) => write!(f, "{align} is not a power of 2"), + AlignFromBytesError::TooLarge(align) => write!(f, "{align} is too large"), } } } @@ -1731,7 +1717,7 @@ impl AddressSpace { pub enum BackendRepr { Scalar(Scalar), ScalarPair(Scalar, Scalar), - ScalableVector { + SimdScalableVector { element: Scalar, count: u64, }, @@ -1758,7 +1744,7 @@ pub fn is_unsized(&self) -> bool { // fully implemented, scalable vectors will remain `Sized`, they just won't be // `const Sized` - whether `is_unsized` continues to return `false` at that point will // need to be revisited and will depend on what `is_unsized` is used for. - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => !sized, } @@ -1801,7 +1787,7 @@ pub fn scalar_align(&self, cx: &C) -> Option { // The align of a Vector can vary in surprising ways BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } - | BackendRepr::ScalableVector { .. } => None, + | BackendRepr::SimdScalableVector { .. } => None, } } @@ -1825,7 +1811,7 @@ pub fn scalar_size(&self, cx: &C) -> Option { // The size of a Vector can vary in surprising ways BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } - | BackendRepr::ScalableVector { .. } => None, + | BackendRepr::SimdScalableVector { .. } => None, } } @@ -1840,8 +1826,8 @@ pub fn to_union(&self) -> Self { BackendRepr::SimdVector { element: element.to_union(), count } } BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true }, - BackendRepr::ScalableVector { element, count } => { - BackendRepr::ScalableVector { element: element.to_union(), count } + BackendRepr::SimdScalableVector { element, count } => { + BackendRepr::SimdScalableVector { element: element.to_union(), count } } } } @@ -2085,7 +2071,7 @@ pub fn is_aggregate(&self) -> bool { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } => false, + | BackendRepr::SimdScalableVector { .. } => false, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } @@ -2182,13 +2168,13 @@ pub fn is_1zst(&self) -> bool { /// Returns `true` if the size of the type is only known at runtime. pub fn is_runtime_sized(&self) -> bool { - matches!(self.backend_repr, BackendRepr::ScalableVector { .. }) + matches!(self.backend_repr, BackendRepr::SimdScalableVector { .. }) } /// Returns the elements count of a scalable vector. pub fn scalable_vector_element_count(&self) -> Option { match self.backend_repr { - BackendRepr::ScalableVector { count, .. } => Some(count), + BackendRepr::SimdScalableVector { count, .. } => Some(count), _ => None, } } @@ -2201,7 +2187,7 @@ pub fn is_zst(&self) -> bool { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5258f179d95d..024624cd3bb8 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -30,8 +30,9 @@ use rustc_data_structures::tagged_ptr::Tag; use rustc_macros::{Decodable, Encodable, HashStable_Generic, Walkable}; pub use rustc_span::AttrId; -use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; +use rustc_span::{ + ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Spanned, Symbol, kw, respan, sym, +}; use thin_vec::{ThinVec, thin_vec}; use crate::attr::data_structures::CfgEntry; @@ -937,7 +938,7 @@ pub enum PatKind { Never, /// A guard pattern (e.g., `x if guard(x)`). - Guard(Box, Box), + Guard(Box, Box), /// Parentheses in patterns used for grouping (i.e., `(PAT)`). Paren(Box), @@ -1345,7 +1346,7 @@ pub struct Arm { /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`. pub pat: Box, /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`. - pub guard: Option>, + pub guard: Option>, /// Match arm body. Omitted if the pattern is a never pattern. pub body: Option>, pub span: Span, @@ -3953,6 +3954,18 @@ impl ConstBlockItem { pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP }; } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct Guard { + pub cond: Expr, + pub span_with_leading_if: Span, +} + +impl Guard { + pub fn span(&self) -> Span { + self.cond.span + } +} + // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum ItemKind { diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 72e7b27a1f97..369fe12539fa 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -876,11 +876,15 @@ pub trait AttributeExt: Debug { /// a doc comment) will return `false`. fn is_doc_comment(&self) -> Option; + /// Returns true if the attribute's first *and only* path segment is equal to the passed-in + /// symbol. #[inline] fn has_name(&self, name: Symbol) -> bool { self.name().map(|x| x == name).unwrap_or(false) } + /// Returns true if the attribute's first *and only* path segment is any of the passed-in + /// symbols. #[inline] fn has_any_name(&self, names: &[Symbol]) -> bool { names.iter().any(|&name| self.has_name(name)) @@ -889,6 +893,7 @@ fn has_any_name(&self, names: &[Symbol]) -> bool { /// get the span of the entire attribute fn span(&self) -> Span; + /// Returns whether the attribute is a path, without any arguments. fn is_word(&self) -> bool; fn path(&self) -> SmallVec<[Symbol; 1]> { @@ -911,11 +916,14 @@ fn has_any_name(&self, names: &[Symbol]) -> bool { /// * `#[deprecated(note = "note", ...)]` returns `Some("note")`. fn deprecation_note(&self) -> Option; + /// Returns whether this attribute is any of the proc macro attributes. + /// i.e. `proc_macro`, `proc_macro_attribute` or `proc_macro_derive`. fn is_proc_macro_attr(&self) -> bool { [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] .iter() .any(|kind| self.has_name(*kind)) } + /// Returns true if this attribute is `#[automatically_deived]`. fn is_automatically_derived_attr(&self) -> bool; /// Returns the documentation and its kind if this is a doc comment or a sugared doc comment. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index be8e1d22c9db..881b6ff107b5 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -11,8 +11,7 @@ use std::panic; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_span::source_map::Spanned; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{Ident, Span, Spanned, Symbol}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index f82513094aa1..62ec06358517 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -94,6 +94,7 @@ pub enum MetaVarKind { }, Path, Vis, + Guard, TT, } @@ -114,6 +115,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { MetaVarKind::Meta { .. } => sym::meta, MetaVarKind::Path => sym::path, MetaVarKind::Vis => sym::vis, + MetaVarKind::Guard => sym::guard, MetaVarKind::TT => sym::tt, }; write!(f, "{sym}") @@ -1124,6 +1126,7 @@ pub enum NonterminalKind { Meta, Path, Vis, + Guard, TT, } @@ -1161,6 +1164,7 @@ pub fn from_symbol( sym::meta => NonterminalKind::Meta, sym::path => NonterminalKind::Path, sym::vis => NonterminalKind::Vis, + sym::guard => NonterminalKind::Guard, sym::tt => NonterminalKind::TT, _ => return None, }) @@ -1182,6 +1186,7 @@ fn symbol(self) -> Symbol { NonterminalKind::Meta => sym::meta, NonterminalKind::Path => sym::path, NonterminalKind::Vis => sym::vis, + NonterminalKind::Guard => sym::guard, NonterminalKind::TT => sym::tt, } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index c3c1c518d849..6aa8d5f38ad2 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -15,8 +15,7 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; -use rustc_span::source_map::Spanned; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{Ident, Span, Spanned, Symbol}; use thin_vec::ThinVec; use crate::ast::*; @@ -443,6 +442,7 @@ pub fn ctxt(&self) -> Option { FormatArguments, FormatPlaceholder, GenericParamKind, + Guard, Impl, ImplPolarity, Inline, diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index a7bf1c99a7e2..3a27962feca3 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -1,5 +1,4 @@ use std::collections::hash_map::Entry; -use std::fmt::Write; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; @@ -23,7 +22,7 @@ AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt, }; -impl<'a, 'hir> LoweringContext<'a, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { pub(crate) fn lower_inline_asm( &mut self, sp: Span, @@ -124,13 +123,9 @@ pub(crate) fn lower_inline_asm( self.dcx().emit_err(ClobberAbiNotSupported { abi_span: *abi_span }); } Err(supported_abis) => { - let mut abis = format!("`{}`", supported_abis[0]); - for m in &supported_abis[1..] { - let _ = write!(abis, ", `{m}`"); - } self.dcx().emit_err(InvalidAbiClobberAbi { abi_span: *abi_span, - supported_abis: abis, + supported_abis: supported_abis.to_vec().into(), }); } } @@ -164,15 +159,12 @@ pub(crate) fn lower_inline_asm( asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else( |supported_register_classes| { - let mut register_classes = - format!("`{}`", supported_register_classes[0]); - for m in &supported_register_classes[1..] { - let _ = write!(register_classes, ", `{m}`"); - } self.dcx().emit_err(InvalidRegisterClass { op_span: *op_sp, reg_class, - supported_register_classes: register_classes, + supported_register_classes: supported_register_classes + .to_vec() + .into(), }); asm::InlineAsmRegClass::Err }, @@ -272,23 +264,20 @@ pub(crate) fn lower_inline_asm( } let valid_modifiers = class.valid_modifiers(asm_arch.unwrap()); if !valid_modifiers.contains(&modifier) { - let sub = if !valid_modifiers.is_empty() { - let mut mods = format!("`{}`", valid_modifiers[0]); - for m in &valid_modifiers[1..] { - let _ = write!(mods, ", `{m}`"); - } - InvalidAsmTemplateModifierRegClassSub::SupportModifier { - class_name: class.name(), - modifiers: mods, - } - } else { + let sub = if valid_modifiers.is_empty() { InvalidAsmTemplateModifierRegClassSub::DoesNotSupportModifier { class_name: class.name(), } + } else { + InvalidAsmTemplateModifierRegClassSub::SupportModifier { + class_name: class.name(), + modifiers: valid_modifiers.to_vec().into(), + } }; self.dcx().emit_err(InvalidAsmTemplateModifierRegClass { placeholder_span, op_span: op_sp, + modifier: modifier.to_string(), sub, }); } diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index cf3f331a701b..94839485c603 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -4,9 +4,9 @@ use rustc_span::sym; use smallvec::SmallVec; -use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext}; +use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext, ResolverAstLoweringExt}; -impl<'a, 'hir> LoweringContext<'a, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { pub(super) fn lower_block( &mut self, b: &Block, diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index 6cffd8e119b7..fd05ed0c78e4 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -2,9 +2,9 @@ use thin_vec::thin_vec; -use crate::LoweringContext; +use crate::{LoweringContext, ResolverAstLoweringExt}; -impl<'a, 'hir> LoweringContext<'a, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { /// Lowered contracts are guarded with the `contract_checks` compiler flag, /// i.e. the flag turns into a boolean guard in the lowered HIR. The reason /// for not eliminating the contract code entirely when the `contract_checks` diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 68b76f7bd3dd..022f9e3c83f1 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -37,6 +37,7 @@ //! also be emitted during HIR ty lowering. use std::iter; +use std::marker::PhantomData; use ast::visit::Visitor; use hir::def::{DefKind, PartialRes, Res}; @@ -44,16 +45,15 @@ use rustc_abi::ExternAbi; use rustc_ast as ast; use rustc_ast::*; -use rustc_attr_parsing::{AttributeParser, ShouldEmit}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::attrs::{AttributeKind, InlineAttr}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_middle::span_bug; -use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs, ResolverAstLowering}; +use rustc_middle::ty::Asyncness; use rustc_span::symbol::kw; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; +use rustc_span::{Ident, Span, Symbol}; use smallvec::SmallVec; use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults}; @@ -79,7 +79,7 @@ struct AttrAdditionInfo { enum AttrAdditionKind { Default { factory: fn(Span) -> hir::Attribute }, - Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute }, + Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute }, } const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; @@ -96,7 +96,6 @@ enum AttrAdditionKind { hir::Attribute::Parsed(AttributeKind::MustUse { span, reason }) }, - flag: DelegationFnSigAttrs::MUST_USE, }, }, AttrAdditionInfo { @@ -107,45 +106,11 @@ enum AttrAdditionKind { }, ]; -type DelegationIdsVec = SmallVec<[DefId; 1]>; - -// As delegations can now refer to another delegation, we have a delegation path -// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id). -// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id) -struct DelegationIds { - path: DelegationIdsVec, -} - -impl DelegationIds { - fn new(path: DelegationIdsVec) -> Self { - assert!(!path.is_empty()); - Self { path } - } - - // Id of the first function in (non)local crate that is being reused - fn root_function_id(&self) -> DefId { - *self.path.last().expect("Ids vector can't be empty") - } - - // Id of the first definition which is being reused, - // can be either function, in this case `root_id == delegee_id`, or other delegation - fn delegee_id(&self) -> DefId { - *self.path.first().expect("Ids vector can't be empty") - } -} - -impl<'hir> LoweringContext<'_, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { fn is_method(&self, def_id: DefId, span: Span) -> bool { match self.tcx.def_kind(def_id) { DefKind::Fn => false, - DefKind::AssocFn => match def_id.as_local() { - Some(local_def_id) => self - .resolver - .delegation_fn_sigs - .get(&local_def_id) - .is_some_and(|sig| sig.has_self), - None => self.tcx.associated_item(def_id).is_method(), - }, + DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(), _ => span_bug!(span, "unexpected DefKind for delegation item"), } } @@ -158,10 +123,10 @@ pub(crate) fn lower_delegation( let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); // Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356) - let ids = if let Some(delegation_info) = - self.resolver.delegation_infos.get(&self.local_def_id(item_id)) + let sig_id = if let Some(delegation_info) = + self.resolver.delegation_info(self.local_def_id(item_id)) { - self.get_delegation_ids(delegation_info.resolution_node, span) + self.get_sig_id(delegation_info.resolution_node, span) } else { return self.generate_delegation_error( self.dcx().span_delayed_bug( @@ -173,60 +138,34 @@ pub(crate) fn lower_delegation( ); }; - match ids { - Ok(ids) => { - self.add_attrs_if_needed(span, &ids); + match sig_id { + Ok(sig_id) => { + self.add_attrs_if_needed(span, sig_id); - let delegee_id = ids.delegee_id(); - let root_function_id = ids.root_function_id(); + let is_method = self.is_method(sig_id, span); - // `is_method` is used to choose the name of the first parameter (`self` or `arg0`), - // if the original function is not a method (without `self`), then it can not be added - // during chain of reuses, so we use `root_function_id` here - let is_method = self.is_method(root_function_id, span); + let (param_count, c_variadic) = self.param_count(sig_id); - // Here we use `root_function_id` as we can not get params information out of potential delegation reuse, - // we need a function to extract this information - let (param_count, c_variadic) = self.param_count(root_function_id); - - let mut generics = self.lower_delegation_generics( - delegation, - ids.root_function_id(), - item_id, - span, - ); + let mut generics = self.uplift_delegation_generics(delegation, sig_id, item_id); let body_id = self.lower_delegation_body( delegation, - item_id, is_method, param_count, &mut generics, span, ); - // Here we use `delegee_id`, as this id will then be used to calculate parent for generics - // inheritance, and we want this id to point on a delegee, not on the original - // function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654) - let decl = self.lower_delegation_decl( - delegee_id, - param_count, - c_variadic, - span, - &generics, - ); + let decl = + self.lower_delegation_decl(sig_id, param_count, c_variadic, span, &generics); - // Here we pass `root_function_id` as we want to inherit signature (including consts, async) - // from the root function that started delegation - let sig = self.lower_delegation_sig(root_function_id, decl, span); + let sig = self.lower_delegation_sig(sig_id, decl, span); let ident = self.lower_ident(delegation.ident); let generics = self.arena.alloc(hir::Generics { has_where_clause_predicates: false, - params: self.arena.alloc_from_iter(generics.all_params(item_id, span, self)), - predicates: self - .arena - .alloc_from_iter(generics.all_predicates(item_id, span, self)), + params: self.arena.alloc_from_iter(generics.all_params(span, self)), + predicates: self.arena.alloc_from_iter(generics.all_predicates(span, self)), span, where_clause_span: span, }); @@ -237,9 +176,9 @@ pub(crate) fn lower_delegation( } } - fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) { + fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) { let new_attrs = - self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID)); + self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID)); if new_attrs.is_empty() { return; @@ -259,15 +198,9 @@ fn create_new_attrs( &self, candidate_additions: &[AttrAdditionInfo], span: Span, - ids: &DelegationIds, + sig_id: DefId, existing_attrs: Option<&&[hir::Attribute]>, ) -> Vec { - let defs_orig_attrs = ids - .path - .iter() - .map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id))) - .collect::>(); - candidate_additions .iter() .filter_map(|addition_info| { @@ -281,83 +214,22 @@ fn create_new_attrs( match addition_info.kind { AttrAdditionKind::Default { factory } => Some(factory(span)), - AttrAdditionKind::Inherit { flag, factory } => { - for (def_id, orig_attrs) in &defs_orig_attrs { - let original_attr = match def_id.as_local() { - Some(local_id) => self - .get_attrs(local_id) - .flags - .contains(flag) - .then(|| { - orig_attrs - .as_ref() - .map(|attrs| { - attrs.iter().find(|base_attr| { - (addition_info.equals)(base_attr) - }) - }) - .flatten() - }) - .flatten(), - None => - { - #[allow(deprecated)] - self.tcx - .get_all_attrs(*def_id) - .iter() - .find(|base_attr| (addition_info.equals)(base_attr)) - } - }; - - if let Some(original_attr) = original_attr { - return Some(factory(span, original_attr)); - } - } - - None + AttrAdditionKind::Inherit { factory, .. } => + { + #[allow(deprecated)] + self.tcx + .get_all_attrs(sig_id) + .iter() + .find_map(|a| (addition_info.equals)(a).then(|| factory(span, a))) } } }) .collect::>() } - fn parse_local_original_attrs(&self, def_id: DefId) -> Option> { - if let Some(local_id) = def_id.as_local() { - let attrs = &self.get_attrs(local_id).to_inherit; - - if !attrs.is_empty() { - return Some(AttributeParser::parse_limited_all( - self.tcx.sess, - attrs, - None, - hir::Target::Fn, - DUMMY_SP, - DUMMY_NODE_ID, - Some(self.tcx.features()), - ShouldEmit::Nothing, - )); - } - } - - None - } - - fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs { - // local_id can correspond either to a function or other delegation - if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) { - &fn_sig.attrs - } else { - &self.resolver.delegation_infos[&local_id].attrs - } - } - - fn get_delegation_ids( - &self, - mut node_id: NodeId, - span: Span, - ) -> Result { + fn get_sig_id(&self, mut node_id: NodeId, span: Span) -> Result { let mut visited: FxHashSet = Default::default(); - let mut path: DelegationIdsVec = Default::default(); + let mut path: SmallVec<[DefId; 1]> = Default::default(); loop { visited.insert(node_id); @@ -378,7 +250,7 @@ fn get_delegation_ids( // it means that we refer to another delegation as a callee, so in order to obtain // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it. if let Some(local_id) = def_id.as_local() - && let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id) + && let Some(delegation_info) = self.resolver.delegation_info(local_id) { node_id = delegation_info.resolution_node; if visited.contains(&node_id) { @@ -390,7 +262,7 @@ fn get_delegation_ids( }); } } else { - return Ok(DelegationIds::new(path)); + return Ok(path[0]); } } } @@ -401,15 +273,8 @@ fn get_resolution_id(&self, node_id: NodeId) -> Option { // Function parameter count, including C variadic `...` if present. fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) { - if let Some(local_sig_id) = def_id.as_local() { - match self.resolver.delegation_fn_sigs.get(&local_sig_id) { - Some(sig) => (sig.param_count, sig.c_variadic), - None => (0, false), - } - } else { - let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder(); - (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic) - } + let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder(); + (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic) } fn lower_delegation_decl( @@ -425,19 +290,22 @@ fn lower_delegation_decl( let decl_param_count = param_count - c_variadic as usize; let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty { hir_id: self.next_id(), - kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)), + kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig( + sig_id, + hir::InferDelegationSig::Input(arg), + )), span, })); let output = self.arena.alloc(hir::Ty { hir_id: self.next_id(), - kind: hir::TyKind::InferDelegation( + kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig( sig_id, - hir::InferDelegationKind::Output(self.arena.alloc(hir::DelegationGenerics { + hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationGenerics { child_args_segment_id: generics.child.args_segment_id, parent_args_segment_id: generics.parent.args_segment_id, })), - ), + )), span, }); @@ -456,41 +324,21 @@ fn lower_delegation_sig( decl: &'hir hir::FnDecl<'hir>, span: Span, ) -> hir::FnSig<'hir> { - let header = if let Some(local_sig_id) = sig_id.as_local() { - match self.resolver.delegation_fn_sigs.get(&local_sig_id) { - Some(sig) => { - let parent = self.tcx.parent(sig_id); - // HACK: we override the default safety instead of generating attributes from the ether. - // We are not forwarding the attributes, as the delegation fn sigs are collected on the ast, - // and here we need the hir attributes. - let default_safety = - if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE) - || self.tcx.def_kind(parent) == DefKind::ForeignMod - { - hir::Safety::Unsafe - } else { - hir::Safety::Safe - }; - self.lower_fn_header(sig.header, default_safety, &[]) - } - None => self.generate_header_error(), - } - } else { - let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder(); - let asyncness = match self.tcx.asyncness(sig_id) { - Asyncness::Yes => hir::IsAsync::Async(span), - Asyncness::No => hir::IsAsync::NotAsync, - }; - hir::FnHeader { - safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features { - hir::HeaderSafety::SafeTargetFeatures - } else { - hir::HeaderSafety::Normal(sig.safety) - }, - constness: self.tcx.constness(sig_id), - asyncness, - abi: sig.abi, - } + let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder(); + let asyncness = match self.tcx.asyncness(sig_id) { + Asyncness::Yes => hir::IsAsync::Async(span), + Asyncness::No => hir::IsAsync::NotAsync, + }; + + let header = hir::FnHeader { + safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features { + hir::HeaderSafety::SafeTargetFeatures + } else { + hir::HeaderSafety::Normal(sig.safety) + }, + constness: self.tcx.constness(sig_id), + asyncness, + abi: sig.abi, }; hir::FnSig { decl, header, span } @@ -550,7 +398,6 @@ fn generate_arg( fn lower_delegation_body( &mut self, delegation: &Delegation, - item_id: NodeId, is_method: bool, param_count: usize, generics: &mut GenericsGenerationResults<'hir>, @@ -573,6 +420,7 @@ fn lower_delegation_body( resolver: this.resolver, path_id: delegation.id, self_param_id: pat_node_id, + phantom: PhantomData, }; self_resolver.visit_block(block); // Target expr needs to lower `self` path. @@ -584,7 +432,18 @@ fn lower_delegation_body( args.push(arg); } - let final_expr = this.finalize_body_lowering(delegation, item_id, args, generics, span); + // If we have no params in signature function but user still wrote some code in + // delegation body, then add this code as first arg, eventually an error will be shown, + // also nested delegations may need to access information about this code (#154332), + // so it is better to leave this code as opposed to bodies of extern functions, + // which are completely erased from existence. + if param_count == 0 + && let Some(block) = block + { + args.push(this.lower_target_expr(&block)); + } + + let final_expr = this.finalize_body_lowering(delegation, args, generics, span); (this.arena.alloc_from_iter(parameters), final_expr) }) @@ -621,7 +480,6 @@ fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> { fn finalize_body_lowering( &mut self, delegation: &Delegation, - item_id: NodeId, args: Vec>, generics: &mut GenericsGenerationResults<'hir>, span: Span, @@ -651,7 +509,7 @@ fn finalize_body_lowering( // FIXME(fn_delegation): proper support for parent generics propagation // in method call scenario. - let segment = self.process_segment(item_id, span, &segment, &mut generics.child, false); + let segment = self.process_segment(span, &segment, &mut generics.child, false); let segment = self.arena.alloc(segment); self.arena.alloc(hir::Expr { @@ -678,7 +536,7 @@ fn finalize_body_lowering( new_path.segments = self.arena.alloc_from_iter( new_path.segments.iter().enumerate().map(|(idx, segment)| { let mut process_segment = |result, add_lifetimes| { - self.process_segment(item_id, span, segment, result, add_lifetimes) + self.process_segment(span, segment, result, add_lifetimes) }; if idx + 2 == len { @@ -694,8 +552,7 @@ fn finalize_body_lowering( hir::QPath::Resolved(ty, self.arena.alloc(new_path)) } hir::QPath::TypeRelative(ty, segment) => { - let segment = - self.process_segment(item_id, span, segment, &mut generics.child, false); + let segment = self.process_segment(span, segment, &mut generics.child, false); hir::QPath::TypeRelative(ty, self.arena.alloc(segment)) } @@ -719,26 +576,26 @@ fn finalize_body_lowering( fn process_segment( &mut self, - item_id: NodeId, span: Span, segment: &hir::PathSegment<'hir>, result: &mut GenericsGenerationResult<'hir>, add_lifetimes: bool, ) -> hir::PathSegment<'hir> { - // The first condition is needed when there is SelfAndUserSpecified case, - // we don't want to propagate generics params in this situation. - let segment = if !result.generics.is_user_specified() - && let Some(args) = result - .generics - .into_hir_generics(self, item_id, span) - .into_generic_args(self, add_lifetimes, span) - { - hir::PathSegment { args: Some(args), ..segment.clone() } + let details = result.generics.args_propagation_details(); + + let segment = if details.should_propagate { + let generics = result.generics.into_hir_generics(self, span); + let args = generics.into_generic_args(self, add_lifetimes, span); + + // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). + let args = if args.is_empty() { None } else { Some(args) }; + + hir::PathSegment { args, ..segment.clone() } } else { segment.clone() }; - if result.generics.is_user_specified() { + if details.use_args_in_sig_inheritance { result.args_segment_id = Some(segment.hir_id); } @@ -816,25 +673,26 @@ fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> } } -struct SelfResolver<'a, 'tcx> { - resolver: &'a mut ResolverAstLowering<'tcx>, +struct SelfResolver<'a, 'tcx, R> { + resolver: &'a mut R, path_id: NodeId, self_param_id: NodeId, + phantom: PhantomData<&'tcx ()>, } -impl SelfResolver<'_, '_> { +impl<'tcx, R: ResolverAstLoweringExt<'tcx>> SelfResolver<'_, 'tcx, R> { fn try_replace_id(&mut self, id: NodeId) { - if let Some(res) = self.resolver.partial_res_map.get(&id) + if let Some(res) = self.resolver.get_partial_res(id) && let Some(Res::Local(sig_id)) = res.full_res() && sig_id == self.path_id { let new_res = PartialRes::new(Res::Local(self.self_param_id)); - self.resolver.partial_res_map.insert(id, new_res); + self.resolver.insert_partial_res(id, new_res); } } } -impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a, '_> { +impl<'ast, 'a, 'tcx, R: ResolverAstLoweringExt<'tcx>> Visitor<'ast> for SelfResolver<'a, 'tcx, R> { fn visit_id(&mut self, id: NodeId) { self.try_replace_id(id); } diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 9e7ec04d38fb..4e960e3b9290 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -5,41 +5,42 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::{bug, ty}; -use rustc_span::sym::{self}; use rustc_span::symbol::kw; -use rustc_span::{DUMMY_SP, Ident, Span}; -use thin_vec::{ThinVec, thin_vec}; +use rustc_span::{Ident, Span}; -use crate::{AstOwner, LoweringContext}; +use crate::{LoweringContext, ResolverAstLoweringExt}; pub(super) enum DelegationGenerics { /// User-specified args are present: `reuse foo::;`. UserSpecified, /// The default case when no user-specified args are present: `reuse Trait::foo;`. - Default(Option), + Default(T), /// In free-to-trait reuse, when user specified args for trait `reuse Trait::::foo;` /// in this case we need to both generate `Self` and process user args. - SelfAndUserSpecified(Option), + SelfAndUserSpecified(T), + /// In delegations from trait impl to other entities like free functions or trait functions, + /// we want to generate a function whose generics matches generics of signature function + /// in trait. + TraitImpl(T, bool /* Has user-specified args */), } -/// Used for storing either AST generics or their lowered HIR version. Firstly we obtain -/// AST generics either from local function from AST index or from external function -/// through `tcx`. Next, at some point of generics processing we need to lower those -/// generics to HIR, for this purpose we use `into_hir_generics` that lowers AST generics -/// and replaces Ast variant with Hir. Such approach is useful as we can call this method -/// at any time knowing that lowering will occur at most only once. Then, in order to obtain generic +/// Used for storing either ty generics or their uplifted HIR version. First we obtain +/// ty generics. Next, at some point of generics processing we need to uplift those +/// generics to HIR, for this purpose we use `into_hir_generics` that uplifts ty generics +/// and replaces Ty variant with Hir. Such approach is useful as we can call this method +/// at any time knowing that uplifting will occur at most only once. Then, in order to obtain generic /// params or args we use `hir_generics_or_empty` or `into_generic_args` functions. -/// There also may be situations when we obtained AST generics but never lowered them to HIR, +/// There also may be situations when we obtained ty generics but never uplifted them to HIR, /// meaning we did not propagate them and thus we do not need to generate generic params /// (i.e., method call scenarios), in such a case this approach helps -/// a lot as if `into_hir_generics` will not be called then lowering will not happen. -pub(super) enum HirOrAstGenerics<'hir> { - Ast(DelegationGenerics), +/// a lot as if `into_hir_generics` will not be called then uplifting will not happen. +pub(super) enum HirOrTyGenerics<'hir> { + Ty(DelegationGenerics<&'hir [ty::GenericParamDef]>), Hir(DelegationGenerics<&'hir hir::Generics<'hir>>), } pub(super) struct GenericsGenerationResult<'hir> { - pub(super) generics: HirOrAstGenerics<'hir>, + pub(super) generics: HirOrTyGenerics<'hir>, pub(super) args_segment_id: Option, } @@ -48,38 +49,57 @@ pub(super) struct GenericsGenerationResults<'hir> { pub(super) child: GenericsGenerationResult<'hir>, } +pub(super) struct GenericArgsPropagationDetails { + pub(super) should_propagate: bool, + pub(super) use_args_in_sig_inheritance: bool, +} + impl DelegationGenerics { - fn is_user_specified(&self) -> bool { - matches!( - self, - DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. } - ) + fn args_propagation_details(&self) -> GenericArgsPropagationDetails { + match self { + DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. } => { + GenericArgsPropagationDetails { + should_propagate: false, + use_args_in_sig_inheritance: true, + } + } + DelegationGenerics::TraitImpl(_, user_specified) => GenericArgsPropagationDetails { + should_propagate: !*user_specified, + use_args_in_sig_inheritance: false, + }, + DelegationGenerics::Default(_) => GenericArgsPropagationDetails { + should_propagate: true, + use_args_in_sig_inheritance: false, + }, + } } } -impl<'hir> HirOrAstGenerics<'hir> { +impl<'hir> HirOrTyGenerics<'hir> { pub(super) fn into_hir_generics( &mut self, - ctx: &mut LoweringContext<'_, 'hir>, - item_id: NodeId, + ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, span: Span, - ) -> &mut HirOrAstGenerics<'hir> { - if let HirOrAstGenerics::Ast(generics) = self { - let process_params = |generics: &mut Generics| { - ctx.lower_delegation_generic_params(item_id, span, &mut generics.params) + ) -> &mut HirOrTyGenerics<'hir> { + if let HirOrTyGenerics::Ty(params) = self { + let mut uplift_params = |generics: &'hir [ty::GenericParamDef]| { + ctx.uplift_delegation_generic_params(span, generics) }; - let hir_generics = match generics { + let hir_generics = match params { DelegationGenerics::UserSpecified => DelegationGenerics::UserSpecified, - DelegationGenerics::Default(generics) => { - DelegationGenerics::Default(generics.as_mut().map(process_params)) + DelegationGenerics::Default(params) => { + DelegationGenerics::Default(uplift_params(params)) } - DelegationGenerics::SelfAndUserSpecified(generics) => { - DelegationGenerics::SelfAndUserSpecified(generics.as_mut().map(process_params)) + DelegationGenerics::SelfAndUserSpecified(params) => { + DelegationGenerics::SelfAndUserSpecified(uplift_params(params)) + } + DelegationGenerics::TraitImpl(params, user_specified) => { + DelegationGenerics::TraitImpl(uplift_params(params), *user_specified) } }; - *self = HirOrAstGenerics::Hir(hir_generics); + *self = HirOrTyGenerics::Hir(hir_generics); } self @@ -87,81 +107,72 @@ pub(super) fn into_hir_generics( fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> { match self { - HirOrAstGenerics::Ast(_) => hir::Generics::empty(), - HirOrAstGenerics::Hir(hir_generics) => match hir_generics { + HirOrTyGenerics::Ty(_) => hir::Generics::empty(), + HirOrTyGenerics::Hir(hir_generics) => match hir_generics { DelegationGenerics::UserSpecified => hir::Generics::empty(), DelegationGenerics::Default(generics) - | DelegationGenerics::SelfAndUserSpecified(generics) => { - generics.unwrap_or(hir::Generics::empty()) - } + | DelegationGenerics::SelfAndUserSpecified(generics) + | DelegationGenerics::TraitImpl(generics, _) => generics, }, } } pub(super) fn into_generic_args( &self, - ctx: &mut LoweringContext<'_, 'hir>, + ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, add_lifetimes: bool, span: Span, - ) -> Option<&'hir hir::GenericArgs<'hir>> { + ) -> &'hir hir::GenericArgs<'hir> { match self { - HirOrAstGenerics::Ast(_) => { - bug!("Attempting to get generic args before lowering to HIR") + HirOrTyGenerics::Ty(_) => { + bug!("Attempting to get generic args before uplifting to HIR") } - HirOrAstGenerics::Hir(hir_generics) => match hir_generics { - DelegationGenerics::UserSpecified => None, + HirOrTyGenerics::Hir(hir_generics) => match hir_generics { + DelegationGenerics::UserSpecified => hir::GenericArgs::NONE, DelegationGenerics::Default(generics) - | DelegationGenerics::SelfAndUserSpecified(generics) => generics.map(|generics| { + | DelegationGenerics::SelfAndUserSpecified(generics) + | DelegationGenerics::TraitImpl(generics, _) => { ctx.create_generics_args_from_params(generics.params, add_lifetimes, span) - }), + } }, } } - pub(super) fn is_user_specified(&self) -> bool { + pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails { match self { - HirOrAstGenerics::Ast(ast_generics) => ast_generics.is_user_specified(), - HirOrAstGenerics::Hir(hir_generics) => hir_generics.is_user_specified(), + HirOrTyGenerics::Ty(ty_generics) => ty_generics.args_propagation_details(), + HirOrTyGenerics::Hir(hir_generics) => hir_generics.args_propagation_details(), } } } -impl<'a> GenericsGenerationResult<'a> { - fn new(generics: DelegationGenerics) -> GenericsGenerationResult<'a> { - GenericsGenerationResult { - generics: HirOrAstGenerics::Ast(generics), - args_segment_id: None, - } +impl<'hir> GenericsGenerationResult<'hir> { + fn new( + generics: DelegationGenerics<&'hir [ty::GenericParamDef]>, + ) -> GenericsGenerationResult<'hir> { + GenericsGenerationResult { generics: HirOrTyGenerics::Ty(generics), args_segment_id: None } } } impl<'hir> GenericsGenerationResults<'hir> { pub(super) fn all_params( &mut self, - item_id: NodeId, span: Span, - ctx: &mut LoweringContext<'_, 'hir>, + ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, ) -> impl Iterator> { // Now we always call `into_hir_generics` both on child and parent, // however in future we would not do that, when scenarios like // method call will be supported (if HIR generics were not obtained // then it means that we did not propagated them, thus we do not need // to generate params). - let parent = self - .parent - .generics - .into_hir_generics(ctx, item_id, span) - .hir_generics_or_empty() - .params; + let mut create_params = |result: &mut GenericsGenerationResult<'hir>| { + result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().params + }; - let child = self - .child - .generics - .into_hir_generics(ctx, item_id, span) - .hir_generics_or_empty() - .params; + let parent = create_params(&mut self.parent); + let child = create_params(&mut self.child); - // Order generics, firstly we have parent and child lifetimes, + // Order generics, first we have parent and child lifetimes, // then parent and child types and consts. // `generics_of` in `rustc_hir_analysis` will order them anyway, // however we want the order to be consistent in HIR too. @@ -174,92 +185,94 @@ pub(super) fn all_params( .copied() } - /// As we add hack predicates(`'a: 'a`) for all lifetimes (see `lower_delegation_generic_params` + /// As we add hack predicates(`'a: 'a`) for all lifetimes (see `uplift_delegation_generic_params` /// and `generate_lifetime_predicate` functions) we need to add them to delegation generics. /// Those predicates will not affect resulting predicate inheritance and folding /// in `rustc_hir_analysis`, as we inherit all predicates from delegation signature. pub(super) fn all_predicates( &mut self, - item_id: NodeId, span: Span, - ctx: &mut LoweringContext<'_, 'hir>, + ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, ) -> impl Iterator> { // Now we always call `into_hir_generics` both on child and parent, // however in future we would not do that, when scenarios like // method call will be supported (if HIR generics were not obtained // then it means that we did not propagated them, thus we do not need // to generate predicates). - self.parent - .generics - .into_hir_generics(ctx, item_id, span) - .hir_generics_or_empty() - .predicates - .into_iter() - .chain( - self.child - .generics - .into_hir_generics(ctx, item_id, span) - .hir_generics_or_empty() - .predicates - .into_iter(), - ) - .copied() + let mut create_predicates = |result: &mut GenericsGenerationResult<'hir>| { + result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().predicates + }; + + let parent = create_predicates(&mut self.parent); + let child = create_predicates(&mut self.child); + + parent.into_iter().chain(child).copied() } } -impl<'hir> LoweringContext<'_, 'hir> { - pub(super) fn lower_delegation_generics( +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { + pub(super) fn uplift_delegation_generics( &mut self, delegation: &Delegation, - root_fn_id: DefId, + sig_id: DefId, item_id: NodeId, - span: Span, ) -> GenericsGenerationResults<'hir> { - let delegation_in_free_ctx = !matches!( - self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))), - DefKind::Trait | DefKind::Impl { .. } - ); - - let root_function_in_trait = - matches!(self.tcx.def_kind(self.tcx.parent(root_fn_id)), DefKind::Trait); - - let generate_self = delegation_in_free_ctx && root_function_in_trait; - - let parent_generics_factory = |this: &mut Self, user_specified: bool| { - this.get_parent_generics( - this.tcx.parent(root_fn_id), - generate_self, - user_specified, - span, - ) - }; + let delegation_parent_kind = + self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))); let segments = &delegation.path.segments; let len = segments.len(); + let child_user_specified = segments[len - 1].args.is_some(); + + let sig_params = &self.tcx.generics_of(sig_id).own_params[..]; + + // If we are in trait impl always generate function whose generics matches + // those that are defined in trait. + if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) { + // Considering parent generics, during signature inheritance + // we will take those args that are in trait impl header trait ref. + let parent = GenericsGenerationResult::new(DelegationGenerics::TraitImpl(&[], true)); + + let child = DelegationGenerics::TraitImpl(sig_params, child_user_specified); + let child = GenericsGenerationResult::new(child); + + return GenericsGenerationResults { parent, child }; + } + + let delegation_in_free_ctx = + !matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. }); + + let sig_parent = self.tcx.parent(sig_id); + let sig_in_trait = matches!(self.tcx.def_kind(sig_parent), DefKind::Trait); let can_add_generics_to_parent = len >= 2 && self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| { matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias) }); + let generate_self = delegation_in_free_ctx && sig_in_trait; let parent_generics = if can_add_generics_to_parent { + let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..]; + if segments[len - 2].args.is_some() { if generate_self { - DelegationGenerics::SelfAndUserSpecified(parent_generics_factory(self, true)) + // Take only first Self parameter, it is trait so Self must be present. + DelegationGenerics::SelfAndUserSpecified(&sig_parent_params[..1]) } else { DelegationGenerics::UserSpecified } } else { - DelegationGenerics::Default(parent_generics_factory(self, false)) + let skip_self = usize::from(!generate_self); + DelegationGenerics::Default(&sig_parent_params[skip_self..]) } } else { - DelegationGenerics::Default(None) + DelegationGenerics::<&'hir [ty::GenericParamDef]>::Default(&[]) }; - let child_generics = if segments[len - 1].args.is_some() { + let child_generics = if child_user_specified { DelegationGenerics::UserSpecified } else { - DelegationGenerics::Default(self.get_fn_like_generics(root_fn_id, span)) + DelegationGenerics::Default(sig_params) }; GenericsGenerationResults { @@ -268,61 +281,70 @@ pub(super) fn lower_delegation_generics( } } - fn lower_delegation_generic_params( + fn uplift_delegation_generic_params( &mut self, - item_id: NodeId, span: Span, - params: &mut ThinVec, + params: &'hir [ty::GenericParamDef], ) -> &'hir hir::Generics<'hir> { - for p in params.iter_mut() { - // We want to create completely new params, so we generate - // a new id, otherwise assertions will be triggered. - p.id = self.next_node_id(); + let params = self.arena.alloc_from_iter(params.iter().map(|p| { + let def_kind = match p.kind { + GenericParamDefKind::Lifetime => DefKind::LifetimeParam, + GenericParamDefKind::Type { .. } => DefKind::TyParam, + GenericParamDefKind::Const { .. } => DefKind::ConstParam, + }; - // Remove default params, as they are not supported on functions - // and there will duplicate DefId when we try to lower them later. - match &mut p.kind { - GenericParamKind::Lifetime => {} - GenericParamKind::Type { default } => *default = None, - GenericParamKind::Const { default, .. } => *default = None, + let param_ident = Ident::new(p.name, span); + let def_name = Some(param_ident.name); + let path_data = def_kind.def_path_data(def_name); + let node_id = self.next_node_id(); + + let def_id = self.create_def(node_id, def_name, def_kind, path_data, span); + + let kind = match p.kind { + GenericParamDefKind::Lifetime => { + hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } + } + GenericParamDefKind::Type { synthetic, .. } => { + hir::GenericParamKind::Type { default: None, synthetic } + } + GenericParamDefKind::Const { .. } => { + let hir_id = self.next_id(); + let kind = hir::TyKind::InferDelegation(hir::InferDelegation::DefId(p.def_id)); + + hir::GenericParamKind::Const { + ty: self.arena.alloc(hir::Ty { kind, hir_id, span }), + default: None, + } + } + }; + + // Important: we don't use `self.next_id()` as we want to execute + // `lower_node_id` routine so param's id is added to `self.children`. + let hir_id = self.lower_node_id(node_id); + + hir::GenericParam { + hir_id, + colon_span: Some(span), + def_id, + kind, + name: hir::ParamName::Plain(param_ident), + pure_wrt_drop: p.pure_wrt_drop, + source: hir::GenericParamSource::Generics, + span, } - - // Note that we use self.disambiguator here, if we will create new every time - // we will get ICE if params have the same name. - self.resolver.node_id_to_def_id.insert( - p.id, - self.tcx - .create_def( - self.resolver.node_id_to_def_id[&item_id], - Some(p.ident.name), - match p.kind { - GenericParamKind::Lifetime => DefKind::LifetimeParam, - GenericParamKind::Type { .. } => DefKind::TyParam, - GenericParamKind::Const { .. } => DefKind::ConstParam, - }, - None, - &mut self.disambiguator, - ) - .def_id(), - ); - } - - // Fallback to default generic param lowering, we modified them in the loop above. - let params = self.arena.alloc_from_iter( - params.iter().map(|p| self.lower_generic_param(p, hir::GenericParamSource::Generics)), - ); + })); // HACK: for now we generate predicates such that all lifetimes are early bound, // we can not not generate early-bound lifetimes, but we can't know which of them // are late-bound at this level of compilation. - // FIXME(fn_delegation): proper support for late bound lifetimes. + let predicates = + self.arena.alloc_from_iter(params.iter().filter_map(|p| { + p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span)) + })); + self.arena.alloc(hir::Generics { params, - predicates: self.arena.alloc_from_iter( - params - .iter() - .filter_map(|p| p.is_lifetime().then(|| self.generate_lifetime_predicate(p))), - ), + predicates, has_where_clause_predicates: false, where_clause_span: span, span, @@ -332,22 +354,21 @@ fn lower_delegation_generic_params( fn generate_lifetime_predicate( &mut self, p: &hir::GenericParam<'hir>, + span: Span, ) -> hir::WherePredicate<'hir> { let create_lifetime = |this: &mut Self| -> &'hir hir::Lifetime { this.arena.alloc(hir::Lifetime { hir_id: this.next_id(), ident: p.name.ident(), - kind: rustc_hir::LifetimeKind::Param(p.def_id), - source: rustc_hir::LifetimeSource::Path { - angle_brackets: rustc_hir::AngleBrackets::Full, - }, - syntax: rustc_hir::LifetimeSyntax::ExplicitBound, + kind: hir::LifetimeKind::Param(p.def_id), + source: hir::LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full }, + syntax: hir::LifetimeSyntax::ExplicitBound, }) }; hir::WherePredicate { hir_id: self.next_id(), - span: DUMMY_SP, + span, kind: self.arena.alloc(hir::WherePredicateKind::RegionPredicate( hir::WhereRegionPredicate { in_where_clause: true, @@ -369,7 +390,7 @@ fn create_generics_args_from_params( self.arena.alloc(hir::GenericArgs { args: self.arena.alloc_from_iter(params.iter().filter_map(|p| { // Skip self generic arg, we do not need to propagate it. - if p.name.ident().name == kw::SelfUpper { + if p.name.ident().name == kw::SelfUpper || p.is_impl_trait() { return None; } @@ -433,146 +454,4 @@ fn create_generics_args_from_params( span_ext: span, }) } - - fn get_fn_like_generics(&mut self, id: DefId, span: Span) -> Option { - if let Some(local_id) = id.as_local() { - match self.ast_index.get(local_id) { - Some(AstOwner::Item(item)) if let ItemKind::Fn(f) = &item.kind => { - Some(f.generics.clone()) - } - Some(AstOwner::AssocItem(item, _)) if let AssocItemKind::Fn(f) = &item.kind => { - Some(f.generics.clone()) - } - _ => None, - } - } else { - self.get_external_generics(id, false, span) - } - } - - fn get_external_generics( - &mut self, - id: DefId, - processing_parent: bool, - span: Span, - ) -> Option { - let generics = self.tcx.generics_of(id); - if generics.own_params.is_empty() { - return None; - } - - // Skip first Self parameter if we are in trait, it will be added later. - let to_skip = (processing_parent && generics.has_self) as usize; - - Some(Generics { - params: generics - .own_params - .iter() - .skip(to_skip) - .map(|p| GenericParam { - attrs: Default::default(), - bounds: Default::default(), - colon_span: None, - id: self.next_node_id(), - ident: Ident::with_dummy_span(p.name), - is_placeholder: false, - kind: match p.kind { - GenericParamDefKind::Lifetime => GenericParamKind::Lifetime, - GenericParamDefKind::Type { .. } => { - GenericParamKind::Type { default: None } - } - GenericParamDefKind::Const { .. } => self.map_const_kind(p, span), - }, - }) - .collect(), - where_clause: Default::default(), - span: DUMMY_SP, - }) - } - - fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericParamKind { - let const_type = self.tcx.type_of(p.def_id).instantiate_identity(); - - let (type_symbol, res) = match const_type.kind() { - ty::Bool => (sym::bool, Res::PrimTy(hir::PrimTy::Bool)), - ty::Uint(uint) => (uint.name(), Res::PrimTy(hir::PrimTy::Uint(*uint))), - ty::Int(int) => (int.name(), Res::PrimTy(hir::PrimTy::Int(*int))), - ty::Char => (sym::char, Res::PrimTy(hir::PrimTy::Char)), - _ => { - self.tcx - .dcx() - .span_delayed_bug(span, format!("Unexpected const type: {}", const_type)); - - (sym::dummy, Res::Err) - } - }; - - let node_id = self.next_node_id(); - - self.resolver.partial_res_map.insert(node_id, hir::def::PartialRes::new(res)); - - GenericParamKind::Const { - ty: Box::new(Ty { - id: node_id, - kind: TyKind::Path( - None, - Path { - segments: thin_vec![PathSegment { - ident: Ident::with_dummy_span(type_symbol), - id: self.next_node_id(), - args: None - }], - span: DUMMY_SP, - tokens: None, - }, - ), - span: DUMMY_SP, - tokens: None, - }), - span: DUMMY_SP, - default: None, - } - } - - fn get_parent_generics( - &mut self, - id: DefId, - add_self: bool, - user_specified: bool, - span: Span, - ) -> Option { - // If args are user-specified we still maybe need to add self. - let mut generics = if user_specified { - None - } else { - if let Some(local_id) = id.as_local() { - if let Some(AstOwner::Item(item)) = self.ast_index.get(local_id) - && matches!(item.kind, ItemKind::Trait(..)) - { - item.opt_generics().cloned() - } else { - None - } - } else { - self.get_external_generics(id, true, span) - } - }; - - if add_self { - generics.get_or_insert_default().params.insert( - 0, - GenericParam { - id: self.next_node_id(), - ident: Ident::new(kw::SelfUpper, DUMMY_SP), - attrs: Default::default(), - bounds: vec![], - is_placeholder: false, - kind: GenericParamKind::Type { default: None }, - colon_span: None, - }, - ); - } - - generics - } } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 1eb72727df66..95b8bb48c6a9 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,5 +1,5 @@ -use rustc_errors::DiagArgFromDisplay; use rustc_errors::codes::*; +use rustc_errors::{DiagArgFromDisplay, DiagSymbolList}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -191,10 +191,10 @@ pub(crate) struct ClobberAbiNotSupported { #[derive(Diagnostic)] #[note("the following ABIs are supported on this target: {$supported_abis}")] #[diag("invalid ABI for `clobber_abi`")] -pub(crate) struct InvalidAbiClobberAbi { +pub(crate) struct InvalidAbiClobberAbi<'a> { #[primary_span] pub abi_span: Span, - pub supported_abis: String, + pub supported_abis: DiagSymbolList<&'a str>, } #[derive(Diagnostic)] @@ -215,17 +215,18 @@ pub(crate) struct InvalidRegisterClass { #[primary_span] pub op_span: Span, pub reg_class: Symbol, - pub supported_register_classes: String, + pub supported_register_classes: DiagSymbolList, } #[derive(Diagnostic)] -#[diag("invalid asm template modifier for this register class")] +#[diag("invalid asm template modifier `{$modifier}` for this register class")] pub(crate) struct InvalidAsmTemplateModifierRegClass { #[primary_span] #[label("template modifier")] pub placeholder_span: Span, #[label("argument")] pub op_span: Span, + pub modifier: String, #[subdiagnostic] pub sub: InvalidAsmTemplateModifierRegClassSub, } @@ -235,7 +236,7 @@ pub(crate) enum InvalidAsmTemplateModifierRegClassSub { #[note( "the `{$class_name}` register class supports the following template modifiers: {$modifiers}" )] - SupportModifier { class_name: Symbol, modifiers: String }, + SupportModifier { class_name: Symbol, modifiers: DiagSymbolList }, #[note("the `{$class_name}` register class does not support template modifiers")] DoesNotSupportModifier { class_name: Symbol }, } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4a2992038003..b6bc122051cb 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -13,8 +13,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; -use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{ByteSymbol, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; +use rustc_span::{ByteSymbol, DUMMY_SP, DesugaringKind, Ident, Span, Spanned, Symbol, respan, sym}; use thin_vec::{ThinVec, thin_vec}; use visit::{Visitor, walk_expr}; @@ -53,7 +52,7 @@ fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result { } } -impl<'hir> LoweringContext<'_, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { fn lower_exprs(&mut self, exprs: &[Box]) -> &'hir [hir::Expr<'hir>] { self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x))) } @@ -231,6 +230,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { e.id, expr_hir_id, *coroutine_kind, + *constness, fn_decl, body, *fn_decl_span, @@ -640,7 +640,7 @@ fn wrap_in_try_constructor( fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { let pat = self.lower_pat(&arm.pat); - let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); + let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm); @@ -663,7 +663,7 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { } else if let Some(body) = &arm.body { self.dcx().emit_err(NeverPatternWithBody { span: body.span }); } else if let Some(g) = &arm.guard { - self.dcx().emit_err(NeverPatternWithGuard { span: g.span }); + self.dcx().emit_err(NeverPatternWithGuard { span: g.span() }); } // We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never @@ -1061,7 +1061,7 @@ fn lower_expr_closure( binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, - constness: Const, + mut constness: Const, movability: Movability, decl: &FnDecl, body: &Expr, @@ -1071,11 +1071,18 @@ fn lower_expr_closure( let closure_def_id = self.local_def_id(closure_id); let (binder_clause, generic_params) = self.lower_closure_binder(binder); + if let Const::Yes(span) = constness { + if !self.is_in_const_context { + self.dcx().span_err(span, "cannot use `const` closures outside of const contexts"); + constness = Const::No; + } + } + let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { let mut coroutine_kind = find_attr!(attrs, Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable)); // FIXME(contracts): Support contracts on closures? - let body_id = this.lower_fn_body(decl, None, |this| { + let body_id = this.lower_fn_body(decl, None, constness, |this| { this.coroutine_kind = coroutine_kind; let e = this.lower_expr_mut(body); coroutine_kind = this.coroutine_kind; @@ -1158,6 +1165,7 @@ fn lower_expr_coroutine_closure( closure_id: NodeId, closure_hir_id: HirId, coroutine_kind: CoroutineKind, + constness: Const, decl: &FnDecl, body: &Expr, fn_decl_span: Span, @@ -1204,6 +1212,10 @@ fn lower_expr_coroutine_closure( let fn_decl = self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None); + if let Const::Yes(span) = constness { + self.dcx().span_err(span, "const coroutines are not supported"); + } + let c = self.arena.alloc(hir::Closure { def_id: closure_def_id, binder: binder_clause, @@ -1217,7 +1229,7 @@ fn lower_expr_coroutine_closure( // knows that a `FnDecl` output type like `-> &str` actually means // "coroutine that returns &str", rather than directly returning a `&str`. kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring), - constness: hir::Constness::NotConst, + constness: self.lower_constness(constness), }); hir::ExprKind::Closure(c) } @@ -1232,7 +1244,10 @@ fn lower_expr_assign( whole_span: Span, ) -> hir::ExprKind<'hir> { // Return early in case of an ordinary assignment. - fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool { + fn is_ordinary<'hir>( + lower_ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, + lhs: &Expr, + ) -> bool { match &lhs.kind { ExprKind::Array(..) | ExprKind::Struct(..) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 602635af1324..1f1f86f7edfd 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -7,8 +7,9 @@ use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym}; use super::LoweringContext; +use crate::ResolverAstLoweringExt; -impl<'hir> LoweringContext<'_, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> { // Never call the const constructor of `fmt::Arguments` if the // format_args!() had any arguments _before_ flattening/inlining. @@ -230,7 +231,7 @@ enum ArgumentType { /// ::new_…(arg) /// ``` fn make_argument<'hir>( - ctx: &mut LoweringContext<'_, 'hir>, + ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, sp: Span, arg: &'hir hir::Expr<'hir>, ty: ArgumentType, @@ -277,7 +278,7 @@ fn make_count( } fn expand_format_args<'hir>( - ctx: &mut LoweringContext<'_, 'hir>, + ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, macsp: Span, fmt: &FormatArgs, allow_const: bool, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ed78b77a704f..fa103099e643 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,6 +1,9 @@ +use std::mem; + use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::attrs::{AttributeKind, EiiImplResolution}; use rustc_hir::def::{DefKind, PerNS, Res}; @@ -10,7 +13,7 @@ }; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; -use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; @@ -25,11 +28,31 @@ RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt, }; -pub(super) struct ItemLowerer<'a, 'hir> { +/// Wraps either IndexVec (during `hir_crate`), which acts like a primary +/// storage for most of the MaybeOwners, or FxIndexMap during delayed AST -> HIR +/// lowering of delegations (`lower_delayed_owner`), +/// in this case we can not modify already created IndexVec, so we use other map. +pub(super) enum Owners<'a, 'hir> { + IndexVec(&'a mut IndexVec>), + Map(&'a mut FxIndexMap>), +} + +impl<'hir> Owners<'_, 'hir> { + fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> { + match self { + Owners::IndexVec(index_vec) => { + index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom) + } + Owners::Map(map) => map.entry(def_id).or_insert(hir::MaybeOwner::Phantom), + } + } +} + +pub(super) struct ItemLowerer<'a, 'hir, R> { pub(super) tcx: TyCtxt<'hir>, - pub(super) resolver: &'a mut ResolverAstLowering<'hir>, + pub(super) resolver: &'a mut R, pub(super) ast_index: &'a IndexSlice>, - pub(super) owners: &'a mut IndexVec>, + pub(super) owners: Owners<'a, 'hir>, } /// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span @@ -51,17 +74,17 @@ fn add_ty_alias_where_clause( if before.0 || !after.0 { before } else { after }; } -impl<'a, 'hir> ItemLowerer<'a, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> { fn with_lctx( &mut self, owner: NodeId, - f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, + f: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::OwnerNode<'hir>, ) { - let mut lctx = LoweringContext::new(self.tcx, self.ast_index, self.resolver); + let mut lctx = LoweringContext::new(self.tcx, self.resolver); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { - let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + let owner = self.owners.get_or_insert_mut(def_id); assert!( matches!(owner, hir::MaybeOwner::Phantom), "duplicate copy of {def_id:?} in lctx.children" @@ -71,13 +94,13 @@ fn with_lctx( } pub(super) fn lower_node(&mut self, def_id: LocalDefId) { - let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + let owner = self.owners.get_or_insert_mut(def_id); if let hir::MaybeOwner::Phantom = owner { let node = self.ast_index[def_id]; match node { AstOwner::NonOwner => {} AstOwner::Crate(c) => { - assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); + assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? @@ -99,7 +122,7 @@ pub(super) fn lower_node(&mut self, def_id: LocalDefId) { } } -impl<'hir> LoweringContext<'_, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { pub(super) fn lower_mod( &mut self, items: &[Box], @@ -345,6 +368,7 @@ fn lower_item_kind( body.as_deref(), attrs, contract.as_deref(), + header.constness, ); let itctx = ImplTraitContext::Universal; @@ -1024,6 +1048,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { Some(body), attrs, contract.as_deref(), + sig.header.constness, ); let (generics, sig) = self.lower_method_sig( generics, @@ -1217,6 +1242,7 @@ fn lower_impl_item( body.as_deref(), attrs, contract.as_deref(), + sig.header.constness, ); let (generics, sig) = self.lower_method_sig( generics, @@ -1346,11 +1372,13 @@ pub(super) fn lower_body( f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>), ) -> hir::BodyId { let prev_coroutine_kind = self.coroutine_kind.take(); + let prev_is_in_const_context = mem::take(&mut self.is_in_const_context); let task_context = self.task_context.take(); let (parameters, result) = f(self); let body_id = self.record_body(parameters, result); self.task_context = task_context; self.coroutine_kind = prev_coroutine_kind; + self.is_in_const_context = prev_is_in_const_context; body_id } @@ -1369,9 +1397,13 @@ pub(super) fn lower_fn_body( &mut self, decl: &FnDecl, contract: Option<&FnContract>, + constness: Const, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::BodyId { self.lower_body(|this| { + if let Const::Yes(_) = constness { + this.is_in_const_context = true; + } let params = this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x))); @@ -1389,8 +1421,9 @@ fn lower_fn_body_block( decl: &FnDecl, body: &Block, contract: Option<&FnContract>, + constness: Const, ) -> hir::BodyId { - self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) + self.lower_fn_body(decl, contract, constness, |this| this.lower_block_expr(body)) } pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { @@ -1398,7 +1431,10 @@ pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hi ( &[], match expr { - Some(expr) => this.lower_expr_mut(expr), + Some(expr) => { + this.is_in_const_context = true; + this.lower_expr_mut(expr) + } None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), }, ) @@ -1417,12 +1453,13 @@ fn lower_maybe_coroutine_body( body: Option<&Block>, attrs: &'hir [hir::Attribute], contract: Option<&FnContract>, + constness: Const, ) -> hir::BodyId { let Some(body) = body else { // Functions without a body are an error, except if this is an intrinsic. For those we // create a fake body so that the entire rest of the compiler doesn't have to deal with // this as a special case. - return self.lower_fn_body(decl, contract, |this| { + return self.lower_fn_body(decl, contract, constness, |this| { if find_attr!(attrs, RustcIntrinsic) || this.tcx.is_sdylib_interface_build() { let span = this.lower_span(span); let empty_block = hir::Block { @@ -1447,7 +1484,7 @@ fn lower_maybe_coroutine_body( }; let Some(coroutine_kind) = coroutine_kind else { // Typical case: not a coroutine. - return self.lower_fn_body_block(decl, body, contract); + return self.lower_fn_body_block(decl, body, contract, constness); }; // FIXME(contracts): Support contracts on async fn. self.lower_body(|this| { @@ -1475,7 +1512,7 @@ fn lower_maybe_coroutine_body( pub(crate) fn lower_coroutine_body_with_moved_arguments( &mut self, decl: &FnDecl, - lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>, + lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::Expr<'hir>, fn_decl_span: Span, body_span: Span, coroutine_kind: CoroutineKind, @@ -1612,7 +1649,7 @@ pub(crate) fn lower_coroutine_body_with_moved_arguments( parameters.push(new_parameter); } - let mkbody = |this: &mut LoweringContext<'_, 'hir>| { + let mkbody = |this: &mut LoweringContext<'_, 'hir, R>| { // Create a block from the user's function body: let user_body = lower_body(this); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c3525d124670..5fcc8f016119 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -42,9 +42,10 @@ use rustc_ast::{self as ast, *}; use rustc_attr_parsing::{AttributeParser, Late, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::spawn; +use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; @@ -57,8 +58,9 @@ }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; +use rustc_middle::hir::{self as mid_hir}; use rustc_middle::span_bug; -use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; +use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt}; use rustc_session::parse::add_feature_diagnostics; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; @@ -67,6 +69,7 @@ use tracing::{debug, instrument, trace}; use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; +use crate::item::Owners; macro_rules! arena_vec { ($this:expr; $($x:expr),*) => ( @@ -87,18 +90,9 @@ macro_rules! arena_vec { mod path; pub mod stability; -struct LoweringContext<'a, 'hir> { +struct LoweringContext<'a, 'hir, R> { tcx: TyCtxt<'hir>, - - // During lowering of delegation we need to access AST of other functions - // in order to properly propagate generics, we could have done it at resolve - // stage, however it will require either to firstly identify functions that - // are being reused and store their generics, or to store generics of all functions - // in resolver. This approach helps with those problems, as functions that are reused - // will be in AST index. - ast_index: &'a IndexSlice>, - - resolver: &'a mut ResolverAstLowering<'hir>, + resolver: &'a mut R, disambiguator: DisambiguatorState, /// Used to allocate HIR nodes. @@ -129,6 +123,7 @@ struct LoweringContext<'a, 'hir> { loop_scope: Option, is_in_loop_condition: bool, is_in_dyn_type: bool, + is_in_const_context: bool, current_hir_id_owner: hir::OwnerId, item_local_id_counter: hir::ItemLocalId, @@ -157,17 +152,11 @@ struct LoweringContext<'a, 'hir> { attribute_parser: AttributeParser<'hir>, } -impl<'a, 'hir> LoweringContext<'a, 'hir> { - fn new( - tcx: TyCtxt<'hir>, - ast_index: &'a IndexSlice>, - resolver: &'a mut ResolverAstLowering<'hir>, - ) -> Self { +impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> { + fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self { let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect(); Self { - // Pseudo-globals. tcx, - ast_index, resolver, disambiguator: DisambiguatorState::new(), arena: tcx.hir_arena, @@ -190,6 +179,7 @@ fn new( loop_scope: None, is_in_loop_condition: false, is_in_dyn_type: false, + is_in_const_context: false, coroutine_kind: None, task_context: None, current_item: None, @@ -246,9 +236,84 @@ fn lower(&self, span: Span) -> Span { } } -#[extension(trait ResolverAstLoweringExt)] -impl ResolverAstLowering<'_> { - fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option> { +struct ResolverDelayedAstLowering<'a, 'tcx> { + node_id_to_def_id: NodeMap, + partial_res_map: NodeMap, + next_node_id: NodeId, + base: &'a ResolverAstLowering<'tcx>, +} + +// FIXME(fn_delegation): delegate this trait impl to `self.base` +impl<'a, 'tcx> ResolverAstLoweringExt<'tcx> for ResolverDelayedAstLowering<'a, 'tcx> { + fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option> { + self.base.legacy_const_generic_args(expr, tcx) + } + + fn get_partial_res(&self, id: NodeId) -> Option { + self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id)) + } + + fn get_import_res(&self, id: NodeId) -> PerNS>> { + self.base.get_import_res(id) + } + + fn get_label_res(&self, id: NodeId) -> Option { + self.base.get_label_res(id) + } + + fn get_lifetime_res(&self, id: NodeId) -> Option { + self.base.get_lifetime_res(id) + } + + fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { + self.base.extra_lifetime_params(id) + } + + fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> { + self.base.delegation_info(id) + } + + fn opt_local_def_id(&self, id: NodeId) -> Option { + self.node_id_to_def_id.get(&id).copied().or_else(|| self.base.opt_local_def_id(id)) + } + + fn local_def_id(&self, id: NodeId) -> LocalDefId { + self.opt_local_def_id(id).expect("must have def_id") + } + + fn lifetime_elision_allowed(&self, id: NodeId) -> bool { + self.base.lifetime_elision_allowed(id) + } + + fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) { + self.node_id_to_def_id.insert(node_id, def_id); + } + + fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) { + self.partial_res_map.insert(node_id, res); + } + + fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> { + self.base.trait_candidates(node_id) + } + + #[inline] + fn next_node_id(&mut self) -> NodeId { + next_node_id(&mut self.next_node_id) + } +} + +fn next_node_id(current_id: &mut NodeId) -> NodeId { + let start = *current_id; + let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); + *current_id = ast::NodeId::from_u32(next); + + start +} + +#[extension(trait ResolverAstLoweringExt<'tcx>)] +impl<'tcx> ResolverAstLowering<'tcx> { + fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option> { let ExprKind::Path(None, path) = &expr.kind else { return None; }; @@ -259,7 +324,7 @@ fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option Option { /// /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring /// should appear at the enclosing `PolyTraitRef`. - fn extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { + fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default() } + + fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> { + self.delegation_infos.get(&id) + } + + fn opt_local_def_id(&self, id: NodeId) -> Option { + self.node_id_to_def_id.get(&id).copied() + } + + fn local_def_id(&self, id: NodeId) -> LocalDefId { + self.opt_local_def_id(id).expect("must have def_id") + } + + fn lifetime_elision_allowed(&self, id: NodeId) -> bool { + self.lifetime_elision_allowed.contains(&id) + } + + fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) { + self.node_id_to_def_id.insert(node_id, def_id); + } + + fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) { + self.partial_res_map.insert(node_id, res); + } + + fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> { + self.trait_map.get(&node_id).copied() + } + + #[inline] + fn next_node_id(&mut self) -> NodeId { + next_node_id(&mut self.next_node_id) + } } /// How relaxed bounds `?Trait` should be treated. @@ -444,42 +542,43 @@ enum TryBlockScope { Heterogeneous(HirId), } -fn index_crate<'a>( - node_id_to_def_id: &NodeMap, +fn index_crate<'a, 'b>( + resolver: &'b impl ResolverAstLoweringExt<'a>, krate: &'a Crate, ) -> IndexVec> { - let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() }; + let mut indexer = Indexer { resolver, index: IndexVec::new() }; *indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner) = AstOwner::Crate(krate); visit::walk_crate(&mut indexer, krate); + return indexer.index; - struct Indexer<'s, 'a> { - node_id_to_def_id: &'s NodeMap, + struct Indexer<'a, 'b, R> { + resolver: &'b R, index: IndexVec>, } - impl<'a> visit::Visitor<'a> for Indexer<'_, 'a> { + impl<'a, 'b, R: ResolverAstLoweringExt<'a>> visit::Visitor<'a> for Indexer<'a, 'b, R> { fn visit_attribute(&mut self, _: &'a Attribute) { // We do not want to lower expressions that appear in attributes, // as they are not accessible to the rest of the HIR. } fn visit_item(&mut self, item: &'a ast::Item) { - let def_id = self.node_id_to_def_id[&item.id]; + let def_id = self.resolver.local_def_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item); visit::walk_item(self, item) } fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) { - let def_id = self.node_id_to_def_id[&item.id]; + let def_id = self.resolver.local_def_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::AssocItem(item, ctxt); visit::walk_assoc_item(self, item, ctxt); } fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) { - let def_id = self.node_id_to_def_id[&item.id]; + let def_id = self.resolver.local_def_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::ForeignItem(item); visit::walk_item(self, item); @@ -510,8 +609,7 @@ fn compute_hir_hash( }) } -pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { - let sess = tcx.sess; +pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { // Queries that borrow `resolver_for_lowering`. tcx.ensure_done().output_filenames(()); tcx.ensure_done().early_lint_checks(()); @@ -519,7 +617,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { tcx.ensure_done().get_lang_items(()); let (mut resolver, krate) = tcx.resolver_for_lowering().steal(); - let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); + let ast_index = index_crate(&resolver, &krate); let mut owners = IndexVec::from_fn_n( |_| hir::MaybeOwner::Phantom, tcx.definitions_untracked().def_index_count(), @@ -529,25 +627,60 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { tcx, resolver: &mut resolver, ast_index: &ast_index, - owners: &mut owners, + owners: Owners::IndexVec(&mut owners), }; + + let mut delayed_ids: FxIndexSet = Default::default(); + for def_id in ast_index.indices() { - lowerer.lower_node(def_id); + match &ast_index[def_id] { + AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. }) + | AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => { + delayed_ids.insert(def_id); + } + _ => lowerer.lower_node(def_id), + }; } - drop(ast_index); - - // Drop AST to free memory. It can be expensive so try to drop it on a separate thread. - let prof = sess.prof.clone(); - spawn(move || { - let _timer = prof.verbose_generic_activity("drop_ast"); - drop(krate); - }); - // Don't hash unless necessary, because it's expensive. let opt_hir_hash = if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None }; - hir::Crate { owners, opt_hir_hash } + + let delayed_resolver = Steal::new((resolver, krate)); + mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash) +} + +/// Lowers an AST owner corresponding to `def_id`, now only delegations are lowered this way. +pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let krate = tcx.hir_crate(()); + + let (resolver, krate) = &*krate.delayed_resolver.borrow(); + + // FIXME!!!(fn_delegation): make ast index lifetime same as resolver, + // as it is too bad to reindex whole crate on each delegation lowering. + let ast_index = index_crate(resolver, krate); + + let mut resolver = ResolverDelayedAstLowering { + next_node_id: resolver.next_node_id, + partial_res_map: Default::default(), + node_id_to_def_id: Default::default(), + base: resolver, + }; + + let mut map = Default::default(); + + let mut lowerer = item::ItemLowerer { + tcx, + resolver: &mut resolver, + ast_index: &ast_index, + owners: Owners::Map(&mut map), + }; + + lowerer.lower_node(def_id); + + for (child_def_id, owner) in map { + tcx.feed_delayed_owner(child_def_id, owner); + } } #[derive(Copy, Clone, PartialEq, Debug)] @@ -577,7 +710,7 @@ enum GenericArgsMode { Silence, } -impl<'a, 'hir> LoweringContext<'a, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { fn create_def( &mut self, node_id: ast::NodeId, @@ -603,22 +736,19 @@ fn create_def( .def_id(); debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); - self.resolver.node_id_to_def_id.insert(node_id, def_id); + self.resolver.insert_new_def_id(node_id, def_id); def_id } fn next_node_id(&mut self) -> NodeId { - let start = self.resolver.next_node_id; - let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); - self.resolver.next_node_id = ast::NodeId::from_u32(next); - start + self.resolver.next_node_id() } /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any). fn opt_local_def_id(&self, node: NodeId) -> Option { - self.resolver.node_id_to_def_id.get(&node).copied() + self.resolver.opt_local_def_id(node) } fn local_def_id(&self, node: NodeId) -> LocalDefId { @@ -747,7 +877,7 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId { self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); } - if let Some(&traits) = self.resolver.trait_map.get(&ast_node_id) { + if let Some(traits) = self.resolver.trait_candidates(ast_node_id) { self.trait_map.insert(hir_id.local_id, traits); } @@ -1135,7 +1265,7 @@ fn lower_assoc_item_constraint( }; gen_args_ctor.into_generic_args(self) } else { - self.arena.alloc(hir::GenericArgs::none()) + hir::GenericArgs::NONE }; let kind = match &constraint.kind { AssocItemConstraintKind::Equality { term } => { @@ -1267,9 +1397,13 @@ fn lower_generic_arg( } GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap()) } - ast::GenericArg::Const(ct) => GenericArg::Const( - self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(), - ), + ast::GenericArg::Const(ct) => { + let ct = self.lower_anon_const_to_const_arg_and_alloc(ct); + match ct.try_as_ambig_ct() { + Some(ct) => GenericArg::Const(ct), + None => GenericArg::Infer(hir::InferArg { hir_id: ct.hir_id, span: ct.span }), + } + } } } @@ -1764,7 +1898,7 @@ fn lower_fn_decl( inputs, output, c_variadic, - lifetime_elision_allowed: self.resolver.lifetime_elision_allowed.contains(&fn_node_id), + lifetime_elision_allowed: self.resolver.lifetime_elision_allowed(fn_node_id), implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| { let is_mutable_pat = matches!( arg.pat.kind, @@ -2951,7 +3085,10 @@ fn is_empty(&self) -> bool { && self.parenthesized == hir::GenericArgsParentheses::No } - fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> { + fn into_generic_args( + self, + this: &LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, + ) -> &'hir hir::GenericArgs<'hir> { let ga = hir::GenericArgs { args: this.arena.alloc_from_iter(self.args), constraints: self.constraints, diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index e066bce95158..40d42ffb5f4f 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -6,8 +6,7 @@ use rustc_hir::definitions::DefPathData; use rustc_hir::{self as hir, LangItem, Target}; use rustc_middle::span_bug; -use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DesugaringKind, Ident, Span}; +use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -15,7 +14,7 @@ use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt}; use crate::{AllowReturnTypeNotation, ImplTraitPosition}; -impl<'a, 'hir> LoweringContext<'a, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> { self.arena.alloc(self.lower_pat_mut(pattern)) } @@ -134,8 +133,11 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { self.lower_range_end(end, e2.is_some()), ); } - PatKind::Guard(inner, cond) => { - break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond)); + PatKind::Guard(inner, guard) => { + break hir::PatKind::Guard( + self.lower_pat(inner), + self.lower_expr(&guard.cond), + ); } PatKind::Slice(pats) => break self.lower_pat_slice(pats), PatKind::Rest => { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index ec57720387c0..139140af3e03 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use rustc_ast::{self as ast, *}; +use rustc_errors::StashKey; use rustc_hir::def::{DefKind, PartialRes, PerNS, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg}; @@ -19,7 +20,7 @@ LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -impl<'a, 'hir> LoweringContext<'a, 'hir> { +impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { #[instrument(level = "trace", skip(self))] pub(crate) fn lower_qpath( &mut self, @@ -298,7 +299,7 @@ pub(crate) fn lower_path_segment( sym::return_type_notation, ); } - err.emit(); + err.stash(path_span, StashKey::ReturnTypeNotation); ( GenericArgsCtor { args: Default::default(), diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index c8dbba006f6d..dd14e9143569 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -27,10 +27,9 @@ use rustc_ast_pretty::pprust::{self, State}; use rustc_attr_parsing::validate_attr; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{DiagCtxtHandle, LintBuffer}; +use rustc_errors::{DiagCtxtHandle, Diagnostic, LintBuffer}; use rustc_feature::Features; use rustc_session::Session; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES, @@ -1371,11 +1370,16 @@ fn visit_item(&mut self, item: &'a Item) { ItemKind::Struct(ident, generics, vdata) => { self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| { // Scalable vectors can only be tuple structs - let is_scalable_vector = - item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector)); - if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) { - this.dcx() - .emit_err(errors::ScalableVectorNotTupleStruct { span: item.span }); + let scalable_vector_attr = + item.attrs.iter().find(|attr| attr.has_name(sym::rustc_scalable_vector)); + if let Some(attr) = scalable_vector_attr { + if !matches!(vdata, VariantData::Tuple(..)) { + this.dcx() + .emit_err(errors::ScalableVectorNotTupleStruct { span: item.span }); + } + if !self.sess.target.arch.supports_scalable_vectors() { + this.dcx().emit_err(errors::ScalableVectorBadArch { span: attr.span }); + } } match vdata { @@ -1419,7 +1423,7 @@ fn visit_item(&mut self, item: &'a Item) { UNUSED_VISIBILITIES, item.id, item.vis.span, - BuiltinLintDiag::UnusedVisibility(item.vis.span), + errors::UnusedVisibility { span: item.vis.span }, ) } @@ -1482,6 +1486,15 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { ident, sig, ); + + if let Some(attr) = attr::find_by_name(fi.attrs(), sym::track_caller) + && self.extern_mod_abi != Some(ExternAbi::Rust) + { + self.dcx().emit_err(errors::RequiresRustAbi { + track_caller_span: attr.span, + extern_abi_span: self.current_extern_span(), + }); + } } ForeignItemKind::TyAlias(box TyAlias { defaultness, @@ -1667,10 +1680,19 @@ fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId) } if let FnKind::Fn(ctxt, _, fun) = fk - && let Extern::Explicit(str_lit, _) = fun.sig.header.ext + && let Extern::Explicit(str_lit, extern_abi_span) = fun.sig.header.ext && let Ok(abi) = ExternAbi::from_str(str_lit.symbol.as_str()) { self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig); + + if let Some(attr) = attr::find_by_name(attrs, sym::track_caller) + && abi != ExternAbi::Rust + { + self.dcx().emit_err(errors::RequiresRustAbi { + track_caller_span: attr.span, + extern_abi_span, + }); + } } self.check_c_variadic_type(fk, attrs); @@ -1708,14 +1730,19 @@ fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId) Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { if let Some(ident) = ident { - self.lint_buffer.buffer_lint( + let is_foreign = matches!(ctxt, FnCtxt::Foreign); + self.lint_buffer.dyn_buffer_lint( PATTERNS_IN_FNS_WITHOUT_BODY, id, span, - BuiltinLintDiag::PatternsInFnsWithoutBody { - span, - ident, - is_foreign: matches!(ctxt, FnCtxt::Foreign), + move |dcx, level| { + let sub = errors::PatternsInFnsWithoutBodySub { ident, span }; + if is_foreign { + errors::PatternsInFnsWithoutBody::Foreign { sub } + } else { + errors::PatternsInFnsWithoutBody::Bodiless { sub } + } + .into_diag(dcx, level) }, ) } @@ -1805,11 +1832,26 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { Some((right, snippet)) } }; - self.lint_buffer.buffer_lint( + let left_sp = err.span; + self.lint_buffer.dyn_buffer_lint( DEPRECATED_WHERE_CLAUSE_LOCATION, item.id, err.span, - BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg), + move |dcx, level| { + let suggestion = match sugg { + Some((right_sp, sugg)) => { + errors::DeprecatedWhereClauseLocationSugg::MoveToEnd { + left: left_sp, + right: right_sp, + sugg, + } + } + None => { + errors::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp } + } + }; + errors::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level) + }, ); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index edc175b99088..b3a22c0c9954 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1133,3 +1133,89 @@ pub(crate) struct ScalableVectorNotTupleStruct { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag("scalable vectors are not supported on this architecture")] +pub(crate) struct ScalableVectorBadArch { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("`#[track_caller]` can only be used with the Rust ABI", code = E0737)] +pub(crate) struct RequiresRustAbi { + #[primary_span] + #[label("using `#[track_caller]` here")] + pub track_caller_span: Span, + #[label("not using the Rust ABI because of this")] + pub extern_abi_span: Span, +} + +#[derive(Diagnostic)] +#[diag("visibility qualifiers have no effect on `const _` declarations")] +#[note("`const _` does not declare a name, so there is nothing for the qualifier to apply to")] +pub(crate) struct UnusedVisibility { + #[suggestion( + "remove the qualifier", + style = "short", + code = "", + applicability = "machine-applicable" + )] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion( + "remove `mut` from the parameter", + code = "{ident}", + applicability = "machine-applicable" +)] +pub(crate) struct PatternsInFnsWithoutBodySub { + #[primary_span] + pub span: Span, + + pub ident: Ident, +} + +#[derive(Diagnostic)] +pub(crate) enum PatternsInFnsWithoutBody { + #[diag("patterns aren't allowed in foreign function declarations")] + Foreign { + #[subdiagnostic] + sub: PatternsInFnsWithoutBodySub, + }, + #[diag("patterns aren't allowed in functions without bodies")] + Bodiless { + #[subdiagnostic] + sub: PatternsInFnsWithoutBodySub, + }, +} + +#[derive(Diagnostic)] +#[diag("where clause not allowed here")] +#[note("see issue #89122 for more information")] +pub(crate) struct DeprecatedWhereClauseLocation { + #[subdiagnostic] + pub suggestion: DeprecatedWhereClauseLocationSugg, +} + +#[derive(Subdiagnostic)] +pub(crate) enum DeprecatedWhereClauseLocationSugg { + #[multipart_suggestion( + "move it to the end of the type declaration", + applicability = "machine-applicable" + )] + MoveToEnd { + #[suggestion_part(code = "")] + left: Span, + #[suggestion_part(code = "{sugg}")] + right: Span, + + sugg: String, + }, + #[suggestion("remove this `where`", code = "", applicability = "machine-applicable")] + RemoveWhere { + #[primary_span] + span: Span, + }, +} diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 72679d745665..830eb3d6d817 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,5 +1,5 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token}; +use rustc_ast::{self as ast, AttrVec, GenericBound, NodeId, PatKind, attr, token}; use rustc_attr_parsing::AttributeParser; use rustc_errors::msg; use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features}; @@ -7,8 +7,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_session::Session; use rustc_session::parse::{feature_err, feature_warn}; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym}; use thin_vec::ThinVec; use crate::errors; @@ -150,7 +149,14 @@ fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) { for param in params { if !param.bounds.is_empty() { let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); - self.sess.dcx().emit_err(errors::ForbiddenBound { spans }); + if param.bounds.iter().any(|bound| matches!(bound, GenericBound::Trait(_))) { + // Issue #149695 + // Abort immediately otherwise items defined in complex bounds will be lowered into HIR, + // which will cause ICEs when errors of the items visit unlowered parents. + self.sess.dcx().emit_fatal(errors::ForbiddenBound { spans }); + } else { + self.sess.dcx().emit_err(errors::ForbiddenBound { spans }); + } } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c85d6f454321..f46ce8fd7686 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -20,9 +20,11 @@ RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr, }; use rustc_span::edition::Edition; -use rustc_span::source_map::{SourceMap, Spanned}; +use rustc_span::source_map::SourceMap; use rustc_span::symbol::IdentPrinter; -use rustc_span::{BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Symbol, kw, sym}; +use rustc_span::{ + BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Spanned, Symbol, kw, sym, +}; use crate::pp::Breaks::{Consistent, Inconsistent}; use crate::pp::{self, BoxMarker, Breaks}; @@ -327,6 +329,19 @@ fn print_crate_inner<'a>( /// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,` /// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]` /// +/// Returns `true` if both token trees are identifier-like tokens that would +/// merge into a single token if printed without a space between them. +/// E.g. `ident` + `where` would merge into `identwhere`. +fn idents_would_merge(tt1: &TokenTree, tt2: &TokenTree) -> bool { + fn is_ident_like(tt: &TokenTree) -> bool { + matches!( + tt, + TokenTree::Token(Token { kind: token::Ident(..) | token::NtIdent(..), .. }, _,) + ) + } + is_ident_like(tt1) && is_ident_like(tt2) +} + fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { use Delimiter::*; use TokenTree::{Delimited as Del, Token as Tok}; @@ -735,6 +750,23 @@ fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) -> Spacing { TokenTree::Token(token, spacing) => { let token_str = self.token_to_string_ext(token, convert_dollar_crate); self.word(token_str); + // Emit hygiene annotations for identity-bearing tokens, + // matching how print_ident() and print_lifetime() call ann_post(). + match token.kind { + token::Ident(name, _) => { + self.ann_post(Ident::new(name, token.span)); + } + token::NtIdent(ident, _) => { + self.ann_post(ident); + } + token::Lifetime(name, _) => { + self.ann_post(Ident::new(name, token.span)); + } + token::NtLifetime(ident, _) => { + self.ann_post(ident); + } + _ => {} + } if let token::DocComment(..) = token.kind { self.hardbreak() } @@ -792,6 +824,13 @@ fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) { if let Some(next) = iter.peek() { if spacing == Spacing::Alone && space_between(tt, next) { self.space(); + } else if spacing != Spacing::Alone && idents_would_merge(tt, next) { + // When tokens from macro `tt` captures preserve their + // original `Joint`/`JointHidden` spacing, adjacent + // identifier-like tokens can be concatenated without a + // space (e.g. `$x:identwhere`). Insert a space to + // prevent this. + self.space(); } } } @@ -1610,6 +1649,85 @@ fn print_mac(&mut self, m: &ast::MacCall) { ); } + fn inline_asm_template_and_operands<'asm>( + asm: &'asm ast::InlineAsm, + ) -> (String, Vec<&'asm InlineAsmOperand>) { + fn is_explicit_reg(op: &InlineAsmOperand) -> bool { + match op { + InlineAsmOperand::In { reg, .. } + | InlineAsmOperand::Out { reg, .. } + | InlineAsmOperand::InOut { reg, .. } + | InlineAsmOperand::SplitInOut { reg, .. } => { + matches!(reg, InlineAsmRegOrRegClass::Reg(_)) + } + InlineAsmOperand::Const { .. } + | InlineAsmOperand::Sym { .. } + | InlineAsmOperand::Label { .. } => false, + } + } + + // After macro expansion, named operands become positional. The grammar + // requires positional operands to precede explicit register operands, + // so we must reorder when any non-explicit operand follows an explicit + // one. When no reordering is needed, we use the original template + // string and operand order to avoid duplicating the Display logic in + // InlineAsmTemplatePiece. + let needs_reorder = { + let mut seen_explicit = false; + asm.operands.iter().any(|(op, _)| { + if is_explicit_reg(op) { + seen_explicit = true; + false + } else { + seen_explicit + } + }) + }; + + if !needs_reorder { + let template = InlineAsmTemplatePiece::to_string(&asm.template); + let operands = asm.operands.iter().map(|(op, _)| op).collect(); + return (template, operands); + } + + let mut non_explicit = Vec::new(); + let mut explicit = Vec::new(); + for (i, (op, _)) in asm.operands.iter().enumerate() { + if is_explicit_reg(op) { + explicit.push(i); + } else { + non_explicit.push(i); + } + } + let order = non_explicit.into_iter().chain(explicit).collect::>(); + + // Build old-index -> new-index mapping for template renumbering. + let mut old_to_new = vec![0usize; asm.operands.len()]; + for (new_idx, old_idx) in order.iter().copied().enumerate() { + old_to_new[old_idx] = new_idx; + } + + // Remap template placeholder indices and reuse the existing Display + // impl to build the template string. + let remapped = asm + .template + .iter() + .map(|piece| match piece { + InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span } => { + InlineAsmTemplatePiece::Placeholder { + operand_idx: old_to_new[*operand_idx], + modifier: *modifier, + span: *span, + } + } + other => other.clone(), + }) + .collect::>(); + let template = InlineAsmTemplatePiece::to_string(&remapped); + let operands = order.iter().map(|&idx| &asm.operands[idx].0).collect(); + (template, operands) + } + fn print_inline_asm(&mut self, asm: &ast::InlineAsm) { enum AsmArg<'a> { Template(String), @@ -1618,8 +1736,9 @@ enum AsmArg<'a> { Options(InlineAsmOptions), } - let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))]; - args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o))); + let (template, operands) = Self::inline_asm_template_and_operands(asm); + let mut args = vec![AsmArg::Template(template)]; + args.extend(operands.into_iter().map(AsmArg::Operand)); for (abi, _) in &asm.clobber_abis { args.push(AsmArg::ClobberAbi(*abi)); } @@ -1747,6 +1866,23 @@ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_pa } } + /// Print a pattern, parenthesizing it if it is an or-pattern (`A | B`). + /// + /// Or-patterns have the lowest precedence among patterns, so they need + /// parentheses when nested inside `@` bindings, `&` references, or `box` + /// patterns — otherwise `x @ A | B` parses as `(x @ A) | B`, `&A | B` + /// parses as `(&A) | B`, etc. + fn print_pat_paren_if_or(&mut self, pat: &ast::Pat) { + let needs_paren = matches!(pat.kind, PatKind::Or(..)); + if needs_paren { + self.popen(); + } + self.print_pat(pat); + if needs_paren { + self.pclose(); + } + } + fn print_pat(&mut self, pat: &ast::Pat) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); @@ -1774,7 +1910,7 @@ fn print_pat(&mut self, pat: &ast::Pat) { if let Some(p) = sub { self.space(); self.word_space("@"); - self.print_pat(p); + self.print_pat_paren_if_or(p); } } PatKind::TupleStruct(qself, path, elts) => { @@ -1846,7 +1982,7 @@ fn print_pat(&mut self, pat: &ast::Pat) { } PatKind::Box(inner) => { self.word("box "); - self.print_pat(inner); + self.print_pat_paren_if_or(inner); } PatKind::Deref(inner) => { self.word("deref!"); @@ -1870,7 +2006,7 @@ fn print_pat(&mut self, pat: &ast::Pat) { self.print_pat(inner); self.pclose(); } else { - self.print_pat(inner); + self.print_pat_paren_if_or(inner); } } PatKind::Expr(e) => self.print_expr(e, FixupContext::default()), @@ -1887,12 +2023,12 @@ fn print_pat(&mut self, pat: &ast::Pat) { self.print_expr(e, FixupContext::default()); } } - PatKind::Guard(subpat, condition) => { + PatKind::Guard(subpat, guard) => { self.popen(); self.print_pat(subpat); self.space(); self.word_space("if"); - self.print_expr(condition, FixupContext::default()); + self.print_expr(&guard.cond, FixupContext::default()); self.pclose(); } PatKind::Slice(elts) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 9b4ff2b63bd4..ad602d5196dc 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -260,12 +260,15 @@ fn print_expr_method_call( // // loop { break x; }.method(); // - self.print_expr_cond_paren( - receiver, - receiver.precedence() < ExprPrecedence::Unambiguous, - fixup.leftmost_subexpression_with_dot(), - ); + let needs_paren = receiver.precedence() < ExprPrecedence::Unambiguous; + self.print_expr_cond_paren(receiver, needs_paren, fixup.leftmost_subexpression_with_dot()); + // If the receiver is an unsuffixed float literal like `0.`, insert + // a space so the `.` of the method call doesn't merge with the + // trailing dot: `0. .method()` instead of `0..method()`. + if !needs_paren && expr_ends_with_dot(receiver) { + self.word(" "); + } self.word("."); self.print_ident(segment.ident); if let Some(args) = &segment.args { @@ -658,11 +661,15 @@ pub(super) fn print_expr_outer_attr_style( ); } ast::ExprKind::Field(expr, ident) => { + let needs_paren = expr.precedence() < ExprPrecedence::Unambiguous; self.print_expr_cond_paren( expr, - expr.precedence() < ExprPrecedence::Unambiguous, + needs_paren, fixup.leftmost_subexpression_with_dot(), ); + if !needs_paren && expr_ends_with_dot(expr) { + self.word(" "); + } self.word("."); self.print_ident(*ident); } @@ -685,11 +692,15 @@ pub(super) fn print_expr_outer_attr_style( let fake_prec = ExprPrecedence::LOr; if let Some(e) = start { let start_fixup = fixup.leftmost_subexpression_with_operator(true); - self.print_expr_cond_paren( - e, - start_fixup.precedence(e) < fake_prec, - start_fixup, - ); + let needs_paren = start_fixup.precedence(e) < fake_prec; + self.print_expr_cond_paren(e, needs_paren, start_fixup); + // If the start expression is a float literal ending with + // `.`, we need a space before `..` or `..=` so that the + // dots don't merge. E.g. `0. ..45.` must not become + // `0...45.`. + if !needs_paren && expr_ends_with_dot(e) { + self.word(" "); + } } match limits { ast::RangeLimits::HalfOpen => self.word(".."), @@ -880,9 +891,9 @@ fn print_arm(&mut self, arm: &ast::Arm) { self.print_outer_attributes(&arm.attrs); self.print_pat(&arm.pat); self.space(); - if let Some(e) = &arm.guard { + if let Some(guard) = &arm.guard { self.word_space("if"); - self.print_expr(e, FixupContext::default()); + self.print_expr(&guard.cond, FixupContext::default()); self.space(); } @@ -1025,3 +1036,18 @@ fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String template.push('"'); template } + +/// Returns `true` if the printed representation of this expression ends with +/// a `.` character — specifically, an unsuffixed float literal like `0.` or +/// `45.`. This is used to insert whitespace before range operators (`..`, +/// `..=`) so that the dots don't merge (e.g. `0. ..45.` instead of `0...45.`). +fn expr_ends_with_dot(expr: &ast::Expr) -> bool { + match &expr.kind { + ast::ExprKind::Lit(token_lit) => { + token_lit.kind == token::Float + && token_lit.suffix.is_none() + && token_lit.symbol.as_str().ends_with('.') + } + _ => false, + } +} diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 3407feb3dcc3..e997fdf49820 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -881,7 +881,13 @@ fn print_use_tree(&mut self, tree: &ast::UseTree) { } if items.is_empty() { self.word("{}"); - } else if let [(item, _)] = items.as_slice() { + } else if let [(item, _)] = items.as_slice() + && !item + .prefix + .segments + .first() + .is_some_and(|seg| seg.ident.name == rustc_span::symbol::kw::SelfLower) + { self.print_use_tree(item); } else { let cb = self.cbox(INDENT_UNIT); diff --git a/compiler/rustc_attr_parsing/src/attributes/autodiff.rs b/compiler/rustc_attr_parsing/src/attributes/autodiff.rs index 118a4103b1a9..edd9d9c196cf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/autodiff.rs +++ b/compiler/rustc_attr_parsing/src/attributes/autodiff.rs @@ -9,7 +9,7 @@ use thin_vec::ThinVec; use crate::attributes::prelude::Allow; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::attributes::{OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, Stage}; use crate::parser::{ArgParser, MetaItemOrLitParser}; use crate::target_checking::AllowedTargets; @@ -18,12 +18,12 @@ impl SingleAttributeParser for RustcAutodiffParser { const PATH: &[Symbol] = &[sym::rustc_autodiff]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::Method(MethodKind::TraitImpl)), ]); const TEMPLATE: AttributeTemplate = template!( diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index d2f743f6c5d8..badf696606e9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -20,7 +20,9 @@ use thin_vec::ThinVec; use crate::context::{AcceptContext, ShouldEmit, Stage}; -use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; +use crate::parser::{ + AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser, +}; use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, @@ -363,6 +365,7 @@ fn parse_cfg_attr_internal<'a>( let meta = MetaItemOrLitParser::parse_single( parser, ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, + AllowExprMetavar::Yes, )?; let pred_span = pred_start.with_hi(parser.token.span.hi()); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 7377159be370..4ff224006ca8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -2,18 +2,18 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrStyle, NodeId, token}; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::Diagnostic; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::CfgEntry; use rustc_hir::{AttrPath, Target}; use rustc_parse::exp; use rustc_parse::parser::{Parser, Recovery}; use rustc_session::Session; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; -use crate::parser::MetaItemOrLitParser; -use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry}; +use crate::parser::{AllowExprMetavar, MetaItemOrLitParser}; +use crate::{AttributeParser, ParsedDescription, ShouldEmit, errors, parse_cfg_entry}; #[derive(Clone)] pub enum CfgSelectPredicate { @@ -94,6 +94,7 @@ pub fn parse_cfg_select( let meta = MetaItemOrLitParser::parse_single( p, ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, + AllowExprMetavar::Yes, ) .map_err(|diag| diag.emit())?; let cfg_span = meta.span(); @@ -152,11 +153,17 @@ fn lint_unreachable( let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| { let span = predicate.span(); - p.psess.buffer_lint( + p.psess.dyn_buffer_lint( UNREACHABLE_CFG_SELECT_PREDICATES, span, lint_node_id, - BuiltinLintDiag::UnreachableCfg { span, wildcard_span }, + move |dcx, level| match wildcard_span { + Some(wildcard_span) => { + errors::UnreachableCfgSelectPredicateWildcard { span, wildcard_span } + .into_diag(dcx, level) + } + None => errors::UnreachableCfgSelectPredicate { span }.into_diag(dcx, level), + }, ); }; diff --git a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs index df1e569743c0..339697649164 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs @@ -8,7 +8,6 @@ impl SingleAttributeParser for CfiEncodingParser { Allow(Target::Enum), Allow(Target::Union), ]); - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding"); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 4909e0d35173..dbf289ebccea 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -12,7 +12,6 @@ impl SingleAttributeParser for OptimizeParser { const PATH: &[Symbol] = &[sym::optimize]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), @@ -68,7 +67,6 @@ impl NoArgsAttributeParser for ColdParser { impl SingleAttributeParser for CoverageParser { const PATH: &[Symbol] = &[sym::coverage]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), @@ -119,7 +117,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for ExportNameParser { const PATH: &[rustc_span::Symbol] = &[sym::export_name]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Static), @@ -157,7 +154,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcObjcClassParser { const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); @@ -169,7 +165,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option, args: &ArgParser) -> Option SingleAttributeParser for RustcObjcSelectorParser { const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); @@ -201,7 +196,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for SanitizeParser { r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, + r#"kernel_hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, @@ -595,7 +591,6 @@ impl SingleAttributeParser for SanitizeParser { r#"realtime = "nonblocking|blocking|caller""#, ]); - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { @@ -654,7 +649,9 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option apply(SanitizerSet::MEMTAG), Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK), Some(sym::thread) => apply(SanitizerSet::THREAD), - Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS), + Some(sym::hwaddress) | Some(sym::kernel_hwaddress) => { + apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS) + } Some(sym::realtime) => match value.value_as_str() { Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking), Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking), @@ -671,6 +668,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option, args: &ArgParser) -> Option NoArgsAttributeParser for RustcEiiForeignItemParser { impl SingleAttributeParser for PatchableFunctionEntryParser { const PATH: &[Symbol] = &[sym::patchable_function_entry]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]); diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 2d2994c02cd6..72a0945a4199 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -10,7 +10,6 @@ impl SingleAttributeParser for CrateNameParser { const PATH: &[Symbol] = &[sym::crate_name]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); @@ -84,7 +83,6 @@ fn extend( impl SingleAttributeParser for RecursionLimitParser { const PATH: &[Symbol] = &[sym::recursion_limit]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); @@ -107,7 +105,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for MoveSizeLimitParser { const PATH: &[Symbol] = &[sym::move_size_limit]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); @@ -130,7 +127,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for TypeLengthLimitParser { const PATH: &[Symbol] = &[sym::type_length_limit]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); @@ -153,7 +149,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for PatternComplexityLimitParser { const PATH: &[Symbol] = &[sym::pattern_complexity_limit]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); @@ -213,7 +208,6 @@ impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { impl SingleAttributeParser for WindowsSubsystemParser { const PATH: &[Symbol] = &[sym::windows_subsystem]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index a2c7e459e0df..804b54e9ee25 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -34,7 +34,6 @@ fn get( pub(crate) struct DeprecatedParser; impl SingleAttributeParser for DeprecatedParser { const PATH: &[Symbol] = &[sym::deprecated]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Fn), diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs index 4a89cf6515ce..9f3d1e29b4de 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs @@ -4,7 +4,7 @@ use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::{Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::attributes::{OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::target_checking::{ALL_TARGETS, AllowedTargets}; @@ -12,7 +12,6 @@ pub(crate) struct DoNotRecommendParser; impl SingleAttributeParser for DoNotRecommendParser { const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr. const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */); diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 8f114b328448..8abcaeb5fbf5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -22,6 +22,7 @@ pub(crate) mod do_not_recommend; pub(crate) mod on_const; +pub(crate) mod on_move; pub(crate) mod on_unimplemented; #[derive(Copy, Clone)] @@ -32,6 +33,8 @@ pub(crate) enum Mode { DiagnosticOnUnimplemented, /// `#[diagnostic::on_const]` DiagnosticOnConst, + /// `#[diagnostic::on_move]` + DiagnosticOnMove, } fn merge_directives( @@ -113,6 +116,13 @@ fn parse_directive_items<'p, S: Stage>( span, ); } + Mode::DiagnosticOnMove => { + cx.emit_lint( + MALFORMED_DIAGNOSTIC_ATTRIBUTES, + AttributeLintKind::MalformedOnMoveAttr { span }, + span, + ); + } } continue; }} @@ -132,7 +142,7 @@ fn parse_directive_items<'p, S: Stage>( Mode::RustcOnUnimplemented => { cx.emit_err(NoValueInOnUnimplemented { span: item.span() }); } - Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst => { + Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => { cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, AttributeLintKind::IgnoredDiagnosticOption { @@ -460,11 +470,12 @@ fn parse_filter(input: Symbol) -> FilterFormatString { // if the integer type has been resolved, to allow targeting all integers. // `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet, // from the `Display` impl of `InferTy` to be precise. + // `"{union|enum|struct}"` is used as a special selector for ADTs. // // Don't try to format these later! - Position::ArgumentNamed(arg @ ("integer" | "integral" | "float")) => { - LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}"))) - } + Position::ArgumentNamed( + arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"), + ) => LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}"))), Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)), Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces), diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs new file mode 100644 index 000000000000..006b3b66658e --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -0,0 +1,72 @@ +use rustc_feature::template; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::lints::AttributeLintKind; +use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES; +use rustc_span::sym; + +use crate::attributes::diagnostic::*; +use crate::attributes::prelude::*; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; +use crate::target_checking::{ALL_TARGETS, AllowedTargets}; + +#[derive(Default)] +pub(crate) struct OnMoveParser { + span: Option, + directive: Option<(Span, Directive)>, +} + +impl OnMoveParser { + fn parse<'sess, S: Stage>( + &mut self, + cx: &mut AcceptContext<'_, 'sess, S>, + args: &ArgParser, + mode: Mode, + ) { + if !cx.features().diagnostic_on_move() { + return; + } + + let span = cx.attr_span; + self.span = Some(span); + let Some(list) = args.list() else { + cx.emit_lint( + MALFORMED_DIAGNOSTIC_ATTRIBUTES, + AttributeLintKind::MissingOptionsForOnMove, + span, + ); + return; + }; + + if list.is_empty() { + cx.emit_lint( + MALFORMED_DIAGNOSTIC_ATTRIBUTES, + AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter, + list.span, + ); + return; + } + + if let Some(directive) = parse_directive_items(cx, mode, list.mixed(), true) { + merge_directives(cx, &mut self.directive, (span, directive)); + } + } +} +impl AttributeParser for OnMoveParser { + const ATTRIBUTES: AcceptMapping = &[( + &[sym::diagnostic, sym::on_move], + template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]), + |this, cx, args| { + this.parse(cx, args, Mode::DiagnosticOnMove); + }, + )]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { + if let Some(span) = self.span { + Some(AttributeKind::OnMove { span, directive: self.directive.map(|d| Box::new(d.1)) }) + } else { + None + } + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 71d10b23a37f..ee5c507b6292 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -2,7 +2,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::attributes::{OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::target_checking::{ALL_TARGETS, AllowedTargets}; @@ -10,7 +10,6 @@ pub(crate) struct RustcDummyParser; impl SingleAttributeParser for RustcDummyParser { const PATH: &[Symbol] = &[sym::rustc_dummy]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 767200bfa9bf..82cec25c997c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -11,7 +11,6 @@ impl SingleAttributeParser for InlineParser { const PATH: &[Symbol] = &[sym::inline]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), @@ -68,7 +67,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcForceInlineParser { const PATH: &[Symbol] = &[sym::rustc_force_inline]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs index 3be9b9ded9c1..5f6108108a77 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -16,7 +16,6 @@ impl SingleAttributeParser for InstructionSetParser { ]); const TEMPLATE: AttributeTemplate = template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"); const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32]; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index c4a483157a19..52ab4ac8a449 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -22,7 +22,6 @@ impl SingleAttributeParser for LinkNameParser { const PATH: &[Symbol] = &[sym::link_name]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ Allow(Target::ForeignFn), @@ -466,7 +465,6 @@ fn parse_link_import_name_type( impl SingleAttributeParser for LinkSectionParser { const PATH: &[Symbol] = &[sym::link_section]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Static), @@ -541,7 +539,6 @@ impl NoArgsAttributeParser for RustcStdInternalSymbolParser { impl SingleAttributeParser for LinkOrdinalParser { const PATH: &[Symbol] = &[sym::link_ordinal]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::ForeignFn), @@ -583,8 +580,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for LinkageParser { const PATH: &[Symbol] = &[sym::linkage]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 00d40687fc85..86dde5b108ff 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -130,7 +130,6 @@ impl NoArgsAttributeParser for AllowInternalUnsafeParser { impl SingleAttributeParser for MacroExportParser { const PATH: &[Symbol] = &[sym::macro_export]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const TEMPLATE: AttributeTemplate = template!(Word, List: &["local_inner_macros"]); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ @@ -168,7 +167,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for CollapseDebugInfoParser { const PATH: &[Symbol] = &[sym::collapse_debuginfo]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!( List: &["no", "external", "yes"], diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 223c88972d75..67147642921c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -124,14 +124,8 @@ pub(crate) trait SingleAttributeParser: 'static { /// If you need the parser to accept more than one path, use [`AttributeParser`] instead const PATH: &[Symbol]; - /// Configures the precedence of attributes with the same `PATH` on a syntax node. - const ATTRIBUTE_ORDER: AttributeOrder; - /// Configures what to do when when the same attribute is /// applied more than once on the same syntax node. - /// - /// [`ATTRIBUTE_ORDER`](Self::ATTRIBUTE_ORDER) specified which one is assumed to be correct, - /// and this specified whether to, for example, warn or error on the other one. const ON_DUPLICATE: OnDuplicate; const ALLOWED_TARGETS: AllowedTargets; @@ -162,21 +156,8 @@ impl, S: Stage> AttributeParser for Single >::TEMPLATE, |group: &mut Single, cx, args| { if let Some(pa) = T::convert(cx, args) { - match T::ATTRIBUTE_ORDER { - // keep the first and report immediately. ignore this attribute - AttributeOrder::KeepInnermost => { - if let Some((_, unused)) = group.1 { - T::ON_DUPLICATE.exec::(cx, cx.attr_span, unused); - return; - } - } - // keep the new one and warn about the previous, - // then replace - AttributeOrder::KeepOutermost => { - if let Some((_, used)) = group.1 { - T::ON_DUPLICATE.exec::(cx, used, cx.attr_span); - } - } + if let Some((_, used)) = group.1 { + T::ON_DUPLICATE.exec::(cx, used, cx.attr_span); } group.1 = Some((pa, cx.attr_span)); @@ -206,7 +187,7 @@ pub(crate) enum OnDuplicate { /// Custom function called when a duplicate attribute is found. /// /// - `unused` is the span of the attribute that was unused or bad because of some - /// duplicate reason (see [`AttributeOrder`]) + /// duplicate reason /// - `used` is the span of the attribute that was used in favor of the unused attribute Custom(fn(cx: &AcceptContext<'_, '_, S>, used: Span, unused: Span)), } @@ -223,8 +204,8 @@ fn exec>( OnDuplicate::WarnButFutureError => cx.warn_unused_duplicate_future_error(used, unused), OnDuplicate::Error => { cx.emit_err(UnusedMultiple { - this: used, - other: unused, + this: unused, + other: used, name: Symbol::intern( &P::PATH.into_iter().map(|i| i.to_string()).collect::>().join(".."), ), @@ -236,30 +217,6 @@ fn exec>( } } -pub(crate) enum AttributeOrder { - /// Duplicates after the innermost instance of the attribute will be an error/warning. - /// Only keep the lowest attribute. - /// - /// Attributes are processed from bottom to top, so this raises a warning/error on all the attributes - /// further above the lowest one: - /// ``` - /// #[stable(since="1.0")] //~ WARNING duplicated attribute - /// #[stable(since="2.0")] - /// ``` - KeepInnermost, - - /// Duplicates before the outermost instance of the attribute will be an error/warning. - /// Only keep the highest attribute. - /// - /// Attributes are processed from bottom to top, so this raises a warning/error on all the attributes - /// below the highest one: - /// ``` - /// #[path="foo.rs"] - /// #[path="bar.rs"] //~ WARNING duplicated attribute - /// ``` - KeepOutermost, -} - /// An even simpler version of [`SingleAttributeParser`]: /// now automatically check that there are no arguments provided to the attribute. /// @@ -284,7 +241,6 @@ fn default() -> Self { impl, S: Stage> SingleAttributeParser for WithoutArgs { const PATH: &[Symbol] = T::PATH; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = T::ON_DUPLICATE; const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); diff --git a/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs index 8456ce797758..7f37210b8c8a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs @@ -4,7 +4,6 @@ impl SingleAttributeParser for MustNotSuspendParser { const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Struct), diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index 673e2c902da0..f1ce810f4eae 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -4,7 +4,6 @@ impl SingleAttributeParser for MustUseParser { const PATH: &[Symbol] = &[sym::must_use]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Fn), diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index b60f8e315e5e..6b5eee7f31bb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -4,7 +4,6 @@ impl SingleAttributeParser for PathParser { const PATH: &[Symbol] = &[sym::path]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Error(Target::Crate)]); diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs index 65c408fa6358..53adf7e31eb7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs @@ -12,8 +12,8 @@ #[doc(hidden)] pub(super) use crate::attributes::{ - AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, - NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, + AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, NoArgsAttributeParser, + OnDuplicate, SingleAttributeParser, }; // contexts #[doc(hidden)] diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index f9ace7e25d1b..aca0e94cff06 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -25,7 +25,6 @@ impl NoArgsAttributeParser for ProcMacroAttributeParser { pub(crate) struct ProcMacroDeriveParser; impl SingleAttributeParser for ProcMacroDeriveParser { const PATH: &[Symbol] = &[sym::proc_macro_derive]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!( @@ -46,7 +45,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcBuiltinMacroParser { const PATH: &[Symbol] = &[sym::rustc_builtin_macro]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index ac50fe33839d..15d9d3453738 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -5,10 +5,11 @@ use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase}; use rustc_span::{Span, Symbol, sym}; -use super::{AttributeOrder, OnDuplicate}; +use super::OnDuplicate; use crate::attributes::SingleAttributeParser; use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; +use crate::session_diagnostics; use crate::target_checking::AllowedTargets; use crate::target_checking::Policy::Allow; @@ -17,8 +18,6 @@ impl SingleAttributeParser for CustomMirParser { const PATH: &[rustc_span::Symbol] = &[sym::custom_mir]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); @@ -57,6 +56,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option( Some((phase, span)) } + +fn check_custom_mir( + cx: &mut AcceptContext<'_, '_, S>, + dialect: Option<(MirDialect, Span)>, + phase: Option<(MirPhase, Span)>, + failed: &mut bool, +) { + let attr_span = cx.attr_span; + let Some((dialect, dialect_span)) = dialect else { + if let Some((_, phase_span)) = phase { + *failed = true; + cx.emit_err(session_diagnostics::CustomMirPhaseRequiresDialect { + attr_span, + phase_span, + }); + } + return; + }; + + match dialect { + MirDialect::Analysis => { + if let Some((MirPhase::Optimized, phase_span)) = phase { + *failed = true; + cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase { + dialect, + phase: MirPhase::Optimized, + attr_span, + dialect_span, + phase_span, + }); + } + } + + MirDialect::Built => { + if let Some((phase, phase_span)) = phase { + *failed = true; + cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase { + dialect, + phase, + attr_span, + dialect_span, + phase_span, + }); + } + } + MirDialect::Runtime => {} + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs index 5782f9473a99..e809ad9ed83b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs @@ -28,7 +28,6 @@ impl SingleAttributeParser for RustcAllocatorZeroedVariantParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function"); - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(name) = args.name_value().and_then(NameValueParser::value_as_str) else { cx.expected_name_value(cx.attr_span, None); diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index e8b4cb343794..15772d874507 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -31,7 +31,6 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser { const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { @@ -105,7 +104,6 @@ impl NoArgsAttributeParser for RustcNoImplicitAutorefsParser { impl SingleAttributeParser for RustcLayoutScalarValidRangeStartParser { const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_start]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["start"]); @@ -120,7 +118,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcLayoutScalarValidRangeEndParser { const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_end]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["end"]); @@ -135,7 +132,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcLegacyConstGenericsParser { const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!(List: &["N"]); @@ -193,7 +189,6 @@ impl NoArgsAttributeParser for RustcInheritOverflowChecksParser { impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser { const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]); const TEMPLATE: AttributeTemplate = template!(Word); @@ -373,7 +368,6 @@ impl SingleAttributeParser for RustcDeprecatedSafe2024Parser { Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), ]); - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { @@ -441,7 +435,6 @@ impl SingleAttributeParser for RustcNeverTypeOptionsParser { const PATH: &[Symbol] = &[sym::rustc_never_type_options]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const TEMPLATE: AttributeTemplate = template!(List: &[ r#"fallback = "unit", "never", "no""#, r#"diverging_block_default = "unit", "never""#, @@ -592,7 +585,6 @@ impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationPa impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser { const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); @@ -610,7 +602,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcScalableVectorParser { const PATH: &[Symbol] = &[sym::rustc_scalable_vector]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]); @@ -636,7 +627,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for LangParser { const PATH: &[Symbol] = &[sym::lang]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes` const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); @@ -981,8 +971,6 @@ fn extend( impl SingleAttributeParser for RustcIfThisChangedParser { const PATH: &[Symbol] = &[sym::rustc_if_this_changed]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ @@ -1147,7 +1135,6 @@ impl NoArgsAttributeParser for RustcEffectiveVisibilityParser { impl SingleAttributeParser for RustcDiagnosticItemParser { const PATH: &[Symbol] = &[sym::rustc_diagnostic_item]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Trait), @@ -1220,7 +1207,6 @@ impl SingleAttributeParser for RustcSymbolNameParser { Allow(Target::Impl { of_trait: false }), ]); const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { if let Err(span) = args.no_args() { @@ -1245,7 +1231,6 @@ impl SingleAttributeParser for RustcDefPathParser { Allow(Target::Impl { of_trait: false }), ]); const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { if let Err(span) = args.no_args() { @@ -1275,7 +1260,6 @@ impl NoArgsAttributeParser for RustcStrictCoherenceParser { impl SingleAttributeParser for RustcReservationImplParser { const PATH: &[Symbol] = &[sym::rustc_reservation_impl]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Impl { of_trait: true })]); @@ -1311,7 +1295,6 @@ impl NoArgsAttributeParser for PreludeImportParser { impl SingleAttributeParser for RustcDocPrimitiveParser { const PATH: &[Symbol] = &[sym::rustc_doc_primitive]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Mod)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name"); diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index e35c10996ceb..25b295c162aa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -1,6 +1,7 @@ use std::num::NonZero; use rustc_errors::ErrorGuaranteed; +use rustc_feature::ACCEPTED_LANG_FEATURES; use rustc_hir::target::GenericParamKind; use rustc_hir::{ DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel, @@ -366,7 +367,7 @@ pub(crate) fn parse_stability( } } -// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` +/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` /// attribute, and return the feature name and its stability information. pub(crate) fn parse_unstability( cx: &AcceptContext<'_, '_, S>, @@ -376,7 +377,6 @@ pub(crate) fn parse_unstability( let mut reason = None; let mut issue = None; let mut issue_num = None; - let mut is_soft = false; let mut implied_by = None; let mut old_name = None; @@ -423,12 +423,6 @@ pub(crate) fn parse_unstability( }, }; } - Some(sym::soft) => { - if let Err(span) = args.no_args() { - cx.emit_err(session_diagnostics::SoftNoArgs { span }); - } - is_soft = true; - } Some(sym::implied_by) => { insert_value_into_option_or_error(cx, ¶m, &mut implied_by, word.unwrap())? } @@ -438,14 +432,7 @@ pub(crate) fn parse_unstability( _ => { cx.expected_specific_argument( param.span(), - &[ - sym::feature, - sym::reason, - sym::issue, - sym::soft, - sym::implied_by, - sym::old_name, - ], + &[sym::feature, sym::reason, sym::issue, sym::implied_by, sym::old_name], ); return None; } @@ -465,10 +452,19 @@ pub(crate) fn parse_unstability( match (feature, issue) { (Ok(feature), Ok(_)) => { + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if ACCEPTED_LANG_FEATURES.iter().any(|f| f.name == feature) { + cx.emit_err(session_diagnostics::UnstableAttrForAlreadyStableFeature { + attr_span: cx.attr_span, + item_span: cx.target_span, + }); + return None; + } + let level = StabilityLevel::Unstable { reason: UnstableReason::from_opt_reason(reason), issue: issue_num, - is_soft, implied_by, old_name, }; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 2775eab1b5d9..db0350f23246 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -7,7 +7,6 @@ impl SingleAttributeParser for IgnoreParser { const PATH: &[Symbol] = &[sym::ignore]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]); @@ -41,7 +40,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for ShouldPanicParser { const PATH: &[Symbol] = &[sym::should_panic]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]); @@ -98,7 +96,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for ReexportTestHarnessMainParser { const PATH: &[Symbol] = &[sym::reexport_test_harness_main]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); @@ -126,7 +123,6 @@ impl SingleAttributeParser for RustcAbiParser { const PATH: &[Symbol] = &[sym::rustc_abi]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::debug, sym::assert_eq]); - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::TyAlias), Allow(Target::Fn), @@ -197,7 +193,6 @@ impl NoArgsAttributeParser for RustcEvaluateWhereClausesParser { impl SingleAttributeParser for TestRunnerParser { const PATH: &[Symbol] = &[sym::test_runner]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(List: &["path"]); @@ -226,7 +221,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcTestMarkerParser { const PATH: &[Symbol] = &[sym::rustc_test_marker]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Const), diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index c09e151fc70c..c418d1d032c4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -1,9 +1,7 @@ use std::mem; use super::prelude::*; -use crate::attributes::{ - AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, -}; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::target_checking::Policy::{Allow, Warn}; @@ -12,7 +10,6 @@ pub(crate) struct RustcSkipDuringMethodDispatchParser; impl SingleAttributeParser for RustcSkipDuringMethodDispatchParser { const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 58b4a0b2fb1a..c3817406c980 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -6,7 +6,6 @@ impl SingleAttributeParser for RustcMacroTransparencyParser { const PATH: &[Symbol] = &[sym::rustc_macro_transparency]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 190568bed508..259a73de5985 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -29,6 +29,7 @@ use crate::attributes::deprecation::*; use crate::attributes::diagnostic::do_not_recommend::*; use crate::attributes::diagnostic::on_const::*; +use crate::attributes::diagnostic::on_move::*; use crate::attributes::diagnostic::on_unimplemented::*; use crate::attributes::doc::*; use crate::attributes::dummy::*; @@ -149,6 +150,7 @@ mod late { MacroUseParser, NakedParser, OnConstParser, + OnMoveParser, OnUnimplementedParser, RustcAlignParser, RustcAlignStaticParser, diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs new file mode 100644 index 000000000000..d4236416dd6a --- /dev/null +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -0,0 +1,52 @@ +use rustc_errors::MultiSpan; +use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(Diagnostic)] +#[diag("`{$name}` attribute cannot be used at crate level")] +pub(crate) struct InvalidAttrAtCrateLevel { + #[primary_span] + pub span: Span, + #[suggestion( + "perhaps you meant to use an outer attribute", + code = "#[", + applicability = "machine-applicable", + style = "verbose" + )] + pub pound_to_opening_bracket: Span, + pub name: Symbol, + #[subdiagnostic] + pub item: Option, +} + +#[derive(Clone, Copy, Subdiagnostic)] +#[label("the inner attribute doesn't annotate this item")] +pub(crate) struct ItemFollowingInnerAttr { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("unreachable configuration predicate")] +pub(crate) struct UnreachableCfgSelectPredicate { + #[label("this configuration predicate is never reached")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("most attributes are not supported in `where` clauses")] +#[help("only `#[cfg]` and `#[cfg_attr]` are supported")] +pub(crate) struct UnsupportedAttributesInWhere { + #[primary_span] + pub span: MultiSpan, +} + +#[derive(Diagnostic)] +#[diag("unreachable configuration predicate")] +pub(crate) struct UnreachableCfgSelectPredicateWildcard { + #[label("this configuration predicate is never reached")] + pub span: Span, + + #[label("always matches")] + pub wildcard_span: Span, +} diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index f75f63a0e811..7305c4b7c2fa 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -14,7 +14,7 @@ use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage}; use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState}; -use crate::parser::{ArgParser, PathParser, RefPathParser}; +use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -139,6 +139,7 @@ pub fn parse_single( emit_errors: ShouldEmit, parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option, template: &AttributeTemplate, + allow_expr_metavar: AllowExprMetavar, ) -> Option { let ast::AttrKind::Normal(normal_attr) = &attr.kind else { panic!("parse_single called on a doc attr") @@ -152,6 +153,7 @@ pub fn parse_single( &parts, &sess.psess, emit_errors, + allow_expr_metavar, )?; Self::parse_single_args( sess, @@ -267,6 +269,11 @@ pub fn parse_attribute_list( mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind), ) -> Vec { let mut attributes = Vec::new(); + // We store the attributes we intend to discard at the end of this function in order to + // check they are applied to the right target and error out if necessary. In practice, we + // end up dropping only derive attributes and derive helpers, both being fully processed + // at macro expansion. + let mut dropped_attributes = Vec::new(); let mut attr_paths: Vec> = Vec::new(); let mut early_parsed_state = EarlyParsedState::default(); @@ -302,7 +309,7 @@ pub fn parse_attribute_list( kind: DocFragmentKind::Sugared(*comment_kind), span: attr_span, comment: *symbol, - })) + })); } ast::AttrKind::Normal(n) => { attr_paths.push(PathParser(&n.item.path)); @@ -333,6 +340,7 @@ pub fn parse_attribute_list( &parts, &self.sess.psess, self.stage.should_emit(), + AllowExprMetavar::No, ) else { continue; }; @@ -390,29 +398,33 @@ pub fn parse_attribute_list( Self::check_target(&accept.allowed_targets, target, &mut cx); } } else { - // If we're here, we must be compiling a tool attribute... Or someone - // forgot to parse their fancy new attribute. Let's warn them in any case. - // If you are that person, and you really think your attribute should - // remain unparsed, carefully read the documentation in this module and if - // you still think so you can add an exception to this assertion. - - // FIXME(jdonszelmann): convert other attributes, and check with this that - // we caught em all - // const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg]; - // assert!( - // self.tools.contains(&parts[0]) || true, - // // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]), - // "attribute {path} wasn't parsed and isn't a know tool attribute", - // ); - - attributes.push(Attribute::Unparsed(Box::new(AttrItem { + let attr = AttrItem { path: attr_path.clone(), args: self .lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span), id: HashIgnoredAttrId { attr_id: attr.id }, style: attr.style, span: attr_span, - }))); + }; + + if !matches!(self.stage.should_emit(), ShouldEmit::Nothing) + && target == Target::Crate + { + self.check_invalid_crate_level_attr_item(&attr, n.item.span()); + } + + let attr = Attribute::Unparsed(Box::new(attr)); + + if self.tools.contains(&parts[0]) + // FIXME: this can be removed once #152369 has been merged. + // https://github.com/rust-lang/rust/pull/152369 + || [sym::allow, sym::deny, sym::expect, sym::forbid, sym::warn] + .contains(&parts[0]) + { + attributes.push(attr); + } else { + dropped_attributes.push(attr); + } } } } @@ -428,6 +440,12 @@ pub fn parse_attribute_list( } } + if !matches!(self.stage.should_emit(), ShouldEmit::Nothing) + && target == Target::WherePredicate + { + self.check_invalid_where_predicate_attrs(attributes.iter().chain(&dropped_attributes)); + } + attributes } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index db09572cc56b..93eb5a0c3ab7 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -79,6 +79,7 @@ // tidy-alphabetical-start #![feature(decl_macro)] #![feature(iter_intersperse)] +#![feature(try_blocks)] #![recursion_limit = "256"] // tidy-alphabetical-end @@ -99,6 +100,7 @@ pub mod parser; mod early_parsed; +mod errors; mod safety; mod session_diagnostics; mod target_checking; diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 354fbab9cfcf..6e8a50096736 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -109,6 +109,7 @@ pub fn from_attr_args<'sess>( parts: &[Symbol], psess: &'sess ParseSess, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, ) -> Option { Some(match value { AttrArgs::Empty => Self::NoArgs, @@ -122,6 +123,7 @@ pub fn from_attr_args<'sess>( args.dspan.entire(), psess, ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }, + allow_expr_metavar, ) { Ok(p) => return Some(ArgParser::List(p)), Err(e) => { @@ -147,9 +149,15 @@ pub fn from_attr_args<'sess>( } Self::List( - MetaItemListParser::new(&args.tokens, args.dspan.entire(), psess, should_emit) - .map_err(|e| should_emit.emit_err(e)) - .ok()?, + MetaItemListParser::new( + &args.tokens, + args.dspan.entire(), + psess, + should_emit, + allow_expr_metavar, + ) + .map_err(|e| should_emit.emit_err(e)) + .ok()?, ) } AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser { @@ -217,8 +225,9 @@ impl MetaItemOrLitParser { pub fn parse_single<'sess>( parser: &mut Parser<'sess>, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, ) -> PResult<'sess, MetaItemOrLitParser> { - let mut this = MetaItemListParserContext { parser, should_emit }; + let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar }; this.parse_meta_item_inner() } @@ -390,7 +399,7 @@ fn expr_to_lit<'sess>( } } } else { - if matches!(should_emit, ShouldEmit::Nothing) { + if matches!(should_emit, ShouldEmit::Nothing) || matches!(expr.kind, ExprKind::Err(_)) { return Ok(None); } @@ -404,9 +413,19 @@ fn expr_to_lit<'sess>( } } +/// Whether expansions of `expr` metavariables from decrarative macros +/// are permitted. Used when parsing meta items; currently, only `cfg` predicates +/// enable this option +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AllowExprMetavar { + No, + Yes, +} + struct MetaItemListParserContext<'a, 'sess> { parser: &'a mut Parser<'sess>, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, } impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { @@ -447,20 +466,44 @@ fn unsuffixed_meta_item_from_lit( Ok(lit) } - fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> { - if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() { - return if has_meta_form { - let attr_item = self - .parser - .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| { - MetaItemListParserContext { parser: this, should_emit: self.should_emit } - .parse_attr_item() - }) - .unwrap(); - Ok(attr_item) - } else { - self.parser.unexpected_any() - }; + fn parse_meta_item(&mut self) -> PResult<'sess, MetaItemParser> { + if let Some(metavar) = self.parser.token.is_metavar_seq() { + match (metavar, self.allow_expr_metavar) { + (kind @ MetaVarKind::Expr { .. }, AllowExprMetavar::Yes) => { + return self + .parser + .eat_metavar_seq(kind, |this| { + MetaItemListParserContext { + parser: this, + should_emit: self.should_emit, + allow_expr_metavar: AllowExprMetavar::Yes, + } + .parse_meta_item() + }) + .ok_or_else(|| { + self.parser.unexpected_any::().unwrap_err() + }); + } + (MetaVarKind::Meta { has_meta_form }, _) => { + return if has_meta_form { + let attr_item = self + .parser + .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| { + MetaItemListParserContext { + parser: this, + should_emit: self.should_emit, + allow_expr_metavar: self.allow_expr_metavar, + } + .parse_meta_item() + }) + .unwrap(); + Ok(attr_item) + } else { + self.parser.unexpected_any() + }; + } + _ => {} + } } let path = self.parser.parse_path(PathStyle::Mod)?; @@ -469,8 +512,12 @@ fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> { let args = if self.parser.check(exp!(OpenParen)) { let start = self.parser.token.span; let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| { - MetaItemListParserContext { parser, should_emit: self.should_emit } - .parse_meta_item_inner() + MetaItemListParserContext { + parser, + should_emit: self.should_emit, + allow_expr_metavar: self.allow_expr_metavar, + } + .parse_meta_item_inner() })?; let end = self.parser.prev_token.span; ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) }) @@ -492,7 +539,7 @@ fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> { Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?)) } else { let prev_pros = self.parser.approx_token_stream_pos(); - match self.parse_attr_item() { + match self.parse_meta_item() { Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)), Err(err) => { // If `parse_attr_item` made any progress, it likely has a more precise error we should prefer @@ -580,13 +627,15 @@ fn parse( psess: &'sess ParseSess, span: Span, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, ) -> PResult<'sess, MetaItemListParser> { let mut parser = Parser::new(psess, tokens, None); if let ShouldEmit::ErrorsAndLints { recovery } = should_emit { parser = parser.recovery(recovery); } - let mut this = MetaItemListParserContext { parser: &mut parser, should_emit }; + let mut this = + MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar }; // Presumably, the majority of the time there will only be one attr. let mut sub_parsers = ThinVec::with_capacity(1); @@ -618,8 +667,15 @@ pub(crate) fn new<'sess>( span: Span, psess: &'sess ParseSess, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, ) -> Result> { - MetaItemListParserContext::parse(tokens.clone(), psess, span, should_emit) + MetaItemListParserContext::parse( + tokens.clone(), + psess, + span, + should_emit, + allow_expr_metavar, + ) } /// Lets you pick and choose as what you want to parse each element in the list diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7c2044ec235a..bab830098f1a 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -7,6 +7,7 @@ }; use rustc_feature::AttributeTemplate; use rustc_hir::AttrPath; +use rustc_hir::attrs::{MirDialect, MirPhase}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use rustc_target::spec::TargetTuple; @@ -374,13 +375,6 @@ pub(crate) struct InvalidSince { pub span: Span, } -#[derive(Diagnostic)] -#[diag("`soft` should not have any arguments")] -pub(crate) struct SoftNoArgs { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag("unknown version literal format, assuming it refers to a future version")] pub(crate) struct UnknownVersionLiteral { @@ -1030,3 +1024,36 @@ pub(crate) struct UnsupportedInstructionSet<'a> { pub instruction_set: Symbol, pub current_target: &'a TargetTuple, } + +#[derive(Diagnostic)] +#[diag("`dialect` key required")] +pub(crate) struct CustomMirPhaseRequiresDialect { + #[primary_span] + pub attr_span: Span, + #[label("`phase` argument requires a `dialect` argument")] + pub phase_span: Span, +} + +#[derive(Diagnostic)] +#[diag("the {$dialect} dialect is not compatible with the {$phase} phase")] +pub(crate) struct CustomMirIncompatibleDialectAndPhase { + pub dialect: MirDialect, + pub phase: MirPhase, + #[primary_span] + pub attr_span: Span, + #[label("this dialect...")] + pub dialect_span: Span, + #[label("... is not compatible with this phase")] + pub phase_span: Span, +} + +#[derive(Diagnostic)] +#[diag("can't mark as unstable using an already stable feature")] +pub(crate) struct UnstableAttrForAlreadyStableFeature { + #[primary_span] + #[label("this feature is already stable")] + #[help("consider removing the attribute")] + pub attr_span: Span, + #[label("the stability attribute annotates this item")] + pub item_span: Span, +} diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index fb005477f0fa..253a089e49f1 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -1,14 +1,18 @@ use std::borrow::Cow; use rustc_ast::AttrStyle; -use rustc_errors::DiagArgValue; +use rustc_errors::{DiagArgValue, MultiSpan, StashKey}; use rustc_feature::Features; +use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::AttributeLintKind; -use rustc_hir::{MethodKind, Target}; -use rustc_span::sym; +use rustc_hir::{AttrItem, Attribute, MethodKind, Target}; +use rustc_span::{BytePos, Span, Symbol, sym}; use crate::AttributeParser; use crate::context::{AcceptContext, Stage}; +use crate::errors::{ + InvalidAttrAtCrateLevel, ItemFollowingInnerAttr, UnsupportedAttributesInWhere, +}; use crate::session_diagnostics::InvalidTarget; use crate::target_checking::Policy::Allow; @@ -96,6 +100,25 @@ pub(crate) fn check_target( return; } + if matches!(cx.attr_path.segments.as_ref(), [sym::repr]) && target == Target::Crate { + // The allowed targets of `repr` depend on its arguments. They can't be checked using + // the `AttributeParser` code. + let span = cx.attr_span; + let item = + cx.cx.first_line_of_next_item(span).map(|span| ItemFollowingInnerAttr { span }); + + let pound_to_opening_bracket = cx.attr_span.until(cx.inner_span); + + cx.dcx() + .create_err(InvalidAttrAtCrateLevel { + span, + pound_to_opening_bracket, + name: sym::repr, + item, + }) + .emit(); + } + match allowed_targets.is_allowed(target) { AllowedResult::Allowed => {} AllowedResult::Warn => { @@ -163,6 +186,113 @@ pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess cx.emit_lint(rustc_session::lint::builtin::UNUSED_ATTRIBUTES, kind, attr_span); } + + // FIXME: Fix "Cannot determine resolution" error and remove built-in macros + // from this check. + pub(crate) fn check_invalid_crate_level_attr_item(&self, attr: &AttrItem, inner_span: Span) { + // Check for builtin attributes at the crate level + // which were unsuccessfully resolved due to cannot determine + // resolution for the attribute macro error. + const ATTRS_TO_CHECK: &[Symbol] = + &[sym::derive, sym::test, sym::test_case, sym::global_allocator, sym::bench]; + + // FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day. + if let Some(name) = ATTRS_TO_CHECK.iter().find(|attr_to_check| matches!(attr.path.segments.as_ref(), [segment] if segment == *attr_to_check)) { + let span = attr.span; + let name = *name; + + let item = self.first_line_of_next_item(span).map(|span| ItemFollowingInnerAttr { span }); + + let err = self.dcx().create_err(InvalidAttrAtCrateLevel { + span, + pound_to_opening_bracket: span.until(inner_span), + name, + item, + }); + + self.dcx().try_steal_replace_and_emit_err( + attr.path.span, + StashKey::UndeterminedMacroResolution, + err, + ); + } + } + + fn first_line_of_next_item(&self, span: Span) -> Option { + // We can't exactly call `tcx.hir_free_items()` here because it's too early and querying + // this would create a circular dependency. Instead, we resort to getting the original + // source code that follows `span` and find the next item from here. + + self.sess() + .source_map() + .span_to_source(span, |content, _, span_end| { + let mut source = &content[span_end..]; + let initial_source_len = source.len(); + let span = try { + loop { + let first = source.chars().next()?; + + if first.is_whitespace() { + let split_idx = source.find(|c: char| !c.is_whitespace())?; + source = &source[split_idx..]; + } else if source.starts_with("//") { + let line_idx = source.find('\n')?; + source = &source[line_idx + '\n'.len_utf8()..]; + } else if source.starts_with("/*") { + // FIXME: support nested comments. + let close_idx = source.find("*/")?; + source = &source[close_idx + "*/".len()..]; + } else if first == '#' { + // FIXME: properly find the end of the attributes in order to accurately + // skip them. This version just consumes the source code until the next + // `]`. + let close_idx = source.find(']')?; + source = &source[close_idx + ']'.len_utf8()..]; + } else { + let lo = span_end + initial_source_len - source.len(); + let last_line = source.split('\n').next().map(|s| s.trim_end())?; + + let hi = lo + last_line.len(); + let lo = BytePos(lo as u32); + let hi = BytePos(hi as u32); + let next_item_span = Span::new(lo, hi, span.ctxt(), None); + + break next_item_span; + } + } + }; + + Ok(span) + }) + .ok() + .flatten() + } + + pub(crate) fn check_invalid_where_predicate_attrs<'attr>( + &self, + attrs: impl IntoIterator, + ) { + // FIXME(where_clause_attrs): Currently, as the following check shows, + // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed + // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`) + // in where clauses. After that, this function would become useless. + let spans = attrs + .into_iter() + // FIXME: We shouldn't need to special-case `doc`! + .filter(|attr| { + matches!( + attr, + Attribute::Parsed(AttributeKind::DocComment { .. } | AttributeKind::Doc(_)) + | Attribute::Unparsed(_) + ) + }) + .map(|attr| attr.span()) + .collect::>(); + if !spans.is_empty() { + self.dcx() + .emit_err(UnsupportedAttributesInWhere { span: MultiSpan::from_spans(spans) }); + } + } } /// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to. diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 0d3c554e4176..4fcb5f3b5a94 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -324,18 +324,23 @@ pub(crate) fn cannot_act_on_moved_value( verb: &str, optional_adverb_for_moved: &str, moved_path: Option, + primary_message: Option, ) -> Diag<'infcx> { - let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); + if let Some(primary_message) = primary_message { + struct_span_code_err!(self.dcx(), use_span, E0382, "{}", primary_message) + } else { + let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); - struct_span_code_err!( - self.dcx(), - use_span, - E0382, - "{} of {}moved value{}", - verb, - optional_adverb_for_moved, - moved_path, - ) + struct_span_code_err!( + self.dcx(), + use_span, + E0382, + "{} of {}moved value{}", + verb, + optional_adverb_for_moved, + moved_path, + ) + } } pub(crate) fn cannot_borrow_path_as_mutable_because( diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 641121597848..cddb37c7d816 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -6,12 +6,16 @@ use either::Either; use hir::{ClosureKind, Path}; use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err}; use rustc_hir as hir; +use rustc_hir::attrs::diagnostic::FormatArgs; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr}; -use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField}; +use rustc_hir::{ + CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField, find_attr, +}; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::{ @@ -138,6 +142,36 @@ pub(crate) fn report_use_of_moved_or_uninitialized( let partial_str = if is_partial_move { "partial " } else { "" }; let partially_str = if is_partial_move { "partially " } else { "" }; + let (on_move_message, on_move_label, on_move_notes) = if let ty::Adt(item_def, args) = + self.body.local_decls[moved_place.local].ty.kind() + && let Some(Some(directive)) = find_attr!(self.infcx.tcx, item_def.did(), OnMove { directive, .. } => directive) + { + let item_name = self.infcx.tcx.item_name(item_def.did()).to_string(); + let mut generic_args: Vec<_> = self + .infcx + .tcx + .generics_of(item_def.did()) + .own_params + .iter() + .filter_map(|param| Some((param.name, args[param.index as usize].to_string()))) + .collect(); + generic_args.push((kw::SelfUpper, item_name)); + + let args = FormatArgs { + this: String::new(), + trait_sugared: String::new(), + item_context: "", + generic_args, + }; + ( + directive.message.as_ref().map(|e| e.1.format(&args)), + directive.label.as_ref().map(|e| e.1.format(&args)), + directive.notes.iter().map(|e| e.format(&args)).collect(), + ) + } else { + (None, None, ThinVec::new()) + }; + let mut err = self.cannot_act_on_moved_value( span, desired_action.as_noun(), @@ -146,8 +180,13 @@ pub(crate) fn report_use_of_moved_or_uninitialized( moved_place, DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, ), + on_move_message, ); + for note in on_move_notes { + err.note(note); + } + let reinit_spans = maybe_reinitialized_locations .iter() .take(3) @@ -275,12 +314,16 @@ pub(crate) fn report_use_of_moved_or_uninitialized( if needs_note { if let Some(local) = place.as_local() { let span = self.body.local_decls[local].source_info.span; - err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move, - ty, - place: ¬e_msg, - span, - }); + if let Some(on_move_label) = on_move_label { + err.span_label(span, on_move_label); + } else { + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move, + ty, + place: ¬e_msg, + span, + }); + } } else { err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note { is_partial_move, @@ -545,8 +588,6 @@ fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) { } // for dbg!(x) which may take ownership, suggest dbg!(&x) instead - // but here we actually do not check whether the macro name is `dbg!` - // so that we may extend the scope a bit larger to cover more cases fn suggest_ref_for_dbg_args( &self, body: &hir::Expr<'_>, @@ -560,29 +601,41 @@ fn suggest_ref_for_dbg_args( }); let Some(var_info) = var_info else { return }; let arg_name = var_info.name; - struct MatchArgFinder { - expr_span: Span, - match_arg_span: Option, + struct MatchArgFinder<'tcx> { + tcx: TyCtxt<'tcx>, + move_span: Span, arg_name: Symbol, + match_arg_span: Option = None, } - impl Visitor<'_> for MatchArgFinder { + impl Visitor<'_> for MatchArgFinder<'_> { fn visit_expr(&mut self, e: &hir::Expr<'_>) { // dbg! is expanded into a match pattern, we need to find the right argument span - if let hir::ExprKind::Match(expr, ..) = &e.kind - && let hir::ExprKind::Path(hir::QPath::Resolved( - _, - path @ Path { segments: [seg], .. }, - )) = &expr.kind - && seg.ident.name == self.arg_name - && self.expr_span.source_callsite().contains(expr.span) + if let hir::ExprKind::Match(scrutinee, ..) = &e.kind + && let hir::ExprKind::Tup(args) = scrutinee.kind + && e.span.macro_backtrace().any(|expn| { + expn.macro_def_id.is_some_and(|macro_def_id| { + self.tcx.is_diagnostic_item(sym::dbg_macro, macro_def_id) + }) + }) { - self.match_arg_span = Some(path.span); + for arg in args { + if let hir::ExprKind::Path(hir::QPath::Resolved( + _, + path @ Path { segments: [seg], .. }, + )) = &arg.kind + && seg.ident.name == self.arg_name + && self.move_span.source_equal(arg.span) + { + self.match_arg_span = Some(path.span); + return; + } + } } hir::intravisit::walk_expr(self, e); } } - let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name }; + let mut finder = MatchArgFinder { tcx: self.infcx.tcx, move_span, arg_name, .. }; finder.visit_expr(body); if let Some(macro_arg_span) = finder.match_arg_span { err.span_suggestion_verbose( @@ -1526,10 +1579,8 @@ fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, let tcx = self.infcx.tcx; let generics = tcx.generics_of(self.mir_def_id()); - let Some(hir_generics) = tcx - .typeck_root_def_id(self.mir_def_id().to_def_id()) - .as_local() - .and_then(|def_id| tcx.hir_get_generics(def_id)) + let Some(hir_generics) = + tcx.hir_get_generics(tcx.typeck_root_def_id_local(self.mir_def_id())) else { return; }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index af8f723ff378..86d7119639a3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -23,8 +23,7 @@ use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Spanned, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind}; use rustc_trait_selection::infer::InferCtxtExt; @@ -1275,12 +1274,9 @@ fn explain_captures( if let ty::Param(param_ty) = *self_ty.kind() && let generics = self.infcx.tcx.generics_of(self.mir_def_id()) && let param = generics.type_param(param_ty, self.infcx.tcx) - && let Some(hir_generics) = self - .infcx - .tcx - .typeck_root_def_id(self.mir_def_id().to_def_id()) - .as_local() - .and_then(|def_id| self.infcx.tcx.hir_get_generics(def_id)) + && let Some(hir_generics) = self.infcx.tcx.hir_get_generics( + self.infcx.tcx.typeck_root_def_id_local(self.mir_def_id()), + ) && let spans = hir_generics .predicates .iter() @@ -1378,7 +1374,9 @@ fn explain_captures( matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) }); if is_option_or_result && maybe_reinitialized_locations_is_empty { - err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span }); + err.subdiagnostic(CaptureReasonLabel::BorrowContent { + var_span: var_span.shrink_to_hi(), + }); } if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { let ty = moved_place.ty(self.body, tcx).ty; diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 54253babafa7..89e008f06ebc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -990,30 +990,25 @@ fn add_move_error_details( let bind_to = &self.body.local_decls[*local]; let binding_span = bind_to.source_info.span; - if j == 0 { - err.span_label(binding_span, "data moved here"); - } else { - err.span_label(binding_span, "...and here"); - } - if binds_to.len() == 1 { let place_desc = self.local_name(*local).map(|sym| format!("`{sym}`")); - if !desugar_spans.contains(&binding_span) - && let Some(expr) = self.find_expr(binding_span) - { - // The binding_span doesn't correspond to a let binding desugaring - // and is an expression where calling `.clone()` would be valid. - let local_place: PlaceRef<'tcx> = (*local).into(); - self.suggest_cloning(err, local_place, bind_to.ty, expr, None); - } - - err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::LabelMovedHere { ty: bind_to.ty, place: place_desc.as_deref().unwrap_or("the place"), span: binding_span, }); + + if !desugar_spans.contains(&binding_span) + && let Some(expr) = self.find_expr(binding_span) + { + let local_place: PlaceRef<'tcx> = (*local).into(); + self.suggest_cloning(err, local_place, bind_to.ty, expr, None); + } + } else if j == 0 { + err.span_label(binding_span, "data moved here"); + } else { + err.span_label(binding_span, "...and here"); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index fba0879e8133..9f65052643e5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -372,6 +372,119 @@ fn give_name_from_error_region(&self, fr: RegionVid) -> Option { } } + /// For closure/coroutine upvar regions, attempts to find a named lifetime + /// from the parent function's signature that corresponds to the anonymous + /// region `fr`. This handles cases where a parent function's named lifetime + /// (like `'a`) appears in a captured variable's type but gets assigned a + /// separate `RegionVid` without an `external_name` during region renumbering. + /// + /// Works by getting the parent function's parameter type (with real named + /// lifetimes via `liberate_late_bound_regions`), then structurally walking + /// both the parent's parameter type and the closure's upvar type to find + /// where `fr` appears and what named lifetime is at the same position. + #[instrument(level = "trace", skip(self))] + fn give_name_if_we_can_match_upvar_args( + &self, + fr: RegionVid, + upvar_index: usize, + ) -> Option { + let tcx = self.infcx.tcx; + let defining_ty = self.regioncx.universal_regions().defining_ty; + + let closure_def_id = match defining_ty { + DefiningTy::Closure(def_id, _) + | DefiningTy::Coroutine(def_id, _) + | DefiningTy::CoroutineClosure(def_id, _) => def_id, + _ => return None, + }; + + let parent_def_id = tcx.parent(closure_def_id); + + // Only works if the parent is a function with a fn_sig. + if !matches!(tcx.def_kind(parent_def_id), DefKind::Fn | DefKind::AssocFn) { + return None; + } + + // Find which parameter index this upvar corresponds to by matching + // the captured variable's HirId against the parent's parameter patterns. + // This only matches simple bindings (not destructuring patterns) and + // only when the upvar is a direct parameter (not a local variable). + let captured_place = self.upvars.get(upvar_index)?; + let upvar_hir_id = captured_place.get_root_variable(); + let parent_local_def_id = parent_def_id.as_local()?; + let parent_body = tcx.hir_body_owned_by(parent_local_def_id); + let param_index = + parent_body.params.iter().position(|param| param.pat.hir_id == upvar_hir_id)?; + + // Get the parent fn's signature with liberated late-bound regions, + // so we have `ReLateParam` instead of `ReBound`. + let parent_fn_sig = tcx.fn_sig(parent_def_id).instantiate_identity(); + let liberated_sig = tcx.liberate_late_bound_regions(parent_def_id, parent_fn_sig); + let parent_param_ty = *liberated_sig.inputs().get(param_index)?; + + // Get the upvar's NLL type (with ReVar regions from renumbering). + let upvar_nll_ty = *defining_ty.upvar_tys().get(upvar_index)?; + + debug!( + "give_name_if_we_can_match_upvar_args: parent_param_ty={:?}, upvar_nll_ty={:?}", + parent_param_ty, upvar_nll_ty + ); + + // Collect free regions from both types in structural order. + // This only works when both types have the same structure, i.e. + // the upvar captures the whole variable, not a partial place like + // `x.field`. Bail out if the region counts differ, since that means + // the types diverged and positional correspondence is unreliable. + let mut parent_regions = vec![]; + tcx.for_each_free_region(&parent_param_ty, |r| parent_regions.push(r)); + + let mut nll_regions = vec![]; + tcx.for_each_free_region(&upvar_nll_ty, |r| nll_regions.push(r)); + + if parent_regions.len() != nll_regions.len() { + debug!( + "give_name_if_we_can_match_upvar_args: region count mismatch ({} vs {})", + parent_regions.len(), + nll_regions.len() + ); + return None; + } + + for (parent_r, nll_r) in iter::zip(&parent_regions, &nll_regions) { + if nll_r.as_var() == fr { + match parent_r.kind() { + ty::ReLateParam(late_param) => { + if let Some(name) = late_param.kind.get_name(tcx) { + let span = late_param + .kind + .get_id() + .and_then(|id| tcx.hir_span_if_local(id)) + .unwrap_or(DUMMY_SP); + return Some(RegionName { + name, + source: RegionNameSource::NamedLateParamRegion(span), + }); + } + } + ty::ReEarlyParam(ebr) => { + if ebr.is_named() { + let def_id = + tcx.generics_of(parent_def_id).region_param(ebr, tcx).def_id; + let span = tcx.hir_span_if_local(def_id).unwrap_or(DUMMY_SP); + return Some(RegionName { + name: ebr.name, + source: RegionNameSource::NamedEarlyParamRegion(span), + }); + } + } + _ => {} + } + } + } + + None + } + /// Finds an argument that contains `fr` and label it with a fully /// elaborated type, returning something like `'1`. Result looks /// like: @@ -644,6 +757,13 @@ fn try_match_adt_and_generic_args<'hir>( #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option { let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; + + // Before synthesizing an anonymous name like `'1`, try to find a + // named lifetime from the parent function's signature that matches. + if let Some(region_name) = self.give_name_if_we_can_match_upvar_args(fr, upvar_index) { + return Some(region_name); + } + let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( self.infcx.tcx, self.upvars, diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index fea5c2b99037..cd4d1f16b21a 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -456,7 +456,18 @@ pub(crate) enum CaptureReasonLabel<'a> { is_move_msg: bool, is_loop_message: bool, }, - #[label("help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents")] + #[suggestion( + "consider calling `.as_ref()` to borrow the value's contents", + applicability = "maybe-incorrect", + code = ".as_ref()", + style = "verbose" + )] + #[suggestion( + "consider calling `.as_mut()` to mutably borrow the value's contents", + applicability = "maybe-incorrect", + code = ".as_mut()", + style = "verbose" + )] BorrowContent { #[primary_span] var_span: Span, @@ -570,6 +581,16 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> { #[primary_span] span: Span, }, + #[label( + "data moved here because {$place} has type `{$ty}`, which does not implement the `Copy` \ + trait" + )] + LabelMovedHere { + ty: Ty<'tcx>, + place: &'a str, + #[primary_span] + span: Span, + }, #[note( "{$is_partial_move -> [true] partial move diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 29d38af472c2..47f14dc3df62 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -32,8 +32,7 @@ use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Spanned, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -375,10 +374,6 @@ fn body(&self) -> &Body<'tcx> { self.body } - fn unsized_feature_enabled(&self) -> bool { - self.tcx().features().unsized_fn_params() - } - /// Equate the inferred type and the annotated type for user type annotations #[instrument(skip(self), level = "debug")] fn check_user_type_annotations(&mut self) { @@ -661,7 +656,7 @@ fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) { ); } - if !self.unsized_feature_enabled() { + if !self.tcx().features().unsized_fn_params() { let trait_ref = ty::TraitRef::new( tcx, tcx.require_lang_item(LangItem::Sized, self.last_span), @@ -937,9 +932,10 @@ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { } } - // When `unsized_fn_params` is enabled, only function calls - // and nullary ops are checked in `check_call_dest`. - if !self.unsized_feature_enabled() { + // When `unsized_fn_params` is enabled, this is checked in `check_call_dest`, + // and `hir_typeck` still forces all non-argument locals to be sized (i.e., we don't + // fully re-check what was already checked on HIR). + if !self.tcx().features().unsized_fn_params() { match self.body.local_kind(local) { LocalKind::ReturnPointer | LocalKind::Arg => { // return values of normal functions are required to be @@ -1954,8 +1950,8 @@ fn check_call_dest( } // When `unsized_fn_params` is not enabled, - // this check is done at `check_local`. - if self.unsized_feature_enabled() { + // this check is done at `visit_local_decl`. + if self.tcx().features().unsized_fn_params() { let span = term.source_info.span; self.ensure_place_sized(dest_ty, span); } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index aeba5ee70cf1..e96c6c7c56f9 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -476,12 +476,10 @@ fn build(self) -> UniversalRegions<'tcx> { let mut indices = self.compute_indices(fr_static, defining_ty); debug!("build: indices={:?}", indices); - let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.to_def_id()); - // If this is a 'root' body (not a closure/coroutine/inline const), then // there are no extern regions, so the local regions start at the same // position as the (empty) sub-list of extern regions - let first_local_index = if self.mir_def.to_def_id() == typeck_root_def_id { + let first_local_index = if !self.infcx.tcx.is_typeck_child(self.mir_def.to_def_id()) { first_extern_index } else { // If this is a closure, coroutine, or inline-const, then the late-bound regions from the enclosing @@ -583,7 +581,7 @@ fn build(self) -> UniversalRegions<'tcx> { /// see `DefiningTy` for details. fn defining_ty(&self) -> DefiningTy<'tcx> { let tcx = self.infcx.tcx; - let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id()); + let typeck_root_def_id = tcx.typeck_root_def_id_local(self.mir_def); match tcx.hir_body_owner_kind(self.mir_def) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { @@ -614,7 +612,7 @@ fn defining_ty(&self) -> DefiningTy<'tcx> { BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); - if self.mir_def.to_def_id() == typeck_root_def_id { + if self.mir_def == typeck_root_def_id { let args = self.infcx.replace_free_regions_with_nll_infer_vars( NllRegionVariableOrigin::FreeRegion, identity_args, @@ -660,7 +658,7 @@ fn compute_indices( defining_ty: DefiningTy<'tcx>, ) -> UniversalRegionIndices<'tcx> { let tcx = self.infcx.tcx; - let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id()); + let typeck_root_def_id = tcx.typeck_root_def_id_local(self.mir_def); let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); let renumbered_args = defining_ty.args(); @@ -948,16 +946,14 @@ fn for_each_late_bound_region_in_recursive_scope<'tcx>( mut mir_def_id: LocalDefId, mut f: impl FnMut(ty::Region<'tcx>), ) { - let typeck_root_def_id = tcx.typeck_root_def_id(mir_def_id.to_def_id()); - // Walk up the tree, collecting late-bound regions until we hit the typeck root loop { for_each_late_bound_region_in_item(tcx, mir_def_id, &mut f); - if mir_def_id.to_def_id() == typeck_root_def_id { - break; - } else { + if tcx.is_typeck_child(mir_def_id.to_def_id()) { mir_def_id = tcx.local_parent(mir_def_id); + } else { + break; } } } diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 259ee25407a5..afa393a545cd 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -20,7 +20,7 @@ mod llvm_enzyme { }; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_hir::attrs::RustcAutodiff; - use rustc_span::{Ident, Span, Symbol, sym}; + use rustc_span::{Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, trace}; @@ -197,7 +197,7 @@ pub(crate) fn expand_reverse( /// } /// #[rustc_autodiff(Reverse, Duplicated, Active)] /// fn cos_box(x: &Box, dx: &mut Box, dret: f32) -> f32 { - /// std::intrinsics::autodiff(sin::<>, cos_box::<>, (x, dx, dret)) + /// std::intrinsics::autodiff(sin::<> as fn(..) -> .., cos_box::<>, (x, dx, dret)) /// } /// ``` /// FIXME(ZuseZ4): Once autodiff is enabled by default, make this a doc comment which is checked @@ -224,16 +224,18 @@ pub(crate) fn expand_with_mode( } _ => None, }, - Annotatable::AssocItem(assoc_item, Impl { of_trait: _ }) => match &assoc_item.kind { - ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => Some(( - assoc_item.vis.clone(), - sig.clone(), - ident.clone(), - generics.clone(), - true, - )), - _ => None, - }, + Annotatable::AssocItem(assoc_item, _ctxt @ (Impl { of_trait: _ } | Trait)) => { + match &assoc_item.kind { + ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => Some(( + assoc_item.vis.clone(), + sig.clone(), + ident.clone(), + generics.clone(), + true, + )), + _ => None, + } + } _ => None, }) else { dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); @@ -326,6 +328,7 @@ pub(crate) fn expand_with_mode( primal, first_ident(&meta_item_vec[0]), span, + &sig, &d_sig, &generics, is_impl, @@ -392,14 +395,14 @@ fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool { } Annotatable::Item(iitem.clone()) } - Annotatable::AssocItem(ref mut assoc_item, i @ Impl { .. }) => { + Annotatable::AssocItem(ref mut assoc_item, ctxt @ (Impl { .. } | Trait)) => { if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { assoc_item.attrs.push(attr); } if assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) { has_inline_never = true; } - Annotatable::AssocItem(assoc_item.clone(), i) + Annotatable::AssocItem(assoc_item.clone(), ctxt) } Annotatable::Stmt(ref mut stmt) => { match stmt.kind { @@ -440,7 +443,7 @@ fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool { } let d_annotatable = match &item { - Annotatable::AssocItem(_, _) => { + Annotatable::AssocItem(_, ctxt) => { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(d_fn); let d_fn = Box::new(ast::AssocItem { attrs: d_attrs, @@ -450,7 +453,7 @@ fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool { kind: assoc_item, tokens: None, }); - Annotatable::AssocItem(d_fn, Impl { of_trait: false }) + Annotatable::AssocItem(d_fn, *ctxt) } Annotatable::Item(_) => { let mut d_fn = ecx.item(span, d_attrs, ItemKind::Fn(d_fn)); @@ -496,18 +499,62 @@ fn assure_mut_ref(ty: &ast::Ty) -> ast::Ty { // Generate `autodiff` intrinsic call // ``` - // std::intrinsics::autodiff(source, diff, (args)) + // std::intrinsics::autodiff(source as fn(..) -> .., diff, (args)) // ``` fn call_autodiff( ecx: &ExtCtxt<'_>, primal: Ident, diff: Ident, span: Span, + p_sig: &FnSig, d_sig: &FnSig, generics: &Generics, is_impl: bool, ) -> rustc_ast::Stmt { let primal_path_expr = gen_turbofish_expr(ecx, primal, generics, span, is_impl); + + let self_ty = || ecx.ty_path(ast::Path::from_ident(Ident::with_dummy_span(kw::SelfUpper))); + let fn_ptr_params: ThinVec = p_sig + .decl + .inputs + .iter() + .map(|param| { + let ty = match ¶m.ty.kind { + TyKind::ImplicitSelf => self_ty(), + TyKind::Ref(lt, mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => ecx.ty( + span, + TyKind::Ref(lt.clone(), ast::MutTy { ty: self_ty(), mutbl: mt.mutbl }), + ), + TyKind::Ptr(mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => { + ecx.ty(span, TyKind::Ptr(ast::MutTy { ty: self_ty(), mutbl: mt.mutbl })) + } + _ => param.ty.clone(), + }; + ast::Param { + attrs: ast::AttrVec::new(), + ty, + pat: Box::new(ecx.pat_wild(span)), + id: ast::DUMMY_NODE_ID, + span, + is_placeholder: false, + } + }) + .collect(); + let fn_ptr_ty = ecx.ty( + span, + TyKind::FnPtr(Box::new(ast::FnPtrTy { + safety: p_sig.header.safety, + ext: p_sig.header.ext, + generic_params: ThinVec::new(), + decl: Box::new(ast::FnDecl { + inputs: fn_ptr_params, + output: p_sig.decl.output.clone(), + }), + decl_span: span, + })), + ); + let primal_fn_ptr = ecx.expr(span, ast::ExprKind::Cast(primal_path_expr, fn_ptr_ty)); + let diff_path_expr = gen_turbofish_expr(ecx, diff, generics, span, is_impl); let tuple_expr = ecx.expr_tuple( @@ -529,7 +576,7 @@ fn call_autodiff( let call_expr = ecx.expr_call( span, ecx.expr_path(enzyme_path), - vec![primal_path_expr, diff_path_expr, tuple_expr].into(), + vec![primal_fn_ptr, diff_path_expr, tuple_expr].into(), ); ecx.stmt_expr(call_expr) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 3ebde949b99b..c4a458089f2d 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -4,10 +4,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrStyle, token}; -use rustc_attr_parsing as attr; -use rustc_attr_parsing::parser::MetaItemOrLitParser; +use rustc_attr_parsing::parser::{AllowExprMetavar, MetaItemOrLitParser}; use rustc_attr_parsing::{ - AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry, + self as attr, AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry, }; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_hir::attrs::CfgEntry; @@ -44,6 +43,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result` (global). Has support diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index af78db156a22..f60113dbfc9b 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -51,7 +51,7 @@ pub(crate) fn expand_option_env<'cx>( let sp = cx.with_def_site_ctxt(sp); let value = lookup_env(cx, var); - cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied())); + cx.sess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied())); let e = match value { Err(VarError::NotPresent) => { let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); @@ -130,7 +130,7 @@ pub(crate) fn expand_env<'cx>( let span = cx.with_def_site_ctxt(sp); let value = lookup_env(cx, var); - cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied())); + cx.sess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied())); let e = match value { Err(err) => { let ExprKind::Lit(token::Lit { @@ -140,18 +140,21 @@ pub(crate) fn expand_env<'cx>( unreachable!("`expr_to_string` ensures this is a string lit") }; + let var = var.as_str(); let guar = match err { VarError::NotPresent => { if let Some(msg_from_user) = custom_msg { cx.dcx() .emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }) - } else if let Some(suggested_var) = find_similar_cargo_var(var.as_str()) { + } else if let Some(suggested_var) = find_similar_cargo_var(var) + && suggested_var != var + { cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVarTypo { span, var: *symbol, suggested_var: Symbol::intern(suggested_var), }) - } else if is_cargo_env_var(var.as_str()) { + } else if is_cargo_env_var(var) { cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { span, var: *symbol, @@ -177,7 +180,7 @@ pub(crate) fn expand_env<'cx>( ExpandResult::Ready(MacEager::expr(e)) } -/// Returns `true` if an environment variable from `env!` is one used by Cargo. +/// Returns `true` if an environment variable from `env!` could be one used by Cargo. fn is_cargo_env_var(var: &str) -> bool { var.starts_with("CARGO_") || var.starts_with("DEP_") @@ -187,25 +190,28 @@ fn is_cargo_env_var(var: &str) -> bool { const KNOWN_CARGO_VARS: &[&str] = &[ // List of known Cargo environment variables that are set for crates (not build scripts, OUT_DIR etc). // See: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates + // tidy-alphabetical-start + "CARGO_BIN_NAME", + "CARGO_CRATE_NAME", + "CARGO_MANIFEST_DIR", + "CARGO_MANIFEST_PATH", + "CARGO_PKG_AUTHORS", + "CARGO_PKG_DESCRIPTION", + "CARGO_PKG_HOMEPAGE", + "CARGO_PKG_LICENSE", + "CARGO_PKG_LICENSE_FILE", + "CARGO_PKG_NAME", + "CARGO_PKG_README", + "CARGO_PKG_REPOSITORY", + "CARGO_PKG_RUST_VERSION", "CARGO_PKG_VERSION", "CARGO_PKG_VERSION_MAJOR", "CARGO_PKG_VERSION_MINOR", "CARGO_PKG_VERSION_PATCH", "CARGO_PKG_VERSION_PRE", - "CARGO_PKG_AUTHORS", - "CARGO_PKG_NAME", - "CARGO_PKG_DESCRIPTION", - "CARGO_PKG_HOMEPAGE", - "CARGO_PKG_REPOSITORY", - "CARGO_PKG_LICENSE", - "CARGO_PKG_LICENSE_FILE", - "CARGO_PKG_RUST_VERSION", - "CARGO_PKG_README", - "CARGO_MANIFEST_DIR", - "CARGO_MANIFEST_PATH", - "CARGO_CRATE_NAME", - "CARGO_BIN_NAME", "CARGO_PRIMARY_PACKAGE", + "CARGO_TARGET_TMPDIR", + // tidy-alphabetical-end ]; fn find_similar_cargo_var(var: &str) -> Option<&'static str> { @@ -219,7 +225,13 @@ fn find_similar_cargo_var(var: &str) -> Option<&'static str> { let mut best_distance = usize::MAX; for &known_var in KNOWN_CARGO_VARS { - if let Some(distance) = edit_distance(var, known_var, max_dist) { + if let Some(mut distance) = edit_distance(var, known_var, max_dist) { + // assume `PACKAGE` to equals `PKG` + // (otherwise, `d("CARGO_PACKAGE_NAME", "CARGO_PKG_NAME") == d("CARGO_PACKAGE_NAME", "CARGO_CRATE_NAME") == 4`) + if var.contains("PACKAGE") && known_var.contains("PKG") { + distance = distance.saturating_sub(const { "PACKAGE".len() - "PKG".len() }) // == d("PACKAGE", "PKG") + } + if distance < best_distance { best_distance = distance; best_match = Some(known_var); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 39d210e14a09..171c15eb4b9f 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -545,6 +545,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { #[derive(Diagnostic)] pub(crate) enum EnvNotDefined<'a> { #[diag("environment variable `{$var}` not defined at compile time")] + #[help("`{$var}` may not be available for the current Cargo target")] #[help( "Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead" )] diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 1bce3c03743a..85ad8a63a54f 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -180,7 +180,7 @@ fn usize(&self) -> Box { } fn ptr_alignment(&self) -> Box { - let path = self.cx.std_path(&[sym::ptr, sym::Alignment]); + let path = self.cx.std_path(&[sym::mem, sym::Alignment]); let path = self.cx.path(self.span, path); self.cx.ty_path(path) } diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 16003c8ba135..ab7a9c3bccb3 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -277,7 +277,6 @@ fn load_binary_file( match cx.source_map().load_binary_file(&resolved_path) { Ok(data) => { cx.sess - .psess .file_depinfo .borrow_mut() .insert(Symbol::intern(&resolved_path.to_string_lossy())); diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml index 3367562f2683..c11fc5921ef1 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml @@ -43,7 +43,7 @@ jobs: # TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features if: matrix.os == 'ubuntu-latest' @@ -56,7 +56,7 @@ jobs: run: .github/scripts/free-disk-space.sh - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml deleted file mode 100644 index 95a4dcd3266d..000000000000 --- a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Security audit -on: - workflow_dispatch: - schedule: - - cron: '0 10 * * 1' # every monday at 10:00 UTC -permissions: - issues: write - checks: write -jobs: - audit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: | - sed -i 's/components.*/components = []/' rust-toolchain.toml - - uses: rustsec/audit-check@v2.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 07d9af4a9b54..7f9fd0cc7c5e 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -19,12 +19,22 @@ env: RUSTFLAGS: "-Dwarnings" jobs: + todo_check: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v6 + + - name: Check todo + run: ./y.sh check-todo + rustfmt: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Avoid installing rustc-dev run: | @@ -78,14 +88,14 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features if: matrix.os == 'ubuntu-latest' run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} @@ -127,7 +137,7 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features run: cat /proc/cpuinfo @@ -149,13 +159,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} @@ -201,10 +211,10 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} @@ -223,7 +233,7 @@ jobs: run: tar cvfJ cg_clif.tar.xz dist - name: Upload prebuilt cg_clif - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar.xz @@ -232,7 +242,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 if: ${{ github.ref == 'refs/heads/main' }} - needs: [rustfmt, test, bench, dist] + needs: [todo_check, rustfmt, test, bench, dist] permissions: contents: write # for creating the dev tag and release @@ -242,7 +252,7 @@ jobs: cancel-in-progress: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Download all built artifacts uses: actions/download-artifact@v4 diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml index b22725fdc9d4..0f91bc11753e 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml @@ -11,13 +11,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }} @@ -31,13 +31,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }} diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index afc1d0d0ab95..2d84d2c57fc6 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -28,9 +28,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" dependencies = [ "allocator-api2", ] @@ -43,42 +43,46 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cranelift-assembler-x64" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0377b13bf002a0774fcccac4f1102a10f04893d24060cf4b7350c87e4cbb647c" +checksum = "4f248321c6a7d4de5dcf2939368e96a397ad3f53b6a076e38d0104d1da326d37" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa027979140d023b25bf7509fb7ede3a54c3d3871fb5ead4673c4b633f671a2" +checksum = "ab6d78ff1f7d9bf8b7e1afbedbf78ba49e38e9da479d4c8a2db094e22f64e2bc" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618e4da87d9179a70b3c2f664451ca8898987aa6eb9f487d16988588b5d8cc40" +checksum = "6b6005ba640213a5b95382aeaf6b82bf028309581c8d7349778d66f27dc1180b" dependencies = [ "cranelift-entity", + "wasmtime-internal-core", ] [[package]] name = "cranelift-bitset" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db53764b5dad233b37b8f5dc54d3caa9900c54579195e00f17ea21f03f71aaa7" +checksum = "81fb5b134a12b559ff0c0f5af0fcd755ad380723b5016c4e0d36f74d39485340" +dependencies = [ + "wasmtime-internal-core", +] [[package]] name = "cranelift-codegen" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae927f1d8c0abddaa863acd201471d56e7fc6c3925104f4861ed4dc3e28b421" +checksum = "85837de8be7f17a4034a6b08816f05a3144345d2091937b39d415990daca28f4" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -90,21 +94,22 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown", + "hashbrown 0.16.1", + "libm", "log", "regalloc2", "rustc-hash", "serde", "smallvec", "target-lexicon", - "wasmtime-internal-math", + "wasmtime-internal-core", ] [[package]] name = "cranelift-codegen-meta" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fcf1e3e6757834bd2584f4cbff023fcc198e9279dcb5d684b4bb27a9b19f54" +checksum = "e433faa87d38e5b8ff469e44a26fea4f93e58abd7a7c10bad9810056139700c9" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -114,33 +119,34 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "205dcb9e6ccf9d368b7466be675ff6ee54a63e36da6fe20e72d45169cf6fd254" +checksum = "5397ba61976e13944ca71230775db13ee1cb62849701ed35b753f4761ed0a9b7" [[package]] name = "cranelift-control" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "108eca9fcfe86026054f931eceaf57b722c1b97464bf8265323a9b5877238817" +checksum = "cc81c88765580720eb30f4fc2c1bfdb75fcbf3094f87b3cd69cecca79d77a245" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d96496910065d3165f84ff8e1e393916f4c086f88ac8e1b407678bc78735aa" +checksum = "463feed5d46cf8763f3ba3045284cf706dd161496e20ec9c14afbb4ba09b9e66" dependencies = [ "cranelift-bitset", + "wasmtime-internal-core", ] [[package]] name = "cranelift-frontend" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e303983ad7e23c850f24d9c41fc3cb346e1b930f066d3966545e4c98dac5c9fb" +checksum = "a4c5eca7696c1c04ab4c7ed8d18eadbb47d6cc9f14ec86fe0881bf1d7e97e261" dependencies = [ "cranelift-codegen", "log", @@ -150,15 +156,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b0cf8d867d891245836cac7abafb0a5b0ea040a019d720702b3b8bcba40bfa" +checksum = "f1153844610cc9c6da8cf10ce205e45da1a585b7688ed558aa808bbe2e4e6d77" [[package]] name = "cranelift-jit" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf1e35da6eca2448395f483eb172ce71dd7842f7dc96f44bb8923beafe43c6d" +checksum = "41836de8321b303d3d4188e58cc09c30c7645337342acfcfb363732695cae098" dependencies = [ "anyhow", "cranelift-codegen", @@ -176,9 +182,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "792ba2a54100e34f8a36e3e329a5207cafd1f0918a031d34695db73c163fdcc7" +checksum = "b731f66cb1b69b60a74216e632968ebdbb95c488d26aa1448ec226ae0ffec33e" dependencies = [ "anyhow", "cranelift-codegen", @@ -187,9 +193,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24b641e315443e27807b69c440fe766737d7e718c68beb665a2d69259c77bf3" +checksum = "a97b583fe9a60f06b0464cee6be5a17f623fd91b217aaac99b51b339d19911af" dependencies = [ "cranelift-codegen", "libc", @@ -198,9 +204,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecba1f219a201cf946150538e631defd620c5051b62c52ecb89a0004bab263d4" +checksum = "9809d2d419cd18f17377f4ce64a7ad22eeda0d042c08833d3796657f1ddebc82" dependencies = [ "anyhow", "cranelift-codegen", @@ -213,9 +219,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e378a54e7168a689486d67ee1f818b7e5356e54ae51a1d7a53f4f13f7f8b7a" +checksum = "8594dc6bb4860fa8292f1814c76459dbfb933e1978d8222de6380efce45c7cee" [[package]] name = "crc32fast" @@ -233,24 +239,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "fallible-iterator" -version = "0.3.0" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "gimli" -version = "0.32.3" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" dependencies = [ - "fallible-iterator", + "fnv", + "hashbrown 0.16.1", "indexmap", "stable_deref_trait", ] @@ -260,6 +267,12 @@ name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "foldhash", ] @@ -272,12 +285,12 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", ] [[package]] @@ -325,12 +338,12 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "object" -version = "0.37.3" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc" dependencies = [ "crc32fast", - "hashbrown", + "hashbrown 0.16.1", "indexmap", "memchr", ] @@ -355,13 +368,13 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.13.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa" +checksum = "952ddbfc6f9f64d006c3efd8c9851a6ba2f2b944ba94730db255d55006e0ffda" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown", + "hashbrown 0.15.5", "log", "rustc-hash", "smallvec", @@ -468,24 +481,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] -name = "wasmtime-internal-jit-icache-coherence" -version = "41.0.3" +name = "wasmtime-internal-core" +version = "43.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bada5ca1cc47df7d14100e2254e187c2486b426df813cea2dd2553a7469f7674" +checksum = "e671917bb6856ae360cb59d7aaf26f1cfd042c7b924319dd06fd380739fc0b2e" dependencies = [ - "anyhow", - "cfg-if", - "libc", - "windows-sys 0.61.2", + "hashbrown 0.16.1", + "libm", ] [[package]] -name = "wasmtime-internal-math" -version = "41.0.3" +name = "wasmtime-internal-jit-icache-coherence" +version = "43.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf6f615d528eda9adc6eefb062135f831b5215c348f4c3ec3e143690c730605b" +checksum = "9b3112806515fac8495883885eb8dbdde849988ae91fe6beb544c0d7c0f4c9aa" dependencies = [ - "libm", + "cfg-if", + "libc", + "wasmtime-internal-core", + "windows-sys 0.61.2", ] [[package]] diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index a7b4664282ed..6707557f06f7 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,15 +8,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.128.3", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.128.3" } -cranelift-module = { version = "0.128.3" } -cranelift-native = { version = "0.128.3" } -cranelift-jit = { version = "0.128.3", optional = true } -cranelift-object = { version = "0.128.3" } +cranelift-codegen = { version = "0.130.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.130.0" } +cranelift-module = { version = "0.130.0" } +cranelift-native = { version = "0.130.0" } +cranelift-jit = { version = "0.130.0", optional = true } +cranelift-object = { version = "0.130.0" } target-lexicon = "0.13" -gimli = { version = "0.32", default-features = false, features = ["write"] } -object = { version = "0.37.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.33", default-features = false, features = ["write"] } +object = { version = "0.38.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.9.0", optional = true } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs index 6251687babc6..0720d72c6d7c 100644 --- a/compiler/rustc_codegen_cranelift/build_system/main.rs +++ b/compiler/rustc_codegen_cranelift/build_system/main.rs @@ -17,6 +17,7 @@ mod rustc_info; mod shared_utils; mod tests; +mod todo; mod utils; fn usage() { @@ -38,6 +39,7 @@ enum Command { Test, AbiCafe, Bench, + CheckTodo, } #[derive(Copy, Clone, Debug)] @@ -66,6 +68,7 @@ fn main() { Some("test") => Command::Test, Some("abi-cafe") => Command::AbiCafe, Some("bench") => Command::Bench, + Some("check-todo") => Command::CheckTodo, Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag), Some(command) => arg_error!("Unknown command {}", command), None => { @@ -139,6 +142,10 @@ fn main() { process::exit(0); } + if command == Command::CheckTodo { + todo::run(); + } + let rustup_toolchain_name = match (env::var("CARGO"), env::var("RUSTC"), env::var("RUSTDOC")) { (Ok(_), Ok(_), Ok(_)) => None, (_, Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()), @@ -202,7 +209,7 @@ fn main() { )) }; match command { - Command::Prepare => { + Command::Prepare | Command::CheckTodo => { // Handled above } Command::Test => { diff --git a/compiler/rustc_codegen_cranelift/build_system/todo.rs b/compiler/rustc_codegen_cranelift/build_system/todo.rs new file mode 100644 index 000000000000..66b31a10a065 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/build_system/todo.rs @@ -0,0 +1,70 @@ +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::{fs, process}; + +const EXTENSIONS: &[&str] = + &["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "toml", "yml", "yaml"]; + +fn has_supported_extension(path: &Path) -> bool { + path.extension().is_some_and(|ext| EXTENSIONS.iter().any(|e| ext == OsStr::new(e))) +} + +fn list_tracked_files() -> Result, String> { + let output = Command::new("git") + .args(["ls-files", "-z"]) + .output() + .map_err(|e| format!("Failed to run `git ls-files`: {e}"))?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(format!("`git ls-files` failed: {stderr}")); + } + + let mut files = Vec::new(); + for entry in output.stdout.split(|b| *b == 0) { + if entry.is_empty() { + continue; + } + let path = std::str::from_utf8(entry).unwrap(); + files.push(PathBuf::from(path)); + } + + Ok(files) +} + +pub(crate) fn run() -> ! { + let files = list_tracked_files().unwrap(); + let mut error_count = 0; + // Avoid embedding the task marker in source so greps only find real occurrences. + let todo_marker = "todo".to_ascii_uppercase(); + + for file in files { + if !has_supported_extension(&file) { + continue; + } + + let bytes = fs::read(&file).unwrap(); + let contents = std::str::from_utf8(&bytes).unwrap(); + + for (i, line) in contents.split('\n').enumerate() { + let trimmed = line.trim(); + if trimmed.contains(&todo_marker) { + eprintln!( + "{}:{}: {} is used for tasks that should be done before merging a PR; if you want to leave a message in the codebase use FIXME", + file.display(), + i + 1, + todo_marker + ); + error_count += 1; + } + } + } + + if error_count == 0 { + process::exit(0); + } + + eprintln!("found {} {}(s)", error_count, todo_marker); + process::exit(1); +} diff --git a/compiler/rustc_codegen_cranelift/build_system/usage.txt b/compiler/rustc_codegen_cranelift/build_system/usage.txt index 6c98087e5239..572fe7805810 100644 --- a/compiler/rustc_codegen_cranelift/build_system/usage.txt +++ b/compiler/rustc_codegen_cranelift/build_system/usage.txt @@ -6,6 +6,7 @@ USAGE: ./y.sh test [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME] ./y.sh abi-cafe [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] ./y.sh bench [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] + ./y.sh check-todo OPTIONS: --sysroot none|clif|llvm diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index 4dbd9dac94a8..32ed19300ac6 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -2,9 +2,3 @@ set -e rm -rf target/ build_system/target download/ build/ dist/ - -# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh -# FIXME remove at some point in the future -rm y.bin y.bin.dSYM y.exe y.pdb 2>/dev/null || true -rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/ -rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} diff --git a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs index b7491b7e522f..206c56e887c7 100644 --- a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs +++ b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs @@ -33,24 +33,24 @@ fn main() { let n = f32x4([nan, nan, nan, nan]); unsafe { - let min0 = simd_fmin(x, y); - let min1 = simd_fmin(y, x); + let min0 = simd_minimum_number_nsz(x, y); + let min1 = simd_minimum_number_nsz(y, x); assert_eq!(min0.into_array(), min1.into_array()); let e = f32x4([1.0, 1.0, 3.0, 3.0]); assert_eq!(min0.into_array(), e.into_array()); - let minn = simd_fmin(x, n); + let minn = simd_minimum_number_nsz(x, n); assert_eq!(minn.into_array(), x.into_array()); - let minn = simd_fmin(y, n); + let minn = simd_minimum_number_nsz(y, n); assert_eq!(minn.into_array(), y.into_array()); - let max0 = simd_fmax(x, y); - let max1 = simd_fmax(y, x); + let max0 = simd_maximum_number_nsz(x, y); + let max1 = simd_maximum_number_nsz(y, x); assert_eq!(max0.into_array(), max1.into_array()); let e = f32x4([2.0, 2.0, 4.0, 4.0]); assert_eq!(max0.into_array(), e.into_array()); - let maxn = simd_fmax(x, n); + let maxn = simd_maximum_number_nsz(x, n); assert_eq!(maxn.into_array(), x.into_array()); - let maxn = simd_fmax(y, n); + let maxn = simd_maximum_number_nsz(y, n); assert_eq!(maxn.into_array(), y.into_array()); } } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 5293b458d8c4..218050982e6d 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -9,9 +9,9 @@ rustc_private, transparent_unions, auto_traits, - freeze_impls, - thread_local + freeze_impls )] +#![cfg_attr(not(all(windows, target_env = "gnu")), feature(thread_local))] #![no_core] #![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)] diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 10549cd2a41e..6734d19fbb48 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,13 +1,5 @@ -#![feature( - no_core, - lang_items, - never_type, - linkage, - extern_types, - thread_local, - repr_simd, - rustc_private -)] +#![feature(no_core, lang_items, never_type, extern_types, thread_local, repr_simd, rustc_private)] +#![cfg_attr(not(any(jit, target_vendor = "apple", windows)), feature(linkage))] #![no_core] #![allow(dead_code, non_camel_case_types, internal_features)] diff --git a/compiler/rustc_codegen_cranelift/example/neon.rs b/compiler/rustc_codegen_cranelift/example/neon.rs index fb3e10a41c02..98a2a7af38f6 100644 --- a/compiler/rustc_codegen_cranelift/example/neon.rs +++ b/compiler/rustc_codegen_cranelift/example/neon.rs @@ -1,6 +1,6 @@ // Most of these tests are copied from https://github.com/japaric/stdsimd/blob/0f4413d01c4f0c3ffbc5a69e9a37fbc7235b31a9/coresimd/arm/neon.rs -#![feature(portable_simd)] +#![cfg_attr(target_arch = "aarch64", feature(portable_simd))] #[cfg(target_arch = "aarch64")] use std::arch::aarch64::*; diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 33db75f0943a..f0e38ae0610c 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -1,14 +1,8 @@ -#![feature( - core_intrinsics, - coroutines, - stmt_expr_attributes, - coroutine_trait, - repr_simd, - tuple_trait, - unboxed_closures -)] +#![feature(core_intrinsics, coroutines, coroutine_trait, repr_simd, tuple_trait, unboxed_closures)] #![allow(internal_features)] +#[cfg(target_arch = "x86_64")] +use std::arch::asm; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; use std::hint::black_box; @@ -173,6 +167,9 @@ enum Never {} rust_call_abi(); + // #[cfg(target_arch = "x86_64")] + // inline_asm_call_custom_abi(); + const fn no_str() -> Option> { None } @@ -279,6 +276,17 @@ unsafe fn test_simd() { #[cfg(not(jit))] test_crc32(); + + #[cfg(not(jit))] + test_xmm_roundtrip(); + #[cfg(not(jit))] + if is_x86_feature_detected!("avx") { + test_ymm_roundtrip(); + } + #[cfg(not(jit))] + if is_x86_feature_detected!("avx512f") { + test_zmm_roundtrip(); + } } } @@ -576,6 +584,65 @@ unsafe fn test_mm_cvtps_ph() { assert_eq_m128i(r, e); } +#[cfg(target_arch = "x86_64")] +#[cfg(not(jit))] +unsafe fn test_xmm_roundtrip() { + unsafe { + let input = [1u8; 16]; + let mut output = [0u8; 16]; + + asm!( + "movups {xmm}, [{input}]", + "movups [{output}], {xmm}", + input = in(reg) input.as_ptr(), + output = in(reg) output.as_mut_ptr(), + xmm = out(xmm_reg) _, + ); + + assert_eq!(input, output); + } +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx")] +#[cfg(not(jit))] +unsafe fn test_ymm_roundtrip() { + unsafe { + let input = [1u8; 32]; + let mut output = [0u8; 32]; + + asm!( + "vmovups {ymm}, [{input}]", + "vmovups [{output}], {ymm}", + input = in(reg) input.as_ptr(), + output = in(reg) output.as_mut_ptr(), + ymm = out(ymm_reg) _, + ); + + assert_eq!(input, output); + } +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx512f")] +#[cfg(not(jit))] +unsafe fn test_zmm_roundtrip() { + unsafe { + let input = [1u8; 64]; + let mut output = [0u8; 64]; + + asm!( + "vmovups {zmm}, [{input}]", + "vmovups [{output}], {zmm}", + input = in(reg) input.as_ptr(), + output = in(reg) output.as_mut_ptr(), + zmm = out(zmm_reg) _, + ); + + assert_eq!(input, output); + } +} + fn test_checked_mul() { let u: Option = u8::from_str_radix("1000", 10).ok(); assert_eq!(u, None); @@ -614,3 +681,18 @@ fn map(a: Option<(u8, Box)>) -> Option> { Some((_, instr)) => Some(instr), } } + +// FIXME enable once inline asm sym references are stabilized in cg_clif +// #[cfg(target_arch = "x86_64")] +// fn inline_asm_call_custom_abi() { +// use std::arch::{asm, naked_asm}; +// +// #[unsafe(naked)] +// unsafe extern "custom" fn double() { +// naked_asm!("add rax, rax", "ret"); +// } +// +// let mut x: u64 = 21; +// unsafe { asm!("call {}", sym double, inout("rax") x) }; +// assert_eq!(x, 42); +// } diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch index 38bb43f8204b..b7276e43153b 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch @@ -37,16 +37,7 @@ diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index bf2b6d59f88..d5ccce03bbf 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -300,8 +300,6 @@ impl_atomic_primitive!(AtomicI32(i32), size("32"), align(4)); - impl_atomic_primitive!(AtomicU32(u32), size("32"), align(4)); - impl_atomic_primitive!(AtomicI64(i64), size("64"), align(8)); - impl_atomic_primitive!(AtomicU64(u64), size("64"), align(8)); --impl_atomic_primitive!(AtomicI128(i128), size("128"), align(16)); --impl_atomic_primitive!(AtomicU128(u128), size("128"), align(16)); - - #[cfg(target_pointer_width = "16")] - impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(2)); -@@ -3585,44 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type { +@@ -3585,42 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type { 8, u64 AtomicU64 } @@ -62,7 +53,6 @@ index bf2b6d59f88..d5ccce03bbf 100644 - unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), -- rustc_diagnostic_item = "AtomicI128", - "i128", - "#![feature(integer_atomics)]\n\n", - atomic_min, atomic_max, @@ -81,7 +71,6 @@ index bf2b6d59f88..d5ccce03bbf 100644 - unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), -- rustc_diagnostic_item = "AtomicU128", - "u128", - "#![feature(integer_atomics)]\n\n", - atomic_umin, atomic_umax, diff --git a/compiler/rustc_codegen_cranelift/patches/0028-stdlib-Ensure-va_end-doesn-t-get-emitted-unless-VaList-is-a.patch b/compiler/rustc_codegen_cranelift/patches/0028-stdlib-Ensure-va_end-doesn-t-get-emitted-unless-VaList-is-a.patch deleted file mode 100644 index 2aa93164674f..000000000000 --- a/compiler/rustc_codegen_cranelift/patches/0028-stdlib-Ensure-va_end-doesn-t-get-emitted-unless-VaList-is-a.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 116abc64add4d617104993a7a3011f20bcf31ef2 Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Mon, 26 Jan 2026 16:20:58 +0000 -Subject: [PATCH] Ensure va_end doesn't get emitted unless VaList is actually - used - ---- - library/core/src/ffi/va_list.rs | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs -index d0f1553..75129af 100644 ---- a/library/core/src/ffi/va_list.rs -+++ b/library/core/src/ffi/va_list.rs -@@ -217,6 +217,7 @@ impl Clone for VaList<'_> { - - #[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")] - impl<'f> const Drop for VaList<'f> { -+ #[inline] - fn drop(&mut self) { - // SAFETY: this variable argument list is being dropped, so won't be read from again. - unsafe { va_end(self) } --- -2.43.0 - diff --git a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch index 340f6cc9b0e7..2a6bfe816457 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch @@ -4,13 +4,13 @@ Date: Sun, 15 Feb 2026 14:06:49 +0000 Subject: [PATCH] Disable f16 math tests for cranelift --- - coretests/tests/floats/mod.rs | 26 +++++++++++++------------- + coretests/tests/num/floats.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs index c61961f8584..d7b4fa20322 100644 ---- a/coretests/tests/floats/mod.rs -+++ b/coretests/tests/floats/mod.rs +--- a/coretests/tests/num/floats.rs ++++ b/coretests/tests/num/floats.rs @@ -1534,7 +1534,7 @@ fn s_nan() -> Float { name: powf, attrs: { @@ -128,6 +128,5 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, test { --- +-- 2.50.1 - diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain.toml b/compiler/rustc_codegen_cranelift/rust-toolchain.toml index fe967c84352c..d4bb9bea82bb 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain.toml +++ b/compiler/rustc_codegen_cranelift/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-02-18" +channel = "nightly-2026-03-25" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index bb9f69b5c974..2ca0c3cab910 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -63,18 +63,18 @@ index 2e16f2cf27..3ac3df99a8 100644 # Note that RUSTFLAGS_BOOTSTRAP should always be added to the end of # RUSTFLAGS, since that causes RUSTFLAGS_BOOTSTRAP to override RUSTFLAGS. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs -index a656927b1f6..44fc5546fac 100644 +index bc68bfe396..00143ef3ed 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs -@@ -2249,7 +2249,7 @@ pub fn parse_download_ci_llvm<'a>( - } +@@ -2230,7 +2230,7 @@ pub fn download_ci_rustc_commit<'a>( + return None; + } - #[cfg(not(test))] -- if b && dwn_ctx.is_running_on_ci && CiEnv::is_rust_lang_managed_ci_job() { -+ if false && dwn_ctx.is_running_on_ci && CiEnv::is_rust_lang_managed_ci_job() { - // On rust-lang CI, we must always rebuild LLVM if there were any modifications to it - panic!( - "\`llvm.download-ci-llvm\` cannot be set to \`true\` on CI. Use \`if-unchanged\` instead." +- if dwn_ctx.is_running_on_ci() { ++ if false && dwn_ctx.is_running_on_ci() { + eprintln!("CI rustc commit matches with HEAD and we are in CI."); + eprintln!( + "\`rustc.download-ci\` functionality will be skipped as artifacts are not available." diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 330fb465de..a4593ed96f 100644 --- a/src/build_helper/src/git.rs diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 4cad18f2a94f..71ff4eef071c 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -20,7 +20,6 @@ for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|//@ error-pa done git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed -git checkout -- tests/ui/proc-macro/pretty-print-hack/ git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs # missing features @@ -152,7 +151,6 @@ rm -r tests/run-make/short-ice # ICE backtrace begin/end marker mismatch rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump rm -r tests/run-make/strip # same rm -r tests/run-make-cargo/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source -rm -r tests/run-make/translation # same rm -r tests/run-make-cargo/panic-immediate-abort-works # same rm -r tests/run-make-cargo/panic-immediate-abort-codegen # same rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features @@ -175,7 +173,7 @@ rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort # bugs in the test suite # ====================== -rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue +rm tests/ui/process/nofile-limit.rs # FIXME some AArch64 linking issue rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables rm -r tests/incremental/extern_static/issue-49153.rs # assumes reference to undefined static gets optimized away diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 97a19b8976d3..13f5ad5157ce 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use rustc_target::callconv::{FnAbi, PassMode}; use rustc_target::spec::Arch; use smallvec::{SmallVec, smallvec}; diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index b11f42408f58..b22afca847aa 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -6,8 +6,7 @@ use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, }; -use rustc_span::Symbol; -use rustc_span::source_map::Spanned; +use rustc_span::{Spanned, Symbol}; use rustc_target::callconv::FnAbi; use rustc_target::spec::{Arch, HasTargetSpec, Target}; diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 1daf428acf76..b14988577845 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -120,9 +120,15 @@ fn codegen_global_asm_inner<'tcx>( } let symbol = tcx.symbol_name(instance); + let symbol_name = if tcx.sess.target.is_like_darwin { + format!("_{}", symbol.name) + } else { + symbol.name.to_owned() + }; + // FIXME handle the case where the function was made private to the // current codegen unit - global_asm.push_str(&escape_symbol_name(tcx, symbol.name, span)); + global_asm.push_str(&escape_symbol_name(tcx, &symbol_name, span)); } GlobalAsmOperandRef::SymStatic { def_id } => { if cfg!(not(feature = "inline_asm_sym")) { @@ -134,7 +140,13 @@ fn codegen_global_asm_inner<'tcx>( let instance = Instance::mono(tcx, def_id); let symbol = tcx.symbol_name(instance); - global_asm.push_str(&escape_symbol_name(tcx, symbol.name, span)); + let symbol_name = if tcx.sess.target.is_like_darwin { + format!("_{}", symbol.name) + } else { + symbol.name.to_owned() + }; + + global_asm.push_str(&escape_symbol_name(tcx, &symbol_name, span)); } } } diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index ac0da06cbb8e..8100d565b397 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -3,8 +3,10 @@ use std::fmt::Write; use cranelift_codegen::isa::CallConv; +use rustc_abi::CanonAbi; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::LangItem; +use rustc_middle::ty::layout::FnAbiOf; use rustc_span::sym; use rustc_target::asm::*; use rustc_target::spec::Arch; @@ -120,21 +122,30 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( .unwrap(); let symbol = fx.tcx.symbol_name(instance); - // Pass a wrapper rather than the function itself as the function itself may not - // be exported from the main codegen unit and may thus be unreachable from the - // object file created by an external assembler. - let wrapper_name = format!( - "{}__inline_asm_{}_wrapper_n{}", - fx.symbol_name, - fx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - fx.inline_asm_index, - ); - fx.inline_asm_index += 1; - let sig = - get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); - create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name); + if FullyMonomorphizedLayoutCx(fx.tcx) + .fn_abi_of_instance(instance, ty::List::empty()) + .conv + == CanonAbi::Custom + { + // We can't create a wrapper for custom ABI functions. + CInlineAsmOperand::Symbol { symbol: symbol.name.to_owned() } + } else { + // Pass a wrapper rather than the function itself as the function itself may not + // be exported from the main codegen unit and may thus be unreachable from the + // object file created by an external assembler. + let wrapper_name = format!( + "{}__inline_asm_{}_wrapper_n{}", + fx.symbol_name, + fx.cgu_name.as_str().replace('.', "__").replace('-', "_"), + fx.inline_asm_index, + ); + fx.inline_asm_index += 1; + let sig = + get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); + create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name); - CInlineAsmOperand::Symbol { symbol: wrapper_name } + CInlineAsmOperand::Symbol { symbol: wrapper_name } + } } else { span_bug!(span, "invalid type for asm sym (fn)"); } @@ -548,22 +559,21 @@ fn generate_asm_wrapper(&self, asm_name: &str) -> String { match self.arch { InlineAsmArch::X86_64 => match reg { InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + if matches!( + reg.reg_class(), + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg + ) => { - // rustc emits x0 rather than xmm0 - let class = match *modifier { - None | Some('x') => "xmm", - Some('y') => "ymm", - Some('z') => "zmm", - _ => unreachable!(), - }; - write!( - generated_asm, - "{class}{}", - reg as u32 - X86InlineAsmReg::xmm0 as u32 - ) - .unwrap(); + // rustc emits x0/y0/z0 rather than xmm0/ymm0/zmm0 + let name = reg.name(); + if let Some(prefix) = modifier { + let index = &name[3..]; + write!(generated_asm, "{prefix}mm{index}").unwrap(); + } else { + write!(generated_asm, "{name}").unwrap(); + } } _ => reg .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) @@ -575,7 +585,13 @@ fn generate_asm_wrapper(&self, asm_name: &str) -> String { CInlineAsmOperand::Const { ref value } => { generated_asm.push_str(value); } - CInlineAsmOperand::Symbol { ref symbol } => generated_asm.push_str(symbol), + CInlineAsmOperand::Symbol { ref symbol } => { + if binary_format == BinaryFormat::Macho { + generated_asm.push('_'); + } + + generated_asm.push_str(symbol); + } } } } @@ -716,12 +732,17 @@ fn save_register( InlineAsmArch::X86_64 => { match reg { InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + if matches!( + reg.reg_class(), + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg + ) => { - // rustc emits x0 rather than xmm0 - write!(generated_asm, " movups [rbx+0x{:x}], ", offset.bytes()).unwrap(); - write!(generated_asm, "xmm{}", reg as u32 - X86InlineAsmReg::xmm0 as u32) + // rustc emits x0/y0/z0 rather than xmm0/ymm0/zmm0 + let name = reg.name(); + let mov = if name.starts_with("xmm") { "movups" } else { "vmovups" }; + write!(generated_asm, " {mov} [rbx+0x{:x}], {name}", offset.bytes()) .unwrap(); } _ => { @@ -761,16 +782,17 @@ fn restore_register( InlineAsmArch::X86_64 => { match reg { InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + if matches!( + reg.reg_class(), + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg + ) => { - // rustc emits x0 rather than xmm0 - write!( - generated_asm, - " movups xmm{}", - reg as u32 - X86InlineAsmReg::xmm0 as u32 - ) - .unwrap(); + // rustc emits x0/y0/z0 rather than xmm0/ymm0/zmm0 + let name = reg.name(); + let mov = if name.starts_with("xmm") { "movups" } else { "vmovups" }; + write!(generated_asm, " {mov} {name}").unwrap(); } _ => { generated_asm.push_str(" mov "); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index ab9a11305baa..780550fc4cc7 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -24,8 +24,7 @@ macro_rules! intrinsic_args { use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_span::source_map::Spanned; -use rustc_span::{Symbol, sym}; +use rustc_span::{Spanned, Symbol, sym}; use rustc_target::spec::PanicStrategy; pub(crate) use self::llvm::codegen_llvm_intrinsic_call; @@ -347,19 +346,15 @@ fn codegen_float_intrinsic_call<'tcx>( sym::log10f32 => ("log10f", 1, fx.tcx.types.f32, types::F32), sym::log10f64 => ("log10", 1, fx.tcx.types.f64, types::F64), sym::log10f128 => ("log10f128", 1, fx.tcx.types.f128, types::F128), - sym::fabsf16 => ("fabsf16", 1, fx.tcx.types.f16, types::F16), - sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32, types::F32), - sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64), - sym::fabsf128 => ("fabsf128", 1, fx.tcx.types.f128, types::F128), sym::fmaf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16), sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64), sym::fmaf128 => ("fmaf128", 3, fx.tcx.types.f128, types::F128), // FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation - sym::fmuladdf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f16 - sym::fmuladdf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f32 - sym::fmuladdf64 => ("fma", 3, fx.tcx.types.f64, types::F64), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f64 - sym::fmuladdf128 => ("fmaf128", 3, fx.tcx.types.f128, types::F128), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f128 + sym::fmuladdf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16), // FIXME: use cranelift intrinsic analogous to llvm.fmuladd.f16 + sym::fmuladdf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), // FIXME: use cranelift intrinsic analogous to llvm.fmuladd.f32 + sym::fmuladdf64 => ("fma", 3, fx.tcx.types.f64, types::F64), // FIXME: use cranelift intrinsic analogous to llvm.fmuladd.f64 + sym::fmuladdf128 => ("fmaf128", 3, fx.tcx.types.f128, types::F128), // FIXME: use cranelift intrinsic analogous to llvm.fmuladd.f128 sym::copysignf16 => ("copysignf16", 2, fx.tcx.types.f16, types::F16), sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32), sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64), @@ -442,11 +437,7 @@ fn codegen_float_intrinsic_call<'tcx>( sym::copysignf32 | sym::copysignf64 => { CValue::by_val(fx.bcx.ins().fcopysign(args[0], args[1]), layout) } - sym::fabsf16 => CValue::by_val(codegen_f16_f128::abs_f16(fx, args[0]), layout), - sym::fabsf128 => CValue::by_val(codegen_f16_f128::abs_f128(fx, args[0]), layout), - sym::fabsf32 - | sym::fabsf64 - | sym::floorf32 + sym::floorf32 | sym::floorf64 | sym::ceilf32 | sym::ceilf64 @@ -457,7 +448,6 @@ fn codegen_float_intrinsic_call<'tcx>( | sym::sqrtf32 | sym::sqrtf64 => { let val = match intrinsic { - sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(args[0]), sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]), sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]), sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]), @@ -1180,6 +1170,28 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, old); } + sym::fabs => { + intrinsic_args!(fx, args => (arg); intrinsic); + let layout = arg.layout(); + let ty::Float(float_ty) = layout.ty.kind() else { + span_bug!( + source_info.span, + "expected float type for fabs intrinsic: {:?}", + layout.ty + ); + }; + let x = arg.load_scalar(fx); + let val = match float_ty { + FloatTy::F32 | FloatTy::F64 => fx.bcx.ins().fabs(x), + // FIXME(bytecodealliance/wasmtime#8312): Use `fabsf16` once Cranelift + // backend lowerings are implemented. + FloatTy::F16 => codegen_f16_f128::abs_f16(fx, x), + FloatTy::F128 => codegen_f16_f128::abs_f128(fx, x), + }; + let val = CValue::by_val(val, layout); + ret.write_cvalue(fx, val); + } + sym::minimumf16 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1267,7 +1279,7 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); } - sym::minnumf16 => { + sym::minimum_number_nsz_f16 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); let b = b.load_scalar(fx); @@ -1276,7 +1288,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); ret.write_cvalue(fx, val); } - sym::minnumf32 => { + sym::minimum_number_nsz_f32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); let b = b.load_scalar(fx); @@ -1285,7 +1297,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); ret.write_cvalue(fx, val); } - sym::minnumf64 => { + sym::minimum_number_nsz_f64 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); let b = b.load_scalar(fx); @@ -1294,7 +1306,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } - sym::minnumf128 => { + sym::minimum_number_nsz_f128 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); let b = b.load_scalar(fx); @@ -1303,7 +1315,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); ret.write_cvalue(fx, val); } - sym::maxnumf16 => { + sym::maximum_number_nsz_f16 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); let b = b.load_scalar(fx); @@ -1312,7 +1324,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); ret.write_cvalue(fx, val); } - sym::maxnumf32 => { + sym::maximum_number_nsz_f32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); let b = b.load_scalar(fx); @@ -1321,7 +1333,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); ret.write_cvalue(fx, val); } - sym::maxnumf64 => { + sym::maximum_number_nsz_f64 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); let b = b.load_scalar(fx); @@ -1330,7 +1342,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } - sym::maxnumf128 => { + sym::maximum_number_nsz_f128 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); let b = b.load_scalar(fx); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 200cedf0f6ae..cc2311a67b5d 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -493,7 +493,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } } - sym::simd_fmin | sym::simd_fmax => { + sym::simd_minimum_number_nsz | sym::simd_maximum_number_nsz => { intrinsic_args!(fx, args => (x, y); intrinsic); if !x.layout().ty.is_simd() { @@ -508,8 +508,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( _ => unreachable!("{:?}", lane_ty), } match intrinsic { - sym::simd_fmin => crate::num::codegen_float_min(fx, x_lane, y_lane), - sym::simd_fmax => crate::num::codegen_float_max(fx, x_lane, y_lane), + sym::simd_minimum_number_nsz => { + crate::num::codegen_float_min(fx, x_lane, y_lane) + } + sym::simd_maximum_number_nsz => { + crate::num::codegen_float_max(fx, x_lane, y_lane) + } _ => unreachable!(), } }); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 82c2e91b4b0f..cbbb0ccbbc21 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -46,7 +46,7 @@ use rustc_session::Session; use rustc_session::config::OutputFilenames; use rustc_span::{Symbol, sym}; -use rustc_target::spec::{Abi, Arch, Env, Os}; +use rustc_target::spec::{Arch, CfgAbi, Env, Os}; pub use crate::config::*; use crate::prelude::*; @@ -178,7 +178,7 @@ fn target_config(&self, sess: &Session) -> TargetConfig { let has_reliable_f16_f128 = !(sess.target.arch == Arch::X86_64 && sess.target.os == Os::Windows && sess.target.env == Env::Gnu - && sess.target.abi != Abi::Llvm); + && sess.target.cfg_abi != CfgAbi::Llvm); // FIXME(f128): f128 math operations need f128 math symbols, which currently aren't always // filled in by compiler-builtins. The only libc that provides these currently is glibc. diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 95d44dfb6d95..e583f3f2f754 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -498,10 +498,10 @@ fn codegen_ptr_binop<'tcx>( } } -// In Rust floating point min and max don't propagate NaN. In Cranelift they do however. -// For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*` -// and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing -// a float against itself. Only in case of NaN is it not equal to itself. +// In Rust floating point min and max don't propagate NaN (not even SNaN). In Cranelift they do +// however. For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for +// `minimum_number_nsz` and `a.is_nan() ? b : (a <= b ? b : a)` for `maximum_number_nsz`. NaN checks +// are done by comparing a float against itself. Only in case of NaN is it not equal to itself. pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift `fcmp` once // `f16`/`f128` backend lowerings have been added to Cranelift. diff --git a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml index aa4b4dc22c3e..a2a932893054 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml @@ -1,4 +1,4 @@ -# TODO: refactor to avoid duplication with the ci.yml file. +# FIXME: refactor to avoid duplication with the ci.yml file. name: Failures on: @@ -92,7 +92,7 @@ jobs: run: ./y.sh prepare - name: Run tests - # TODO: re-enable those tests for libgccjit 12. + # FIXME: re-enable those tests for libgccjit 12. if: matrix.libgccjit_version.gcc != 'libgccjit12.so' id: tests run: | @@ -100,7 +100,7 @@ jobs: rg --text "test result" output_log >> $GITHUB_STEP_SUMMARY - name: Run failing ui pattern tests for ICE - # TODO: re-enable those tests for libgccjit 12. + # FIXME: re-enable those tests for libgccjit 12. if: matrix.libgccjit_version.gcc != 'libgccjit12.so' id: ui-tests run: | diff --git a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml index 11bc88e67d2d..c36db18ed4aa 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml @@ -1,4 +1,4 @@ -# TODO: check if qemu-user-static-binfmt is needed (perhaps to run some tests since it probably calls exec). +# FIXME: check if qemu-user-static-binfmt is needed (perhaps to run some tests since it probably calls exec). name: m68k CI @@ -24,7 +24,7 @@ jobs: matrix: commands: [ "--std-tests", - # TODO(antoyo): fix those on m68k. + # FIXME(antoyo): fix those on m68k. #"--test-libcore", #"--extended-rand-tests", #"--extended-regex-example-tests", diff --git a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml index c0a0e3344cc2..a58728573168 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml @@ -38,7 +38,7 @@ jobs: - name: Install packages run: sudo apt-get install ninja-build ripgrep - # TODO: remove when we have binutils version 2.43 in the repo. + # FIXME: remove when we have binutils version 2.43 in the repo. - name: Install more recent binutils run: | echo "deb http://archive.ubuntu.com/ubuntu plucky main universe" | sudo tee /etc/apt/sources.list.d/plucky-copies.list @@ -94,7 +94,7 @@ jobs: if: ${{ matrix.cargo_runner }} run: | # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro. - # TODO: remove --skip test_tile_ when it's implemented. + # FIXME: remove --skip test_tile_ when it's implemented. STDARCH_TEST_SKIP_FUNCTION="xsave,xsaveopt,xsave64,xsaveopt64" STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_tile_ # Summary job for the merge queue. diff --git a/compiler/rustc_codegen_gcc/build_system/src/prepare.rs b/compiler/rustc_codegen_gcc/build_system/src/prepare.rs index 1e97e8d93274..b62527f241fb 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/prepare.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/prepare.rs @@ -148,7 +148,7 @@ fn prepare_libcore( Ok(()) } -// TODO: remove when we can ignore warnings in rustdoc tests. +// FIXME: remove when we can ignore warnings in rustdoc tests. fn prepare_rand() -> Result<(), String> { // Apply patch for the rand crate. let file_path = "patches/crates/0001-Remove-deny-warnings.patch"; diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index 096f8c98376c..8189e6b39747 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -285,7 +285,7 @@ fn build_sysroot(env: &Env, args: &TestArg) -> Result<(), String> { Ok(()) } -// TODO(GuillaumeGomez): when rewriting in Rust, refactor with the code in tests/lang_tests_common.rs if possible. +// FIXME(GuillaumeGomez): when rewriting in Rust, refactor with the code in tests/lang_tests_common.rs if possible. fn maybe_run_command_in_vm( command: &[&dyn AsRef], env: &Env, @@ -648,16 +648,16 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> { "https://github.com/BurntSushi/memchr", "https://github.com/dtolnay/itoa", "https://github.com/rust-lang/cfg-if", - //"https://github.com/rust-lang-nursery/lazy-static.rs", // TODO: re-enable when the + //"https://github.com/rust-lang-nursery/lazy-static.rs", // FIXME: re-enable when the //failing test is fixed upstream. //"https://github.com/marshallpierce/rust-base64", // FIXME: one test is OOM-killed. - // TODO: ignore the base64 test that is OOM-killed. + // FIXME: ignore the base64 test that is OOM-killed. //"https://github.com/time-rs/time", // FIXME: one test fails (https://github.com/time-rs/time/issues/719). "https://github.com/rust-lang/log", "https://github.com/bitflags/bitflags", //"https://github.com/serde-rs/serde", // FIXME: one test fails. - //"https://github.com/rayon-rs/rayon", // TODO: very slow, only run on master? - //"https://github.com/rust-lang/cargo", // TODO: very slow, only run on master? + //"https://github.com/rayon-rs/rayon", // FIXME: very slow, only run on master? + //"https://github.com/rust-lang/cargo", // FIXME: very slow, only run on master? ]; let mut env = env.clone(); @@ -699,7 +699,7 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { println!("[TEST] libcore"); let path = get_sysroot_dir().join("sysroot_src/library/coretests"); let _ = remove_dir_all(path.join("target")); - // TODO(antoyo): run in release mode when we fix the failures. + // FIXME(antoyo): run in release mode when we fix the failures. run_cargo_command(&[&"test"], Some(&path), env, args)?; Ok(()) } diff --git a/compiler/rustc_codegen_gcc/doc/debugging-libgccjit.md b/compiler/rustc_codegen_gcc/doc/debugging-libgccjit.md index be0ec83f7cdc..b2741b4134da 100644 --- a/compiler/rustc_codegen_gcc/doc/debugging-libgccjit.md +++ b/compiler/rustc_codegen_gcc/doc/debugging-libgccjit.md @@ -71,4 +71,4 @@ Maybe by calling the following at the beginning of gdb: set substitute-path /usr/src/debug/gcc /path/to/gcc-repo/gcc ``` -TODO(antoyo): but that's not what I remember I was doing. +FIXME(antoyo): but that's not what I remember I was doing. diff --git a/compiler/rustc_codegen_gcc/doc/subtree.md b/compiler/rustc_codegen_gcc/doc/subtree.md index 5d7af2a066bd..a81b6c9c74bd 100644 --- a/compiler/rustc_codegen_gcc/doc/subtree.md +++ b/compiler/rustc_codegen_gcc/doc/subtree.md @@ -47,6 +47,6 @@ git push PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name ``` -TODO: write a script that does the above. +FIXME: write a script that does the above. https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.20madness/near/258877725 diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index d5c386ffb3dd..6e155f89ee5c 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -275,7 +275,7 @@ unsafe fn uninitialized() -> T { } } - // TODO(antoyo): to make this work, support weak linkage. + // FIXME(antoyo): to make this work, support weak linkage. //unsafe { assert_eq!(ABC as usize, 0); } &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>; diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 56ed7c01ed20..4d1274a63d1f 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -105,7 +105,7 @@ pub struct FnAbiGcc<'gcc> { } pub trait FnAbiGccExt<'gcc, 'tcx> { - // TODO(antoyo): return a function pointer type instead? + // FIXME(antoyo): return a function pointer type instead? fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> FnAbiGcc<'gcc>; fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; #[cfg(feature = "master")] @@ -260,7 +260,7 @@ pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option FnAttribute::NvptxKernel, arch => panic!("Arch {arch} does not support GpuKernel calling convention"), }, - // TODO(antoyo): check if those AVR attributes are mapped correctly. + // FIXME(antoyo): check if those AVR attributes are mapped correctly. CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { InterruptKind::Avr => FnAttribute::AvrSignal, InterruptKind::AvrNonBlocking => FnAttribute::AvrInterrupt, diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 1f464d7e1226..6b92174ddf1c 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -98,7 +98,7 @@ fn create_wrapper_function( ))); if tcx.sess.must_emit_unwind_tables() { - // TODO(antoyo): emit unwind tables. + // FIXME(antoyo): emit unwind tables. } let block = func.new_block("entry"); @@ -138,6 +138,6 @@ fn create_wrapper_function( block.end_with_void_return(None); } - // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances + // FIXME(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 } diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 319f3d327873..c5fb257107ff 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -308,13 +308,13 @@ fn codegen_inline_asm( } InlineAsmOperandRef::SymFn { instance } => { - // TODO(@Amanieu): Additional mangling is needed on + // FIXME(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) // or byte count suffixes (x86 Windows). constants_len += self.tcx.symbol_name(instance).name.len(); } InlineAsmOperandRef::SymStatic { def_id } => { - // TODO(@Amanieu): Additional mangling is needed on + // FIXME(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O). constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len(); @@ -440,7 +440,7 @@ fn codegen_inline_asm( match *piece { InlineAsmTemplatePiece::String(ref string) => { for char in string.chars() { - // TODO(antoyo): might also need to escape | if rustc doesn't do it. + // FIXME(antoyo): might also need to escape | if rustc doesn't do it. let escaped_char = match char { '%' => "%%", '{' => "%{", @@ -496,7 +496,7 @@ fn codegen_inline_asm( } InlineAsmOperandRef::SymFn { instance } => { - // TODO(@Amanieu): Additional mangling is needed on + // FIXME(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) // or byte count suffixes (x86 Windows). let name = self.tcx.symbol_name(instance).name; @@ -504,7 +504,7 @@ fn codegen_inline_asm( } InlineAsmOperandRef::SymStatic { def_id } => { - // TODO(@Amanieu): Additional mangling is needed on + // FIXME(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O). let instance = Instance::mono(self.tcx, def_id); let name = self.tcx.symbol_name(instance).name; @@ -557,7 +557,7 @@ fn codegen_inline_asm( InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { // "cc" is cr0 on powerpc. } - // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient + // FIXME(@Commeownist): I'm not 100% sure this one clobber is sufficient // on all architectures. For instance, what about FP stack? _ => { extended_asm.add_clobber("cc"); @@ -571,7 +571,7 @@ fn codegen_inline_asm( extended_asm.set_volatile_flag(true); } if !options.contains(InlineAsmOptions::NOSTACK) { - // TODO(@Commeownist): figure out how to align stack + // FIXME(@Commeownist): figure out how to align stack } if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) { let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); @@ -640,7 +640,7 @@ fn explicit_reg_to_gcc(reg: InlineAsmReg) -> &'static str { // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119 match reg { InlineAsmReg::X86(reg) => { - // TODO(antoyo): add support for vector register. + // FIXME(antoyo): add support for vector register. match reg.reg_class() { X86InlineAsmRegClass::reg_byte => { // GCC does not support the `b` suffix, so we just strip it @@ -901,7 +901,7 @@ fn codegen_global_asm( GlobalAsmOperandRef::SymFn { instance } => { let function = get_fn(self, instance); self.add_used_function(function); - // TODO(@Amanieu): Additional mangling is needed on + // FIXME(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) // or byte count suffixes (x86 Windows). let name = self.tcx.symbol_name(instance).name; @@ -909,8 +909,8 @@ fn codegen_global_asm( } GlobalAsmOperandRef::SymStatic { def_id } => { - // TODO(antoyo): set the global variable as used. - // TODO(@Amanieu): Additional mangling is needed on + // FIXME(antoyo): set the global variable as used. + // FIXME(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O). let instance = Instance::mono(self.tcx, def_id); let name = self.tcx.symbol_name(instance).name; @@ -930,7 +930,7 @@ fn codegen_global_asm( } fn mangled_name(&self, instance: Instance<'tcx>) -> String { - // TODO(@Amanieu): Additional mangling is needed on + // FIXME(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) // or byte count suffixes (x86 Windows). self.tcx.symbol_name(instance).name.to_string() diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index cd8c1206c821..ce1877b308e9 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -126,19 +126,19 @@ pub fn from_fn_attrs<'gcc, 'tcx>( .map(|features| features.name.as_str()) .flat_map(|feat| to_gcc_features(cx.tcx.sess, feat).into_iter()) .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match *x { - InstructionSetAttr::ArmA32 => "-thumb-mode", // TODO(antoyo): support removing feature. + InstructionSetAttr::ArmA32 => "-thumb-mode", // FIXME(antoyo): support removing feature. InstructionSetAttr::ArmT32 => "thumb-mode", })) .collect::>(); - // TODO(antoyo): cg_llvm adds global features to each function so that LTO keep them. + // FIXME(antoyo): cg_llvm adds global features to each function so that LTO keep them. // Check if GCC requires the same. let mut global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str()); function_features.extend(&mut global_features); let target_features = function_features .iter() .filter_map(|feature| { - // TODO(antoyo): support soft-float. + // FIXME(antoyo): support soft-float. if feature.contains("soft-float") { return None; } diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 347a15a392af..aee164cf3222 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -10,7 +10,7 @@ // Maybe that's because the combined object files contain the IR (true) and the final link // does not remove it? // -// TODO(antoyo): for performance, check which optimizations the C++ frontend enables. +// FIXME(antoyo): for performance, check which optimizations the C++ frontend enables. // cSpell:disable // Fix these warnings: // /usr/bin/ld: warning: type of symbol `_RNvNvNvNtCs5JWOrf9uCus_5rayon11thread_pool19WORKER_THREAD_STATE7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o @@ -39,7 +39,7 @@ use crate::{GccCodegenBackend, GccContext, LtoMode, to_gcc_opt_level}; struct LtoData { - // TODO(antoyo): use symbols_below_threshold. + // FIXME(antoyo): use symbols_below_threshold. //symbols_below_threshold: Vec, upstream_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, @@ -173,7 +173,7 @@ fn fat_lto( .filter(|&(_, module)| module.kind == ModuleKind::Regular) .map(|(i, _module)| { //let cost = unsafe { llvm::LLVMRustModuleCost(module.module_llvm.llmod()) }; - // TODO(antoyo): compute the cost of a module if GCC allows this. + // FIXME(antoyo): compute the cost of a module if GCC allows this. (0, i) }) .max(); diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 24ea2b66ba7d..64674423de2c 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -44,7 +44,7 @@ pub(crate) fn codegen( let _timer = prof.generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name); - // TODO(antoyo) + // FIXME(antoyo) /*if let Some(bitcode_filename) = bc_out.file_name() { cgcx.prof.artifact_size( "llvm_bitcode", @@ -68,14 +68,14 @@ pub(crate) fn codegen( let _timer = prof .generic_activity_with_arg("GCC_module_codegen_embed_bitcode", &*module.name); if lto_supported { - // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes? + // FIXME(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes? //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); context.add_command_line_option("-flto=auto"); context.add_command_line_option("-flto-partition=one"); context.add_command_line_option("-ffat-lto-objects"); } - // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument). + // FIXME(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument). context .compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str")); } @@ -135,7 +135,7 @@ pub(crate) fn codegen( // NOTE: without -fuse-linker-plugin, we get the following error: // lto1: internal compiler error: decompressed stream: Destination buffer is too small - // TODO(antoyo): since we do not do LTO when the linker is invoked anymore, perhaps + // FIXME(antoyo): since we do not do LTO when the linker is invoked anymore, perhaps // the following flag is not necessary anymore. context.add_driver_option("-fuse-linker-plugin"); } diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 18058d9491ad..d1637dd663bb 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -50,7 +50,7 @@ pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind { Linkage::WeakAny => unimplemented!(), Linkage::WeakODR => unimplemented!(), Linkage::Internal => GlobalKind::Internal, - Linkage::ExternalWeak => GlobalKind::Imported, // TODO(antoyo): should be weak linkage. + Linkage::ExternalWeak => GlobalKind::Imported, // FIXME(antoyo): should be weak linkage. Linkage::Common => unimplemented!(), } } @@ -58,7 +58,7 @@ pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind { pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { match linkage { Linkage::External => FunctionType::Exported, - // TODO(antoyo): set the attribute externally_visible. + // FIXME(antoyo): set the attribute externally_visible. Linkage::AvailableExternally => FunctionType::Extern, Linkage::LinkOnceAny => unimplemented!(), Linkage::LinkOnceODR => unimplemented!(), @@ -198,7 +198,7 @@ fn module_codegen( context.set_allow_unreachable_blocks(true); { - // TODO: to make it less error-prone (calling get_target_info() will add the flag + // FIXME: to make it less error-prone (calling get_target_info() will add the flag // -fsyntax-only), forbid the compilation when get_target_info() is called on a // context. let f16_type_supported = target_info.supports_target_dependent_type(CType::Float16); @@ -206,7 +206,7 @@ fn module_codegen( let f64_type_supported = target_info.supports_target_dependent_type(CType::Float64); let f128_type_supported = target_info.supports_target_dependent_type(CType::Float128); let u128_type_supported = target_info.supports_target_dependent_type(CType::UInt128t); - // TODO: improve this to avoid passing that many arguments. + // FIXME: improve this to avoid passing that many arguments. let mut cx = CodegenCx::new( &context, cgu, diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 1d5db049f7dc..3eb0fd95284a 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -38,7 +38,7 @@ use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; -// TODO(antoyo) +// FIXME(antoyo) type Funclet = (); enum ExtremumOperation { @@ -75,7 +75,7 @@ fn atomic_extremum( let func = self.current_func(); let load_ordering = match order { - // TODO(antoyo): does this make sense? + // FIXME(antoyo): does this make sense? AtomicOrdering::AcqRel | AtomicOrdering::Release => AtomicOrdering::Acquire, _ => order, }; @@ -284,8 +284,8 @@ fn check_ptr_call<'b>( func_ptr, index ); - // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - // TODO: remove bitcast now that vector types can be compared? + // FIXME(antoyo): perhaps use __builtin_convertvector for vector casting. + // FIXME: remove bitcast now that vector types can be compared? // ==> We use bitcast to avoid having to do many manual casts from e.g. __m256i to __v32qi (in // the case of _mm256_aesenc_epi128). self.bitcast(actual_val, expected_ty) @@ -430,7 +430,7 @@ pub fn overflow_call( // That's why we assign the result to a local. let return_type = self.context.new_type::(); let current_func = self.block.get_function(); - // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects. + // FIXME(antoyo): return the new_call() directly? Since the overflow function has no side-effects. let result = current_func.new_local( self.location, return_type, @@ -610,7 +610,7 @@ fn invoke( let current_block = self.block; self.block = try_block; - let call = self.call(typ, fn_attrs, None, func, args, None, instance); // TODO(antoyo): use funclet here? + let call = self.call(typ, fn_attrs, None, func, args, None, instance); // FIXME(antoyo): use funclet here? self.block = current_block; let return_value = @@ -648,7 +648,7 @@ fn invoke( let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(self.location, condition, then, catch); if let Some(_fn_abi) = fn_abi { - // TODO(bjorn3): Apply function attributes + // FIXME(bjorn3): Apply function attributes } call_site } @@ -675,7 +675,7 @@ fn fadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { self.assign_to_var(a + b) } - // TODO(antoyo): should we also override the `unchecked_` versions? + // FIXME(antoyo): should we also override the `unchecked_` versions? fn sub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { self.assign_to_var(self.gcc_sub(a, b)) } @@ -703,7 +703,7 @@ fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { } fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): poison if not exact. + // FIXME(antoyo): poison if not exact. let a_type = a.get_type().to_unsigned(self); let a = self.gcc_int_cast(a, a_type); let b_type = b.get_type().to_unsigned(self); @@ -716,7 +716,7 @@ fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { } fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): poison if not exact. + // FIXME(antoyo): poison if not exact. // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they // should be the same. let typ = a.get_type().to_signed(self); @@ -737,7 +737,7 @@ fn srem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { } fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): add check in libgccjit since using the binary operator % causes the following error: + // FIXME(antoyo): add check in libgccjit since using the binary operator % causes the following error: // during RTL pass: expand // libgccjit.so: error: in expmed_mode_index, at expmed.h:240 // 0x7f0101d58dc6 expmed_mode_index @@ -789,7 +789,7 @@ fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { return self.context.new_call(self.location, fmod, &[a, b]); } TypeKind::FP128 => { - // TODO(antoyo): use get_simple_function_f128_2args. + // FIXME(antoyo): use get_simple_function_f128_2args. let f128_type = self.type_f128(); let fmodf128 = self.context.new_function( None, @@ -837,7 +837,7 @@ fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { } fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): check whether behavior is an arithmetic shift for >> . + // FIXME(antoyo): check whether behavior is an arithmetic shift for >> . // It seems to be if the value is signed. self.gcc_lshr(a, b) } @@ -937,7 +937,7 @@ fn checked_binop( fn alloca(&mut self, size: Size, align: Align) -> RValue<'gcc> { let ty = self.cx.type_array(self.cx.type_i8(), size.bytes()).get_aligned(align.bytes()); - // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. + // FIXME(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. self.current_func() .new_local(self.location, ty, format!("stack_var_{}", self.next_value_counter())) .get_address(self.location) @@ -1006,8 +1006,8 @@ fn atomic_load( order: AtomicOrdering, size: Size, ) -> RValue<'gcc> { - // TODO(antoyo): use ty. - // TODO(antoyo): handle alignment. + // FIXME(antoyo): use ty. + // FIXME(antoyo): handle alignment. let atomic_load = self.context.get_builtin_function(format!("__atomic_load_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); @@ -1128,11 +1128,11 @@ fn write_operand_repeatedly( } fn range_metadata(&mut self, _load: RValue<'gcc>, _range: WrappingRange) { - // TODO(antoyo) + // FIXME(antoyo) } fn nonnull_metadata(&mut self, _load: RValue<'gcc>) { - // TODO(antoyo) + // FIXME(antoyo) } fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { @@ -1161,7 +1161,7 @@ fn store_with_flags( self.cx.context.new_cast(self.location, ptr, modified_destination_type.make_pointer()); let modified_destination = modified_ptr.dereference(self.location); self.llbb().add_assignment(self.location, modified_destination, val); - // TODO(antoyo): handle `MemFlags::NONTEMPORAL`. + // FIXME(antoyo): handle `MemFlags::NONTEMPORAL`. // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here? // When adding support for NONTEMPORAL, make sure to not just emit MOVNT on x86; see the // LLVM backend for details. @@ -1175,7 +1175,7 @@ fn atomic_store( order: AtomicOrdering, size: Size, ) { - // TODO(antoyo): handle alignment. + // FIXME(antoyo): handle alignment. let atomic_store = self.context.get_builtin_function(format!("__atomic_store_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); @@ -1205,7 +1205,7 @@ fn gep( let ptr_type = ptr.get_type(); let mut pointee_type = ptr.get_type(); // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is - // always considered in bounds in GCC (TODO(antoyo): to be verified). + // always considered in bounds in GCC (FIXME(antoyo): to be verified). // So, we have to cast to a number. let mut result = self.context.new_bitcast(self.location, ptr, self.sizet_type); // FIXME(antoyo): if there were more than 1 index, this code is probably wrong and would @@ -1233,7 +1233,7 @@ fn inbounds_gep( ) -> RValue<'gcc> { // NOTE: due to opaque pointers now being used, we need to cast here. let ptr = self.context.new_cast(self.location, ptr, typ.make_pointer()); - // NOTE: array indexing is always considered in bounds in GCC (TODO(antoyo): to be verified). + // NOTE: array indexing is always considered in bounds in GCC (FIXME(antoyo): to be verified). let mut indices = indices.iter(); let index = indices.next().expect("first index in inbounds_gep"); let mut result = self.context.new_array_access(self.location, ptr, *index); @@ -1245,14 +1245,14 @@ fn inbounds_gep( /* Casts */ fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): check that it indeed truncate the value. + // FIXME(antoyo): check that it indeed truncate the value. self.gcc_int_cast(value, dest_ty) } fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): check that it indeed sign extend the value. + // FIXME(antoyo): check that it indeed sign extend the value. if dest_ty.dyncast_vector().is_some() { - // TODO(antoyo): nothing to do as it is only for LLVM? + // FIXME(antoyo): nothing to do as it is only for LLVM? return value; } self.context.new_cast(self.location, value, dest_ty) @@ -1275,7 +1275,7 @@ fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { } fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): make sure it truncates. + // FIXME(antoyo): make sure it truncates. set_rvalue_location(self, self.context.new_cast(self.location, value, dest_ty)) } @@ -1405,7 +1405,7 @@ fn memcpy( let dst = self.pointercast(dst, self.type_i8p()); let src = self.pointercast(src, self.type_ptr_to(self.type_void())); let memcpy = self.context.get_builtin_function("memcpy"); - // TODO(antoyo): handle aligns and is_volatile. + // FIXME(antoyo): handle aligns and is_volatile. self.block.add_eval( self.location, self.context.new_call(self.location, memcpy, &[dst, src, size]), @@ -1428,7 +1428,7 @@ fn memmove( let src = self.pointercast(src, self.type_ptr_to(self.type_void())); let memmove = self.context.get_builtin_function("memmove"); - // TODO(antoyo): handle is_volatile. + // FIXME(antoyo): handle is_volatile. self.block.add_eval( self.location, self.context.new_call(self.location, memmove, &[dst, src, size]), @@ -1447,7 +1447,7 @@ fn memset( let _is_volatile = flags.contains(MemFlags::VOLATILE); let ptr = self.pointercast(ptr, self.type_i8p()); let memset = self.context.get_builtin_function("memset"); - // TODO(antoyo): handle align and is_volatile. + // FIXME(antoyo): handle align and is_volatile. let fill_byte = self.context.new_cast(self.location, fill_byte, self.i32_type); let size = self.intcast(size, self.type_size_t(), false); self.block.add_eval( @@ -1599,7 +1599,7 @@ fn cleanup_landing_pad(&mut self, pers_fn: Function<'gcc>) -> (RValue<'gcc>, RVa let value1_type = self.u8_type.make_pointer(); let ptr = self.cx.context.new_cast(self.location, ptr, value1_type); let value1 = ptr; - let value2 = zero; // TODO(antoyo): set the proper value here (the type of exception?). + let value2 = zero; // FIXME(antoyo): set the proper value here (the type of exception?). (value1, value2) } @@ -1616,7 +1616,7 @@ fn cleanup_landing_pad(&mut self, _pers_fn: Function<'gcc>) -> (RValue<'gcc>, RV } fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) { - // TODO(antoyo): generate the correct landing pad + // FIXME(antoyo): generate the correct landing pad self.cleanup_landing_pad(pers_fn); } @@ -1747,15 +1747,15 @@ fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) { fn set_invariant_load(&mut self, load: RValue<'gcc>) { // NOTE: Hack to consider vtable function pointer as non-global-variable function pointer. self.normal_function_addresses.borrow_mut().insert(load); - // TODO(antoyo) + // FIXME(antoyo) } fn lifetime_start(&mut self, _ptr: RValue<'gcc>, _size: Size) { - // TODO(antoyo) + // FIXME(antoyo) } fn lifetime_end(&mut self, _ptr: RValue<'gcc>, _size: Size) { - // TODO(antoyo) + // FIXME(antoyo) } fn call( @@ -1771,7 +1771,7 @@ fn call( // FIXME(antoyo): remove when having a proper API. let gcc_func = unsafe { std::mem::transmute::, Function<'gcc>>(func) }; let call = if self.functions.borrow().values().any(|value| *value == gcc_func) { - // TODO(antoyo): remove when the API supports a different type for functions. + // FIXME(antoyo): remove when the API supports a different type for functions. let func: Function<'gcc> = self.cx.rvalue_as_function(func); self.function_call(func, args, funclet) } else { @@ -1779,7 +1779,7 @@ fn call( self.function_ptr_call(typ, func, args, funclet) }; if let Some(_fn_abi) = fn_abi { - // TODO(bjorn3): Apply function attributes + // FIXME(bjorn3): Apply function attributes } call } @@ -1886,7 +1886,7 @@ fn int_min(signed: bool, int_width: u64) -> i128 { if signed { i128::MIN >> (128 - int_width) } else { 0 } } - // TODO: rewrite using a generic function with . + // FIXME: rewrite using a generic function with . let compute_clamp_bounds_half = |signed: bool, int_width: u64| -> (u128, u128) { let rounded_min = ieee::Half::from_i128_r(int_min(signed, int_width), Round::TowardZero); @@ -2023,7 +2023,7 @@ pub fn shuffle_vector( block.add_assignment(self.location, mask_var, mask); let mask = mask_var.to_rvalue(); - // TODO(antoyo): use a recursive unqualified() here. + // FIXME(antoyo): use a recursive unqualified() here. let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type"); let element_type = vector_type.get_element_type(); let vec_num_units = vector_type.get_num_units(); @@ -2278,6 +2278,8 @@ pub fn vector_reduce_max(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { }) } + /// Emits a SIMD min/max operation for floats. The semantics for each lane are: if one + /// side is NaN (QNaN or SNaN), the other side is returned. fn vector_extremum( &mut self, a: RValue<'gcc>, @@ -2286,8 +2288,9 @@ fn vector_extremum( ) -> RValue<'gcc> { let vector_type = a.get_type(); - // mask out the NaNs in b and replace them with the corresponding lane in a, so when a and - // b get compared & spliced together, we get the numeric values instead of NaNs. + // Mask out the NaNs (both QNaN and SNaN) in b and replace them with the corresponding lane + // in a, so when a and b get compared & spliced together, we get the numeric values instead + // of NaNs. let b_nan_mask = self.context.new_comparison(self.location, ComparisonOp::NotEquals, b, b); let mask_type = b_nan_mask.get_type(); let b_nan_mask_inverted = @@ -2309,7 +2312,7 @@ fn vector_extremum( self.context.new_bitcast(self.location, res, vector_type) } - pub fn vector_fmin(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_minimum_number_nsz(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { self.vector_extremum(a, b, ExtremumOperation::Min) } @@ -2341,7 +2344,7 @@ pub fn vector_reduce_fmin(&mut self, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } - pub fn vector_fmax(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_maximum_number_nsz(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { self.vector_extremum(a, b, ExtremumOperation::Max) } @@ -2387,7 +2390,7 @@ pub fn vector_select( #[cfg(feature = "master")] let (cond, element_type) = { - // TODO(antoyo): dyncast_vector should not require a call to unqualified. + // FIXME(antoyo): dyncast_vector should not require a call to unqualified. let then_val_vector_type = then_val.get_type().unqualified().dyncast_vector().expect("vector type"); let then_val_element_type = then_val_vector_type.get_element_type(); @@ -2426,7 +2429,7 @@ pub fn vector_select( // NOTE: sometimes, the type of else_val can be different than the type of then_val in // libgccjit (vector of int vs vector of int32_t), but they should be the same for the AND // operation to work. - // TODO: remove bitcast now that vector types can be compared? + // FIXME: remove bitcast now that vector types can be compared? let else_val = self.context.new_bitcast(self.location, else_val, then_val.get_type()); let else_vals = inverted_masks & else_val; @@ -2508,7 +2511,7 @@ fn to_gcc_comparison(&self) -> ComparisonOp { impl ToGccComp for RealPredicate { fn to_gcc_comparison(&self) -> ComparisonOp { - // TODO(antoyo): check that ordered vs non-ordered is respected. + // FIXME(antoyo): check that ordered vs non-ordered is respected. match *self { RealPredicate::RealPredicateFalse => unreachable!(), RealPredicate::RealOEQ => ComparisonOp::Equals, @@ -2550,7 +2553,7 @@ fn to_gcc(self) -> i32 { use MemOrdering::*; let ordering = match self { - AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. + AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // FIXME(antoyo): check if that's the same. AtomicOrdering::Acquire => __ATOMIC_ACQUIRE, AtomicOrdering::Release => __ATOMIC_RELEASE, AtomicOrdering::AcqRel => __ATOMIC_ACQ_REL, diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index 8487a85bd035..00f095ed5437 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -60,7 +60,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. if cx.val_ty(func) != ptrtype { - // TODO(antoyo): cast the pointer. + // FIXME(antoyo): cast the pointer. func } else { @@ -76,7 +76,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) { let instance_def_id = instance.def_id(); - // TODO(antoyo): set linkage and attributes. + // FIXME(antoyo): set linkage and attributes. // Apply an appropriate linkage/visibility value to our item that we // just declared. diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 79cae9e02826..9e548ac0a8b0 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -26,13 +26,13 @@ pub fn const_u16(&self, i: u16) -> RValue<'gcc> { } fn global_string(&self, string: &str) -> LValue<'gcc> { - // TODO(antoyo): handle non-null-terminated strings. + // FIXME(antoyo): handle non-null-terminated strings. let string = self.context.new_string_literal(string); let sym = self.generate_local_symbol_name("str"); let global = self.declare_private_global(&sym, self.val_ty(string)); global.global_set_initializer_rvalue(string); global - // TODO(antoyo): set linkage. + // FIXME(antoyo): set linkage. } pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { @@ -204,7 +204,7 @@ fn const_str(&self, s: &str) -> (RValue<'gcc>, RValue<'gcc>) { fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> { let fields: Vec<_> = values.iter().map(|value| value.get_type()).collect(); - // TODO(antoyo): cache the type? It's anonymous, so probably not. + // FIXME(antoyo): cache the type? It's anonymous, so probably not. let typ = self.type_struct(&fields, packed); let struct_type = typ.is_struct().expect("struct type"); self.context.new_struct_constructor(None, struct_type.as_type(), None, values) @@ -216,12 +216,12 @@ fn const_vector(&self, values: &[RValue<'gcc>]) -> RValue<'gcc> { } fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option { - // TODO(antoyo) + // FIXME(antoyo) None } fn const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option { - // TODO(antoyo) + // FIXME(antoyo) None } @@ -236,10 +236,10 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> // NOTE: since the intrinsic _xabort is called with a bitcast, which // is non-const, but expects a constant, do a normal cast instead of a bitcast. // FIXME(antoyo): fix bitcast to work in constant contexts. - // TODO(antoyo): perhaps only use bitcast for pointers? + // FIXME(antoyo): perhaps only use bitcast for pointers? self.context.new_cast(None, value, ty) } else { - // TODO(bjorn3): assert size is correct + // FIXME(bjorn3): assert size is correct self.const_bitcast(value, ty) } } @@ -270,7 +270,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> _ => self.static_addr_of(alloc, None), }; if !self.sess().fewer_names() { - // TODO(antoyo): set value name. + // FIXME(antoyo): set value name. } value } diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 8afa57bc28fc..42ff93096850 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -166,7 +166,7 @@ fn codegen_static(&mut self, def_id: DefId) { unimplemented!(); } } else { - // TODO(antoyo): set link section. + // FIXME(antoyo): set link section. } if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) @@ -180,7 +180,7 @@ fn codegen_static(&mut self, def_id: DefId) { impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*. pub fn add_used_global(&mut self, _global: RValue<'gcc>) { - // TODO(antoyo) + // FIXME(antoyo) } #[cfg_attr(not(feature = "master"), expect(unused_variables))] @@ -198,7 +198,7 @@ pub fn static_addr_of_mut( let global = match kind { Some(kind) if !self.tcx.sess.fewer_names() => { let name = self.generate_local_symbol_name(kind); - // TODO(antoyo): check if it's okay that no link_section is set. + // FIXME(antoyo): check if it's okay that no link_section is set. let typ = self.val_ty(cv).get_aligned(align.bytes()); self.declare_private_global(&name[..], typ) @@ -209,7 +209,7 @@ pub fn static_addr_of_mut( } }; global.global_set_initializer_rvalue(cv); - // TODO(antoyo): set unnamed address. + // FIXME(antoyo): set unnamed address. let rvalue = global.get_address(None); self.global_lvalues.borrow_mut().insert(rvalue, global); rvalue @@ -276,7 +276,7 @@ pub(crate) fn get_static_inner(&self, def_id: DefId, gcc_type: Type<'gcc>) -> LV }; if !def_id.is_local() { - let needs_dll_storage_attr = false; // TODO(antoyo) + let needs_dll_storage_attr = false; // FIXME(antoyo) // If this assertion triggers, there's something wrong with commandline // argument validation. @@ -303,7 +303,7 @@ pub(crate) fn get_static_inner(&self, def_id: DefId, gcc_type: Type<'gcc>) -> LV } } - // TODO(antoyo): set dll storage class. + // FIXME(antoyo): set dll storage class. self.instances.borrow_mut().insert(instance, global); global @@ -412,7 +412,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>( let real_name = format!("_rust_extern_with_linkage_{:016x}_{sym}", cx.tcx.stable_crate_id(LOCAL_CRATE)); let global2 = cx.define_global(&real_name, gcc_type, is_tls, attrs.link_section); - // TODO(antoyo): set linkage. + // FIXME(antoyo): set linkage. let value = cx.const_ptrcast(global1.get_address(None), gcc_type); global2.global_set_initializer_rvalue(value); global2 diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index ada3d73f612e..c34c615306aa 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -21,8 +21,7 @@ use rustc_session::Session; #[cfg(feature = "master")] use rustc_session::config::DebugInfo; -use rustc_span::source_map::respan; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, respan}; use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi}; #[cfg(feature = "master")] @@ -37,7 +36,7 @@ pub struct CodegenCx<'gcc, 'tcx> { pub codegen_unit: &'tcx CodegenUnit<'tcx>, pub context: &'gcc Context<'gcc>, - // TODO(bjorn3): Can this field be removed? + // FIXME(bjorn3): Can this field be removed? pub current_func: RefCell>>, pub normal_function_addresses: RefCell>>, pub function_address_names: RefCell, String>>, @@ -100,7 +99,7 @@ pub struct CodegenCx<'gcc, 'tcx> { pub vtables: RefCell, Option>), RValue<'gcc>>>, - // TODO(antoyo): improve the SSA API to not require those. + // FIXME(antoyo): improve the SSA API to not require those. /// Mapping from function pointer type to indexes of on stack parameters. pub on_stack_params: RefCell, FxHashSet>>, /// Mapping from function to indexes of on stack parameters. @@ -110,7 +109,7 @@ pub struct CodegenCx<'gcc, 'tcx> { pub const_globals: RefCell, RValue<'gcc>>>, /// Map from the address of a global variable (rvalue) to the global variable itself (lvalue). - /// TODO(antoyo): remove when the rustc API is fixed. + /// FIXME(antoyo): remove when the rustc API is fixed. pub global_lvalues: RefCell, LValue<'gcc>>>, /// Cache of constant strings, @@ -199,7 +198,7 @@ pub fn new( let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap(); let u128_align = layout.align.bytes();*/ - // TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in + // FIXME(antoyo): re-enable the alignment when libgccjit fixed the issue in // gcc_jit_context_new_array_constructor (it should not use reinterpret_cast). let i128_type = new_array_type(context, None, i64_type, 2)/*.get_aligned(i128_align)*/; let u128_type = new_array_type(context, None, u64_type, 2)/*.get_aligned(u128_align)*/; @@ -208,7 +207,7 @@ pub fn new( let tls_model = to_gcc_tls_mode(tcx.sess.tls_model()); - // TODO(antoyo): set alignment on those types as well. + // FIXME(antoyo): set alignment on those types as well. let float_type = context.new_type::(); let double_type = context.new_type::(); @@ -309,7 +308,7 @@ pub fn new( #[cfg(feature = "master")] cleanup_blocks: Default::default(), }; - // TODO(antoyo): instead of doing this, add SsizeT to libgccjit. + // FIXME(antoyo): instead of doing this, add SsizeT to libgccjit. cx.isize_type = usize_type.to_signed(&cx); cx } @@ -382,15 +381,15 @@ pub fn bitcast_if_needed( impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { type Function = Function<'gcc>; type BasicBlock = Block<'gcc>; - type Funclet = (); // TODO(antoyo) + type Funclet = (); // FIXME(antoyo) type Value = RValue<'gcc>; type Type = Type<'gcc>; type FunctionSignature = Type<'gcc>; - type DIScope = (); // TODO(antoyo) + type DIScope = (); // FIXME(antoyo) type DILocation = Location<'gcc>; - type DIVariable = (); // TODO(antoyo) + type DIVariable = (); // FIXME(antoyo) } impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { @@ -414,7 +413,7 @@ fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { }; let ptr = func.get_address(None); - // TODO(antoyo): don't do this twice: i.e. in declare_fn and here. + // FIXME(antoyo): don't do this twice: i.e. in declare_fn and here. // FIXME(antoyo): the rustc API seems to call get_fn_addr() when not needed (e.g. for FFI). self.normal_function_addresses.borrow_mut().insert(ptr); @@ -472,7 +471,7 @@ fn eh_personality(&self) -> Function<'gcc> { self.declare_func(name, self.type_i32(), &[], true) } }; - // TODO(antoyo): apply target cpu attributes. + // FIXME(antoyo): apply target cpu attributes. self.eh_personality.set(Some(func)); func } @@ -482,11 +481,11 @@ fn sess(&self) -> &Session { } fn set_frame_pointer_type(&self, _llfn: Function<'gcc>) { - // TODO(antoyo) + // FIXME(antoyo) } fn apply_target_cpu_attr(&self, _llfn: Function<'gcc>) { - // TODO(antoyo) + // FIXME(antoyo) } fn declare_c_main(&self, fn_type: Self::Type) -> Option { @@ -539,7 +538,7 @@ fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> | LayoutError::InvalidSimd { .. } | LayoutError::ReferencesError(_) = err { - self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic())) + self.tcx.dcx().span_fatal(span, err.to_string()) } else { self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) } diff --git a/compiler/rustc_codegen_gcc/src/coverageinfo.rs b/compiler/rustc_codegen_gcc/src/coverageinfo.rs index 4e44f78f23c2..bbe9296661a7 100644 --- a/compiler/rustc_codegen_gcc/src/coverageinfo.rs +++ b/compiler/rustc_codegen_gcc/src/coverageinfo.rs @@ -6,6 +6,6 @@ impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn add_coverage(&mut self, _instance: Instance<'tcx>, _kind: &CoverageKind) { - // TODO(antoyo) + // FIXME(antoyo) } } diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 53d3670c1524..cf938a3988ce 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -48,7 +48,7 @@ fn dbg_var_value( } fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { - // TODO(antoyo): insert reference to gdb debug scripts section global. + // FIXME(antoyo): insert reference to gdb debug scripts section global. } /// FIXME(tempdragon): Currently, this function is not yet implemented. It seems that the @@ -153,7 +153,7 @@ fn make_mir_scope<'gcc, 'tcx>( // FIXME(eddyb) this doesn't account for the macro-related // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does. - // TODO(tempdragon): Add scope support and then revert to cg_llvm version of this closure + // FIXME(tempdragon): Add scope support and then revert to cg_llvm version of this closure // NOTE: These variables passed () here. // Changed to comply to clippy. @@ -162,7 +162,7 @@ fn make_mir_scope<'gcc, 'tcx>( cx.dbg_loc(/* callsite_scope */ (), parent_scope.inlined_at, callsite_span) }); let p_inlined_at = parent_scope.inlined_at; - // TODO(tempdragon): dbg_scope: Add support for scope extension here. + // FIXME(tempdragon): dbg_scope: Add support for scope extension here. inlined_at.or(p_inlined_at); debug_context.scopes[scope] = DebugScope { @@ -225,7 +225,7 @@ fn create_vtable_debuginfo( _trait_ref: Option>, _vtable: Self::Value, ) { - // TODO(antoyo) + // FIXME(antoyo) } fn create_function_debug_context( @@ -262,7 +262,7 @@ fn extend_scope_to_file( _scope_metadata: Self::DIScope, _file: &SourceFile, ) -> Self::DIScope { - // TODO(antoyo): implement. + // FIXME(antoyo): implement. } fn debuginfo_finalize(&self) { @@ -285,7 +285,7 @@ fn dbg_scope_fn( _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option>, ) -> Self::DIScope { - // TODO(antoyo): implement. + // FIXME(antoyo): implement. } fn dbg_loc( diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index 6450e2d4039c..4174eebcf7b0 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -94,7 +94,7 @@ pub fn declare_entry_fn( #[cfg(feature = "master")] callconv: Option>, #[cfg(not(feature = "master"))] callconv: Option<()>, ) -> Function<'gcc> { - // TODO(antoyo): use the fn_type parameter. + // FIXME(antoyo): use the fn_type parameter. let const_string = self.context.new_type::().make_pointer().make_pointer(); let return_type = self.type_i32(); let variadic = false; @@ -142,7 +142,7 @@ pub fn define_global( } pub fn get_declared_value(&self, name: &str) -> Option> { - // TODO(antoyo): use a different field than globals, because this seems to return a function? + // FIXME(antoyo): use a different field than globals, because this seems to return a function? self.globals.borrow().get(name).cloned() } } @@ -166,7 +166,7 @@ fn declare_raw_fn<'gcc>( let params: Vec<_> = param_types .iter() .enumerate() - .map(|(index, param)| cx.context.new_parameter(None, *param, format!("param{}", index))) // TODO(antoyo): set name. + .map(|(index, param)| cx.context.new_parameter(None, *param, format!("param{}", index))) // FIXME(antoyo): set name. .collect(); #[cfg(not(feature = "master"))] let name = &mangle_name(name); @@ -194,7 +194,7 @@ fn declare_raw_fn<'gcc>( .enumerate() .map(|(index, param)| { cx.context.new_parameter(None, *param, format!("param{}", index)) - }) // TODO(antoyo): set name. + }) // FIXME(antoyo): set name. .collect(); let gcc_func = cx.context.new_function( None, @@ -228,11 +228,11 @@ fn declare_raw_fn<'gcc>( func }; - // TODO(antoyo): set function calling convention. - // TODO(antoyo): set unnamed address. - // TODO(antoyo): set no red zone function attribute. - // TODO(antoyo): set attributes for optimisation. - // TODO(antoyo): set attributes for non lazy bind. + // FIXME(antoyo): set function calling convention. + // FIXME(antoyo): set unnamed address. + // FIXME(antoyo): set no red zone function attribute. + // FIXME(antoyo): set attributes for optimisation. + // FIXME(antoyo): set attributes for non lazy bind. // FIXME(antoyo): invalid cast. func diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 51612d604c8f..dfae4eceebe4 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -75,7 +75,7 @@ pub fn gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { let b_native = self.is_native_int_type(b_type); if a_native && b_native { // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by a signed number. - // TODO(antoyo): cast to unsigned to do a logical shift if that does not work. + // FIXME(antoyo): cast to unsigned to do a logical shift if that does not work. if a_type.is_signed(self) != b_type.is_signed(self) { let b = self.context.new_cast(self.location, b, a_type); a >> b @@ -168,7 +168,7 @@ fn additive_operation( if a_type != b_type { if a_type.is_vector() { // Vector types need to be bitcast. - // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. + // FIXME(antoyo): perhaps use __builtin_convertvector for vector casting. b = self.context.new_bitcast(self.location, b, a_type); } else { b = self.context.new_cast(self.location, b, a_type); @@ -228,7 +228,7 @@ fn multiplicative_operation( if !a_type.is_compatible_with(b_type) { if a_type.is_vector() { // Vector types need to be bitcast. - // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. + // FIXME(antoyo): perhaps use __builtin_convertvector for vector casting. b = self.context.new_bitcast(self.location, b, a_type); } else { b = self.context.new_cast(self.location, b, a_type); @@ -255,9 +255,9 @@ fn multiplicative_operation( } pub fn gcc_sdiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): check if the types are signed? + // FIXME(antoyo): check if the types are signed? // 128-bit, signed: __divti3 - // TODO(antoyo): convert the arguments to signed? + // FIXME(antoyo): convert the arguments to signed? self.multiplicative_operation(BinaryOp::Divide, "div", true, a, b) } @@ -284,7 +284,7 @@ pub fn gcc_checked_binop( _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), }; - // TODO(antoyo): remove duplication with intrinsic? + // FIXME(antoyo): remove duplication with intrinsic? let name = if self.is_native_int_type(lhs.get_type()) { match oop { OverflowOp::Add => "__builtin_add_overflow", @@ -306,7 +306,7 @@ pub fn gcc_checked_binop( OverflowOp::Mul => match new_kind { Int(I32) => ("__mulosi4", 32), Int(I64) => ("__mulodi4", 64), - Int(I128) => ("__rust_i128_mulo", 128), // TODO(antoyo): use __muloti4d instead? + Int(I128) => ("__rust_i128_mulo", 128), // FIXME(antoyo): use __muloti4d instead? Uint(U128) => ("__rust_u128_mulo", 128), _ => unreachable!(), }, @@ -317,7 +317,7 @@ pub fn gcc_checked_binop( let intrinsic = self.context.get_builtin_function(name); let res = self .current_func() - // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? + // FIXME(antoyo): is it correct to use rhs type instead of the parameter typ? .new_local(self.location, rhs.get_type(), "binopResult") .get_address(self.location); let new_type = type_kind_to_gcc_type(new_kind); @@ -462,7 +462,7 @@ pub fn gcc_icmp( lhs_high = self.context.new_cast(self.location, lhs_high, unsigned_type); rhs_high = self.context.new_cast(self.location, rhs_high, unsigned_type); } - // TODO(antoyo): we probably need to handle signed comparison for unsigned + // FIXME(antoyo): we probably need to handle signed comparison for unsigned // integers. _ => (), } @@ -556,7 +556,7 @@ pub fn gcc_icmp( self.context.new_rvalue_one(self.int_type), ); } - // TODO(antoyo): cast to u128 for unsigned comparison. See below. + // FIXME(antoyo): cast to u128 for unsigned comparison. See below. IntPredicate::IntUGT => (ComparisonOp::Equals, 2), IntPredicate::IntUGE => (ComparisonOp::GreaterThanEquals, 1), IntPredicate::IntULT => (ComparisonOp::Equals, 0), @@ -602,7 +602,7 @@ pub fn gcc_icmp( rhs = self.context.new_cast(self.location, rhs, unsigned_type); } } - // TODO(antoyo): we probably need to handle signed comparison for unsigned + // FIXME(antoyo): we probably need to handle signed comparison for unsigned // integers. _ => (), } @@ -693,7 +693,7 @@ pub fn gcc_shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { b0_block.end_with_jump(self.location, after_block); // NOTE: cast low to its unsigned type in order to perform a logical right shift. - // TODO(antoyo): adjust this ^ comment. + // FIXME(antoyo): adjust this ^ comment. let unsigned_type = native_int_type.to_unsigned(self.cx); let casted_low = self.context.new_cast(self.location, self.low(a), unsigned_type); let shift_value = self.context.new_cast(self.location, sixty_four - b, unsigned_type); @@ -732,7 +732,7 @@ pub fn gcc_bswap(&mut self, mut arg: RValue<'gcc>, width: u64) -> RValue<'gcc> { return self.concat_low_high_rvalues(arg_type, swapped_msb, swapped_lsb); } - // TODO(antoyo): check if it's faster to use string literals and a + // FIXME(antoyo): check if it's faster to use string literals and a // match instead of format!. let bswap = self.cx.context.get_builtin_function(format!("__builtin_bswap{}", width)); // FIXME(antoyo): this cast should not be necessary. Remove @@ -862,12 +862,12 @@ pub fn gcc_or( self.bitwise_operation(BinaryOp::BitwiseOr, a, b, loc) } - // TODO(antoyo): can we use https://github.com/rust-lang/compiler-builtins/blob/master/src/int/mod.rs#L379 instead? + // FIXME(antoyo): can we use https://github.com/rust-lang/compiler-builtins/blob/master/src/int/mod.rs#L379 instead? pub fn gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { let value_type = value.get_type(); if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type) { - // TODO: use self.location. + // FIXME: use self.location. self.context.new_cast(None, value, dest_typ) } else if self.is_native_int_type_or_bool(dest_typ) { self.context.new_cast(None, self.low(value), dest_typ) @@ -888,7 +888,7 @@ pub fn gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue< // Since u128 and i128 are the only types that can be unsupported, we know the type of // value and the destination type have the same size, so a bitcast is fine. - // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. + // FIXME(antoyo): perhaps use __builtin_convertvector for vector casting. self.context.new_bitcast(None, value, dest_typ) } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index 11a69acdde42..60e007a25c68 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -123,7 +123,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( mut args: Cow<'b, [RValue<'gcc>]>, func_name: &str, ) -> Cow<'b, [RValue<'gcc>]> { - // TODO: this might not be a good way to workaround the missing tile builtins. + // FIXME: this might not be a good way to workaround the missing tile builtins. if func_name == "__builtin_trap" { return vec![].into(); } @@ -1578,7 +1578,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.uitofp.round.v8f32.v8i64" => "__builtin_ia32_cvtuqq2ps512_mask", "llvm.x86.avx512.uitofp.round.v4f32.v4i64" => "__builtin_ia32_cvtuqq2ps256_mask", - // TODO: support the tile builtins: + // FIXME: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", "llvm.x86.sttilecfg" => "__builtin_trap", "llvm.x86.tileloadd64" => "__builtin_trap", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index fb1127ab4f48..83ac627d27c5 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -23,11 +23,11 @@ IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods, }; use rustc_data_structures::fx::FxHashSet; -use rustc_middle::bug; #[cfg(feature = "master")] use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_target::callconv::{ArgAbi, PassMode}; @@ -68,12 +68,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::fmaf32 => "fmaf", sym::fmaf64 => "fma", // FIXME: calling `fma` from libc without FMA target feature uses expensive software emulation - sym::fmuladdf32 => "fmaf", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f32 - sym::fmuladdf64 => "fma", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f64 - sym::fabsf32 => "fabsf", - sym::fabsf64 => "fabs", - sym::minnumf32 => "fminf", - sym::minnumf64 => "fmin", + sym::fmuladdf32 => "fmaf", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f32 + sym::fmuladdf64 => "fma", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f64 sym::minimumf32 => "fminimumf", sym::minimumf64 => "fminimum", sym::minimumf128 => { @@ -92,8 +88,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>( false, )); } - sym::maxnumf32 => "fmaxf", - sym::maxnumf64 => "fmax", sym::maximumf32 => "fmaximumf", sym::maximumf64 => "fmaximum", sym::maximumf128 => { @@ -131,7 +125,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>( Some(cx.context.get_builtin_function(gcc_name)) } -// TODO(antoyo): We can probably remove these and use the fallback intrinsic implementation. +// FIXME(antoyo): We can probably remove these and use the fallback intrinsic implementation. fn get_simple_function<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, name: Symbol, @@ -198,60 +192,29 @@ fn get_simple_function<'gcc, 'tcx>( } fn get_simple_function_f128<'gcc, 'tcx>( + span: Span, cx: &CodegenCx<'gcc, 'tcx>, name: Symbol, -) -> Option> { - if !cx.supports_f128_type { - return None; - } - +) -> Function<'gcc> { let f128_type = cx.type_f128(); let func_name = match name { sym::ceilf128 => "ceilf128", - sym::fabsf128 => "fabsf128", + sym::fabs => "fabsf128", sym::floorf128 => "floorf128", sym::truncf128 => "truncf128", sym::roundf128 => "roundf128", sym::round_ties_even_f128 => "roundevenf128", sym::sqrtf128 => "sqrtf128", - _ => return None, + _ => span_bug!(span, "used get_simple_function_f128 for non-unary f128 intrinsic"), }; - Some(cx.context.new_function( + cx.context.new_function( None, FunctionType::Extern, f128_type, &[cx.context.new_parameter(None, f128_type, "a")], func_name, false, - )) -} - -fn get_simple_function_f128_2args<'gcc, 'tcx>( - cx: &CodegenCx<'gcc, 'tcx>, - name: Symbol, -) -> Option> { - if !cx.supports_f128_type { - return None; - } - - let f128_type = cx.type_f128(); - let func_name = match name { - sym::maxnumf128 => "fmaxf128", - sym::minnumf128 => "fminf128", - sym::copysignf128 => "copysignf128", - _ => return None, - }; - Some(cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[ - cx.context.new_parameter(None, f128_type, "a"), - cx.context.new_parameter(None, f128_type, "b"), - ], - func_name, - false, - )) + ) } fn f16_builtin<'gcc, 'tcx>( @@ -263,11 +226,9 @@ fn f16_builtin<'gcc, 'tcx>( let builtin_name = match name { sym::ceilf16 => "__builtin_ceilf", sym::copysignf16 => "__builtin_copysignf", - sym::fabsf16 => "fabsf", + sym::fabs => "fabsf", sym::floorf16 => "__builtin_floorf", sym::fmaf16 => "fmaf", - sym::maxnumf16 => "__builtin_fmaxf", - sym::minnumf16 => "__builtin_fminf", sym::powf16 => "__builtin_powf", sym::powif16 => { let func = cx.context.get_builtin_function("__builtin_powif"); @@ -305,11 +266,7 @@ fn codegen_intrinsic_call( let fn_args = instance.args; let simple = get_simple_intrinsic(self, name); - // TODO(antoyo): Only call get_simple_function_f128 and get_simple_function_f128_2args when - // it is the symbols for the supported f128 builtins. - let simple_func = get_simple_function(self, name) - .or_else(|| get_simple_function_f128(self, name)) - .or_else(|| get_simple_function_f128_2args(self, name)); + let simple_func = get_simple_function(self, name); let value = match name { _ if simple.is_some() => { @@ -330,17 +287,48 @@ fn codegen_intrinsic_call( } sym::ceilf16 | sym::copysignf16 - | sym::fabsf16 | sym::floorf16 | sym::fmaf16 - | sym::maxnumf16 - | sym::minnumf16 | sym::powf16 | sym::powif16 | sym::roundf16 | sym::round_ties_even_f16 | sym::sqrtf16 | sym::truncf16 => f16_builtin(self, name, args), + sym::ceilf128 + | sym::floorf128 + | sym::truncf128 + | sym::roundf128 + | sym::round_ties_even_f128 + | sym::sqrtf128 + if self.cx.supports_f128_type => + { + let func = get_simple_function_f128(span, self, name); + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } + sym::copysignf128 if self.cx.supports_f128_type => { + let f128_type = self.cx.type_f128(); + let func = self.cx.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[ + self.cx.context.new_parameter(None, f128_type, "a"), + self.cx.context.new_parameter(None, f128_type, "b"), + ], + "copysignf128", + false, + ); + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } sym::fmaf128 => { let f128_type = self.cx.type_f128(); let func = self.cx.context.new_function( @@ -406,7 +394,7 @@ fn codegen_intrinsic_call( sym::volatile_load | sym::unaligned_volatile_load => { let ptr = args[0].immediate(); let load = self.volatile_load(result.layout.gcc_type(self), ptr); - // TODO(antoyo): set alignment. + // FIXME(antoyo): set alignment. if let BackendRepr::Scalar(scalar) = result.layout.backend_repr { self.to_immediate_scalar(load, scalar) } else { @@ -498,6 +486,23 @@ fn codegen_intrinsic_call( } } } + sym::fabs => 'fabs: { + let ty = args[0].layout.ty; + let ty::Float(float_ty) = *ty.kind() else { + span_bug!(span, "expected float type for fabs intrinsic: {:?}", ty); + }; + let func = match float_ty { + ty::FloatTy::F16 => break 'fabs f16_builtin(self, name, args), + ty::FloatTy::F32 => self.context.get_builtin_function("fabsf"), + ty::FloatTy::F64 => self.context.get_builtin_function("fabs"), + ty::FloatTy::F128 => get_simple_function_f128(span, self, name), + }; + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } sym::raw_eq => { use rustc_abi::BackendRepr::*; @@ -505,7 +510,7 @@ fn codegen_intrinsic_call( let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - SimdVector { .. } | ScalableVector { .. } => false, + SimdVector { .. } | SimdScalableVector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), @@ -697,14 +702,14 @@ fn abort(&mut self) { } fn assume(&mut self, value: Self::Value) { - // TODO(antoyo): switch to assume when it exists. + // FIXME(antoyo): switch to assume when it exists. // Or use something like this: // #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0) self.expect(value, true); } fn expect(&mut self, cond: Self::Value, _expected: bool) -> Self::Value { - // TODO(antoyo) + // FIXME(antoyo) cond } @@ -723,7 +728,7 @@ fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> { } fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): implement. + // FIXME(antoyo): implement. self.context.new_rvalue_from_int(self.int_type, 0) } } @@ -945,7 +950,7 @@ fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> { if width == 8 { step3 } else { self.gcc_bswap(step3, width) } } 128 => { - // TODO(antoyo): find a more efficient implementation? + // FIXME(antoyo): find a more efficient implementation? let sixty_four = self.gcc_int(typ, 64); let right_shift = self.gcc_lshr(value, sixty_four); let high = self.gcc_int_cast(right_shift, self.u64_type); @@ -1026,7 +1031,7 @@ fn use_builtin_function<'a, 'gcc, 'tcx>( builder.context.new_cast(builder.location, res, builder.u32_type) } - // TODO(antoyo): use width? + // FIXME(antoyo): use width? let result_type = self.u32_type; let mut arg_type = arg.get_type(); let arg = if arg_type.is_signed(self.cx) { @@ -1035,7 +1040,7 @@ fn use_builtin_function<'a, 'gcc, 'tcx>( } else { arg }; - // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here + // FIXME(antoyo): write a new function Type::is_compatible_with(&Type) and use it here // instead of using is_uint(). if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) { let builtin = if count_leading { "__builtin_clz" } else { "__builtin_ctz" }; @@ -1139,7 +1144,7 @@ fn count_trailing_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RV } fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): use the optimized version with fewer operations. + // FIXME(antoyo): use the optimized version with fewer operations. let result_type = self.u32_type; let arg_type = value.get_type(); let value_type = arg_type.to_unsigned(self.cx); @@ -1148,7 +1153,7 @@ fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> { if arg_type.is_signed(self.cx) { self.gcc_int_cast(value, value_type) } else { value }; // only break apart 128-bit ints if they're not natively supported - // TODO(antoyo): remove this if/when native 128-bit integers land in libgccjit + // FIXME(antoyo): remove this if/when native 128-bit integers land in libgccjit if value_type.is_u128(self.cx) && !self.cx.supports_128bit_integers { let sixty_four = self.gcc_int(value_type, 64); let right_shift = self.gcc_lshr(value, sixty_four); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index eab067a02b7b..4ca890fee191 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -53,7 +53,7 @@ macro_rules! require_simd { }; } - // TODO(antoyo): refactor with the above require_simd macro that was changed in cg_llvm. + // FIXME(antoyo): refactor with the above require_simd macro that was changed in cg_llvm. #[cfg(feature = "master")] macro_rules! require_simd2 { ($ty: expr, $variant:ident) => {{ @@ -473,14 +473,14 @@ macro_rules! require_simd2 { } ); - // TODO(antoyo): For simd_insert, check if the index is a constant of the correct size. + // FIXME(antoyo): For simd_insert, check if the index is a constant of the correct size. let vector = args[0].immediate(); let index = args[1].immediate(); let value = args[2].immediate(); let variable = bx.current_func().new_local(None, vector.get_type(), "new_vector"); bx.llbb().add_assignment(None, variable, vector); let lvalue = bx.context.new_vector_access(None, variable.to_rvalue(), index); - // TODO(antoyo): if simd_insert is constant, use BIT_REF. + // FIXME(antoyo): if simd_insert is constant, use BIT_REF. bx.llbb().add_assignment(None, lvalue, value); return Ok(variable.to_rvalue()); } @@ -491,7 +491,7 @@ macro_rules! require_simd2 { ret_ty == in_elem, InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } ); - // TODO(antoyo): For simd_extract, check if the index is a constant of the correct size. + // FIXME(antoyo): For simd_extract, check if the index is a constant of the correct size. let vector = args[0].immediate(); let index = args[1].immediate(); return Ok(bx.context.new_vector_access(None, vector, index).to_rvalue()); @@ -737,7 +737,7 @@ macro_rules! arith_binary { // endian and MSB-first for big endian. let vector = args[0].immediate(); - // TODO(antoyo): dyncast_vector should not require a call to unqualified. + // FIXME(antoyo): dyncast_vector should not require a call to unqualified. let vector_type = vector.get_type().unqualified().dyncast_vector().expect("vector type"); let elem_type = vector_type.get_element_type(); @@ -811,7 +811,7 @@ macro_rules! return_error { }}; } let ty::Float(ref f) = *in_elem.kind() else { - return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); + return_error!(InvalidMonomorphization::BasicFloatType { span, name, ty: in_ty }); }; let elem_ty = bx.cx.type_float_from_ty(*f); let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() { @@ -832,7 +832,7 @@ macro_rules! return_error { let intr_name = match name { sym::simd_ceil => "ceil", - sym::simd_fabs => "fabs", // TODO(antoyo): pand with 170141183420855150465331762880109871103 + sym::simd_fabs => "fabs", // FIXME(antoyo): pand with 170141183420855150465331762880109871103 sym::simd_fcos => "cos", sym::simd_fexp2 => "exp2", sym::simd_fexp => "exp", @@ -852,7 +852,7 @@ macro_rules! return_error { let builtin_name = format!("{}{}", intr_name, elem_ty_str); let function = bx.context.get_builtin_function(builtin_name); - // TODO(antoyo): add platform-specific behavior here for architectures that have these + // FIXME(antoyo): add platform-specific behavior here for architectures that have these // intrinsics as instructions (for instance, gpus) let mut vector_elements = vec![]; for i in 0..in_len { @@ -1060,7 +1060,7 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> { assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be an integer type of any width: - // TODO: also support unsigned integers. + // FIXME: also support unsigned integers. let (_, element_ty2) = args[2].layout.ty.simd_size_and_type(bx.tcx()); match *element_ty2.kind() { ty::Int(_) => (), @@ -1175,7 +1175,7 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> { assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - // TODO: also support unsigned integers. + // FIXME: also support unsigned integers. match *element_ty2.kind() { ty::Int(_) => (), _ => { @@ -1222,8 +1222,8 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> { simd_and: Uint, Int => and; simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors. simd_xor: Uint, Int => xor; - simd_fmin: Float => vector_fmin; - simd_fmax: Float => vector_fmax; + simd_minimum_number_nsz: Float => vector_minimum_number_nsz; + simd_maximum_number_nsz: Float => vector_maximum_number_nsz; } macro_rules! arith_unary { @@ -1273,10 +1273,10 @@ macro_rules! arith_unary { } (true, true) => { // Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition - // TODO(antoyo): improve using conditional operators if possible. - // TODO(antoyo): dyncast_vector should not require a call to unqualified. + // FIXME(antoyo): improve using conditional operators if possible. + // FIXME(antoyo): dyncast_vector should not require a call to unqualified. let arg_type = lhs.get_type().unqualified(); - // TODO(antoyo): convert lhs and rhs to unsigned. + // FIXME(antoyo): convert lhs and rhs to unsigned. let sum = lhs + rhs; let vector_type = arg_type.dyncast_vector().expect("vector type"); let unit = vector_type.get_num_units(); @@ -1308,13 +1308,13 @@ macro_rules! arith_unary { res & cmp } (true, false) => { - // TODO(antoyo): dyncast_vector should not require a call to unqualified. + // FIXME(antoyo): dyncast_vector should not require a call to unqualified. let arg_type = lhs.get_type().unqualified(); - // TODO(antoyo): this uses the same algorithm from saturating add, but add the + // FIXME(antoyo): this uses the same algorithm from saturating add, but add the // negative of the right operand. Find a proper subtraction algorithm. let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs); - // TODO(antoyo): convert lhs and rhs to unsigned. + // FIXME(antoyo): convert lhs and rhs to unsigned. let sum = lhs + rhs; let vector_type = arg_type.dyncast_vector().expect("vector type"); let unit = vector_type.get_num_units(); @@ -1391,7 +1391,7 @@ macro_rules! arith_red { vector_reduce_fadd_reassoc, false, add, - 0.0 // TODO: Use this argument. + 0.0 // FIXME: Use this argument. ); arith_red!( simd_reduce_mul_unordered: BinaryOp::Mult, @@ -1507,7 +1507,7 @@ macro_rules! bitwise_red { // those lanes whose `mask` bit is enabled. // The memory addresses corresponding to the “off” lanes are not accessed. - // TODO: handle the alignment. + // FIXME: handle the alignment. // The element type of the "mask" argument must be a signed integer type of any width let mask_ty = in_ty; @@ -1595,7 +1595,7 @@ macro_rules! bitwise_red { // those lanes whose `mask` bit is enabled. // The memory addresses corresponding to the “off” lanes are not accessed. - // TODO: handle the alignment. + // FIXME: handle the alignment. // The element type of the "mask" argument must be a signed integer type of any width let mask_ty = in_ty; diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 592eb68ce275..bf13f0b2127b 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -1,5 +1,5 @@ /* - * TODO(antoyo): implement equality in libgccjit based on https://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?) + * FIXME(antoyo): implement equality in libgccjit based on https://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?) * For Thin LTO, this might be helpful: // cspell:disable-next-line * In gcc 4.6 -fwhopr was removed and became default with -flto. The non-whopr path can still be executed via -flto-partition=none. @@ -8,9 +8,9 @@ * Maybe some missing optimizations enabled by rustc's LTO is in there: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html // cspell:disable-next-line * Like -fipa-icf (should be already enabled) and maybe -fdevirtualize-at-ltrans. - * TODO: disable debug info always being emitted. Perhaps this slows down things? + * FIXME: disable debug info always being emitted. Perhaps this slows down things? * - * TODO(antoyo): remove the patches. + * FIXME(antoyo): remove the patches. */ #![feature(rustc_private)] @@ -328,7 +328,7 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { version, )); } - // TODO(antoyo): check if this should only be added when using -Cforce-unwind-tables=n. + // FIXME(antoyo): check if this should only be added when using -Cforce-unwind-tables=n. context.add_command_line_option("-fno-asynchronous-unwind-tables"); context } @@ -425,7 +425,7 @@ fn target_machine_factory( _opt_level: OptLevel, _features: &[String], ) -> TargetMachineFactoryFn { - // TODO(antoyo): set opt level. + // FIXME(antoyo): set opt level. Arc::new(|_, _| ()) } @@ -531,7 +531,7 @@ fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig sess, |feature| to_gcc_features(sess, feature), |feature| { - // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. + // FIXME: we disable Neon for now since we don't support the LLVM intrinsics for it. if feature == "neon" { return false; } diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index 31c03eddaca5..1429738a7e7a 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -37,7 +37,7 @@ fn predefine_static( #[cfg(feature = "master")] global.add_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); - // TODO(antoyo): set linkage. + // FIXME(antoyo): set linkage. self.instances.borrow_mut().insert(instance, global); } @@ -69,9 +69,9 @@ fn predefine_fn( decl.add_attribute(FnAttribute::Visibility(base::visibility_to_gcc(visibility))); } - // TODO(antoyo): call set_link_section() to allow initializing argc/argv. - // TODO(antoyo): set unique comdat. - // TODO(antoyo): use inline attribute from there in linkage.set() above. + // FIXME(antoyo): call set_link_section() to allow initializing argc/argv. + // FIXME(antoyo): set unique comdat. + // FIXME(antoyo): use inline attribute from there in linkage.set() above. self.functions.borrow_mut().insert(symbol_name.to_string(), decl); self.function_instances.borrow_mut().insert(instance, decl); diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 3b1ee53f8336..5252f93a92eb 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -66,7 +66,7 @@ pub fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> { } pub fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> { - // TODO(antoyo): use address_space, perhaps with TYPE_ADDR_SPACE? + // FIXME(antoyo): use address_space, perhaps with TYPE_ADDR_SPACE? ty.make_pointer() } @@ -110,7 +110,7 @@ pub fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { .iter() .enumerate() .map(|(index, field)| { - self.context.new_field(None, *field, format!("field{}_TODO", index)) + self.context.new_field(None, *field, format!("field{}_FIXME", index)) }) .collect(); let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); @@ -213,7 +213,7 @@ fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { } else if typ == self.type_void() { TypeKind::Void } else { - // TODO(antoyo): support other types. + // FIXME(antoyo): support other types. unimplemented!(); } } @@ -239,7 +239,7 @@ fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { } else if typ == self.type_void() { TypeKind::Void } else { - // TODO(antoyo): support other types. + // FIXME(antoyo): support other types. unimplemented!(); } } @@ -288,7 +288,7 @@ fn float_width(&self, typ: Type<'gcc>) -> usize { } else { panic!("Cannot get width of float type {:?}", typ); } - // TODO(antoyo): support other sizes. + // FIXME(antoyo): support other sizes. } fn int_width(&self, typ: Type<'gcc>) -> u64 { diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 48d1b0163909..5b198eeaf018 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -85,7 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( ); } BackendRepr::Memory { .. } => {} - BackendRepr::ScalableVector { .. } => todo!(), + BackendRepr::SimdScalableVector { .. } => todo!(), } let name = match *layout.ty.kind() { @@ -181,7 +181,7 @@ fn is_gcc_immediate(&self) -> bool { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, // FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc. - BackendRepr::ScalableVector { .. } => todo!(), + BackendRepr::SimdScalableVector { .. } => todo!(), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -191,7 +191,7 @@ fn is_gcc_scalar_pair(&self) -> bool { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::Memory { .. } => false, } } @@ -221,7 +221,7 @@ fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { let ty = match *self.ty.kind() { // NOTE: we cannot remove this match like in the LLVM codegen because the call // to fn_ptr_backend_type handle the on-stack attribute. - // TODO(antoyo): find a less hackish way to handle the on-stack attribute. + // FIXME(antoyo): find a less hackish way to handle the on-stack attribute. ty::FnPtr(sig_tys, hdr) => cx .fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig_tys.with(hdr), ty::List::empty())), _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), @@ -320,7 +320,7 @@ fn scalar_pair_element_gcc_type<'gcc>( // immediate, just like `bool` is typically `i8` in memory and only `i1` // when immediate. We need to load/store `bool` as `i8` to avoid // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. - // TODO(antoyo): this bugs certainly don't happen in this case since the bool type is used instead of i1. + // FIXME(antoyo): this bugs certainly don't happen in this case since the bool type is used instead of i1. if scalar.is_bool() { return cx.type_i1(); } diff --git a/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs b/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs index 0f2cb9231062..fb3e0f0d8f1f 100644 --- a/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs +++ b/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs @@ -73,14 +73,14 @@ fn filter(filename: &Path) -> bool { path.to_str().expect("to_str"), ]); - // TODO(antoyo): find a way to send this via a cli argument. + // FIXME(antoyo): find a way to send this via a cli argument. let test_target = std::env::var("CG_GCC_TEST_TARGET"); if let Ok(ref target) = test_target { compiler.args(["--target", target]); let linker = format!("{}-gcc", target); compiler.args(&[format!("-Clinker={}", linker)]); let mut env_path = std::env::var("PATH").unwrap_or_default(); - // TODO(antoyo): find a better way to add the PATH necessary locally. + // FIXME(antoyo): find a better way to add the PATH necessary locally. env_path = format!("/opt/m68k-unknown-linux-gnu/bin:{}", env_path); compiler.env("PATH", env_path); } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 994077251acc..a6e841e440a2 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -23,7 +23,6 @@ use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, Attribute, AttributePlace, Type, Value}; -use crate::llvm_util; use crate::type_of::LayoutLlvmExt; trait ArgAttributesExt { @@ -46,6 +45,12 @@ fn apply_attrs_to_callsite( (ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef), ]; +const CAPTURES_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 3] = [ + (ArgAttribute::CapturesNone, llvm::AttributeKind::CapturesNone), + (ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress), + (ArgAttribute::CapturesReadOnly, llvm::AttributeKind::CapturesReadOnly), +]; + fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 8]> { let mut regular = this.regular; @@ -82,18 +87,10 @@ fn apply_attrs_to_callsite( attrs.push(llattr.create_attr(cx.llcx)); } } - // captures(...) is only available since LLVM 21. - if (21, 0, 0) <= llvm_util::get_version() { - const CAPTURES_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 3] = [ - (ArgAttribute::CapturesNone, llvm::AttributeKind::CapturesNone), - (ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress), - (ArgAttribute::CapturesReadOnly, llvm::AttributeKind::CapturesReadOnly), - ]; - for (attr, llattr) in CAPTURES_ATTRIBUTES { - if regular.contains(attr) { - attrs.push(llattr.create_attr(cx.llcx)); - break; - } + for (attr, llattr) in CAPTURES_ATTRIBUTES { + if regular.contains(attr) { + attrs.push(llattr.create_attr(cx.llcx)); + break; } } } else if cx.tcx.sess.sanitizers().contains(SanitizerSet::MEMORY) { @@ -508,9 +505,7 @@ fn apply_attrs_llfn( } PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => { let i = apply(attrs); - if cx.sess().opts.optimize != config::OptLevel::No - && llvm_util::get_version() >= (21, 0, 0) - { + if cx.sess().opts.optimize != config::OptLevel::No { attributes::apply_to_llfn( llfn, llvm::AttributePlace::Argument(i), diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 546fa87ff561..f300ee5d4c99 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -120,7 +120,8 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>( if enabled.contains(SanitizerSet::THREAD) { attrs.push(llvm::AttributeKind::SanitizeThread.create_attr(cx.llcx)); } - if enabled.contains(SanitizerSet::HWADDRESS) { + if enabled.contains(SanitizerSet::HWADDRESS) || enabled.contains(SanitizerSet::KERNELHWADDRESS) + { attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx)); } if enabled.contains(SanitizerSet::SHADOWCALLSTACK) { @@ -506,15 +507,11 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); // applies to argument place instead of function place let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) { - // "Does not capture provenance" means "if the function call stashes the pointer somewhere, - // accessing that pointer after the function returns is UB". That is definitely the case here since - // freeing will destroy the provenance. - let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx); - &[allocated_pointer, captures_addr] - } else { - &[allocated_pointer] - }; + // "Does not capture provenance" means "if the function call stashes the pointer somewhere, + // accessing that pointer after the function returns is UB". That is definitely the case here since + // freeing will destroy the provenance. + let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx); + let attrs = &[allocated_pointer, captures_addr]; attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs); } if let Some(align) = codegen_fn_attrs.alignment { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index efd4e55d5a85..515b571a9f4b 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -23,9 +23,7 @@ use rustc_session::Session; use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath}; use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym}; -use rustc_target::spec::{ - Arch, CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel, -}; +use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::{debug, trace}; use crate::back::lto::{Buffer, ModuleBuffer}; @@ -38,7 +36,7 @@ use crate::common::AsCCharPtr; use crate::errors::{ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, ParseTargetMachineConfig, - UnknownCompression, WithLlvmError, WriteBytecode, + UnsupportedCompression, WithLlvmError, WriteBytecode, }; use crate::llvm::diagnostic::OptimizationDiagnosticKind::*; use crate::llvm::{self, DiagnosticInfo}; @@ -206,13 +204,7 @@ pub(crate) fn target_machine_factory( let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let (opt_level, _) = to_llvm_opt_settings(optlvl); - let float_abi = if sess.target.arch == Arch::Arm && sess.opts.cg.soft_float { - llvm::FloatAbi::Soft - } else { - // `validate_commandline_args_with_session_available` has already warned about this being - // ignored. Let's make sure LLVM doesn't suddenly start using this flag on more targets. - to_llvm_float_abi(sess.target.llvm_floatabi) - }; + let float_abi = to_llvm_float_abi(sess.target.llvm_floatabi); let ffunction_sections = sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections); @@ -233,7 +225,7 @@ pub(crate) fn target_machine_factory( let triple = SmallCStr::new(&versioned_llvm_target(sess)); let cpu = SmallCStr::new(llvm_util::target_cpu(sess)); let features = CString::new(target_features.join(",")).unwrap(); - let abi = SmallCStr::new(&sess.target.llvm_abiname); + let abi = SmallCStr::new(sess.target.llvm_abiname.desc()); let trap_unreachable = sess.opts.unstable_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); let emit_stack_size_section = sess.opts.unstable_opts.emit_stack_sizes; @@ -256,7 +248,7 @@ pub(crate) fn target_machine_factory( if llvm::LLVMRustLLVMHasZlibCompression() { llvm::CompressionKind::Zlib } else { - sess.dcx().emit_warn(UnknownCompression { algorithm: "zlib" }); + sess.dcx().emit_warn(UnsupportedCompression { algorithm: "zlib" }); llvm::CompressionKind::None } } @@ -264,7 +256,7 @@ pub(crate) fn target_machine_factory( if llvm::LLVMRustLLVMHasZstdCompression() { llvm::CompressionKind::Zstd } else { - sess.dcx().emit_warn(UnknownCompression { algorithm: "zstd" }); + sess.dcx().emit_warn(UnsupportedCompression { algorithm: "zstd" }); llvm::CompressionKind::None } } @@ -652,6 +644,10 @@ pub(crate) unsafe fn llvm_optimize( sanitize_kernel_address_recover: config .sanitizer_recover .contains(SanitizerSet::KERNELADDRESS), + sanitize_kernel_hwaddress: config.sanitizer.contains(SanitizerSet::KERNELHWADDRESS), + sanitize_kernel_hwaddress_recover: config + .sanitizer_recover + .contains(SanitizerSet::KERNELHWADDRESS), }) } else { None diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index d00e70638b45..227680947712 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -210,10 +210,14 @@ pub(crate) fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility { } pub(crate) fn set_variable_sanitizer_attrs(llval: &Value, attrs: &CodegenFnAttrs) { - if attrs.sanitizers.disabled.contains(SanitizerSet::ADDRESS) { + if attrs.sanitizers.disabled.contains(SanitizerSet::ADDRESS) + || attrs.sanitizers.disabled.contains(SanitizerSet::KERNELADDRESS) + { unsafe { llvm::LLVMRustSetNoSanitizeAddress(llval) }; } - if attrs.sanitizers.disabled.contains(SanitizerSet::HWADDRESS) { + if attrs.sanitizers.disabled.contains(SanitizerSet::HWADDRESS) + || attrs.sanitizers.disabled.contains(SanitizerSet::KERNELHWADDRESS) + { unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(llval) }; } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 2d91caf40f3c..f3508c10d1f6 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1605,12 +1605,16 @@ fn write_operand_repeatedly_unoptimized( *self = Self::build(self.cx, next_bb); } - pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.call_intrinsic("llvm.minnum", &[self.val_ty(lhs)], &[lhs, rhs]) + pub(crate) fn minimum_number_nsz(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + let call = self.call_intrinsic("llvm.minimumnum", &[self.val_ty(lhs)], &[lhs, rhs]); + unsafe { llvm::LLVMRustSetNoSignedZeros(call) }; + call } - pub(crate) fn maxnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.call_intrinsic("llvm.maxnum", &[self.val_ty(lhs)], &[lhs, rhs]) + pub(crate) fn maximum_number_nsz(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + let call = self.call_intrinsic("llvm.maximumnum", &[self.val_ty(lhs)], &[lhs, rhs]); + unsafe { llvm::LLVMRustSetNoSignedZeros(call) }; + call } pub(crate) fn insert_element( diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index f8f6439a7b0e..1cefdaae5ebd 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -6,7 +6,7 @@ use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::attrs::RustcAutodiff; -use rustc_middle::ty::{Instance, PseudoCanonicalInput, TyCtxt, TypingEnv}; +use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt, TypingEnv}; use rustc_middle::{bug, ty}; use rustc_target::callconv::PassMode; use tracing::debug; @@ -18,25 +18,23 @@ pub(crate) fn adjust_activity_to_abi<'tcx>( tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, + fn_ptr_ty: Ty<'tcx>, typing_env: TypingEnv<'tcx>, da: &mut ThinVec, ) { - let fn_ty = instance.ty(tcx, typing_env); - - if !matches!(fn_ty.kind(), ty::FnDef(..)) { - bug!("expected fn def for autodiff, got {:?}", fn_ty); + if !matches!(fn_ptr_ty.kind(), ty::FnPtr(..)) { + bug!("expected fn ptr for autodiff, got {:?}", fn_ptr_ty); } // We don't actually pass the types back into the type system. // All we do is decide how to handle the arguments. - let sig = fn_ty.fn_sig(tcx).skip_binder(); + let fn_sig = fn_ptr_ty.fn_sig(tcx); + let sig = fn_sig.skip_binder(); // FIXME(Sa4dUs): pass proper varargs once we have support for differentiating variadic functions - let Ok(fn_abi) = - tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty()))) + let Ok(fn_abi) = tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((fn_sig, ty::List::empty()))) else { - bug!("failed to get fn_abi of instance with empty varargs"); + bug!("failed to get fn_abi of fn_ptr with empty varargs"); }; let mut new_activities = vec![]; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 2760683dad9d..e02c4ae6ea69 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -25,11 +25,10 @@ use rustc_session::config::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet, }; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_span::{DUMMY_SP, Span, Spanned, Symbol}; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{ - Abi, Arch, Env, HasTargetSpec, Os, RelocModel, SmallDataThresholdSupport, Target, TlsModel, + Arch, CfgAbi, Env, HasTargetSpec, Os, RelocModel, SmallDataThresholdSupport, Target, TlsModel, }; use smallvec::SmallVec; @@ -191,17 +190,6 @@ pub(crate) unsafe fn create_module<'ll>( let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); - if llvm_version < (21, 0, 0) { - if sess.target.arch == Arch::Nvptx64 { - // LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961 - target_data_layout = target_data_layout.replace("e-p6:32:32-i64", "e-i64"); - } - if sess.target.arch == Arch::AmdGpu { - // LLVM 21 adds the address width for address space 8. - // See https://github.com/llvm/llvm-project/pull/139419 - target_data_layout = target_data_layout.replace("p8:128:128:128:48", "p8:128:128") - } - } if llvm_version < (22, 0, 0) { if sess.target.arch == Arch::Avr { // LLVM 22.0 updated the default layout on avr: https://github.com/llvm/llvm-project/pull/153010 @@ -343,11 +331,6 @@ pub(crate) unsafe fn create_module<'ll>( // Add "kcfi-arity" module flag if KCFI arity indicator is enabled. (See // https://github.com/llvm/llvm-project/pull/117121.) if sess.is_sanitizer_kcfi_arity_enabled() { - // KCFI arity indicator requires LLVM 21.0.0 or later. - if llvm_version < (21, 0, 0) { - tcx.dcx().emit_err(crate::errors::SanitizerKcfiArityRequiresLLVM2100); - } - llvm::add_module_flag_u32( llmod, llvm::ModuleFlagMergeBehavior::Override, @@ -361,7 +344,7 @@ pub(crate) unsafe fn create_module<'ll>( if sess.target.is_like_msvc || (sess.target.options.os == Os::Windows && sess.target.options.env == Env::Gnu - && sess.target.options.abi == Abi::Llvm) + && sess.target.options.cfg_abi == CfgAbi::Llvm) { match sess.opts.cg.control_flow_guard { CFGuard::Disabled => {} @@ -526,14 +509,13 @@ pub(crate) unsafe fn create_module<'ll>( // to workaround lld as the LTO plugin not // correctly setting target-abi for the LTO object // FIXME: https://github.com/llvm/llvm-project/issues/50591 - // If llvm_abiname is empty, emit nothing. let llvm_abiname = &sess.target.options.llvm_abiname; - if matches!(sess.target.arch, Arch::RiscV32 | Arch::RiscV64) && !llvm_abiname.is_empty() { + if matches!(sess.target.arch, Arch::RiscV32 | Arch::RiscV64) { llvm::add_module_flag_str( llmod, llvm::ModuleFlagMergeBehavior::Error, "target-abi", - llvm_abiname, + llvm_abiname.desc(), ); } @@ -1136,7 +1118,7 @@ fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> | LayoutError::ReferencesError(_) | LayoutError::InvalidSimd { .. } = err { - self.tcx.dcx().emit_fatal(Spanned { span, node: err.into_diagnostic() }) + self.tcx.dcx().span_fatal(span, err.to_string()) } else { self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) } diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index a7b5bdbf7bdf..880abb3fbc24 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -182,9 +182,9 @@ pub(crate) struct CopyBitcode { #[derive(Diagnostic)] #[diag( - "unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo" + "unsupported debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo" )] -pub(crate) struct UnknownCompression { +pub(crate) struct UnsupportedCompression { pub algorithm: &'static str, } @@ -204,7 +204,3 @@ pub(crate) struct MismatchedDataLayout<'a> { pub(crate) struct FixedX18InvalidArch<'a> { pub arch: &'a str, } - -#[derive(Diagnostic)] -#[diag("`-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later")] -pub(crate) struct SanitizerKcfiArityRequiresLLVM2100; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index af50afa057ed..39bf4c10dab1 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -107,16 +107,6 @@ fn call_simple_intrinsic<'ll, 'tcx>( sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]), sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]), - sym::fabsf16 => ("llvm.fabs", &[bx.type_f16()]), - sym::fabsf32 => ("llvm.fabs", &[bx.type_f32()]), - sym::fabsf64 => ("llvm.fabs", &[bx.type_f64()]), - sym::fabsf128 => ("llvm.fabs", &[bx.type_f128()]), - - sym::minnumf16 => ("llvm.minnum", &[bx.type_f16()]), - sym::minnumf32 => ("llvm.minnum", &[bx.type_f32()]), - sym::minnumf64 => ("llvm.minnum", &[bx.type_f64()]), - sym::minnumf128 => ("llvm.minnum", &[bx.type_f128()]), - // FIXME: LLVM currently mis-compile those intrinsics, re-enable them // when llvm/llvm-project#{139380,139381,140445} are fixed. //sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]), @@ -124,11 +114,6 @@ fn call_simple_intrinsic<'ll, 'tcx>( //sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), //sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), // - sym::maxnumf16 => ("llvm.maxnum", &[bx.type_f16()]), - sym::maxnumf32 => ("llvm.maxnum", &[bx.type_f32()]), - sym::maxnumf64 => ("llvm.maxnum", &[bx.type_f64()]), - sym::maxnumf128 => ("llvm.maxnum", &[bx.type_f128()]), - // FIXME: LLVM currently mis-compile those intrinsics, re-enable them // when llvm/llvm-project#{139380,139381,140445} are fixed. //sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]), @@ -195,6 +180,32 @@ fn codegen_intrinsic_call( let simple = call_simple_intrinsic(self, name, args); let llval = match name { _ if simple.is_some() => simple.unwrap(), + sym::minimum_number_nsz_f16 + | sym::minimum_number_nsz_f32 + | sym::minimum_number_nsz_f64 + | sym::minimum_number_nsz_f128 + | sym::maximum_number_nsz_f16 + | sym::maximum_number_nsz_f32 + | sym::maximum_number_nsz_f64 + | sym::maximum_number_nsz_f128 + // Need at least LLVM 22 for `min/maximumnum` to not crash LLVM. + if crate::llvm_util::get_version() >= (22, 0, 0) => + { + let intrinsic_name = if name.as_str().starts_with("min") { + "llvm.minimumnum" + } else { + "llvm.maximumnum" + }; + let call = self.call_intrinsic( + intrinsic_name, + &[args[0].layout.immediate_llvm_type(self.cx)], + &[args[0].immediate(), args[1].immediate()], + ); + // `nsz` on minimumnum/maximumnum is special: its only effect is to make + // signed-zero ordering non-deterministic. + unsafe { llvm::LLVMRustSetNoSignedZeros(call) }; + call + } sym::ptr_mask => { let ptr = args[0].immediate(); self.call_intrinsic( @@ -486,6 +497,20 @@ fn codegen_intrinsic_call( } } + sym::fabs => { + let ty = args[0].layout.ty; + let ty::Float(f) = ty.kind() else { + span_bug!(span, "the `fabs` intrinsic requires a floating-point argument, got {:?}", ty); + }; + let llty = self.type_float_from_ty(*f); + let llvm_name = "llvm.fabs"; + self.call_intrinsic( + llvm_name, + &[llty], + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } + sym::raw_eq => { use BackendRepr::*; let tp_ty = fn_args.type_at(0); @@ -493,7 +518,7 @@ fn codegen_intrinsic_call( let use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, SimdVector { .. } => false, - ScalableVector { .. } => { + SimdScalableVector { .. } => { tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType { span, name: sym::raw_eq, @@ -1322,29 +1347,8 @@ fn codegen_autodiff<'ll, 'tcx>( let ret_ty = sig.output(); let llret_ty = bx.layout_of(ret_ty).llvm_type(bx); - // Get source, diff, and attrs - let (source_id, source_args) = match fn_args.into_type_list(tcx)[0].kind() { - ty::FnDef(def_id, source_params) => (def_id, source_params), - _ => bug!("invalid autodiff intrinsic args"), - }; - - let fn_source = match Instance::try_resolve(tcx, bx.cx.typing_env(), *source_id, source_args) { - Ok(Some(instance)) => instance, - Ok(None) => bug!( - "could not resolve ({:?}, {:?}) to a specific autodiff instance", - source_id, - source_args - ), - Err(_) => { - // An error has already been emitted - return; - } - }; - - let source_symbol = symbol_name_for_instance_in_crate(tcx, fn_source.clone(), LOCAL_CRATE); - let Some(fn_to_diff) = bx.cx.get_function(&source_symbol) else { - bug!("could not find source function") - }; + let source_fn_ptr_ty = fn_args.into_type_list(tcx)[0]; + let fn_to_diff = args[0].immediate(); let (diff_id, diff_args) = match fn_args.into_type_list(tcx)[1].kind() { ty::FnDef(def_id, diff_args) => (def_id, diff_args), @@ -1375,13 +1379,12 @@ fn codegen_autodiff<'ll, 'tcx>( adjust_activity_to_abi( tcx, - fn_source, + source_fn_ptr_ty, TypingEnv::fully_monomorphized(), &mut diff_attrs.input_activity, ); - let fnc_tree = - rustc_middle::ty::fnc_typetrees(tcx, fn_source.ty(tcx, TypingEnv::fully_monomorphized())); + let fnc_tree = rustc_middle::ty::fnc_typetrees(tcx, source_fn_ptr_ty); // Build body generate_enzyme_call( @@ -1942,7 +1945,7 @@ macro_rules! return_error { } let ty::Float(f) = in_elem.kind() else { - return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); + return_error!(InvalidMonomorphization::BasicFloatType { span, name, ty: in_ty }); }; let elem_ty = bx.cx.type_float_from_ty(*f); @@ -2776,8 +2779,8 @@ macro_rules! arith_binary { simd_and: Uint, Int => and; simd_or: Uint, Int => or; simd_xor: Uint, Int => xor; - simd_fmax: Float => maxnum; - simd_fmin: Float => minnum; + simd_maximum_number_nsz: Float => maximum_number_nsz; + simd_minimum_number_nsz: Float => minimum_number_nsz; } macro_rules! arith_unary { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index f9af42494cad..7355d1136792 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -464,6 +464,8 @@ pub(crate) struct SanitizerOptions { pub sanitize_hwaddress_recover: bool, pub sanitize_kernel_address: bool, pub sanitize_kernel_address_recover: bool, + pub sanitize_kernel_hwaddress: bool, + pub sanitize_kernel_hwaddress_recover: bool, } /// LLVMRustRelocModel @@ -2045,6 +2047,7 @@ pub(crate) fn LLVMRustAddCallSiteAttributes<'a>( pub(crate) fn LLVMRustSetFastMath(Instr: &Value); pub(crate) fn LLVMRustSetAlgebraicMath(Instr: &Value); pub(crate) fn LLVMRustSetAllowReassoc(Instr: &Value); + pub(crate) fn LLVMRustSetNoSignedZeros(Instr: &Value); // Miscellaneous instructions pub(crate) fn LLVMRustBuildMemCpy<'a>( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index fbb582fe8601..3e0a6efde025 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -16,7 +16,7 @@ use rustc_session::Session; use rustc_session::config::{PrintKind, PrintRequest}; use rustc_target::spec::{ - Abi, Arch, Env, MergeFunctions, Os, PanicStrategy, SmallDataThresholdSupport, + Arch, CfgAbi, Env, MergeFunctions, Os, PanicStrategy, SmallDataThresholdSupport, }; use smallvec::{SmallVec, smallvec}; @@ -252,12 +252,11 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("fullfp16")), s => Some(LLVMFeature::new(s)), }, - - // Filter out features that are not supported by the current LLVM version - Arch::LoongArch32 | Arch::LoongArch64 => match s { - "32s" if major < 21 => None, + Arch::Bpf => match s { + "allows-misaligned-mem-access" if major < 22 => None, s => Some(LLVMFeature::new(s)), }, + // Filter out features that are not supported by the current LLVM version Arch::PowerPC | Arch::PowerPC64 => match s { "power8-crypto" => Some(LLVMFeature::new("crypto")), s => Some(LLVMFeature::new(s)), @@ -366,29 +365,20 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { let target_arch = &sess.target.arch; let target_os = &sess.target.options.os; let target_env = &sess.target.options.env; - let target_abi = &sess.target.options.abi; + let target_abi = &sess.target.options.cfg_abi; let target_pointer_width = sess.target.pointer_width; let version = get_version(); let (major, _, _) = version; cfg.has_reliable_f16 = match (target_arch, target_os) { - // LLVM crash without neon (fixed in LLVM 20.1.1) - (Arch::AArch64, _) - if !cfg.target_features.iter().any(|f| f.as_str() == "neon") - && version < (20, 1, 1) => - { - false - } // Unsupported (fixed in llvm22) (Arch::Arm64EC, _) if major < 22 => false, - // Selection failure (fixed in llvm21) - (Arch::S390x, _) if major < 21 => false, // MinGW ABI bugs - (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false, + (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != CfgAbi::Llvm => { + false + } // Infinite recursion (Arch::CSky, _) if major < 22 => false, // (fixed in llvm22) - (Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21) - (Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21) (Arch::PowerPC | Arch::PowerPC64, _) if major < 22 => false, // (fixed in llvm22) (Arch::Sparc | Arch::Sparc64, _) if major < 22 => false, // (fixed in llvm22) (Arch::Wasm32 | Arch::Wasm64, _) if major < 22 => false, // (fixed in llvm22) @@ -403,21 +393,18 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { (Arch::AmdGpu, _) => false, // Unsupported (Arch::Arm64EC, _) => false, - // Selection bug (fixed in LLVM 20.1.0) - (Arch::Mips64 | Arch::Mips64r6, _) if version < (20, 1, 0) => false, // Selection bug . This issue is closed // but basic math still does not work. (Arch::Nvptx64, _) => false, // ABI bugs et al. (full // list at ) (Arch::PowerPC | Arch::PowerPC64, _) => false, - // ABI unsupported - (Arch::Sparc, _) => false, - // Stack alignment bug . NB: tests may - // not fail if our compiler-builtins is linked. (fixed in llvm21) - (Arch::X86, _) if major < 21 => false, + // ABI unsupported (fixed in llvm22) + (Arch::Sparc, _) if major < 22 => false, // MinGW ABI bugs - (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false, + (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != CfgAbi::Llvm => { + false + } // There are no known problems on other platforms, so the only requirement is that symbols // are available. `compiler-builtins` provides all symbols required for core `f128` // support, so this should work for everything else. @@ -702,7 +689,9 @@ pub(crate) fn global_llvm_features(sess: &Session, only_base_features: bool) -> features_string }; - features.extend(features_string.split(',').map(String::from)); + if !features_string.is_empty() { + features.extend(features_string.split(',').map(String::from)); + } } Some(_) | None => {} }; diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 1ed06fbd2821..e586ed0dd6b0 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -24,7 +24,7 @@ fn uncached_llvm_type<'a, 'tcx>( let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } - BackendRepr::ScalableVector { ref element, count } => { + BackendRepr::SimdScalableVector { ref element, count } => { let element = if element.is_bool() { cx.type_i1() } else { @@ -187,7 +187,7 @@ fn is_llvm_immediate(&self) -> bool { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } => true, + | BackendRepr::SimdScalableVector { .. } => true, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -197,7 +197,7 @@ fn is_llvm_scalar_pair(&self) -> bool { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 9e6b36646434..fbe9cb813fc5 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -8,7 +8,7 @@ use rustc_middle::bug; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_target::spec::{Arch, Env, RustcAbi}; +use rustc_target::spec::{Arch, Env, LlvmAbi, RustcAbi}; use crate::builder::Builder; use crate::llvm::{Type, Value}; @@ -551,7 +551,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( registers_for_primitive(scalar1.primitive()); registers_for_primitive(scalar2.primitive()); } - BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => { // Because no instance of VaArgSafe uses a non-scalar `BackendRepr`. unreachable!( "No x86-64 SysV va_arg implementation for {:?}", @@ -692,7 +692,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( } // The Previous match on `BackendRepr` means control flow already escaped. BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::Memory { .. } => unreachable!(), }; @@ -1077,7 +1077,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( AllowHigherAlign::Yes, ForceRightAdjust::Yes, ), - Arch::RiscV32 if target.llvm_abiname == "ilp32e" => { + Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => { // FIXME: clang manually adjusts the alignment for this ABI. It notes: // // > To be compatible with GCC's behaviors, we force arguments with diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 56dca6c8b902..20e75f0fdfd2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -30,7 +30,7 @@ walk_native_lib_search_dirs, }; use rustc_middle::bug; -use rustc_middle::lint::diag_lint_level; +use rustc_middle::lint::emit_lint_base; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; @@ -47,7 +47,7 @@ use rustc_span::Symbol; use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ - Abi, BinaryFormat, Cc, Env, LinkOutputKind, LinkSelfContainedComponents, + BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, Os, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, }; @@ -784,7 +784,7 @@ fn for_each(bytes: &[u8], mut f: impl FnMut(&str, &mut String)) -> String { } let lint_msg = |msg| { - diag_lint_level( + emit_lint_base( sess, LINKER_MESSAGES, levels.linker_messages, @@ -793,7 +793,7 @@ fn for_each(bytes: &[u8], mut f: impl FnMut(&str, &mut String)) -> String { ); }; let lint_info = |msg| { - diag_lint_level(sess, LINKER_INFO, levels.linker_info, None, LinkerOutput { inner: msg }); + emit_lint_base(sess, LINKER_INFO, levels.linker_info, None, LinkerOutput { inner: msg }); }; if !escaped_stderr.is_empty() { @@ -1917,7 +1917,7 @@ fn self_contained_components( LinkSelfContainedDefault::InferredForMusl => sess.crt_static(Some(crate_type)), LinkSelfContainedDefault::InferredForMingw => { sess.host == sess.target - && sess.target.abi != Abi::Uwp + && sess.target.cfg_abi != CfgAbi::Uwp && detect_self_contained_mingw(sess, linker) } } @@ -2767,6 +2767,10 @@ fn add_order_independent_options( cmd.pgo_gen(); } + if sess.opts.unstable_opts.instrument_mcount { + cmd.enable_profiling(); + } + if sess.opts.cg.control_flow_guard != CFGuard::Disabled { cmd.control_flow_guard(); } diff --git a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs index 477c9478c360..ddc30ee9f3ac 100644 --- a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs +++ b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs @@ -9,7 +9,7 @@ use rustc_hashes::Hash128; use rustc_hir::attrs::NativeLibKind; use rustc_session::Session; -use rustc_session::cstore::DllImport; +use rustc_session::cstore::{DllImport, DllImportSymbolType}; use rustc_span::Symbol; use rustc_target::spec::Arch; @@ -95,14 +95,14 @@ pub(super) fn create_raw_dylib_dll_import_libs<'a>( true, ) }), - is_data: !import.is_fn, + is_data: import.symbol_type != DllImportSymbolType::Function, } } else { ImportLibraryItem { name: import.name.to_string(), ordinal: import.ordinal(), symbol_name: None, - is_data: !import.is_fn, + is_data: import.symbol_type != DllImportSymbolType::Function, } } }) @@ -271,10 +271,10 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] vers.push((version_name, dynstr)); id }; - syms.push((name, dynstr, Some(ver), symbol.is_fn)); + syms.push((name, dynstr, Some(ver), symbol.symbol_type, symbol.size)); } else { let dynstr = stub.add_dynamic_string(symbol_name.as_bytes()); - syms.push((symbol_name, dynstr, None, symbol.is_fn)); + syms.push((symbol_name, dynstr, None, symbol.symbol_type, symbol.size)); } } @@ -296,6 +296,8 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] stub.reserve_shstrtab_section_index(); let text_section_name = stub.add_section_name(".text".as_bytes()); let text_section = stub.reserve_section_index(); + let data_section_name = stub.add_section_name(".data".as_bytes()); + let data_section = stub.reserve_section_index(); stub.reserve_dynsym_section_index(); stub.reserve_dynstr_section_index(); if !vers.is_empty() { @@ -375,7 +377,7 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] // Section headers stub.write_null_section_header(); stub.write_shstrtab_section_header(); - // Create a dummy .text section for our dummy symbols. + // Create a dummy .text section for our dummy non-data symbols. stub.write_section_header(&write::SectionHeader { name: Some(text_section_name), sh_type: elf::SHT_PROGBITS, @@ -385,7 +387,20 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] sh_size: 0, sh_link: 0, sh_info: 0, - sh_addralign: 1, + sh_addralign: 16, + sh_entsize: 0, + }); + // And also a dummy .data section for our dummy data symbols. + stub.write_section_header(&write::SectionHeader { + name: Some(data_section_name), + sh_type: elf::SHT_PROGBITS, + sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC) as u64, + sh_addr: 0, + sh_offset: 0, + sh_size: 0, + sh_link: 0, + sh_info: 0, + sh_addralign: 16, sh_entsize: 0, }); stub.write_dynsym_section_header(0, 1); @@ -398,17 +413,28 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] // .dynsym stub.write_null_dynamic_symbol(); - for (_name, dynstr, _ver, is_fn) in syms.iter().copied() { - let sym_type = if is_fn { elf::STT_FUNC } else { elf::STT_NOTYPE }; + // Linkers like LLD require at least somewhat reasonable symbol values rather than zero, + // otherwise all the symbols might get put at the same address. Thus we increment the value + // every time we write a symbol. + let mut st_value = 0; + for (_name, dynstr, _ver, symbol_type, size) in syms.iter().copied() { + let sym_type = match symbol_type { + DllImportSymbolType::Function => elf::STT_FUNC, + DllImportSymbolType::Static => elf::STT_OBJECT, + DllImportSymbolType::ThreadLocal => elf::STT_TLS, + }; + let section = + if symbol_type == DllImportSymbolType::Static { data_section } else { text_section }; stub.write_dynamic_symbol(&write::Sym { name: Some(dynstr), st_info: (elf::STB_GLOBAL << 4) | sym_type, st_other: elf::STV_DEFAULT, - section: Some(text_section), + section: Some(section), st_shndx: 0, // ignored by object in favor of the `section` field - st_value: 0, - st_size: 0, + st_value, + st_size: size.bytes(), }); + st_value += 8; } // .dynstr @@ -418,7 +444,7 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] if !vers.is_empty() { // .gnu_version stub.write_null_gnu_versym(); - for (_name, _dynstr, ver, _is_fn) in syms.iter().copied() { + for (_name, _dynstr, ver, _symbol_type, _size) in syms.iter().copied() { stub.write_gnu_versym(if let Some(ver) = ver { assert!((2 + ver as u16) < elf::VERSYM_HIDDEN); elf::VERSYM_HIDDEN | (2 + ver as u16) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3ace1a8c266c..eb908e19be54 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; -use rustc_target::spec::{Abi, Arch, Cc, LinkOutputKind, LinkerFlavor, Lld, Os}; +use rustc_target::spec::{Arch, Cc, CfgAbi, LinkOutputKind, LinkerFlavor, Lld, Os}; use tracing::{debug, warn}; use super::command::Command; @@ -84,7 +84,7 @@ pub(crate) fn get_linker<'a>( // To comply with the Windows App Certification Kit, // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc). let t = &sess.target; - if matches!(flavor, LinkerFlavor::Msvc(..)) && t.abi == Abi::Uwp { + if matches!(flavor, LinkerFlavor::Msvc(..)) && t.cfg_abi == CfgAbi::Uwp { if let Some(ref tool) = msvc_tool { let original_path = tool.path(); if let Some(root_lib_path) = original_path.ancestors().nth(4) { @@ -135,7 +135,7 @@ pub(crate) fn get_linker<'a>( // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction // to the linker args construction. - assert!(cmd.get_args().is_empty() || sess.target.abi == Abi::Uwp); + assert!(cmd.get_args().is_empty() || sess.target.cfg_abi == CfgAbi::Uwp); match flavor { LinkerFlavor::Unix(Cc::No) if sess.target.os == Os::L4Re => { Box::new(L4Bender::new(cmd, sess)) as Box @@ -352,6 +352,7 @@ fn add_eh_frame_header(&mut self) {} fn add_no_exec(&mut self) {} fn add_as_needed(&mut self) {} fn reset_per_library_state(&mut self) {} + fn enable_profiling(&mut self) {} } impl dyn Linker + '_ { @@ -732,6 +733,19 @@ fn pgo_gen(&mut self) { self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]); } + fn enable_profiling(&mut self) { + // This flag is also used when linking to choose target specific + // libraries needed to enable profiling. + self.cc_arg("-pg"); + // On windows-gnu targets, libgmon also needs to be linked, and this + // requires readding libraries to satisfy its dependencies. + if self.sess.target.is_like_windows { + self.cc_arg("-lgmon"); + self.cc_arg("-lkernel32"); + self.cc_arg("-lmsvcrt"); + } + } + fn control_flow_guard(&mut self) {} fn ehcont_guard(&mut self) {} diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8a2a6823fdf4..f6544c035145 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -20,7 +20,7 @@ use rustc_middle::bug; use rustc_session::Session; use rustc_span::sym; -use rustc_target::spec::{Abi, Os, RelocModel, Target, ef_avr_arch}; +use rustc_target::spec::{CfgAbi, LlvmAbi, Os, RelocModel, Target, ef_avr_arch}; use tracing::debug; use super::apple; @@ -294,18 +294,13 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { _ => elf::EF_MIPS_ARCH_64R2, }; - // If the ABI is explicitly given, use it, or default to O32 on 32-bit MIPS, - // which is the only "true" 32-bit option that LLVM supports. - match sess.target.options.llvm_abiname.as_ref() { - "o32" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, - "n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2, - "n64" if !is_32bit => {} - "" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, - "" => sess.dcx().fatal("LLVM ABI must be specified for 64-bit MIPS targets"), - s if is_32bit => { - sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s)) - } - s => sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 64-bit MIPS target", s)), + // Use the explicitly given ABI. + match &sess.target.options.llvm_abiname { + LlvmAbi::O32 if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, + LlvmAbi::N32 if !is_32bit => e_flags |= elf::EF_MIPS_ABI2, + LlvmAbi::N64 if !is_32bit => {} + // The rest is invalid (which is already ensured by the target spec check). + s => bug!("invalid LLVM ABI `{}` for MIPS target", s), }; if sess.target.options.relocation_model != RelocModel::Static { @@ -341,12 +336,12 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { // Set the appropriate flag based on ABI // This needs to match LLVM `RISCVELFStreamer.cpp` - match &*sess.target.llvm_abiname { - "ilp32" | "lp64" => (), - "ilp32f" | "lp64f" => e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE, - "ilp32d" | "lp64d" => e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE, + match &sess.target.llvm_abiname { + LlvmAbi::Ilp32 | LlvmAbi::Lp64 => (), + LlvmAbi::Ilp32f | LlvmAbi::Lp64f => e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE, + LlvmAbi::Ilp32d | LlvmAbi::Lp64d => e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE, // Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI. - "ilp32e" | "lp64e" => e_flags |= elf::EF_RISCV_RVE, + LlvmAbi::Ilp32e | LlvmAbi::Lp64e => e_flags |= elf::EF_RISCV_RVE, _ => bug!("unknown RISC-V ABI name"), } @@ -358,10 +353,10 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { // Set the appropriate flag based on ABI // This needs to match LLVM `LoongArchELFStreamer.cpp` - match &*sess.target.llvm_abiname { - "ilp32s" | "lp64s" => e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT, - "ilp32f" | "lp64f" => e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT, - "ilp32d" | "lp64d" => e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT, + match &sess.target.llvm_abiname { + LlvmAbi::Ilp32s | LlvmAbi::Lp64s => e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT, + LlvmAbi::Ilp32f | LlvmAbi::Lp64f => e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT, + LlvmAbi::Ilp32d | LlvmAbi::Lp64d => e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT, _ => bug!("unknown LoongArch ABI name"), } @@ -377,7 +372,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { } } Architecture::Csky => { - if matches!(sess.target.options.abi, Abi::AbiV2) { + if matches!(sess.target.options.cfg_abi, CfgAbi::AbiV2) { elf::EF_CSKY_ABIV2 } else { elf::EF_CSKY_ABIV1 @@ -388,14 +383,14 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { const EF_PPC64_ABI_ELF_V1: u32 = 1; const EF_PPC64_ABI_ELF_V2: u32 = 2; - match sess.target.options.llvm_abiname.as_ref() { + match sess.target.options.llvm_abiname { // If the flags do not correctly indicate the ABI, // linkers such as ld.lld assume that the ppc64 object files are always ELFv2 // which leads to broken binaries if ELFv1 is used for the object files. - "elfv1" => EF_PPC64_ABI_ELF_V1, - "elfv2" => EF_PPC64_ABI_ELF_V2, - "" if sess.target.options.binary_format.to_object() == BinaryFormat::Elf => { - bug!("No ABI specified for this PPC64 ELF target"); + LlvmAbi::ElfV1 => EF_PPC64_ABI_ELF_V1, + LlvmAbi::ElfV2 => EF_PPC64_ABI_ELF_V2, + _ if sess.target.options.binary_format.to_object() == BinaryFormat::Elf => { + bug!("invalid ABI specified for this PPC64 ELF target"); } // Fall back _ => EF_PPC64_ABI_UNKNOWN, diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 557b00b911aa..3269fc5c9c1d 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -199,6 +199,14 @@ fn exported_non_generic_symbols_provider_local<'tcx>( })) } + symbols.extend(sorted.iter().flat_map(|&(&def_id, &info)| { + tcx.codegen_fn_attrs(def_id).foreign_item_symbol_aliases.iter().map( + move |&(foreign_item, _linkage, _visibility)| { + (ExportedSymbol::NonGeneric(foreign_item), info) + }, + ) + })); + if tcx.entry_fn(()).is_some() { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref())); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index b8a8bb3ad419..6dd4f2d6b592 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -150,7 +150,8 @@ fn process_builtin_attrs( && let Some(fn_sig) = try_fn_sig(tcx, did, *attr_span) && fn_sig.skip_binder().abi() != ExternAbi::Rust { - tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span }); + // This error is already reported in `rustc_ast_passes/src/ast_validation.rs`. + tcx.dcx().delayed_bug("`#[track_caller]` requires the Rust ABI"); } if is_closure && !tcx.features().closure_track_caller() diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 89a3f8061a8c..fe4d1da4329d 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -5,9 +5,9 @@ use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; -use rustc_session::cstore::{DllCallingConvention, DllImport}; +use rustc_session::cstore::{DllCallingConvention, DllImport, DllImportSymbolType}; use rustc_span::Span; -use rustc_target::spec::{Abi, Env, Os, Target}; +use rustc_target::spec::{CfgAbi, Env, Os, Target}; use crate::traits::*; @@ -171,7 +171,7 @@ pub fn asm_const_to_str<'tcx>( } pub fn is_mingw_gnu_toolchain(target: &Target) -> bool { - target.os == Os::Windows && target.env == Env::Gnu && target.abi == Abi::Unspecified + target.os == Os::Windows && target.env == Env::Gnu && target.cfg_abi == CfgAbi::Unspecified } pub fn i686_decorated_name( @@ -199,7 +199,7 @@ pub fn i686_decorated_name( decorated_name.push('\x01'); } - let prefix = if add_prefix && dll_import.is_fn { + let prefix = if add_prefix && dll_import.symbol_type == DllImportSymbolType::Function { match dll_import.calling_convention { DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None, DllCallingConvention::Stdcall(_) => (!mingw @@ -207,7 +207,7 @@ pub fn i686_decorated_name( .then_some('_'), DllCallingConvention::Fastcall(_) => Some('@'), } - } else if !dll_import.is_fn && !mingw { + } else if dll_import.symbol_type != DllImportSymbolType::Function && !mingw { // For static variables, prefix with '_' on MSVC. Some('_') } else { @@ -219,7 +219,7 @@ pub fn i686_decorated_name( decorated_name.push_str(name); - if add_suffix && dll_import.is_fn { + if add_suffix && dll_import.symbol_type == DllImportSymbolType::Function { use std::fmt::Write; match dll_import.calling_convention { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index d3b2caca4742..d207cdca4d4b 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -95,7 +95,7 @@ fn push_debuginfo_type_name<'tcx>( // Computing the layout can still fail here, e.g. if the target architecture // cannot represent the type. See // https://github.com/rust-lang/rust/issues/94961. - tcx.dcx().emit_fatal(e.into_diagnostic()); + tcx.dcx().fatal(e.to_string()); } } } else { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index be1965f67491..cec84f60a7b0 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -8,7 +8,8 @@ use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg, + Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg, + Level, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::layout::LayoutError; @@ -111,13 +112,6 @@ pub(crate) struct NoSavedObjectFile<'a> { pub cgu_name: &'a str, } -#[derive(Diagnostic)] -#[diag("`#[track_caller]` requires Rust ABI", code = E0737)] -pub(crate) struct RequiresRustAbi { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag("unable to copy {$source_file} to {$output_path}: {$error}")] pub(crate) struct CopyPathBuf { @@ -739,14 +733,6 @@ pub enum InvalidMonomorphization<'tcx> { in_ty: Ty<'tcx>, }, - #[diag("invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type", code = E0511)] - FloatingPointType { - #[primary_span] - span: Span, - name: Symbol, - in_ty: Ty<'tcx>, - }, - #[diag("invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`", code = E0511)] UnrecognizedIntrinsic { #[primary_span] @@ -1248,8 +1234,30 @@ pub(crate) struct FeatureNotValid<'a> { #[primary_span] #[label("`{$feature}` is not valid for this target")] pub span: Span, - #[help("consider removing the leading `+` in the feature name")] - pub plus_hint: bool, + #[subdiagnostic] + pub hint: FeatureNotValidHint<'a>, +} + +#[derive(Subdiagnostic)] +pub(crate) enum FeatureNotValidHint<'a> { + #[suggestion( + "consider removing the leading `+` in the feature name", + code = "enable = \"{stripped}\"", + applicability = "maybe-incorrect", + style = "verbose" + )] + RemovePlusFromFeatureName { + #[primary_span] + span: Span, + stripped: &'a str, + }, + #[help( + "valid names are: {$possibilities}{$and_more -> + [0] {\"\"} + *[other] {\" \"}and {$and_more} more + }" + )] + ValidFeatureNames { possibilities: DiagSymbolList<&'a str>, and_more: usize }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index cf643931717b..dcbd7f7e7708 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -12,8 +12,7 @@ use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; -use rustc_span::Span; -use rustc_span::source_map::Spanned; +use rustc_span::{Span, Spanned}; use rustc_target::callconv::{ArgAbi, ArgAttributes, CastTarget, FnAbi, PassMode}; use tracing::{debug, info}; @@ -1019,10 +1018,9 @@ fn codegen_call_terminator( if let Some(hir_id) = terminator.source_info.scope.lint_root(&self.mir.source_scopes) { - let msg = "tail calling a function marked with `#[track_caller]` has no special effect"; - bx.tcx().node_lint(TAIL_CALL_TRACK_CALLER, hir_id, |d| { - _ = d.primary_message(msg).span(fn_span) - }); + bx.tcx().emit_node_lint(TAIL_CALL_TRACK_CALLER, hir_id, rustc_errors::DiagDecorator(|d| { + _ = d.primary_message("tail calling a function marked with `#[track_caller]` has no special effect").span(fn_span) + })); } let instance = ty::Instance::resolve_for_fn_ptr( diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 1a0f66d31cca..5c14d6f2c093 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -437,7 +437,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( assert_eq!( None, num_untupled.replace(tupled_arg_tys.len()), - "Replaced existing num_tupled" + "Replaced existing num_untupled" ); return LocalRef::Place(place); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 85fa890453d8..e1d1ef858c01 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -404,7 +404,7 @@ pub(crate) fn extract_field>( } BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } - | BackendRepr::ScalableVector { .. } => bug!(), + | BackendRepr::SimdScalableVector { .. } => bug!(), }) }; @@ -691,7 +691,7 @@ pub(super) fn new(layout: TyAndLayout<'tcx>) -> Self { BackendRepr::ScalarPair(a, b) => { OperandValueBuilder::Pair(Either::Right(a), Either::Right(b)) } - BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => { OperandValueBuilder::Vector(Either::Right(())) } BackendRepr::Memory { .. } => { diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index e9209657984e..8ac3f0555db2 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -9,12 +9,12 @@ use rustc_session::Session; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol, edit_distance, sym}; use rustc_target::spec::Arch; use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability}; use smallvec::SmallVec; -use crate::errors::FeatureNotValid; +use crate::errors::{FeatureNotValid, FeatureNotValidHint}; use crate::{errors, target_features}; /// Compute the enabled target features from the `#[target_feature]` function attribute. @@ -32,14 +32,25 @@ pub(crate) fn from_target_feature_attr( for &(feature, feature_span) in features { let feature_str = feature.as_str(); let Some(stability) = rust_target_features.get(feature_str) else { - let plus_hint = feature_str - .strip_prefix('+') - .is_some_and(|stripped| rust_target_features.contains_key(stripped)); - tcx.dcx().emit_err(FeatureNotValid { - feature: feature_str, - span: feature_span, - plus_hint, - }); + let hint = if let Some(stripped) = feature_str.strip_prefix('+') + && rust_target_features.contains_key(stripped) + { + FeatureNotValidHint::RemovePlusFromFeatureName { span: feature_span, stripped } + } else { + // Show the 5 feature names that are most similar to the input. + let mut valid_names: Vec<_> = + rust_target_features.keys().map(|name| name.as_str()).into_sorted_stable_ord(); + valid_names.sort_by_key(|name| { + edit_distance::edit_distance(name, feature.as_str(), 5).unwrap_or(usize::MAX) + }); + valid_names.truncate(5); + + FeatureNotValidHint::ValidFeatureNames { + possibilities: valid_names.into(), + and_more: rust_target_features.len().saturating_sub(5), + } + }; + tcx.dcx().emit_err(FeatureNotValid { feature: feature_str, span: feature_span, hint }); continue; }; diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index f41b68bb1f7e..7c5f867929f0 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -25,17 +25,8 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, $($tt)*) } } + impl rustc_middle::mir::interpret::MachineStopType for Zst {} - impl rustc_middle::mir::interpret::MachineStopType for Zst { - fn diagnostic_message(&self) -> rustc_errors::DiagMessage { - self.to_string().into() - } - - fn add_args( - self: Box, - _: &mut dyn FnMut(rustc_errors::DiagArgName, rustc_errors::DiagArgValue), - ) {} - } throw_machine_stop!(Zst) }} diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 41d21bd74f98..c48b33e29eb6 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,15 +1,17 @@ -use std::mem; +use std::{fmt, mem}; -use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg}; +use rustc_errors::{Diag, E0080}; use rustc_middle::mir::AssertKind; -use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo, UndefinedBehaviorInfo}; +use rustc_middle::mir::interpret::{ + AllocId, Provenance, ReportedErrorInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, +}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::ConstInt; use rustc_middle::ty::layout::LayoutError; -use rustc_span::{Span, Symbol}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use super::CompileTimeMachine; -use crate::errors::{self, FrameNote, ReportErrorExt}; +use crate::errors::{self, FrameNote}; use crate::interpret::{ CtfeProvenance, ErrorHandled, Frame, InterpCx, InterpErrorInfo, InterpErrorKind, MachineStopType, Pointer, err_inval, err_machine_stop, @@ -40,65 +42,49 @@ pub enum ConstEvalErrKind { ConstMakeGlobalWithOffset(Pointer>), } -impl MachineStopType for ConstEvalErrKind { - fn diagnostic_message(&self) -> DiagMessage { +impl fmt::Display for ConstEvalErrKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use ConstEvalErrKind::*; - use rustc_errors::msg; - match self { - ConstAccessesMutGlobal => "constant accesses mutable global memory".into(), + ConstAccessesMutGlobal => write!(f, "constant accesses mutable global memory"), ModifiedGlobal => { - "modifying a static's initial value from another static's initializer".into() + write!(f, "modifying a static's initial value from another static's initializer") } - Panic { .. } => msg!("evaluation panicked: {$msg}"), + Panic { msg, .. } => write!(f, "evaluation panicked: {msg}"), RecursiveStatic => { - "encountered static that tried to access itself during initialization".into() + write!(f, "encountered static that tried to access itself during initialization") } - AssertFailure(x) => x.diagnostic_message(), + AssertFailure(x) => write!(f, "{x}"), WriteThroughImmutablePointer => { - msg!( + write!( + f, "writing through a pointer that was derived from a shared (immutable) reference" ) } - ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => { - msg!("attempting to call `const_make_global` twice on the same allocation {$alloc}") - } - ConstMakeGlobalPtrIsNonHeap(_) => { - msg!( - "pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}" + ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => { + write!( + f, + "attempting to call `const_make_global` twice on the same allocation {alloc}" ) } - ConstMakeGlobalWithDanglingPtr(_) => { - msg!("pointer passed to `const_make_global` is dangling: {$ptr}") + ConstMakeGlobalPtrIsNonHeap(ptr) => { + write!( + f, + "pointer passed to `const_make_global` does not point to a heap allocation: {ptr}" + ) } - ConstMakeGlobalWithOffset(_) => { - msg!("making {$ptr} global which does not point to the beginning of an object") + ConstMakeGlobalWithDanglingPtr(ptr) => { + write!(f, "pointer passed to `const_make_global` is dangling: {ptr}") } - } - } - fn add_args(self: Box, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) { - use ConstEvalErrKind::*; - match *self { - RecursiveStatic - | ConstAccessesMutGlobal - | ModifiedGlobal - | WriteThroughImmutablePointer => {} - AssertFailure(kind) => kind.add_args(adder), - Panic { msg, .. } => { - adder("msg".into(), msg.into_diag_arg(&mut None)); - } - ConstMakeGlobalPtrIsNonHeap(ptr) - | ConstMakeGlobalWithOffset(ptr) - | ConstMakeGlobalWithDanglingPtr(ptr) => { - adder("ptr".into(), format!("{ptr:?}").into_diag_arg(&mut None)); - } - ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => { - adder("alloc".into(), alloc.into_diag_arg(&mut None)); + ConstMakeGlobalWithOffset(ptr) => { + write!(f, "making {ptr} global which does not point to the beginning of an object") } } } } +impl MachineStopType for ConstEvalErrKind {} + /// The errors become [`InterpErrorKind::MachineStop`] when being raised. impl<'tcx> Into> for ConstEvalErrKind { fn into(self) -> InterpErrorInfo<'tcx> { @@ -178,43 +164,43 @@ pub fn get_span_and_frames<'tcx>( /// This will use the `mk` function for adding more information to the error. /// You can use it to add a stacktrace of current execution according to /// `get_span_and_frames` or just give context on where the const eval error happened. -pub(super) fn report<'tcx, C, F>( +pub(super) fn report<'tcx>( ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, error: InterpErrorKind<'tcx>, - span: Span, - get_span_and_frames: C, - mk: F, -) -> ErrorHandled -where - C: FnOnce() -> (Span, Vec), - F: FnOnce(&mut Diag<'_>, Span, Vec), -{ + mk: impl FnOnce(&mut Diag<'_>, Span, Vec), +) -> ErrorHandled { let tcx = ecx.tcx.tcx; // Special handling for certain errors match error { // Don't emit a new diagnostic for these errors, they are already reported elsewhere or // should remain silent. - err_inval!(AlreadyReported(info)) => ErrorHandled::Reported(info, span), + err_inval!(AlreadyReported(info)) => ErrorHandled::Reported(info, DUMMY_SP), err_inval!(Layout(LayoutError::TooGeneric(_))) | err_inval!(TooGeneric) => { - ErrorHandled::TooGeneric(span) + ErrorHandled::TooGeneric(DUMMY_SP) } err_inval!(Layout(LayoutError::ReferencesError(guar))) => { // This can occur in infallible promoteds e.g. when a non-existent type or field is // encountered. - ErrorHandled::Reported(ReportedErrorInfo::allowed_in_infallible(guar), span) + ErrorHandled::Reported(ReportedErrorInfo::allowed_in_infallible(guar), DUMMY_SP) } // Report remaining errors. _ => { - let (our_span, frames) = get_span_and_frames(); - let span = span.substitute_dummy(our_span); - let mut err = tcx.dcx().struct_span_err(our_span, error.diagnostic_message()); - // We allow invalid programs in infallible promoteds since invalid layouts can occur - // anyway (e.g. due to size overflow). And we allow OOM as that can happen any time. - let allowed_in_infallible = matches!( + let (span, frames) = super::get_span_and_frames(ecx.tcx, ecx.stack()); + let mut err = tcx.dcx().struct_span_err(span, error.to_string()); + err.code(E0080); + if matches!( error, - InterpErrorKind::ResourceExhaustion(_) | InterpErrorKind::InvalidProgram(_) - ); - + InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { + ptr_bytes_warning: true, + .. + }) | InterpErrorKind::Unsupported( + UnsupportedOpInfo::ReadPointerAsInt(..) + | UnsupportedOpInfo::ReadPartialPointer(..) + ) + ) { + err.help("this code performed an operation that depends on the underlying bytes representing a pointer"); + err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported"); + } if let InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes( Some((alloc_id, _access)), )) = error @@ -229,7 +215,12 @@ pub(super) fn report<'tcx, C, F>( err.subdiagnostic(raw_bytes); } - error.add_args(&mut err); + // We allow invalid programs in infallible promoteds since invalid layouts can occur + // anyway (e.g. due to size overflow). And we allow OOM as that can happen any time. + let allowed_in_infallible = matches!( + error, + InterpErrorKind::ResourceExhaustion(_) | InterpErrorKind::InvalidProgram(_) + ); mk(&mut err, span, frames); let g = err.emit(); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 2dbf2cc91058..ccfdf571fb27 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -2,7 +2,6 @@ use either::{Left, Right}; use rustc_abi::{self as abi, BackendRepr}; -use rustc_errors::{E0080, msg}; use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; @@ -11,8 +10,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, throw_inval}; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; @@ -88,7 +87,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( &ret.clone().into(), ReturnContinuation::Stop { cleanup: false }, )?; - ecx.storage_live_for_always_live_locals()?; + ecx.push_stack_frame_done()?; // The main interpreter loop. while ecx.step()? { @@ -425,7 +424,7 @@ fn const_validate_mplace<'tcx>( cid: GlobalId<'tcx>, ) -> Result<(), ErrorHandled> { let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); - let mut ref_tracking = RefTracking::new(mplace.clone()); + let mut ref_tracking = RefTracking::new(mplace.clone(), mplace.layout.ty); let mut inner = false; while let Some((mplace, path)) = ref_tracking.next() { let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) { @@ -458,32 +457,20 @@ fn report_eval_error<'tcx>( let (error, backtrace) = error.into_parts(); backtrace.print_backtrace(); - super::report( - ecx, - error, - DUMMY_SP, - || super::get_span_and_frames(ecx.tcx, ecx.stack()), - |diag, span, frames| { - let num_frames = frames.len(); - // FIXME(oli-obk): figure out how to use structured diagnostics again. - diag.code(E0080); - diag.span_label( - span, - msg!( - "evaluation of `{$instance}` failed {$num_frames -> - [0] here - *[other] inside this call - }" - ), - ); - for frame in frames { - diag.subdiagnostic(frame); - } - // Add after the frame rendering above, as it adds its own `instance` args. - diag.arg("instance", with_no_trimmed_paths!(cid.instance.to_string())); - diag.arg("num_frames", num_frames); - }, - ) + super::report(ecx, error, |diag, span, frames| { + let num_frames = frames.len(); + diag.span_label( + span, + format!( + "evaluation of `{instance}` failed {where_}", + instance = with_no_trimmed_paths!(cid.instance.to_string()), + where_ = if num_frames == 0 { "here" } else { "inside this call" }, + ), + ); + for frame in frames { + diag.subdiagnostic(frame); + } + }) } #[inline(never)] @@ -506,20 +493,10 @@ fn report_validation_error<'tcx>( let raw_bytes = errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes }; - crate::const_eval::report( - ecx, - error, - DUMMY_SP, - || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), - move |diag, span, frames| { - // FIXME(oli-obk): figure out how to use structured diagnostics again. - diag.code(E0080); - diag.span_label(span, "it is undefined behavior to use this value"); - diag.note("the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior."); - for frame in frames { - diag.subdiagnostic(frame); - } - diag.subdiagnostic(raw_bytes); - }, - ) + crate::const_eval::report(ecx, error, move |diag, span, frames| { + diag.span_label(span, "it is undefined behavior to use this value"); + diag.note("the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior."); + assert!(frames.is_empty()); // we just report validation errors for the final const here + diag.subdiagnostic(raw_bytes); + }) } diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index ad4c9aa5ff9b..0b5065f12f80 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -37,7 +37,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness { } } Node::TraitItem(ti @ TraitItem { kind: TraitItemKind::Fn(..), .. }) => { - if find_attr!(tcx.hir_attrs(ti.hir_id()), RustcNonConstTraitMethod) { + if find_attr!(tcx, ti.hir_id(), RustcNonConstTraitMethod) { Constness::NotConst } else { tcx.trait_def(tcx.local_parent(def_id)).constness diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index e88123334dd5..a19bf0b4da8b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -5,7 +5,6 @@ use rustc_abi::{Align, FIRST_VARIANT, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; -use rustc_errors::msg; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem, find_attr}; use rustc_middle::mir::AssertMessage; @@ -24,7 +23,7 @@ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, compile_time_machine, ensure_monomorphic_enough, err_inval, interp_ok, throw_exhaust, - throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, + throw_inval, throw_ub, throw_ub_format, throw_unsup, throw_unsup_format, type_implements_dyn_trait, }; @@ -489,18 +488,9 @@ fn call_intrinsic( let align = match Align::from_bytes(align) { Ok(a) => a, - Err(err) => throw_ub_custom!( - msg!( - "invalid align passed to `{$name}`: {$align} is {$err_kind -> - [not_power_of_two] not a power of 2 - [too_large] too large - *[other] {\"\"} - }" - ), - name = "const_allocate", - err_kind = err.diag_ident(), - align = err.align() - ), + Err(err) => { + throw_ub_format!("invalid align passed to `const_allocate`: {err}") + } }; let ptr = ecx.allocate_ptr( @@ -519,18 +509,9 @@ fn call_intrinsic( let size = Size::from_bytes(size); let align = match Align::from_bytes(align) { Ok(a) => a, - Err(err) => throw_ub_custom!( - msg!( - "invalid align passed to `{$name}`: {$align} is {$err_kind -> - [not_power_of_two] not a power of 2 - [too_large] too large - *[other] {\"\"} - }" - ), - name = "const_deallocate", - err_kind = err.diag_ident(), - align = err.align() - ), + Err(err) => { + throw_ub_format!("invalid align passed to `const_deallocate`: {err}") + } }; // If an allocation is created in an another const, diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 07d001e9d847..3943be0cf15e 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -1,22 +1,11 @@ use std::borrow::Cow; -use std::fmt::Write; -use either::Either; -use rustc_abi::WrappingRange; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; -use rustc_errors::{ - Diag, DiagArgMap, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, - Subdiagnostic, format_diag_message, msg, -}; +use rustc_errors::{Diag, DiagArgValue, EmissionGuarantee, MultiSpan, Subdiagnostic, msg}; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::mir::interpret::{ - CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, InvalidProgramInfo, - Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, - UnsupportedOpInfo, ValidationErrorInfo, -}; -use rustc_middle::ty::{self, Mutability, Ty}; +use rustc_middle::ty::{Mutability, Ty}; use rustc_span::{Span, Symbol}; use crate::interpret::InternKind; @@ -394,8 +383,6 @@ pub struct RawBytesNote { pub bytes: String, } -// FIXME(fee1-dead) do not use stringly typed `ConstContext` - #[derive(Diagnostic)] #[diag( r#"cannot match on `{$ty}` in {$kind -> @@ -609,699 +596,6 @@ pub struct LiveDrop<'tcx> { pub dropped_at: Span, } -pub trait ReportErrorExt { - /// Returns the diagnostic message for this error. - fn diagnostic_message(&self) -> DiagMessage; - fn add_args(self, diag: &mut Diag<'_, G>); - - fn debug(self) -> String - where - Self: Sized, - { - ty::tls::with(move |tcx| { - let dcx = tcx.dcx(); - let mut diag = dcx.struct_allow(DiagMessage::Str(String::new().into())); - let message = self.diagnostic_message(); - self.add_args(&mut diag); - let s = format_diag_message(&message, &diag.args).into_owned(); - diag.cancel(); - s - }) - } -} - -impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { - fn diagnostic_message(&self) -> DiagMessage { - use UndefinedBehaviorInfo::*; - - match self { - Ub(msg) => msg.clone().into(), - Custom(x) => (x.msg)(), - ValidationError(e) => e.diagnostic_message(), - - Unreachable => "entering unreachable code".into(), - BoundsCheckFailed { .. } => msg!("indexing out of bounds: the len is {$len} but the index is {$index}"), - DivisionByZero => "dividing by zero".into(), - RemainderByZero => "calculating the remainder with a divisor of zero".into(), - DivisionOverflow => "overflow in signed division (dividing MIN by -1)".into(), - RemainderOverflow => "overflow in signed remainder (dividing MIN by -1)".into(), - PointerArithOverflow => "overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`".into(), - ArithOverflow { .. } => msg!("arithmetic overflow in `{$intrinsic}`"), - ShiftOverflow { .. } => msg!("overflowing shift by {$shift_amount} in `{$intrinsic}`"), - InvalidMeta(InvalidMetaKind::SliceTooBig) => "invalid metadata in wide pointer: slice is bigger than largest supported object".into(), - InvalidMeta(InvalidMetaKind::TooBig) => "invalid metadata in wide pointer: total size is bigger than largest supported object".into(), - UnterminatedCString(_) => "reading a null-terminated string starting at {$pointer} with no null found before end of allocation".into(), - PointerUseAfterFree(_, _) => msg!( - "{$operation -> - [MemoryAccess] memory access failed - [InboundsPointerArithmetic] in-bounds pointer arithmetic failed - *[Dereferenceable] pointer not dereferenceable - }: {$alloc_id} has been freed, so this pointer is dangling" - ), - PointerOutOfBounds { .. } => msg!( - "{$operation -> - [MemoryAccess] memory access failed - [InboundsPointerArithmetic] in-bounds pointer arithmetic failed - *[Dereferenceable] pointer not dereferenceable - }: {$operation -> - [MemoryAccess] attempting to access {$inbounds_size -> - [1] 1 byte - *[x] {$inbounds_size} bytes - } - [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> - [1] 1 byte - *[x] {$inbounds_size} bytes - } - *[Dereferenceable] pointer must {$inbounds_size -> - [0] point to some allocation - [1] be dereferenceable for 1 byte - *[x] be dereferenceable for {$inbounds_size} bytes - } - }, but got {$pointer} which {$ptr_offset_is_neg -> - [true] points to before the beginning of the allocation - *[false] {$inbounds_size_is_neg -> - [false] {$alloc_size_minus_ptr_offset -> - [0] is at or beyond the end of the allocation of size {$alloc_size -> - [1] 1 byte - *[x] {$alloc_size} bytes - } - [1] is only 1 byte from the end of the allocation - *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation - } - *[true] {$ptr_offset_abs -> - [0] is at the beginning of the allocation - *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation - } - } - }" - ), - DanglingIntPointer { addr: 0, .. } => msg!( - "{$operation -> - [MemoryAccess] memory access failed - [InboundsPointerArithmetic] in-bounds pointer arithmetic failed - *[Dereferenceable] pointer not dereferenceable - }: {$operation -> - [MemoryAccess] attempting to access {$inbounds_size -> - [1] 1 byte - *[x] {$inbounds_size} bytes - } - [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> - [1] 1 byte - *[x] {$inbounds_size} bytes - } - *[Dereferenceable] pointer must {$inbounds_size -> - [0] point to some allocation - [1] be dereferenceable for 1 byte - *[x] be dereferenceable for {$inbounds_size} bytes - } - }, but got null pointer"), - DanglingIntPointer { .. } => msg!( - "{$operation -> - [MemoryAccess] memory access failed - [InboundsPointerArithmetic] in-bounds pointer arithmetic failed - *[Dereferenceable] pointer not dereferenceable - }: {$operation -> - [MemoryAccess] attempting to access {$inbounds_size -> - [1] 1 byte - *[x] {$inbounds_size} bytes - } - [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> - [1] 1 byte - *[x] {$inbounds_size} bytes - } - *[Dereferenceable] pointer must {$inbounds_size -> - [0] point to some allocation - [1] be dereferenceable for 1 byte - *[x] be dereferenceable for {$inbounds_size} bytes - } - }, but got {$pointer} which is a dangling pointer (it has no provenance)"), - AlignmentCheckFailed { .. } => msg!( - "{$msg -> - [AccessedPtr] accessing memory - *[other] accessing memory based on pointer - } with alignment {$has}, but alignment {$required} is required" - ), - WriteToReadOnly(_) => msg!("writing to {$allocation} which is read-only"), - DerefFunctionPointer(_) => msg!("accessing {$allocation} which contains a function"), - DerefVTablePointer(_) => msg!("accessing {$allocation} which contains a vtable"), - DerefVaListPointer(_) => msg!("accessing {$allocation} which contains a variable argument list"), - DerefTypeIdPointer(_) => msg!("accessing {$allocation} which contains a `TypeId`"), - InvalidBool(_) => msg!("interpreting an invalid 8-bit value as a bool: 0x{$value}"), - InvalidChar(_) => msg!("interpreting an invalid 32-bit value as a char: 0x{$value}"), - InvalidTag(_) => msg!("enum value has invalid tag: {$tag}"), - InvalidFunctionPointer(_) => msg!("using {$pointer} as function pointer but it does not point to a function"), - InvalidVaListPointer(_) => msg!("using {$pointer} as variable argument list pointer but it does not point to a variable argument list"), - InvalidVTablePointer(_) => msg!("using {$pointer} as vtable pointer but it does not point to a vtable"), - InvalidVTableTrait { .. } => msg!("using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected"), - InvalidStr(_) => msg!("this string is not valid UTF-8: {$err}"), - InvalidUninitBytes(None) => "using uninitialized data, but this operation requires initialized memory".into(), - InvalidUninitBytes(Some(_)) => msg!("reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory"), - DeadLocal => "accessing a dead local variable".into(), - ScalarSizeMismatch(_) => msg!("scalar size mismatch: expected {$target_size} bytes but got {$data_size} bytes instead"), - UninhabitedEnumVariantWritten(_) => "writing discriminant of an uninhabited enum variant".into(), - UninhabitedEnumVariantRead(_) => "read discriminant of an uninhabited enum variant".into(), - InvalidNichedEnumVariantWritten { .. } => { - msg!("trying to set discriminant of a {$ty} to the niched variant, but the value does not match") - } - AbiMismatchArgument { .. } => msg!("calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}"), - AbiMismatchReturn { .. } => msg!("calling a function with return type {$callee_ty} passing return place of type {$caller_ty}"), - VaArgOutOfBounds => "more C-variadic arguments read than were passed".into(), - CVariadicMismatch { ..} => "calling a function where the caller and callee disagree on whether the function is C-variadic".into(), - CVariadicFixedCountMismatch { .. } => msg!("calling a C-variadic function with {$caller} fixed arguments, but the function expects {$callee}"), - } - } - - fn add_args(self, diag: &mut Diag<'_, G>) { - use UndefinedBehaviorInfo::*; - match self { - Ub(_) => {} - Custom(custom) => { - (custom.add_args)(&mut |name, value| { - diag.arg(name, value); - }); - } - ValidationError(e) => e.add_args(diag), - - Unreachable - | DivisionByZero - | RemainderByZero - | DivisionOverflow - | RemainderOverflow - | PointerArithOverflow - | InvalidMeta(InvalidMetaKind::SliceTooBig) - | InvalidMeta(InvalidMetaKind::TooBig) - | InvalidUninitBytes(None) - | DeadLocal - | VaArgOutOfBounds - | UninhabitedEnumVariantWritten(_) - | UninhabitedEnumVariantRead(_) => {} - - ArithOverflow { intrinsic } => { - diag.arg("intrinsic", intrinsic); - } - ShiftOverflow { intrinsic, shift_amount } => { - diag.arg("intrinsic", intrinsic); - diag.arg( - "shift_amount", - match shift_amount { - Either::Left(v) => v.to_string(), - Either::Right(v) => v.to_string(), - }, - ); - } - BoundsCheckFailed { len, index } => { - diag.arg("len", len); - diag.arg("index", index); - } - UnterminatedCString(ptr) - | InvalidFunctionPointer(ptr) - | InvalidVaListPointer(ptr) - | InvalidVTablePointer(ptr) => { - diag.arg("pointer", ptr); - } - InvalidVTableTrait { expected_dyn_type, vtable_dyn_type } => { - diag.arg("expected_dyn_type", expected_dyn_type.to_string()); - diag.arg("vtable_dyn_type", vtable_dyn_type.to_string()); - } - PointerUseAfterFree(alloc_id, msg) => { - diag.arg("alloc_id", alloc_id).arg("operation", format!("{:?}", msg)); - } - PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => { - diag.arg("alloc_size", alloc_size.bytes()); - diag.arg("pointer", { - let mut out = format!("{:?}", alloc_id); - if ptr_offset > 0 { - write!(out, "+{:#x}", ptr_offset).unwrap(); - } else if ptr_offset < 0 { - write!(out, "-{:#x}", ptr_offset.unsigned_abs()).unwrap(); - } - out - }); - diag.arg("inbounds_size", inbounds_size); - diag.arg("inbounds_size_is_neg", inbounds_size < 0); - diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs()); - diag.arg("ptr_offset", ptr_offset); - diag.arg("ptr_offset_is_neg", ptr_offset < 0); - diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs()); - diag.arg( - "alloc_size_minus_ptr_offset", - alloc_size.bytes().saturating_sub(ptr_offset as u64), - ); - diag.arg("operation", format!("{:?}", msg)); - } - DanglingIntPointer { addr, inbounds_size, msg } => { - if addr != 0 { - diag.arg( - "pointer", - Pointer::>::without_provenance(addr).to_string(), - ); - } - - diag.arg("inbounds_size", inbounds_size); - diag.arg("inbounds_size_is_neg", inbounds_size < 0); - diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs()); - diag.arg("operation", format!("{:?}", msg)); - } - AlignmentCheckFailed(Misalignment { required, has }, msg) => { - diag.arg("required", required.bytes()); - diag.arg("has", has.bytes()); - diag.arg("msg", format!("{msg:?}")); - } - WriteToReadOnly(alloc) - | DerefFunctionPointer(alloc) - | DerefVTablePointer(alloc) - | DerefVaListPointer(alloc) - | DerefTypeIdPointer(alloc) => { - diag.arg("allocation", alloc); - } - InvalidBool(b) => { - diag.arg("value", format!("{b:02x}")); - } - InvalidChar(c) => { - diag.arg("value", format!("{c:08x}")); - } - InvalidTag(tag) => { - diag.arg("tag", format!("{tag:x}")); - } - InvalidStr(err) => { - diag.arg("err", format!("{err}")); - } - InvalidUninitBytes(Some((alloc, info))) => { - diag.arg("alloc", alloc); - diag.arg("access", info.access); - diag.arg("uninit", info.bad); - } - ScalarSizeMismatch(info) => { - diag.arg("target_size", info.target_size); - diag.arg("data_size", info.data_size); - } - InvalidNichedEnumVariantWritten { enum_ty } => { - diag.arg("ty", enum_ty); - } - AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => { - diag.arg("arg_idx", arg_idx + 1); // adjust for 1-indexed lists in output - diag.arg("caller_ty", caller_ty); - diag.arg("callee_ty", callee_ty); - } - AbiMismatchReturn { caller_ty, callee_ty } => { - diag.arg("caller_ty", caller_ty); - diag.arg("callee_ty", callee_ty); - } - CVariadicMismatch { caller_is_c_variadic, callee_is_c_variadic } => { - diag.arg("caller_is_c_variadic", caller_is_c_variadic); - diag.arg("callee_is_c_variadic", callee_is_c_variadic); - } - CVariadicFixedCountMismatch { caller, callee } => { - diag.arg("caller", caller); - diag.arg("callee", callee); - } - } - } -} - -impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { - fn diagnostic_message(&self) -> DiagMessage { - use rustc_middle::mir::interpret::ValidationErrorKind::*; - - match self.kind { - PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => { - msg!("{$front_matter}: encountered a box pointing to uninhabited type {$ty}") - } - PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => { - msg!("{$front_matter}: encountered a reference pointing to uninhabited type {$ty}") - } - - PointerAsInt { .. } => { - msg!("{$front_matter}: encountered a pointer, but {$expected}") - } - PartialPointer => { - msg!("{$front_matter}: encountered a partial pointer or a mix of pointers") - } - MutableRefToImmutable => { - msg!( - "{$front_matter}: encountered mutable reference or box pointing to read-only memory" - ) - } - NullFnPtr { .. } => { - msg!( - "{$front_matter}: encountered a {$maybe -> - [true] maybe-null - *[false] null - } function pointer" - ) - } - NeverVal => { - msg!("{$front_matter}: encountered a value of the never type `!`") - } - NonnullPtrMaybeNull { .. } => { - msg!( - "{$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero" - ) - } - PtrOutOfRange { .. } => { - msg!( - "{$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range}" - ) - } - OutOfRange { .. } => { - msg!("{$front_matter}: encountered {$value}, but expected something {$in_range}") - } - UnsafeCellInImmutable => { - msg!("{$front_matter}: encountered `UnsafeCell` in read-only memory") - } - UninhabitedVal { .. } => { - msg!("{$front_matter}: encountered a value of uninhabited type `{$ty}`") - } - InvalidEnumTag { .. } => { - msg!("{$front_matter}: encountered {$value}, but expected a valid enum tag") - } - UninhabitedEnumVariant => { - msg!("{$front_matter}: encountered an uninhabited enum variant") - } - Uninit { .. } => { - msg!("{$front_matter}: encountered uninitialized memory, but {$expected}") - } - InvalidVTablePtr { .. } => { - msg!("{$front_matter}: encountered {$value}, but expected a vtable pointer") - } - InvalidMetaWrongTrait { .. } => { - msg!( - "{$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`" - ) - } - InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => { - msg!( - "{$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object" - ) - } - InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => { - msg!( - "{$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object" - ) - } - - InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => { - msg!( - "{$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object" - ) - } - InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => { - msg!( - "{$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object" - ) - } - UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => { - msg!( - "{$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})" - ) - } - UnalignedPtr { ptr_kind: PointerKind::Box, .. } => { - msg!( - "{$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})" - ) - } - - NullPtr { ptr_kind: PointerKind::Box, .. } => { - msg!( - "{$front_matter}: encountered a {$maybe -> - [true] maybe-null - *[false] null - } box" - ) - } - NullPtr { ptr_kind: PointerKind::Ref(_), .. } => { - msg!( - "{$front_matter}: encountered a {$maybe -> - [true] maybe-null - *[false] null - } reference" - ) - } - DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => { - msg!("{$front_matter}: encountered a dangling box ({$pointer} has no provenance)") - } - DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => { - msg!( - "{$front_matter}: encountered a dangling reference ({$pointer} has no provenance)" - ) - } - DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => { - msg!( - "{$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)" - ) - } - DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => { - msg!( - "{$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation)" - ) - } - DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => { - msg!("{$front_matter}: encountered a dangling box (use-after-free)") - } - DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => { - msg!("{$front_matter}: encountered a dangling reference (use-after-free)") - } - InvalidBool { .. } => { - msg!("{$front_matter}: encountered {$value}, but expected a boolean") - } - InvalidChar { .. } => { - msg!( - "{$front_matter}: encountered {$value}, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" - ) - } - InvalidFnPtr { .. } => { - msg!("{$front_matter}: encountered {$value}, but expected a function pointer") - } - } - } - - fn add_args(self, err: &mut Diag<'_, G>) { - use rustc_errors::msg; - use rustc_middle::mir::interpret::ValidationErrorKind::*; - - if let PointerAsInt { .. } | PartialPointer = self.kind { - err.help(msg!("this code performed an operation that depends on the underlying bytes representing a pointer")); - err.help(msg!("the absolute address of a pointer is not known at compile-time, so such operations are not supported")); - } - - let message = if let Some(path) = self.path { - format_diag_message( - &msg!("constructing invalid value at {$path}"), - &DiagArgMap::from_iter([("path".into(), DiagArgValue::Str(path.into()))]), - ) - } else { - Cow::Borrowed("constructing invalid value") - }; - - err.arg("front_matter", message); - - fn add_range_arg( - r: WrappingRange, - max_hi: u128, - err: &mut Diag<'_, G>, - ) { - let WrappingRange { start: lo, end: hi } = r; - assert!(hi <= max_hi); - let msg = if lo > hi { - msg!("less or equal to {$hi}, or greater or equal to {$lo}") - } else if lo == hi { - msg!("equal to {$lo}") - } else if lo == 0 { - assert!(hi < max_hi, "should not be printing if the range covers everything"); - msg!("less or equal to {$hi}") - } else if hi == max_hi { - assert!(lo > 0, "should not be printing if the range covers everything"); - msg!("greater or equal to {$lo}") - } else { - msg!("in the range {$lo}..={$hi}") - }; - - let message = format_diag_message( - &msg, - &DiagArgMap::from_iter([ - ("lo".into(), DiagArgValue::Str(lo.to_string().into())), - ("hi".into(), DiagArgValue::Str(hi.to_string().into())), - ]), - ); - err.arg("in_range", message); - } - - match self.kind { - PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => { - err.arg("ty", ty); - } - PointerAsInt { expected } | Uninit { expected } => { - let msg = match expected { - ExpectedKind::Reference => "expected a reference", - ExpectedKind::Box => "expected a box", - ExpectedKind::RawPtr => "expected a raw pointer", - ExpectedKind::InitScalar => "expected initialized scalar value", - ExpectedKind::Bool => "expected a boolean", - ExpectedKind::Char => "expected a unicode scalar value", - ExpectedKind::Float => "expected a floating point number", - ExpectedKind::Int => "expected an integer", - ExpectedKind::FnPtr => "expected a function pointer", - ExpectedKind::EnumTag => "expected a valid enum tag", - ExpectedKind::Str => "expected a string", - }; - err.arg("expected", msg); - } - InvalidEnumTag { value } - | InvalidVTablePtr { value } - | InvalidBool { value } - | InvalidChar { value } - | InvalidFnPtr { value } => { - err.arg("value", value); - } - PtrOutOfRange { range, max_value } => add_range_arg(range, max_value, err), - OutOfRange { range, max_value, value } => { - err.arg("value", value); - add_range_arg(range, max_value, err); - } - UnalignedPtr { required_bytes, found_bytes, .. } => { - err.arg("required_bytes", required_bytes); - err.arg("found_bytes", found_bytes); - } - DanglingPtrNoProvenance { pointer, .. } => { - err.arg("pointer", pointer); - } - InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => { - err.arg("vtable_dyn_type", vtable_dyn_type.to_string()); - err.arg("expected_dyn_type", expected_dyn_type.to_string()); - } - NullPtr { maybe, .. } | NullFnPtr { maybe } => { - err.arg("maybe", maybe); - } - MutableRefToImmutable - | NonnullPtrMaybeNull - | NeverVal - | UnsafeCellInImmutable - | InvalidMetaSliceTooLarge { .. } - | InvalidMetaTooLarge { .. } - | DanglingPtrUseAfterFree { .. } - | DanglingPtrOutOfBounds { .. } - | UninhabitedEnumVariant - | PartialPointer => {} - } - } -} - -impl ReportErrorExt for UnsupportedOpInfo { - fn diagnostic_message(&self) -> DiagMessage { - match self { - UnsupportedOpInfo::Unsupported(s) => s.clone().into(), - UnsupportedOpInfo::ExternTypeField => { - "`extern type` field does not have a known offset".into() - } - UnsupportedOpInfo::UnsizedLocal => "unsized locals are not supported".into(), - UnsupportedOpInfo::ReadPartialPointer(_) => { - msg!("unable to read parts of a pointer from memory at {$ptr}") - } - UnsupportedOpInfo::ReadPointerAsInt(_) => "unable to turn pointer into integer".into(), - UnsupportedOpInfo::ThreadLocalStatic(_) => { - msg!("cannot access thread local static `{$did}`") - } - UnsupportedOpInfo::ExternStatic(_) => { - msg!("cannot access extern static `{$did}`") - } - } - .into() - } - - fn add_args(self, diag: &mut Diag<'_, G>) { - use UnsupportedOpInfo::*; - - if let ReadPointerAsInt(_) | ReadPartialPointer(_) = self { - diag.help("this code performed an operation that depends on the underlying bytes representing a pointer"); - diag.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported"); - } - match self { - // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to - // be further processed by validity checking which then turns it into something nice to - // print. So it's not worth the effort of having diagnostics that can print the `info`. - UnsizedLocal - | UnsupportedOpInfo::ExternTypeField - | Unsupported(_) - | ReadPointerAsInt(_) => {} - ReadPartialPointer(ptr) => { - diag.arg("ptr", ptr); - } - ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| { - diag.arg("did", tcx.def_path_str(did)); - }), - } - } -} - -impl<'tcx> ReportErrorExt for InterpErrorKind<'tcx> { - fn diagnostic_message(&self) -> DiagMessage { - match self { - InterpErrorKind::UndefinedBehavior(ub) => ub.diagnostic_message(), - InterpErrorKind::Unsupported(e) => e.diagnostic_message(), - InterpErrorKind::InvalidProgram(e) => e.diagnostic_message(), - InterpErrorKind::ResourceExhaustion(e) => e.diagnostic_message(), - InterpErrorKind::MachineStop(e) => e.diagnostic_message(), - } - } - fn add_args(self, diag: &mut Diag<'_, G>) { - match self { - InterpErrorKind::UndefinedBehavior(ub) => ub.add_args(diag), - InterpErrorKind::Unsupported(e) => e.add_args(diag), - InterpErrorKind::InvalidProgram(e) => e.add_args(diag), - InterpErrorKind::ResourceExhaustion(e) => e.add_args(diag), - InterpErrorKind::MachineStop(e) => e.add_args(&mut |name, value| { - diag.arg(name, value); - }), - } - } -} - -impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { - fn diagnostic_message(&self) -> DiagMessage { - match self { - InvalidProgramInfo::TooGeneric => "encountered overly generic constant".into(), - InvalidProgramInfo::AlreadyReported(_) => { - "an error has already been reported elsewhere (this should not usually be printed)" - .into() - } - InvalidProgramInfo::Layout(e) => e.diagnostic_message(), - } - } - fn add_args(self, diag: &mut Diag<'_, G>) { - match self { - InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {} - InvalidProgramInfo::Layout(e) => { - // The level doesn't matter, `dummy_diag` is consumed without it being used. - let dummy_level = Level::Bug; - let dummy_diag: Diag<'_, ()> = e.into_diagnostic().into_diag(diag.dcx, dummy_level); - for (name, val) in dummy_diag.args.iter() { - diag.arg(name.clone(), val.clone()); - } - dummy_diag.cancel(); - } - } - } -} - -impl ReportErrorExt for ResourceExhaustionInfo { - fn diagnostic_message(&self) -> DiagMessage { - match self { - ResourceExhaustionInfo::StackFrameLimitReached => { - "reached the configured maximum number of stack frames" - } - ResourceExhaustionInfo::MemoryExhausted => { - "tried to allocate more memory than available to compiler" - } - ResourceExhaustionInfo::AddressSpaceFull => { - "there are no more free addresses in the address space" - } - ResourceExhaustionInfo::Interrupted => "compilation was interrupted", - } - .into() - } - fn add_args(self, _: &mut Diag<'_, G>) {} -} - impl rustc_errors::IntoDiagArg for InternKind { fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(match self { diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 0de1fcd7c3a9..0ac9f3025d48 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -6,20 +6,19 @@ use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; -use rustc_errors::msg; use rustc_hir::def_id::DefId; use rustc_hir::find_attr; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; -use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, FnAbi}; use tracing::field::Empty; use tracing::{info, instrument, trace}; use super::{ CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, interp_ok, throw_ub, - throw_ub_custom, + throw_ub_format, }; use crate::enter_trace_span; use crate::interpret::EnteredTraceSpan; @@ -61,7 +60,7 @@ pub fn copy_fn_args(args: &[FnArg<'tcx, M::Provenance>]) -> Vec, field: FieldIdx, @@ -284,7 +283,7 @@ fn pass_argument<'x, 'y>( 'tcx: 'y, { assert_eq!(callee_ty, callee_abi.layout.ty); - if callee_abi.mode == PassMode::Ignore { + if callee_abi.is_ignore() { // This one is skipped. Still must be made live though! if !already_live { self.storage_live(callee_arg.as_local().unwrap())?; @@ -293,7 +292,7 @@ fn pass_argument<'x, 'y>( } // Find next caller arg. let Some((caller_arg, caller_abi)) = caller_args.next() else { - throw_ub_custom!(msg!("calling a function with fewer arguments than it requires")); + throw_ub_format!("calling a function with fewer arguments than it requires"); }; assert_eq!(caller_arg.layout().layout, caller_abi.layout.layout); // Sadly we cannot assert that `caller_arg.layout().ty` and `caller_abi.layout.ty` are @@ -364,12 +363,10 @@ pub fn init_stack_frame( let callee_fn_abi = self.fn_abi_of_instance_no_deduced_attrs(instance, extra_tys)?; if caller_fn_abi.conv != callee_fn_abi.conv { - throw_ub_custom!( - rustc_errors::msg!( - "calling a function with calling convention \"{$callee_conv}\" using calling convention \"{$caller_conv}\"" - ), - callee_conv = format!("{}", callee_fn_abi.conv), - caller_conv = format!("{}", caller_fn_abi.conv), + throw_ub_format!( + "calling a function with calling convention \"{callee_conv}\" using calling convention \"{caller_conv}\"", + callee_conv = callee_fn_abi.conv, + caller_conv = caller_fn_abi.conv, ) } @@ -407,161 +404,158 @@ pub fn init_stack_frame( // Push the "raw" frame -- this leaves locals uninitialized. self.push_stack_frame_raw(instance, body, destination, cont)?; + let preamble_span = self.frame().loc.unwrap_right(); // the span used for preamble errors - // If an error is raised here, pop the frame again to get an accurate backtrace. - // To this end, we wrap it all in a `try` block. - let res: InterpResult<'tcx> = try { - trace!( - "caller ABI: {:#?}, args: {:#?}", - caller_fn_abi, - args.iter() - .map(|arg| ( - arg.layout().ty, - match arg { - FnArg::Copy(op) => format!("copy({op:?})"), - FnArg::InPlace(mplace) => format!("in-place({mplace:?})"), - } - )) - .collect::>() - ); - trace!( - "spread_arg: {:?}, locals: {:#?}", - body.spread_arg, - body.args_iter() - .map(|local| ( - local, - self.layout_of_local(self.frame(), local, None).unwrap().ty, - )) - .collect::>() - ); - - // In principle, we have two iterators: Where the arguments come from, and where - // they go to. - - // The "where they come from" part is easy, we expect the caller to do any special handling - // that might be required here (e.g. for untupling). - // If `with_caller_location` is set we pretend there is an extra argument (that - // we will not pass; our `caller_location` intrinsic implementation walks the stack instead). - assert_eq!( - args.len() + if with_caller_location { 1 } else { 0 }, - caller_fn_abi.args.len(), - "mismatch between caller ABI and caller arguments", - ); - let mut caller_args = args - .iter() - .zip(caller_fn_abi.args.iter()) - .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore)); - - // Now we have to spread them out across the callee's locals, - // taking into account the `spread_arg`. If we could write - // this is a single iterator (that handles `spread_arg`), then - // `pass_argument` would be the loop body. It takes care to - // not advance `caller_iter` for ignored arguments. - let mut callee_args_abis = callee_fn_abi.args.iter().enumerate(); - // Determine whether there is a special VaList argument. This is always the - // last argument, and since arguments start at index 1 that's `arg_count`. - let va_list_arg = - callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count)); - for local in body.args_iter() { - // Construct the destination place for this argument. At this point all - // locals are still dead, so we cannot construct a `PlaceTy`. - let dest = mir::Place::from(local); - // `layout_of_local` does more than just the instantiation we need to get the - // type, but the result gets cached so this avoids calling the instantiation - // query *again* the next time this local is accessed. - let ty = self.layout_of_local(self.frame(), local, None)?.ty; - if Some(local) == va_list_arg { - // This is the last callee-side argument of a variadic function. - // This argument is a VaList holding the remaining caller-side arguments. - self.storage_live(local)?; - - let place = self.eval_place(dest)?; - let mplace = self.force_allocation(&place)?; - - // Consume the remaining arguments by putting them into the variable argument - // list. - let varargs = self.allocate_varargs(&mut caller_args, &mut callee_args_abis)?; - // When the frame is dropped, these variable arguments are deallocated. - self.frame_mut().va_list = varargs.clone(); - let key = self.va_list_ptr(varargs.into()); - - // Zero the VaList, so it is fully initialized. - self.write_bytes_ptr( - mplace.ptr(), - (0..mplace.layout.size.bytes()).map(|_| 0u8), - )?; - - // Store the "key" pointer in the right field. - let key_mplace = self.va_list_key_field(&mplace)?; - self.write_pointer(key, &key_mplace)?; - } else if Some(local) == body.spread_arg { - // Make the local live once, then fill in the value field by field. - self.storage_live(local)?; - // Must be a tuple - let ty::Tuple(fields) = ty.kind() else { - span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}") - }; - for (i, field_ty) in fields.iter().enumerate() { - let dest = dest.project_deeper( - &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], - *self.tcx, - ); - let (idx, callee_abi) = callee_args_abis.next().unwrap(); - self.pass_argument( - &mut caller_args, - callee_abi, - idx, - &dest, - field_ty, - /* already_live */ true, - )?; + trace!( + "caller ABI: {:#?}, args: {:#?}", + caller_fn_abi, + args.iter() + .map(|arg| ( + arg.layout().ty, + match arg { + FnArg::Copy(op) => format!("copy({op:?})"), + FnArg::InPlace(mplace) => format!("in-place({mplace:?})"), } - } else { - // Normal argument. Cannot mark it as live yet, it might be unsized! + )) + .collect::>() + ); + trace!( + "spread_arg: {:?}, locals: {:#?}", + body.spread_arg, + body.args_iter() + .map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty,)) + .collect::>() + ); + + // In principle, we have two iterators: Where the arguments come from, and where + // they go to. + + // The "where they come from" part is easy, we expect the caller to do any special handling + // that might be required here (e.g. for untupling). + // If `with_caller_location` is set we pretend there is an extra argument (that + // we will not pass; our `caller_location` intrinsic implementation walks the stack instead). + assert_eq!( + args.len() + if with_caller_location { 1 } else { 0 }, + caller_fn_abi.args.len(), + "mismatch between caller ABI and caller arguments", + ); + let mut caller_args = args + .iter() + .zip(caller_fn_abi.args.iter()) + .filter(|arg_and_abi| !arg_and_abi.1.is_ignore()); + + // Now we have to spread them out across the callee's locals, + // taking into account the `spread_arg`. If we could write + // this is a single iterator (that handles `spread_arg`), then + // `pass_argument` would be the loop body. It takes care to + // not advance `caller_iter` for ignored arguments. + let mut callee_args_abis = callee_fn_abi.args.iter().enumerate(); + // Determine whether there is a special VaList argument. This is always the + // last argument, and since arguments start at index 1 that's `arg_count`. + let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count)); + for local in body.args_iter() { + // Update the span that we show in case of an error to point to this argument. + self.frame_mut().loc = Right(body.local_decls[local].source_info.span); + // Construct the destination place for this argument. At this point all + // locals are still dead, so we cannot construct a `PlaceTy`. + let dest = mir::Place::from(local); + // `layout_of_local` does more than just the instantiation we need to get the + // type, but the result gets cached so this avoids calling the instantiation + // query *again* the next time this local is accessed. + let ty = self.layout_of_local(self.frame(), local, None)?.ty; + if Some(local) == va_list_arg { + // This is the last callee-side argument of a variadic function. + // This argument is a VaList holding the remaining caller-side arguments. + self.storage_live(local)?; + + let place = self.eval_place(dest)?; + let mplace = self.force_allocation(&place)?; + + // Consume the remaining arguments by putting them into the variable argument + // list. + let varargs = self.allocate_varargs( + &mut caller_args, + // "Ignored" arguments aren't actually passed, so the callee should also + // ignore them. (`pass_argument` does this for regular arguments.) + (&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()), + )?; + // When the frame is dropped, these variable arguments are deallocated. + self.frame_mut().va_list = varargs.clone(); + let key = self.va_list_ptr(varargs.into()); + + // Zero the VaList, so it is fully initialized. + self.write_bytes_ptr(mplace.ptr(), (0..mplace.layout.size.bytes()).map(|_| 0u8))?; + + // Store the "key" pointer in the right field. + let key_mplace = self.va_list_key_field(&mplace)?; + self.write_pointer(key, &key_mplace)?; + } else if Some(local) == body.spread_arg { + // Make the local live once, then fill in the value field by field. + self.storage_live(local)?; + // Must be a tuple + let ty::Tuple(fields) = ty.kind() else { + span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}") + }; + for (i, field_ty) in fields.iter().enumerate() { + let dest = dest.project_deeper( + &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], + *self.tcx, + ); let (idx, callee_abi) = callee_args_abis.next().unwrap(); self.pass_argument( &mut caller_args, callee_abi, idx, &dest, - ty, - /* already_live */ false, + field_ty, + /* already_live */ true, )?; } + } else { + // Normal argument. Cannot mark it as live yet, it might be unsized! + let (idx, callee_abi) = callee_args_abis.next().unwrap(); + self.pass_argument( + &mut caller_args, + callee_abi, + idx, + &dest, + ty, + /* already_live */ false, + )?; } - // If the callee needs a caller location, pretend we consume one more argument from the ABI. - if instance.def.requires_caller_location(*self.tcx) { - callee_args_abis.next().unwrap(); - } - // Now we should have no more caller args or callee arg ABIs. - assert!( - callee_args_abis.next().is_none(), - "mismatch between callee ABI and callee body arguments" - ); - if caller_args.next().is_some() { - throw_ub_custom!(msg!("calling a function with more arguments than it expected")); - } - // Don't forget to check the return type! - if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? { - throw_ub!(AbiMismatchReturn { - caller_ty: caller_fn_abi.ret.layout.ty, - callee_ty: callee_fn_abi.ret.layout.ty - }); - } + } - // Protect return place for in-place return value passing. - // We only need to protect anything if this is actually an in-memory place. - if let Some(mplace) = destination_mplace { - M::protect_in_place_function_argument(self, &mplace)?; - } + // Don't forget to check the return type! + self.frame_mut().loc = Right(body.local_decls[mir::RETURN_PLACE].source_info.span); + if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? { + throw_ub!(AbiMismatchReturn { + caller_ty: caller_fn_abi.ret.layout.ty, + callee_ty: callee_fn_abi.ret.layout.ty + }); + } + // Protect return place for in-place return value passing. + // We only need to protect anything if this is actually an in-memory place. + if let Some(mplace) = destination_mplace { + M::protect_in_place_function_argument(self, &mplace)?; + } - // Don't forget to mark "initially live" locals as live. - self.storage_live_for_always_live_locals()?; - }; - res.inspect_err_kind(|_| { - // Don't show the incomplete stack frame in the error stacktrace. - self.stack_mut().pop(); - }) + // For the final checks, use same span as preamble since it is unclear what else to do. + self.frame_mut().loc = Right(preamble_span); + // If the callee needs a caller location, pretend we consume one more argument from the ABI. + if instance.def.requires_caller_location(*self.tcx) { + callee_args_abis.next().unwrap(); + } + // Now we should have no more caller args or callee arg ABIs. + assert!( + callee_args_abis.next().is_none(), + "mismatch between callee ABI and callee body arguments" + ); + if caller_args.next().is_some() { + throw_ub_format!("calling a function with more arguments than it expected"); + } + + // Done! + self.push_stack_frame_done() } /// Initiate a call to this function -- pushing the stack frame and initializing the arguments. @@ -661,12 +655,17 @@ pub(super) fn init_fn_call( if caller_abi == ExternAbi::RustCall && !args.is_empty() { // Untuple let (untuple_arg, args) = args.split_last().unwrap(); + let ty::Tuple(untuple_fields) = untuple_arg.layout().ty.kind() else { + span_bug!(self.cur_span(), "untuple argument must be a tuple") + }; trace!("init_fn_call: Will pass last argument by untupling"); Cow::from( args.iter() + // The regular arguments. .map(|a| interp_ok(a.clone())) - .chain((0..untuple_arg.layout().fields.count()).map(|i| { - self.fn_arg_field(untuple_arg, FieldIdx::from_usize(i)) + // The fields of the untupled argument. + .chain((0..untuple_fields.len()).map(|i| { + self.fn_arg_project_field(untuple_arg, FieldIdx::from_usize(i)) })) .collect::>>()?, ) @@ -739,9 +738,7 @@ pub(super) fn init_fn_call( let vtable_entries = self.vtable_entries(receiver_trait.principal(), dyn_ty); let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else { // FIXME(fee1-dead) these could be variants of the UB info enum instead of this - throw_ub_custom!(msg!( - "`dyn` call trying to call something that is not a method" - )); + throw_ub_format!("`dyn` call trying to call something that is not a method"); }; trace!("Virtual call dispatches to {fn_inst:#?}"); // We can also do the lookup based on `def_id` and `dyn_ty`, and check that that @@ -947,7 +944,7 @@ pub(super) fn return_from_current_stack_frame( } ); if unwinding && self.frame_idx() == 0 { - throw_ub_custom!(msg!("unwinding past the topmost frame of the stack")); + throw_ub_format!("unwinding past the topmost frame of the stack"); } // Get out the return value. Must happen *before* the frame is popped as we have to get the diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 6972a79226f3..faef78253428 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -3,7 +3,6 @@ use rustc_abi::{FieldIdx, Integer}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; -use rustc_errors::msg; use rustc_middle::mir::CastKind; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::adjustment::PointerCoercion; @@ -15,7 +14,7 @@ use super::util::ensure_monomorphic_enough; use super::{ FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub, - throw_ub_custom, + throw_ub_format, }; use crate::enter_trace_span; use crate::interpret::Writeable; @@ -139,10 +138,8 @@ pub fn cast( assert!(dest.layout.is_sized()); assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely... if src.layout.size != dest.layout.size { - throw_ub_custom!( - msg!( - "transmuting from {$src_bytes}-byte type to {$dest_bytes}-byte type: `{$src}` -> `{$dest}`" - ), + throw_ub_format!( + "transmuting from {src_bytes}-byte type to {dest_bytes}-byte type: `{src}` -> `{dest}`", src_bytes = src.layout.size.bytes(), dest_bytes = dest.layout.size.bytes(), src = src.layout.ty, diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index b7e7f65c95c7..3a7c1ea65f3d 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -111,23 +111,30 @@ pub fn read_discriminant( .try_to_scalar_int() .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))? .to_bits(tag_layout.size); + // Ensure the tag is in its layout range. Codegen adds range metadata on the + // discriminant load so we really have to make this UB. + if !tag_scalar_layout.valid_range(self).contains(tag_bits) { + throw_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))) + } // Cast bits from tag layout to discriminant layout. // After the checks we did above, this cannot fail, as // discriminants are int-like. let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap(); let discr_bits = discr_val.to_scalar().to_bits(discr_layout.size)?; - // Convert discriminant to variant index, and catch invalid discriminants. + // Convert discriminant to variant index. Since we validated the tag against the + // layout range above, this cannot fail. let index = match *ty.kind() { ty::Adt(adt, _) => { - adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits) + adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits).unwrap() } ty::Coroutine(def_id, args) => { let args = args.as_coroutine(); - args.discriminants(def_id, *self.tcx).find(|(_, var)| var.val == discr_bits) + args.discriminants(def_id, *self.tcx) + .find(|(_, var)| var.val == discr_bits) + .unwrap() } _ => span_bug!(self.cur_span(), "tagged layout for non-adt non-coroutine"), - } - .ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?; + }; // Return the cast value, and the index. index.0 } @@ -174,13 +181,22 @@ pub fn read_discriminant( let variants = ty.ty_adt_def().expect("tagged layout for non adt").variants(); assert!(variant_index < variants.next_index()); + // This should imply that the tag is in its layout range. + assert!(tag_scalar_layout.valid_range(self).contains(tag_bits)); + if variant_index == untagged_variant { // The untagged variant can be in the niche range, but even then it - // is not a valid encoding. + // is not a valid encoding. Codegen inserts an `assume` here + // so we really have to make this UB. throw_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))) } variant_index } else { + // Ensure the tag is in its layout range. Codegen adds range metadata on + // the discriminant load so we really have to make this UB. + if !tag_scalar_layout.valid_range(self).contains(tag_bits) { + throw_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))) + } untagged_variant } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 956be147d748..0bfe012bfe7a 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -2,7 +2,6 @@ use either::{Left, Right}; use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout}; -use rustc_errors::{DiagCtxtHandle, format_diag_message, msg}; use rustc_hir::def_id::DefId; use rustc_hir::limit::Limit; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; @@ -22,9 +21,9 @@ use super::{ Frame, FrameInfo, GlobalId, InterpErrorInfo, InterpErrorKind, InterpResult, MPlaceTy, Machine, MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, - err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom, + err_inval, interp_ok, throw_inval, throw_ub, throw_ub_format, }; -use crate::{ReportErrorExt, enter_trace_span, util}; +use crate::{enter_trace_span, util}; pub struct InterpCx<'tcx, M: Machine<'tcx>> { /// Stores the `Machine` instance. @@ -228,17 +227,10 @@ pub(super) fn from_known_layout<'tcx>( /// /// This is NOT the preferred way to render an error; use `report` from `const_eval` instead. /// However, this is useful when error messages appear in ICEs. -pub fn format_interp_error<'tcx>(dcx: DiagCtxtHandle<'_>, e: InterpErrorInfo<'tcx>) -> String { +pub fn format_interp_error<'tcx>(e: InterpErrorInfo<'tcx>) -> String { let (e, backtrace) = e.into_parts(); backtrace.print_backtrace(); - // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the - // label and arguments from the InterpError. - let mut diag = dcx.struct_allow(""); - let msg = e.diagnostic_message(); - e.add_args(&mut diag); - let msg = format_diag_message(&msg, &diag.args).into_owned(); - diag.cancel(); - msg + e.to_string() } impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { @@ -556,9 +548,7 @@ pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tc mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }), mir::UnwindAction::Continue => Right(self.frame_mut().body.span), mir::UnwindAction::Unreachable => { - throw_ub_custom!(msg!( - "unwinding past a stack frame that does not allow unwinding" - )); + throw_ub_format!("unwinding past a stack frame that does not allow unwinding"); } mir::UnwindAction::Terminate(reason) => { self.frame_mut().loc = Right(self.frame_mut().body.span); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index c9106d691f7c..17311188879c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -8,7 +8,6 @@ use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; -use rustc_errors::msg; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; @@ -21,8 +20,8 @@ use super::util::ensure_monomorphic_enough; use super::{ AllocId, CheckInAllocMsg, ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Pointer, - PointerArithmetic, Projectable, Provenance, Scalar, err_ub_custom, err_unsup_format, interp_ok, - throw_inval, throw_ub, throw_ub_custom, throw_ub_format, throw_unsup_format, + PointerArithmetic, Projectable, Provenance, Scalar, err_ub_format, err_unsup_format, interp_ok, + throw_inval, throw_ub, throw_ub_format, throw_unsup_format, }; use crate::interpret::Writeable; @@ -41,20 +40,20 @@ pub(crate) enum MinMax { /// In particular, `-0.0` is considered smaller than `+0.0` and /// if either input is NaN, the result is NaN. Minimum, - /// The IEEE-2008 `minNum` operation with the SNaN handling of the - /// IEEE-2019 `minimumNumber` operation - see `f32::min` etc. + /// The IEEE-2019 `minimumNumber` operation but with non-deterministic signed zero handling + /// (like in IEEE-2008 `minNum`) - see `f32::min` etc. /// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic, /// and if one argument is NaN (quiet or signaling), the other one is returned. - MinimumNumber, + MinimumNumberNsz, /// The IEEE-2019 `maximum` operation - see `f32::maximum` etc. /// In particular, `-0.0` is considered smaller than `+0.0` and /// if either input is NaN, the result is NaN. Maximum, - /// The IEEE-2008 `maxNum` operation with the SNaN handling of the - /// IEEE-2019 `maximumNumber` operation - see `f32::max` etc. + /// The IEEE-2019 `maximumNumber` operation but with non-deterministic signed zero handling + /// (like in IEEE-2008 `maxNum`) - see `f32::max` etc. /// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic, /// and if one argument is NaN (quiet or signaling), the other one is returned. - MaximumNumber, + MaximumNumberNsz, } /// Directly returns an `Allocation` containing an absolute path representation of the given type. @@ -402,10 +401,8 @@ pub fn eval_intrinsic( } _ => { // Not into the same allocation -- this is UB. - throw_ub_custom!( - msg!( - "`{$name}` called on two different pointers that are not both derived from the same allocation" - ), + throw_ub_format!( + "`{name}` called on two different pointers that are not both derived from the same allocation", name = intrinsic_name, ); } @@ -425,16 +422,11 @@ pub fn eval_intrinsic( if overflowed.to_bool()? { // a < b if intrinsic_name == sym::ptr_offset_from_unsigned { - throw_ub_custom!( - msg!( - "`ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr -> - [true] address - *[false] offset - } than second: {$a_offset} < {$b_offset}" - ), + throw_ub_format!( + "`ptr_offset_from_unsigned` called when first pointer has smaller {is_addr} than second: {a_offset} < {b_offset}", a_offset = a_offset, b_offset = b_offset, - is_addr = is_addr, + is_addr = if is_addr { "address" } else { "offset" }, ); } // The signed form of the intrinsic allows this. If we interpret the @@ -442,11 +434,8 @@ pub fn eval_intrinsic( // seems *positive* or equal to isize::MIN, they were more than isize::MAX apart. let dist = val.to_target_isize(self)?; if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() { - throw_ub_custom!( - msg!( - "`{$name}` called when first pointer is too far before second" - ), - name = intrinsic_name, + throw_ub_format!( + "`{intrinsic_name}` called when first pointer is too far before second" ); } dist @@ -456,11 +445,8 @@ pub fn eval_intrinsic( // If converting to isize produced a *negative* result, we had an overflow // because they were more than isize::MAX apart. if dist < 0 { - throw_ub_custom!( - msg!( - "`{$name}` called when first pointer is too far ahead of second" - ), - name = intrinsic_name, + throw_ub_format!( + "`{intrinsic_name}` called when first pointer is too far ahead of second" ); } dist @@ -477,14 +463,12 @@ pub fn eval_intrinsic( && let Ok((b_alloc_id, ..)) = self.ptr_try_get_alloc_id(b, 0) && a_alloc_id == b_alloc_id { - err_ub_custom!( - msg!("`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation"), - name = intrinsic_name, + err_ub_format!( + "`{intrinsic_name}` called on two different pointers where the memory range between them is not in-bounds of an allocation" ) } else { - err_ub_custom!( - msg!("`{$name}` called on two different pointers that are not both derived from the same allocation"), - name = intrinsic_name, + err_ub_format!( + "`{intrinsic_name}` called on two different pointers that are not both derived from the same allocation" ) } })?; @@ -497,9 +481,8 @@ pub fn eval_intrinsic( ) .map_err_kind(|_| { // Make the error more specific. - err_ub_custom!( - msg!("`{$name}` called on two different pointers that are not both derived from the same allocation"), - name = intrinsic_name, + err_ub_format!( + "`{intrinsic_name}` called on two different pointers that are not both derived from the same allocation" ) })?; @@ -543,17 +526,17 @@ pub fn eval_intrinsic( self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; } - sym::minnumf16 => { - self.float_minmax_intrinsic::(args, MinMax::MinimumNumber, dest)? + sym::minimum_number_nsz_f16 => { + self.float_minmax_intrinsic::(args, MinMax::MinimumNumberNsz, dest)? } - sym::minnumf32 => { - self.float_minmax_intrinsic::(args, MinMax::MinimumNumber, dest)? + sym::minimum_number_nsz_f32 => { + self.float_minmax_intrinsic::(args, MinMax::MinimumNumberNsz, dest)? } - sym::minnumf64 => { - self.float_minmax_intrinsic::(args, MinMax::MinimumNumber, dest)? + sym::minimum_number_nsz_f64 => { + self.float_minmax_intrinsic::(args, MinMax::MinimumNumberNsz, dest)? } - sym::minnumf128 => { - self.float_minmax_intrinsic::(args, MinMax::MinimumNumber, dest)? + sym::minimum_number_nsz_f128 => { + self.float_minmax_intrinsic::(args, MinMax::MinimumNumberNsz, dest)? } sym::minimumf16 => self.float_minmax_intrinsic::(args, MinMax::Minimum, dest)?, @@ -565,17 +548,17 @@ pub fn eval_intrinsic( } sym::minimumf128 => self.float_minmax_intrinsic::(args, MinMax::Minimum, dest)?, - sym::maxnumf16 => { - self.float_minmax_intrinsic::(args, MinMax::MaximumNumber, dest)? + sym::maximum_number_nsz_f16 => { + self.float_minmax_intrinsic::(args, MinMax::MaximumNumberNsz, dest)? } - sym::maxnumf32 => { - self.float_minmax_intrinsic::(args, MinMax::MaximumNumber, dest)? + sym::maximum_number_nsz_f32 => { + self.float_minmax_intrinsic::(args, MinMax::MaximumNumberNsz, dest)? } - sym::maxnumf64 => { - self.float_minmax_intrinsic::(args, MinMax::MaximumNumber, dest)? + sym::maximum_number_nsz_f64 => { + self.float_minmax_intrinsic::(args, MinMax::MaximumNumberNsz, dest)? } - sym::maxnumf128 => { - self.float_minmax_intrinsic::(args, MinMax::MaximumNumber, dest)? + sym::maximum_number_nsz_f128 => { + self.float_minmax_intrinsic::(args, MinMax::MaximumNumberNsz, dest)? } sym::maximumf16 => self.float_minmax_intrinsic::(args, MinMax::Maximum, dest)?, @@ -592,10 +575,23 @@ pub fn eval_intrinsic( sym::copysignf64 => self.float_copysign_intrinsic::(args, dest)?, sym::copysignf128 => self.float_copysign_intrinsic::(args, dest)?, - sym::fabsf16 => self.float_abs_intrinsic::(args, dest)?, - sym::fabsf32 => self.float_abs_intrinsic::(args, dest)?, - sym::fabsf64 => self.float_abs_intrinsic::(args, dest)?, - sym::fabsf128 => self.float_abs_intrinsic::(args, dest)?, + sym::fabs => { + let arg = self.read_immediate(&args[0])?; + let ty::Float(float_ty) = arg.layout.ty.kind() else { + span_bug!( + self.cur_span(), + "non-float type for float intrinsic: {}", + arg.layout.ty, + ); + }; + let out_val = match float_ty { + FloatTy::F16 => self.unop_float_intrinsic::(intrinsic_name, arg)?, + FloatTy::F32 => self.unop_float_intrinsic::(intrinsic_name, arg)?, + FloatTy::F64 => self.unop_float_intrinsic::(intrinsic_name, arg)?, + FloatTy::F128 => self.unop_float_intrinsic::(intrinsic_name, arg)?, + }; + self.write_scalar(out_val, dest)?; + } sym::floorf16 => self.float_round_intrinsic::( args, @@ -779,7 +775,7 @@ pub(super) fn eval_nondiverging_intrinsic( let op = self.eval_operand(op, None)?; let cond = self.read_scalar(&op)?.to_bool()?; if !cond { - throw_ub_custom!(msg!("`assume` called with `false`")); + throw_ub_format!("`assume` called with `false`"); } interp_ok(()) } @@ -809,7 +805,7 @@ pub fn numeric_intrinsic( let bits_out = match name { sym::ctpop => u128::from(bits.count_ones()), sym::ctlz_nonzero | sym::cttz_nonzero if bits == 0 => { - throw_ub_custom!(msg!("`{$name}` called on 0"), name = name,); + throw_ub_format!("`{name}` called on 0"); } sym::ctlz | sym::ctlz_nonzero => u128::from(bits.leading_zeros()) - extra, sym::cttz | sym::cttz_nonzero => u128::from((bits << extra).trailing_zeros()) - extra, @@ -841,11 +837,7 @@ pub fn exact_div( let rem = self.binary_op(BinOp::Rem, a, b)?; // sign does not matter for 0 test, so `to_bits` is fine if rem.to_scalar().to_bits(a.layout.size)? != 0 { - throw_ub_custom!( - msg!("exact_div: {$a} cannot be divided by {$b} without remainder"), - a = format!("{a}"), - b = format!("{b}") - ) + throw_ub_format!("exact_div: {a} cannot be divided by {b} without remainder") } // `Rem` says this is all right, so we can let `Div` do its job. let res = self.binary_op(BinOp::Div, a, b)?; @@ -926,8 +918,8 @@ pub(crate) fn copy_intrinsic( let (size, align) = (layout.size, layout.align.abi); let size = self.compute_size_in_bytes(size, count).ok_or_else(|| { - err_ub_custom!( - msg!("overflow computing total size of `{$name}`"), + err_ub_format!( + "overflow computing total size of `{name}`", name = if nonoverlapping { "copy_nonoverlapping" } else { "copy" } ) })?; @@ -990,9 +982,9 @@ pub fn write_bytes_intrinsic( // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // but no actual allocation can be big enough for the difference to be noticeable. - let len = self.compute_size_in_bytes(layout.size, count).ok_or_else(|| { - err_ub_custom!(msg!("overflow computing total size of `{$name}`"), name = name) - })?; + let len = self + .compute_size_in_bytes(layout.size, count) + .ok_or_else(|| err_ub_format!("overflow computing total size of `{name}`"))?; let bytes = std::iter::repeat_n(byte, len.bytes_usize()); self.write_bytes_ptr(dst, bytes) @@ -1041,6 +1033,22 @@ pub(crate) fn raw_eq_intrinsic( interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) } + fn unop_float_intrinsic( + &self, + name: Symbol, + arg: ImmTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Scalar> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let x: F = arg.to_scalar().to_float()?; + match name { + // bitwise, no NaN adjustments + sym::fabs => interp_ok(x.abs().into()), + _ => bug!("not a unary float intrinsic: {}", name), + } + } + fn float_minmax( &self, a: Scalar, @@ -1052,16 +1060,16 @@ fn float_minmax( { let a: F = a.to_float()?; let b: F = b.to_float()?; - let res = if matches!(op, MinMax::MinimumNumber | MinMax::MaximumNumber) && a == b { + let res = if matches!(op, MinMax::MinimumNumberNsz | MinMax::MaximumNumberNsz) && a == b { // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`. // Let the machine decide which one to return. M::equal_float_min_max(self, a, b) } else { let result = match op { MinMax::Minimum => a.minimum(b), - MinMax::MinimumNumber => a.min(b), + MinMax::MinimumNumberNsz => a.min(b), MinMax::Maximum => a.maximum(b), - MinMax::MaximumNumber => a.max(b), + MinMax::MaximumNumberNsz => a.max(b), }; self.adjust_nan(result, &[a, b]) }; @@ -1099,20 +1107,6 @@ fn float_copysign_intrinsic( interp_ok(()) } - fn float_abs_intrinsic( - &mut self, - args: &[OpTy<'tcx, M::Provenance>], - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ()> - where - F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, - { - let x: F = self.read_scalar(&args[0])?.to_float()?; - // bitwise, no NaN adjustments - self.write_scalar(x.abs(), dest)?; - interp_ok(()) - } - fn float_round( &mut self, x: Scalar, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index dc6841bb89dd..d6cfc559e0df 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -174,8 +174,8 @@ enum Op { | sym::simd_le | sym::simd_gt | sym::simd_ge - | sym::simd_fmax - | sym::simd_fmin + | sym::simd_maximum_number_nsz + | sym::simd_minimum_number_nsz | sym::simd_saturating_add | sym::simd_saturating_sub | sym::simd_arith_offset => { @@ -211,8 +211,8 @@ enum Op { sym::simd_le => Op::MirOp(BinOp::Le), sym::simd_gt => Op::MirOp(BinOp::Gt), sym::simd_ge => Op::MirOp(BinOp::Ge), - sym::simd_fmax => Op::FMinMax(MinMax::MaximumNumber), - sym::simd_fmin => Op::FMinMax(MinMax::MinimumNumber), + sym::simd_maximum_number_nsz => Op::FMinMax(MinMax::MaximumNumberNsz), + sym::simd_minimum_number_nsz => Op::FMinMax(MinMax::MinimumNumberNsz), sym::simd_saturating_add => Op::SaturatingOp(BinOp::Add), sym::simd_saturating_sub => Op::SaturatingOp(BinOp::Sub), sym::simd_arith_offset => Op::WrappingOffset, @@ -304,8 +304,8 @@ enum Op { sym::simd_reduce_xor => Op::MirOp(BinOp::BitXor), sym::simd_reduce_any => Op::MirOpBool(BinOp::BitOr), sym::simd_reduce_all => Op::MirOpBool(BinOp::BitAnd), - sym::simd_reduce_max => Op::MinMax(MinMax::MaximumNumber), - sym::simd_reduce_min => Op::MinMax(MinMax::MinimumNumber), + sym::simd_reduce_max => Op::MinMax(MinMax::MaximumNumberNsz), + sym::simd_reduce_min => Op::MinMax(MinMax::MinimumNumberNsz), _ => unreachable!(), }; @@ -329,8 +329,8 @@ enum Op { } else { // Just boring integers, no NaNs to worry about. let mirop = match mmop { - MinMax::MinimumNumber | MinMax::Minimum => BinOp::Le, - MinMax::MaximumNumber | MinMax::Maximum => BinOp::Ge, + MinMax::MinimumNumberNsz | MinMax::Minimum => BinOp::Le, + MinMax::MaximumNumberNsz | MinMax::Maximum => BinOp::Ge, }; if self.binary_op(mirop, &res, &op)?.to_scalar().to_bool()? { res diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 8a864f372b9c..214d653d23c1 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -14,17 +14,16 @@ use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::msg; +use rustc_middle::bug; use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_middle::{bug, throw_ub_format}; use tracing::{debug, instrument, trace}; use super::{ AllocBytes, AllocId, AllocInit, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MayLeak, Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, - err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, + err_ub_format, interp_ok, throw_ub, throw_ub_format, throw_unsup, throw_unsup_format, }; use crate::const_eval::ConstEvalErrKind; @@ -310,16 +309,8 @@ pub fn reallocate_ptr( ) -> InterpResult<'tcx, Pointer> { let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?; if offset.bytes() != 0 { - throw_ub_custom!( - msg!( - "{$kind -> - [dealloc] deallocating - [realloc] reallocating - *[other] {\"\"} - } {$ptr} which does not point to the beginning of an object" - ), - ptr = format!("{ptr:?}"), - kind = "realloc" + throw_ub_format!( + "reallocating {ptr} which does not point to the beginning of an object" ); } @@ -393,19 +384,11 @@ pub fn deallocate_ptr( kind: MemoryKind, ) -> InterpResult<'tcx> { let (alloc_id, offset, prov) = self.ptr_get_alloc_id(ptr, 0)?; - trace!("deallocating: {alloc_id:?}"); + trace!("deallocating: {alloc_id}"); if offset.bytes() != 0 { - throw_ub_custom!( - msg!( - "{$kind -> - [dealloc] deallocating - [realloc] reallocating - *[other] {\"\"} - } {$ptr} which does not point to the beginning of an object" - ), - ptr = format!("{ptr:?}"), - kind = "dealloc", + throw_ub_format!( + "deallocating {ptr} which does not point to the beginning of an object" ); } @@ -413,60 +396,16 @@ pub fn deallocate_ptr( // Deallocating global memory -- always an error return Err(match self.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Function { .. }) => { - err_ub_custom!( - msg!( - "deallocating {$alloc_id}, which is {$kind -> - [fn] a function - [vtable] a vtable - [static_mem] static memory - *[other] {\"\"} - }" - ), - alloc_id = alloc_id, - kind = "fn", - ) + err_ub_format!("deallocating {alloc_id}, which is a function") } Some(GlobalAlloc::VTable(..)) => { - err_ub_custom!( - msg!( - "deallocating {$alloc_id}, which is {$kind -> - [fn] a function - [vtable] a vtable - [static_mem] static memory - *[other] {\"\"} - }" - ), - alloc_id = alloc_id, - kind = "vtable", - ) + err_ub_format!("deallocating {alloc_id}, which is a vtable") } Some(GlobalAlloc::TypeId { .. }) => { - err_ub_custom!( - msg!( - "deallocating {$alloc_id}, which is {$kind -> - [fn] a function - [vtable] a vtable - [static_mem] static memory - *[other] {\"\"} - }" - ), - alloc_id = alloc_id, - kind = "typeid", - ) + err_ub_format!("deallocating {alloc_id}, which is a type id") } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { - err_ub_custom!( - msg!( - "deallocating {$alloc_id}, which is {$kind -> - [fn] a function - [vtable] a vtable - [static_mem] static memory - *[other] {\"\"} - }" - ), - alloc_id = alloc_id, - kind = "static_mem" - ) + err_ub_format!("deallocating {alloc_id}, which is static memory") } None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccess)), }) @@ -474,25 +413,17 @@ pub fn deallocate_ptr( }; if alloc.mutability.is_not() { - throw_ub_custom!(msg!("deallocating immutable allocation {$alloc}"), alloc = alloc_id,); + throw_ub_format!("deallocating immutable allocation {alloc_id}"); } if alloc_kind != kind { - throw_ub_custom!( - msg!( - "deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation" - ), - alloc = alloc_id, - alloc_kind = format!("{alloc_kind}"), - kind = format!("{kind}"), + throw_ub_format!( + "deallocating {alloc_id}, which is {alloc_kind} memory, using {kind} deallocation operation", ); } if let Some((size, align)) = old_size_and_align { if size != alloc.size() || align != alloc.align { - throw_ub_custom!( - msg!( - "incorrect layout on deallocation: {$alloc} has size {$size} and alignment {$align}, but gave size {$size_found} and alignment {$align_found}" - ), - alloc = alloc_id, + throw_ub_format!( + "incorrect layout on deallocation: {alloc_id} has size {size} and alignment {align}, but gave size {size_found} and alignment {align_found}", size = alloc.size().bytes(), align = alloc.align.bytes(), size_found = size.bytes(), @@ -1653,9 +1584,7 @@ pub fn mem_copy_repeatedly( if (src_offset <= dest_offset && src_offset + size > dest_offset) || (dest_offset <= src_offset && dest_offset + size > src_offset) { - throw_ub_custom!(msg!( - "`copy_nonoverlapping` called on overlapping ranges" - )); + throw_ub_format!("`copy_nonoverlapping` called on overlapping ranges"); } } } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 8df284f0028a..b410e8f6c57e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -904,7 +904,7 @@ pub(super) fn copy_op_no_validate( } // Everything else can only exist in memory anyway, so it doesn't matter. BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::Memory { .. } => true, }; diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 6da6ed2ec757..a73767264dab 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -381,7 +381,7 @@ pub(crate) fn push_stack_frame_raw( let locals = IndexVec::from_elem(dead_local, &body.local_decls); let pre_frame = Frame { body, - loc: Right(body.span), // Span used for errors caused during preamble. + loc: Right(self.tcx.def_span(body.source.def_id())), // Span used for errors caused during preamble. return_cont, return_place: return_place.clone(), locals, @@ -408,7 +408,6 @@ pub(crate) fn push_stack_frame_raw( // Finish things up. M::after_stack_push(self)?; - self.frame_mut().loc = Left(mir::Location::START); // `tracing_separate_thread` is used to instruct the tracing_chrome [tracing::Layer] in Miri // to put the "frame" span on a separate trace thread/line than other spans, to make the // visualization in easier to interpret. It is set to a value of @@ -466,9 +465,11 @@ pub(super) fn cleanup_stack_frame( } } - /// In the current stack frame, mark all locals as live that are not arguments and don't have - /// `Storage*` annotations (this includes the return place). - pub(crate) fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx> { + /// Call this after `push_stack_frame_raw` and when all the other setup that needs to be done + /// is completed. + pub(crate) fn push_stack_frame_done(&mut self) -> InterpResult<'tcx> { + // Mark all locals as live that are not arguments and don't have `Storage*` annotations + // (this includes the return place, but not the arguments). self.storage_live(mir::RETURN_PLACE)?; let body = self.body(); @@ -478,6 +479,10 @@ pub(crate) fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tc self.storage_live(local)?; } } + + // Get ready to execute the first instruction in the stack frame. + self.frame_mut().loc = Left(mir::Location::START); + interp_ok(()) } @@ -631,8 +636,8 @@ impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> { /// of variadic arguments. Return a list of the places that hold those arguments. pub(crate) fn allocate_varargs( &mut self, - caller_args: &mut I, - callee_abis: &mut J, + caller_args: I, + mut callee_abis: J, ) -> InterpResult<'tcx, Vec>> where I: Iterator, &'a ArgAbi<'tcx, Ty<'tcx>>)>, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 083fd97aec4d..2dee1157e2a1 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -10,7 +10,7 @@ use rustc_index::IndexSlice; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use rustc_target::callconv::FnAbi; use tracing::field::Empty; use tracing::{info, instrument, trace}; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 2cf490350e90..de340057d0e8 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -5,8 +5,9 @@ //! to be const-safe. use std::borrow::Cow; -use std::fmt::Write; +use std::fmt::{self, Write}; use std::hash::Hash; +use std::mem; use std::num::NonZero; use either::{Left, Right}; @@ -19,10 +20,9 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::bug; -use rustc_middle::mir::interpret::ValidationErrorKind::{self, *}; use rustc_middle::mir::interpret::{ - ExpectedKind, InterpErrorKind, InvalidMetaKind, Misalignment, PointerKind, Provenance, - UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok, + InterpErrorKind, InvalidMetaKind, Misalignment, Provenance, UnsupportedOpInfo, alloc_range, + interp_ok, }; use rustc_middle::ty::layout::{LayoutCx, TyAndLayout}; use rustc_middle::ty::{self, Ty}; @@ -45,23 +45,31 @@ use super::UnsupportedOpInfo::*; macro_rules! err_validation_failure { - ($where:expr, $kind: expr) => {{ + ($where:expr, $msg:expr ) => {{ let where_ = &$where; - let path = if !where_.is_empty() { + let path = if !where_.projs.is_empty() { let mut path = String::new(); - write_path(&mut path, where_); + write_path(&mut path, &where_.projs); Some(path) } else { None }; - err_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) + #[allow(unused)] + use ValidationErrorKind::*; + let msg = ValidationErrorKind::from($msg); + err_ub!(ValidationError { + orig_ty: where_.orig_ty, + path, + ptr_bytes_warning: msg.ptr_bytes_warning(), + msg: msg.to_string(), + }) }}; } macro_rules! throw_validation_failure { - ($where:expr, $kind: expr) => { - do yeet err_validation_failure!($where, $kind) + ($where:expr, $msg:expr ) => { + do yeet err_validation_failure!($where, $msg) }; } @@ -72,32 +80,15 @@ macro_rules! throw_validation_failure { /// can possibly happen: /// /// ```ignore(illustrative) -/// let v = try_validation!(some_fn(), some_path, { -/// Foo | Bar | Baz => { "some failure" }, +/// let v = try_validation!(some_fn(x), some_path, { +/// Foo | Bar | Baz => format!("some failure involving {x}"), /// }); /// ``` /// /// The patterns must be of type `UndefinedBehaviorInfo`. -/// An additional expected parameter can also be added to the failure message: -/// -/// ```ignore(illustrative) -/// let v = try_validation!(some_fn(), some_path, { -/// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" }, -/// }); -/// ``` -/// -/// An additional nicety is that both parameters actually take format args, so you can just write -/// the format string in directly: -/// -/// ```ignore(illustrative) -/// let v = try_validation!(some_fn(), some_path, { -/// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value }, -/// }); -/// ``` -/// macro_rules! try_validation { ($e:expr, $where:expr, - $( $( $p:pat_param )|+ => $kind: expr ),+ $(,)? + $( $( $p:pat_param )|+ => $msg:expr ),+ $(,)? ) => {{ $e.map_err_kind(|e| { // We catch the error and turn it into a validation failure. We are okay with @@ -107,7 +98,7 @@ macro_rules! try_validation { $($p)|+ => { err_validation_failure!( $where, - $kind + $msg ) } ),+, @@ -117,12 +108,134 @@ macro_rules! try_validation { }}; } +#[derive(Debug, Clone, Copy)] +enum PointerKind { + Ref(Mutability), + Box, +} + +impl fmt::Display for PointerKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let str = match self { + PointerKind::Ref(_) => "reference", + PointerKind::Box => "box", + }; + write!(f, "{str}") + } +} + +#[derive(Debug)] +enum ExpectedKind { + Reference, + Box, + RawPtr, + Bool, + Char, + Float, + Int, + FnPtr, + Str, +} + +impl fmt::Display for ExpectedKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let str = match self { + ExpectedKind::Reference => "expected a reference", + ExpectedKind::Box => "expected a box", + ExpectedKind::RawPtr => "expected a raw pointer", + ExpectedKind::Bool => "expected a boolean", + ExpectedKind::Char => "expected a unicode scalar value", + ExpectedKind::Float => "expected a floating point number", + ExpectedKind::Int => "expected an integer", + ExpectedKind::FnPtr => "expected a function pointer", + ExpectedKind::Str => "expected a string", + }; + write!(f, "{str}") + } +} + +impl From for ExpectedKind { + fn from(x: PointerKind) -> ExpectedKind { + match x { + PointerKind::Box => ExpectedKind::Box, + PointerKind::Ref(_) => ExpectedKind::Reference, + } + } +} + +/// Validation errors that can be emitted in one than one place get a variant here so that +/// we format them consistently. Everything else uses the `String` fallback. +#[derive(Debug)] +enum ValidationErrorKind<'tcx> { + Uninit { + expected: ExpectedKind, + }, + PointerAsInt { + expected: ExpectedKind, + }, + PartialPointer, + InvalidMetaWrongTrait { + /// The vtable that was actually referenced by the wide pointer metadata. + vtable_dyn_type: &'tcx ty::List>, + /// The vtable that was expected at the point in MIR that it was accessed. + expected_dyn_type: &'tcx ty::List>, + }, + GeneralError { + msg: String, + }, +} + +impl<'tcx> ValidationErrorKind<'tcx> { + // We don't do this via `fmt::Display` to so that we can do a move in the `GeneralError` case. + fn to_string(self) -> String { + use ValidationErrorKind::*; + match self { + Uninit { expected } => format!("encountered uninitialized memory, but {expected}"), + PointerAsInt { expected } => format!("encountered a pointer, but {expected}"), + PartialPointer => format!("encountered a partial pointer or a mix of pointers"), + InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => format!( + "wrong trait in wide pointer vtable: expected `{expected_dyn_type}`, but encountered `{vtable_dyn_type}`" + ), + GeneralError { msg } => msg, + } + } + + fn ptr_bytes_warning(&self) -> bool { + use ValidationErrorKind::*; + matches!(self, PointerAsInt { .. } | PartialPointer) + } +} + +impl<'tcx> From for ValidationErrorKind<'tcx> { + fn from(msg: String) -> Self { + ValidationErrorKind::GeneralError { msg } + } +} + +fn fmt_range(r: WrappingRange, max_hi: u128) -> String { + let WrappingRange { start: lo, end: hi } = r; + assert!(hi <= max_hi); + if lo > hi { + format!("less or equal to {hi}, or greater or equal to {lo}") + } else if lo == hi { + format!("equal to {lo}") + } else if lo == 0 { + assert!(hi < max_hi, "should not be printing if the range covers everything"); + format!("less or equal to {hi}") + } else if hi == max_hi { + assert!(lo > 0, "should not be printing if the range covers everything"); + format!("greater or equal to {lo}") + } else { + format!("in the range {lo}..={hi}") + } +} + /// We want to show a nice path to the invalid field for diagnostics, /// but avoid string operations in the happy case where no error happens. /// So we track a `Vec` where `PathElem` contains all the data we /// need to later print something for the user. #[derive(Copy, Clone, Debug)] -pub enum PathElem { +pub enum PathElem<'tcx> { Field(Symbol), Variant(Symbol), CoroutineState(VariantIdx), @@ -132,10 +245,22 @@ pub enum PathElem { Deref, EnumTag, CoroutineTag, - DynDowncast, + DynDowncast(Ty<'tcx>), Vtable, } +#[derive(Clone, Debug)] +pub struct Path<'tcx> { + orig_ty: Ty<'tcx>, + projs: Vec>, +} + +impl<'tcx> Path<'tcx> { + fn new(ty: Ty<'tcx>) -> Self { + Self { orig_ty: ty, projs: vec![] } + } +} + /// Extra things to check for during validation of CTFE results. #[derive(Copy, Clone)] pub enum CtfeValidationMode { @@ -168,16 +293,10 @@ pub struct RefTracking { todo: Vec<(T, PATH)>, } -impl RefTracking { +impl RefTracking { pub fn empty() -> Self { RefTracking { seen: FxHashSet::default(), todo: vec![] } } - pub fn new(val: T) -> Self { - let mut ref_tracking_for_consts = - RefTracking { seen: FxHashSet::default(), todo: vec![(val.clone(), PATH::default())] }; - ref_tracking_for_consts.seen.insert(val); - ref_tracking_for_consts - } pub fn next(&mut self) -> Option<(T, PATH)> { self.todo.pop() } @@ -192,9 +311,17 @@ fn track(&mut self, val: T, path: impl FnOnce() -> PATH) { } } -// FIXME make this translatable as well? +impl<'tcx, T: Clone + Eq + Hash + std::fmt::Debug> RefTracking> { + pub fn new(val: T, ty: Ty<'tcx>) -> Self { + let mut ref_tracking_for_consts = + RefTracking { seen: FxHashSet::default(), todo: vec![(val.clone(), Path::new(ty))] }; + ref_tracking_for_consts.seen.insert(val); + ref_tracking_for_consts + } +} + /// Format a path -fn write_path(out: &mut String, path: &[PathElem]) { +fn write_path(out: &mut String, path: &[PathElem<'_>]) { use self::PathElem::*; for elem in path.iter() { @@ -212,7 +339,7 @@ fn write_path(out: &mut String, path: &[PathElem]) { // even use the usual syntax because we are just showing the projections, // not the root. Deref => write!(out, "."), - DynDowncast => write!(out, "."), + DynDowncast(ty) => write!(out, "."), Vtable => write!(out, "."), } .unwrap() @@ -271,10 +398,9 @@ fn add_range(&mut self, offset: Size, size: Size) { struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> { /// The `path` may be pushed to, but the part that is present when a function - /// starts must not be changed! `visit_fields` and `visit_array` rely on - /// this stack discipline. - path: Vec, - ref_tracking: Option<&'rt mut RefTracking, Vec>>, + /// starts must not be changed! `with_elem` relies on this stack discipline. + path: Path<'tcx>, + ref_tracking: Option<&'rt mut RefTracking, Path<'tcx>>>, /// `None` indicates this is not validating for CTFE (but for runtime). ctfe_mode: Option, ecx: &'rt mut InterpCx<'tcx, M>, @@ -288,10 +414,17 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> { /// If this is `Some`, then `reset_provenance_and_padding` must be true (but not vice versa: /// we might not track data vs padding bytes if the operand isn't stored in memory anyway). data_bytes: Option, + /// True if we are inside of `MaybeDangling`. This disables pointer access checks. + may_dangle: bool, } impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { - fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem { + fn aggregate_field_path_elem( + &mut self, + layout: TyAndLayout<'tcx>, + field: usize, + field_ty: Ty<'tcx>, + ) -> PathElem<'tcx> { // First, check if we are projecting to a variant. match layout.variants { Variants::Multiple { tag_field, .. } => { @@ -361,7 +494,7 @@ fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) // dyn traits ty::Dynamic(..) => { assert_eq!(field, 0); - PathElem::DynDowncast + PathElem::DynDowncast(field_ty) } // nothing else has an aggregate layout @@ -371,17 +504,17 @@ fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) fn with_elem( &mut self, - elem: PathElem, + elem: PathElem<'tcx>, f: impl FnOnce(&mut Self) -> InterpResult<'tcx, R>, ) -> InterpResult<'tcx, R> { // Remember the old state - let path_len = self.path.len(); + let path_len = self.path.projs.len(); // Record new element - self.path.push(elem); + self.path.projs.push(elem); // Perform operation let r = f(self)?; // Undo changes - self.path.truncate(path_len); + self.path.projs.truncate(path_len); // Done interp_ok(r) } @@ -456,10 +589,9 @@ fn check_wide_ptr_meta( self.ecx.get_ptr_vtable_ty(vtable, Some(data)), self.path, Ub(DanglingIntPointer{ .. } | InvalidVTablePointer(..)) => - InvalidVTablePtr { value: format!("{vtable}") }, - Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => { - InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } - }, + format!("encountered {vtable}, but expected a vtable pointer"), + Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => + InvalidMetaWrongTrait { expected_dyn_type, vtable_dyn_type }, ); } ty::Slice(..) | ty::Str => { @@ -489,67 +621,88 @@ fn check_safe_pointer( if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta(), place.layout)?; } - // Make sure this is dereferenceable and all. + + // Determine size and alignment of pointee. let size_and_align = try_validation!( self.ecx.size_and_align_of_val(&place), self.path, - Ub(InvalidMeta(msg)) => match msg { - InvalidMetaKind::SliceTooBig => InvalidMetaSliceTooLarge { ptr_kind }, - InvalidMetaKind::TooBig => InvalidMetaTooLarge { ptr_kind }, - } + Ub(InvalidMeta(msg)) => format!( + "encountered invalid {ptr_kind} metadata: {}", + match msg { + InvalidMetaKind::SliceTooBig => "slice is bigger than largest supported object", + InvalidMetaKind::TooBig => "total size is bigger than largest supported object", + } + ) ); let (size, align) = size_and_align // for the purpose of validity, consider foreign types to have // alignment and size determined by the layout (size will be 0, // alignment should take attributes into account). .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); - // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. - try_validation!( - self.ecx.check_ptr_access( - place.ptr(), - size, - CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message - ), - self.path, - Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false }, - Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance { - ptr_kind, - // FIXME this says "null pointer" when null but we need translate - pointer: format!("{}", Pointer::>::without_provenance(i)) - }, - Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { - ptr_kind - }, - Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree { - ptr_kind, - }, - ); + + // If we're not allow to dangle, make sure this is dereferenceable. + if !self.may_dangle { + try_validation!( + self.ecx.check_ptr_access( + place.ptr(), + size, + CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message + ), + self.path, + Ub(DanglingIntPointer { addr: 0, .. }) => + format!("encountered a null {ptr_kind}"), + Ub(DanglingIntPointer { addr: i, .. }) => + format!( + "encountered a dangling {ptr_kind} ({ptr} has no provenance)", + ptr = Pointer::>::without_provenance(i) + ), + Ub(PointerOutOfBounds { .. }) => + format!("encountered a dangling {ptr_kind} (going beyond the bounds of its allocation)"), + Ub(PointerUseAfterFree(..)) => + format!("encountered a dangling {ptr_kind} (use-after-free)"), + ); + } + // Check alignment after dereferenceable (if both are violated, trigger the error above). try_validation!( self.ecx.check_ptr_align( place.ptr(), align, ), self.path, - Ub(AlignmentCheckFailed(Misalignment { required, has }, _msg)) => UnalignedPtr { - ptr_kind, - required_bytes: required.bytes(), - found_bytes: has.bytes() - }, + Ub(AlignmentCheckFailed(Misalignment { required, has }, _msg)) => format!( + "encountered an unaligned {ptr_kind} (required {required_bytes} byte alignment but found {found_bytes})", + required_bytes = required.bytes(), + found_bytes = has.bytes() + ), ); - // Make sure this is non-null. We checked dereferenceability above, but if `size` is zero - // that does not imply non-null. + + // Make sure this is non-null. This is obviously needed when `may_dangle` is set, + // but even if we did check dereferenceability above that would still allow null + // pointers if `size` is zero. let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx); if self.ecx.scalar_may_be_null(scalar)? { let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..)); - throw_validation_failure!(self.path, NullPtr { ptr_kind, maybe }) + throw_validation_failure!( + self.path, + format!( + "encountered a {maybe}null {ptr_kind}", + maybe = if maybe { "maybe-" } else { "" } + ) + ) } // Do not allow references to uninhabited types. if place.layout.is_uninhabited() { let ty = place.layout.ty; - throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty }) + throw_validation_failure!( + self.path, + format!("encountered a {ptr_kind} pointing to uninhabited type {ty}") + ) } - // Recursive checking - if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() { + + // Recursive checking (but not inside `MaybeDangling` of course). + if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() + && !self.may_dangle + { // Proceed recursively even for ZST, no reason to skip them! // `!` is a ZST and we want to validate it. if let Some(ctfe_mode) = self.ctfe_mode { @@ -574,7 +727,10 @@ fn check_safe_pointer( // though for zero-sized references this isn't really UB. // A potential future alternative would be to resurrect this as a zero-sized allocation // (which codegen will then compile to an aligned dummy pointer anyway). - throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); + throw_validation_failure!( + self.path, + format!("encountered a dangling {ptr_kind} (use-after-free)") + ); }; let (size, _align) = global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env); @@ -637,7 +793,12 @@ fn check_safe_pointer( && alloc_actual_mutbl == Mutability::Not { // This can actually occur with transmutes. - throw_validation_failure!(self.path, MutableRefToImmutable); + throw_validation_failure!( + self.path, + format!( + "encountered mutable reference or box pointing to read-only memory" + ) + ); } } } @@ -655,10 +816,10 @@ fn check_safe_pointer( ref_tracking.track(place, || { // We need to clone the path anyway, make sure it gets created // with enough space for the additional `Deref`. - let mut new_path = Vec::with_capacity(path.len() + 1); - new_path.extend(path); - new_path.push(PathElem::Deref); - new_path + let mut new_projs = Vec::with_capacity(path.projs.len() + 1); + new_projs.extend(&path.projs); + new_projs.push(PathElem::Deref); + Path { projs: new_projs, orig_ty: path.orig_ty } }); } interp_ok(()) @@ -680,9 +841,8 @@ fn try_visit_primitive( try_validation!( scalar.to_bool(), self.path, - Ub(InvalidBool(..)) => ValidationErrorKind::InvalidBool { - value: format!("{scalar:x}"), - } + Ub(InvalidBool(..)) => + format!("encountered {scalar:x}, but expected a boolean"), ); if self.reset_provenance_and_padding { self.ecx.clear_provenance(value)?; @@ -695,9 +855,9 @@ fn try_visit_primitive( try_validation!( scalar.to_char(), self.path, - Ub(InvalidChar(..)) => ValidationErrorKind::InvalidChar { - value: format!("{scalar:x}"), - } + Ub(InvalidChar(..)) => + format!("encountered {scalar:x}, but expected a valid unicode scalar value \ + (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)") ); if self.reset_provenance_and_padding { self.ecx.clear_provenance(value)?; @@ -743,7 +903,7 @@ fn try_visit_primitive( self.ecx.get_ptr_fn(ptr), self.path, Ub(DanglingIntPointer{ .. } | InvalidFunctionPointer(..)) => - InvalidFnPtr { value: format!("{ptr}") }, + format!("encountered {ptr}, but expected a function pointer"), ); // FIXME: Check if the signature matches } else { @@ -752,7 +912,13 @@ fn try_visit_primitive( if self.ecx.scalar_may_be_null(scalar)? { let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..)); - throw_validation_failure!(self.path, NullFnPtr { maybe }); + throw_validation_failure!( + self.path, + format!( + "encountered a {maybe}null function pointer", + maybe = if maybe { "maybe-" } else { "" } + ) + ); } } if self.reset_provenance_and_padding { @@ -765,7 +931,12 @@ fn try_visit_primitive( } interp_ok(true) } - ty::Never => throw_validation_failure!(self.path, NeverVal), + ty::Never => { + throw_validation_failure!( + self.path, + format!("encountered a value of the never type `!`") + ) + } ty::Foreign(..) | ty::FnDef(..) => { // Nothing to check. interp_ok(true) @@ -814,7 +985,12 @@ fn visit_scalar( if start == 1 && end == max_value { // Only null is the niche. So make sure the ptr is NOT null. if self.ecx.scalar_may_be_null(scalar)? { - throw_validation_failure!(self.path, NonnullPtrMaybeNull) + throw_validation_failure!( + self.path, + format!( + "encountered a maybe-null pointer, but expected something that is definitely non-zero" + ) + ) } else { return interp_ok(()); } @@ -822,11 +998,13 @@ fn visit_scalar( // Easy. (This is reachable if `enforce_number_validity` is set.) return interp_ok(()); } else { - // Conservatively, we reject, because the pointer *could* have a bad - // value. + // Conservatively, we reject, because the pointer *could* have a bad value. throw_validation_failure!( self.path, - PtrOutOfRange { range: valid_range, max_value } + format!( + "encountered a pointer with unknown absolute address, but expected something that is definitely {in_range}", + in_range = fmt_range(valid_range, max_value) + ) ) } } @@ -837,7 +1015,10 @@ fn visit_scalar( } else { throw_validation_failure!( self.path, - OutOfRange { value: format!("{bits}"), range: valid_range, max_value } + format!( + "encountered {bits}, but expected something {in_range}", + in_range = fmt_range(valid_range, max_value) + ) ) } } @@ -1042,10 +1223,10 @@ fn read_discriminant( interp_ok(try_validation!( this.ecx.read_discriminant(val), this.path, - Ub(InvalidTag(val)) => InvalidEnumTag { - value: format!("{val:x}"), - }, - Ub(UninhabitedEnumVariantRead(_)) => UninhabitedEnumVariant, + Ub(InvalidTag(val)) => + format!("encountered {val:x}, but expected a valid enum tag"), + Ub(UninhabitedEnumVariantRead(_)) => + format!("encountered an uninhabited enum variant"), // Uninit / bad provenance are not possible since the field was already previously // checked at its integer type. )) @@ -1059,7 +1240,7 @@ fn visit_field( field: usize, new_val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - let elem = self.aggregate_field_path_elem(old_val.layout, field); + let elem = self.aggregate_field_path_elem(old_val.layout, field, new_val.layout.ty); self.with_elem(elem, move |this| this.visit_value(new_val)) } @@ -1092,7 +1273,10 @@ fn visit_union( let zst = self.ecx.size_and_align_of_val(val)?.is_some_and(|(s, _a)| s.bytes() == 0); if !zst && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env) { if !self.in_mutable_memory(val) { - throw_validation_failure!(self.path, UnsafeCellInImmutable); + throw_validation_failure!( + self.path, + format!("encountered `UnsafeCell` in read-only memory") + ); } } } @@ -1142,7 +1326,10 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t && def.is_unsafe_cell() { if !self.in_mutable_memory(val) { - throw_validation_failure!(self.path, UnsafeCellInImmutable); + throw_validation_failure!( + self.path, + format!("encountered `UnsafeCell` in read-only memory") + ); } } } @@ -1152,11 +1339,14 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t ty::Str => { let mplace = val.assert_mem_place(); // strings are unsized and hence never immediate let len = mplace.len(self.ecx)?; + let expected = ExpectedKind::Str; try_validation!( self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len)), self.path, - Ub(InvalidUninitBytes(..)) => Uninit { expected: ExpectedKind::Str }, - Unsup(ReadPointerAsInt(_)) => PointerAsInt { expected: ExpectedKind::Str } + Ub(InvalidUninitBytes(..)) => + Uninit { expected }, + Unsup(ReadPointerAsInt(_)) => + PointerAsInt { expected }, ); } ty::Array(tys, ..) | ty::Slice(tys) @@ -1187,7 +1377,10 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t Left(mplace) => mplace, Right(imm) => match *imm { Immediate::Uninit => - throw_validation_failure!(self.path, Uninit { expected }), + throw_validation_failure!( + self.path, + Uninit { expected } + ), Immediate::Scalar(..) | Immediate::ScalarPair(..) => bug!("arrays/slices can never have Scalar/ScalarPair layout"), } @@ -1212,12 +1405,12 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t access.bad.start.bytes() / layout.size.bytes(), ) .unwrap(); - self.path.push(PathElem::ArrayElem(i)); + self.path.projs.push(PathElem::ArrayElem(i)); if matches!(kind, Ub(InvalidUninitBytes(_))) { err_validation_failure!(self.path, Uninit { expected }) } else { - err_validation_failure!(self.path, PointerAsInt { expected }) + err_validation_failure!(self.path, PointerAsInt {expected}) } } @@ -1265,6 +1458,14 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t ty::PatternKind::Or(_patterns) => {} } } + ty::Adt(adt, _) if adt.is_maybe_dangling() => { + let old_may_dangle = mem::replace(&mut self.may_dangle, true); + + let inner = self.ecx.project_field(val, FieldIdx::ZERO)?; + self.visit_value(&inner)?; + + self.may_dangle = old_may_dangle; + } _ => { // default handler try_validation!( @@ -1272,9 +1473,8 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t self.path, // It's not great to catch errors here, since we can't give a very good path, // but it's better than ICEing. - Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => { - InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } - }, + Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => + InvalidMetaWrongTrait { expected_dyn_type, vtable_dyn_type }, ); } } @@ -1290,13 +1490,18 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t // MyNewtype and then the scalar in there). if val.layout.is_uninhabited() { let ty = val.layout.ty; - throw_validation_failure!(self.path, UninhabitedVal { ty }); + throw_validation_failure!( + self.path, + format!("encountered a value of uninhabited type `{ty}`") + ); } match val.layout.backend_repr { BackendRepr::Scalar(scalar_layout) => { if !scalar_layout.is_uninit_valid() { // There is something to check here. - let scalar = self.read_scalar(val, ExpectedKind::InitScalar)?; + // We read directly via `ecx` since the read cannot fail -- we already read + // this field above when recursing into the field. + let scalar = self.ecx.read_scalar(val)?; self.visit_scalar(scalar, scalar_layout)?; } } @@ -1305,13 +1510,14 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t // FIXME: find a way to also check ScalarPair when one side can be uninit but // the other must be init. if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() { - let (a, b) = - self.read_immediate(val, ExpectedKind::InitScalar)?.to_scalar_pair(); + // We read directly via `ecx` since the read cannot fail -- we already read + // this field above when recursing into the field. + let (a, b) = self.ecx.read_immediate(val)?.to_scalar_pair(); self.visit_scalar(a, a_layout)?; self.visit_scalar(b, b_layout)?; } } - BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => { // No checks here, we assume layout computation gets this right. // (This is harder to check since Miri does not represent these as `Immediate`. We // also cannot use field projections since this might be a newtype around a vector.) @@ -1326,13 +1532,15 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t } impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + /// The internal core entry point for all validation operations. fn validate_operand_internal( &mut self, val: &PlaceTy<'tcx, M::Provenance>, - path: Vec, - ref_tracking: Option<&mut RefTracking, Vec>>, + path: Path<'tcx>, + ref_tracking: Option<&mut RefTracking, Path<'tcx>>>, ctfe_mode: Option, reset_provenance_and_padding: bool, + start_in_may_dangle: bool, ) -> InterpResult<'tcx> { trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty); @@ -1350,6 +1558,7 @@ fn validate_operand_internal( ecx, reset_provenance_and_padding, data_bytes: reset_padding.then_some(RangeSet(Vec::new())), + may_dangle: start_in_may_dangle, }; v.visit_value(val)?; v.reset_padding(val)?; @@ -1362,10 +1571,7 @@ fn validate_operand_internal( | InterpErrorKind::InvalidProgram(_) | InterpErrorKind::Unsupported(UnsupportedOpInfo::ExternTypeField) ) { - bug!( - "Unexpected error during validation: {}", - format_interp_error(self.tcx.dcx(), err) - ); + bug!("Unexpected error during validation: {}", format_interp_error(err)); } err }) @@ -1385,8 +1591,8 @@ fn validate_operand_internal( pub(crate) fn const_validate_operand( &mut self, val: &PlaceTy<'tcx, M::Provenance>, - path: Vec, - ref_tracking: &mut RefTracking, Vec>, + path: Path<'tcx>, + ref_tracking: &mut RefTracking, Path<'tcx>>, ctfe_mode: CtfeValidationMode, ) -> InterpResult<'tcx> { self.validate_operand_internal( @@ -1395,6 +1601,7 @@ pub(crate) fn const_validate_operand( Some(ref_tracking), Some(ctfe_mode), /*reset_provenance*/ false, + /*start_in_may_dangle*/ false, ) } @@ -1415,36 +1622,40 @@ pub fn validate_operand( reset_provenance_and_padding, ?val, ); - // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's // still correct to not use `ctfe_mode`: that mode is for validation of the final constant // value, it rules out things like `UnsafeCell` in awkward places. if !recursive { return self.validate_operand_internal( val, - vec![], + Path::new(val.layout.ty), None, None, reset_provenance_and_padding, + /*start_in_may_dangle*/ false, ); } // Do a recursive check. let mut ref_tracking = RefTracking::empty(); self.validate_operand_internal( val, - vec![], + Path::new(val.layout.ty), Some(&mut ref_tracking), None, reset_provenance_and_padding, + /*start_in_may_dangle*/ false, )?; while let Some((mplace, path)) = ref_tracking.todo.pop() { - // Things behind reference do *not* have the provenance reset. + // Things behind reference do *not* have the provenance reset. In fact + // we treat the entire thing as being inside MaybeDangling, i.e., references + // do not have to be dereferenceable. self.validate_operand_internal( &mplace.into(), path, - Some(&mut ref_tracking), + None, // no further recursion None, /*reset_provenance_and_padding*/ false, + /*start_in_may_dangle*/ true, )?; } interp_ok(()) diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index ade6f1c09475..33da1c5ecf73 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -5,7 +5,6 @@ #![feature(never_type)] #![feature(slice_ptr_get)] #![feature(trait_alias)] -#![feature(try_blocks)] #![feature(unqualified_local_imports)] #![feature(yeet_expr)] #![warn(unqualified_local_imports)] @@ -22,8 +21,6 @@ use rustc_middle::ty; use rustc_middle::util::Providers; -pub use self::errors::ReportErrorExt; - pub fn provide(providers: &mut Providers) { const_eval::provide(&mut providers.queries); providers.queries.tag_for_variant = const_eval::tag_for_variant_provider; diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 939f9151680b..00835a3cc990 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -2,6 +2,7 @@ use rustc_middle::ty::layout::{ HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement, }; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{PseudoCanonicalInput, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, ty}; use rustc_span::DUMMY_SP; @@ -70,13 +71,19 @@ fn check_validity_requirement_strict<'tcx>( // due to this. // The value we are validating is temporary and discarded at the end of this function, so // there is no point in resetting provenance and padding. - cx.validate_operand( - &allocated.into(), - /*recursive*/ false, - /*reset_provenance_and_padding*/ false, + // This is pretty inefficient: we do the full path tracking and even format an error message + // in case there is a problem, only to entirely throw that away again. For a nightly-only + // option this is fine, but if this is ever meant to be stable we should probably add + // a "fast mode" to validation. + with_no_trimmed_paths!( + cx.validate_operand( + &allocated.into(), + /*recursive*/ false, + /*reset_provenance_and_padding*/ false, + ) + .discard_err() + .is_some() ) - .discard_err() - .is_some() } /// Implements the 'lax' (default) version of the [`check_validity_requirement`] checks; see that @@ -119,7 +126,7 @@ fn check_validity_requirement_lax<'tcx>( } BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s), BackendRepr::Memory { .. } => true, // Fields are checked below. - BackendRepr::ScalableVector { element, .. } => scalar_allows_raw_init(element), + BackendRepr::SimdScalableVector { element, .. } => scalar_allows_raw_init(element), }; if !valid { diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs index bfc7556faf68..d653847f1c60 100644 --- a/compiler/rustc_data_structures/src/aligned.rs +++ b/compiler/rustc_data_structures/src/aligned.rs @@ -1,4 +1,7 @@ use std::marker::PointeeSized; +#[cfg(not(bootstrap))] +use std::mem::Alignment; +#[cfg(bootstrap)] use std::ptr::Alignment; /// Returns the ABI-required minimum alignment of a type in bytes. diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index c7c0d0ab0725..06ab95d65b6a 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -181,22 +181,24 @@ fn decode(d: &mut D) -> Self { } } -// `PackedFingerprint` wraps a `Fingerprint`. Its purpose is to, on certain -// architectures, behave like a `Fingerprint` without alignment requirements. -// This behavior is only enabled on x86 and x86_64, where the impact of -// unaligned accesses is tolerable in small doses. -// -// This may be preferable to use in large collections of structs containing -// fingerprints, as it can reduce memory consumption by preventing the padding -// that the more strictly-aligned `Fingerprint` can introduce. An application of -// this is in the query dependency graph, which contains a large collection of -// `DepNode`s. As of this writing, the size of a `DepNode` decreases by ~30% -// (from 24 bytes to 17) by using the packed representation here, which -// noticeably decreases total memory usage when compiling large crates. -// -// The wrapped `Fingerprint` is private to reduce the chance of a client -// invoking undefined behavior by taking a reference to the packed field. -#[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), repr(packed))] +/// `PackedFingerprint` wraps a `Fingerprint`. +/// Its purpose is to behave like a `Fingerprint` without alignment requirements. +/// +/// This may be preferable to use in large collections of structs containing +/// fingerprints, as it can reduce memory consumption by preventing the padding +/// that the more strictly-aligned `Fingerprint` can introduce. An application of +/// this is in the query dependency graph, which contains a large collection of +/// `DepNode`s. As of this writing, the size of a `DepNode` decreases by 25% +/// (from 24 bytes to 18) by using the packed representation here, which +/// noticeably decreases total memory usage when compiling large crates. +/// +/// (Unalignment was previously restricted to `x86` and `x86_64` hosts, but is +/// now enabled by default for all host architectures, in the hope that the +/// memory and cache savings should outweigh any unaligned access penalty.) +/// +/// The wrapped `Fingerprint` is private to reduce the chance of a client +/// invoking undefined behavior by taking a reference to the packed field. +#[repr(packed)] #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)] pub struct PackedFingerprint(Fingerprint); diff --git a/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs index ecb0095626b4..2223e85a2495 100644 --- a/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs @@ -23,6 +23,7 @@ use std::fmt::Debug; use rustc_index::bit_set::DenseBitSet; +use rustc_index::{Idx, IndexSlice, IndexVec}; use tracing::debug; #[cfg(test)] @@ -45,13 +46,13 @@ /// and does not implement those traits, so it has its own implementations of a /// few basic graph algorithms. pub struct LinkedGraph { - nodes: Vec>, + nodes: IndexVec>, edges: Vec>, } pub struct Node { first_edge: [EdgeIndex; 2], // see module comment - pub data: N, + pub data: Option, } #[derive(Debug)] @@ -62,7 +63,7 @@ pub struct Edge { pub data: E, } -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct NodeIndex(pub usize); #[derive(Copy, Clone, PartialEq, Debug)] @@ -87,19 +88,29 @@ pub fn node_id(self) -> usize { } } +impl Idx for NodeIndex { + fn new(idx: usize) -> NodeIndex { + NodeIndex(idx) + } + + fn index(self) -> usize { + self.0 + } +} + impl LinkedGraph { pub fn new() -> Self { - Self { nodes: Vec::new(), edges: Vec::new() } + Self { nodes: IndexVec::new(), edges: Vec::new() } } pub fn with_capacity(nodes: usize, edges: usize) -> Self { - Self { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) } + Self { nodes: IndexVec::with_capacity(nodes), edges: Vec::with_capacity(edges) } } // # Simple accessors #[inline] - pub fn all_nodes(&self) -> &[Node] { + pub fn all_nodes(&self) -> &IndexSlice> { &self.nodes } @@ -124,22 +135,34 @@ pub fn next_node_index(&self) -> NodeIndex { NodeIndex(self.nodes.len()) } + fn ensure_node(&mut self, idx: NodeIndex) -> &mut Node { + self.nodes.ensure_contains_elem(idx, || Node { + first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], + data: None, + }) + } + + pub fn add_node_with_idx(&mut self, idx: NodeIndex, data: N) { + let old_data = self.ensure_node(idx).data.replace(data); + debug_assert!(old_data.is_none()); + } + pub fn add_node(&mut self, data: N) -> NodeIndex { let idx = self.next_node_index(); - self.nodes.push(Node { first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], data }); + self.add_node_with_idx(idx, data); idx } pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { - &mut self.nodes[idx.0].data + self.nodes[idx].data.as_mut().unwrap() } pub fn node_data(&self, idx: NodeIndex) -> &N { - &self.nodes[idx.0].data + self.nodes[idx].data.as_ref().unwrap() } pub fn node(&self, idx: NodeIndex) -> &Node { - &self.nodes[idx.0] + &self.nodes[idx] } // # Edge construction and queries @@ -154,16 +177,16 @@ pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> Edg let idx = self.next_edge_index(); // read current first of the list of edges from each node - let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; - let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; + let source_first = self.ensure_node(source).first_edge[OUTGOING.repr]; + let target_first = self.ensure_node(target).first_edge[INCOMING.repr]; // create the new edge, with the previous firsts from each node // as the next pointers self.edges.push(Edge { next_edge: [source_first, target_first], source, target, data }); // adjust the firsts for each node target be the next object. - self.nodes[source.0].first_edge[OUTGOING.repr] = idx; - self.nodes[target.0].first_edge[INCOMING.repr] = idx; + self.nodes[source].first_edge[OUTGOING.repr] = idx; + self.nodes[target].first_edge[INCOMING.repr] = idx; idx } diff --git a/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs b/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs index 357aa81a57ca..da416cd638d4 100644 --- a/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs @@ -40,7 +40,7 @@ fn each_node() { let expected = ["A", "B", "C", "D", "E", "F"]; graph.each_node(|idx, node| { assert_eq!(&expected[idx.0], graph.node_data(idx)); - assert_eq!(expected[idx.0], node.data); + assert_eq!(expected[idx.0], node.data.unwrap()); true }); } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index d62705120958..de086085c4cb 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -25,6 +25,8 @@ #![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] +#![feature(pattern_type_macro)] +#![feature(pattern_types)] #![feature(ptr_alignment_type)] #![feature(rustc_attrs)] #![feature(sized_hierarchy)] diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index e2193a97a0f4..997077ac4402 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -188,53 +188,6 @@ pub fn assert_dyn_send() {} pub fn assert_dyn_send_val(_t: &T) {} pub fn assert_dyn_send_sync_val(_t: &T) {} -#[derive(Copy, Clone)] -pub struct FromDyn(T); - -impl FromDyn { - #[inline(always)] - pub fn from(val: T) -> Self { - // Check that `sync::is_dyn_thread_safe()` is true on creation so we can - // implement `Send` and `Sync` for this structure when `T` - // implements `DynSend` and `DynSync` respectively. - assert!(crate::sync::is_dyn_thread_safe()); - FromDyn(val) - } - - #[inline(always)] - pub fn derive(&self, val: O) -> FromDyn { - // We already did the check for `sync::is_dyn_thread_safe()` when creating `Self` - FromDyn(val) - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.0 - } -} - -// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true. -unsafe impl Send for FromDyn {} - -// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true. -unsafe impl Sync for FromDyn {} - -impl std::ops::Deref for FromDyn { - type Target = T; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::ops::DerefMut for FromDyn { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - // A wrapper to convert a struct that is already a `Send` or `Sync` into // an instance of `DynSend` and `DynSync`, since the compiler cannot infer // it automatically in some cases. (e.g. Box) diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 2c62034c6e87..83cfa027cc3d 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -702,7 +702,7 @@ fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) { self.apply_rewrites(&node_rewrites); } - node_rewrites.truncate(0); + node_rewrites.clear(); self.reused_node_vec = node_rewrites; } diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 9fb4d4352c2f..f8e72d66d07e 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -555,15 +555,6 @@ fn hash_stable(&self, _ctx: &mut CTX, hasher: &mut StableHasher) { } } -impl HashStable for bit_set::FiniteBitSet -where - T: HashStable + bit_set::FiniteBitSetTy, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.0.hash_stable(hcx, hasher); - } -} - impl_stable_traits_for_trivial_type!(::std::ffi::OsStr); impl_stable_traits_for_trivial_type!(::std::path::Path); diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 31768fe189ae..3d5bc8527828 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -21,11 +21,6 @@ //! | `Lock` | `RefCell` | `RefCell` or | //! | | | `parking_lot::Mutex` | //! | `RwLock` | `RefCell` | `parking_lot::RwLock` | -//! | `MTLock` [^1] | `T` | `Lock` | -//! -//! [^1]: `MTLock` is similar to `Lock`, but the serial version avoids the cost -//! of a `RefCell`. This is appropriate when interior mutability is not -//! required. use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; @@ -39,7 +34,9 @@ pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; #[doc(no_inline)] pub use self::lock::{Lock, LockGuard, Mode}; -pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; +pub use self::mode::{ + FromDyn, check_dyn_thread_safe, is_dyn_thread_safe, set_dyn_thread_safe_mode, +}; pub use self::parallel::{ broadcast, par_fns, par_for_each_in, par_join, par_map, parallel_guard, spawn, try_par_for_each_in, @@ -69,12 +66,20 @@ mod atomic { mod mode { use std::sync::atomic::{AtomicU8, Ordering}; + use crate::sync::{DynSend, DynSync}; + const UNINITIALIZED: u8 = 0; const DYN_NOT_THREAD_SAFE: u8 = 1; const DYN_THREAD_SAFE: u8 = 2; static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); + // Whether thread safety is enabled (due to running under multiple threads). + #[inline] + pub fn check_dyn_thread_safe() -> Option> { + is_dyn_thread_safe().then_some(FromDyn(())) + } + // Whether thread safety is enabled (due to running under multiple threads). #[inline] pub fn is_dyn_thread_safe() -> bool { @@ -104,37 +109,43 @@ pub fn set_dyn_thread_safe_mode(mode: bool) { // Check that the mode was either uninitialized or was already set to the requested mode. assert!(previous.is_ok() || previous == Err(set)); } -} -// FIXME(parallel_compiler): Get rid of these aliases across the compiler. + #[derive(Copy, Clone)] + pub struct FromDyn(T); -#[derive(Debug, Default)] -pub struct MTLock(Lock); + impl FromDyn { + #[inline(always)] + pub fn derive(&self, val: O) -> FromDyn { + // We already did the check for `sync::is_dyn_thread_safe()` when creating `Self` + FromDyn(val) + } -impl MTLock { - #[inline(always)] - pub fn new(inner: T) -> Self { - MTLock(Lock::new(inner)) + #[inline(always)] + pub fn into_inner(self) -> T { + self.0 + } } - #[inline(always)] - pub fn into_inner(self) -> T { - self.0.into_inner() + // `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true. + unsafe impl Send for FromDyn {} + + // `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true. + unsafe impl Sync for FromDyn {} + + impl std::ops::Deref for FromDyn { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } } - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - self.0.get_mut() - } - - #[inline(always)] - pub fn lock(&self) -> LockGuard<'_, T> { - self.0.lock() - } - - #[inline(always)] - pub fn lock_mut(&self) -> LockGuard<'_, T> { - self.lock() + impl std::ops::DerefMut for FromDyn { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } } diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 2ab4a7f75b6b..b112ecc2fbad 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -57,8 +57,8 @@ fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) } pub fn spawn(func: impl FnOnce() + DynSend + 'static) { - if mode::is_dyn_thread_safe() { - let func = FromDyn::from(func); + if let Some(proof) = mode::check_dyn_thread_safe() { + let func = proof.derive(func); rustc_thread_pool::spawn(|| { (func.into_inner())(); }); @@ -73,8 +73,8 @@ pub fn spawn(func: impl FnOnce() + DynSend + 'static) { /// Use that for the longest running function for better scheduling. pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) { parallel_guard(|guard: &ParallelGuard| { - if mode::is_dyn_thread_safe() { - let funcs = FromDyn::from(funcs); + if let Some(proof) = mode::check_dyn_thread_safe() { + let funcs = proof.derive(funcs); rustc_thread_pool::scope(|s| { let Some((first, rest)) = funcs.into_inner().split_at_mut_checked(1) else { return; @@ -84,7 +84,7 @@ pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) { // order when using a single thread. This ensures the execution order matches // that of a single threaded rustc. for f in rest.iter_mut().rev() { - let f = FromDyn::from(f); + let f = proof.derive(f); s.spawn(|_| { guard.run(|| (f.into_inner())()); }); @@ -108,13 +108,13 @@ pub fn par_join(oper_a: A, oper_b: B) -> (RA, RB A: FnOnce() -> RA + DynSend, B: FnOnce() -> RB + DynSend, { - if mode::is_dyn_thread_safe() { - let oper_a = FromDyn::from(oper_a); - let oper_b = FromDyn::from(oper_b); + if let Some(proof) = mode::check_dyn_thread_safe() { + let oper_a = proof.derive(oper_a); + let oper_b = proof.derive(oper_b); let (a, b) = parallel_guard(|guard| { rustc_thread_pool::join( - move || guard.run(move || FromDyn::from(oper_a.into_inner()())), - move || guard.run(move || FromDyn::from(oper_b.into_inner()())), + move || guard.run(move || proof.derive(oper_a.into_inner()())), + move || guard.run(move || proof.derive(oper_b.into_inner()())), ) }); (a.unwrap().into_inner(), b.unwrap().into_inner()) @@ -127,13 +127,30 @@ fn par_slice( items: &mut [I], guard: &ParallelGuard, for_each: impl Fn(&mut I) + DynSync + DynSend, + proof: FromDyn<()>, ) { - let for_each = FromDyn::from(for_each); + match items { + [] => return, + [item] => { + guard.run(|| for_each(item)); + return; + } + _ => (), + } + + let for_each = proof.derive(for_each); let mut items = for_each.derive(items); rustc_thread_pool::scope(|s| { let proof = items.derive(()); - let group_size = std::cmp::max(items.len() / 128, 1); - for group in items.chunks_mut(group_size) { + + const MAX_GROUP_COUNT: usize = 128; + let group_size = items.len().div_ceil(MAX_GROUP_COUNT); + let groups = items.chunks_mut(group_size); + + // Reverse the order of the later functions since Rayon executes them in reverse + // order when using a single thread. This ensures the execution order matches + // that of a single threaded rustc. + for group in groups.rev() { let group = proof.derive(group); s.spawn(|_| { let mut group = group; @@ -150,9 +167,9 @@ pub fn par_for_each_in>( for_each: impl Fn(&I) + DynSync + DynSend, ) { parallel_guard(|guard| { - if mode::is_dyn_thread_safe() { + if let Some(proof) = mode::check_dyn_thread_safe() { let mut items: Vec<_> = t.into_iter().collect(); - par_slice(&mut items, guard, |i| for_each(&*i)) + par_slice(&mut items, guard, |i| for_each(&*i), proof) } else { t.into_iter().for_each(|i| { guard.run(|| for_each(&i)); @@ -173,16 +190,21 @@ pub fn try_par_for_each_in( ::Item: DynSend, { parallel_guard(|guard| { - if mode::is_dyn_thread_safe() { + if let Some(proof) = mode::check_dyn_thread_safe() { let mut items: Vec<_> = t.into_iter().collect(); let error = Mutex::new(None); - par_slice(&mut items, guard, |i| { - if let Err(err) = for_each(&*i) { - *error.lock() = Some(err); - } - }); + par_slice( + &mut items, + guard, + |i| { + if let Err(err) = for_each(&*i) { + *error.lock() = Some(err); + } + }, + proof, + ); if let Some(err) = error.into_inner() { Err(err) } else { Ok(()) } } else { @@ -196,15 +218,20 @@ pub fn par_map, R: DynSend, C: FromIterato map: impl Fn(I) -> R + DynSync + DynSend, ) -> C { parallel_guard(|guard| { - if mode::is_dyn_thread_safe() { - let map = FromDyn::from(map); + if let Some(proof) = mode::check_dyn_thread_safe() { + let map = proof.derive(map); let mut items: Vec<(Option, Option)> = t.into_iter().map(|i| (Some(i), None)).collect(); - par_slice(&mut items, guard, |i| { - i.1 = Some(map(i.0.take().unwrap())); - }); + par_slice( + &mut items, + guard, + |i| { + i.1 = Some(map(i.0.take().unwrap())); + }, + proof, + ); items.into_iter().filter_map(|i| i.1).collect() } else { @@ -214,8 +241,8 @@ pub fn par_map, R: DynSend, C: FromIterato } pub fn broadcast(op: impl Fn(usize) -> R + DynSync) -> Vec { - if mode::is_dyn_thread_safe() { - let op = FromDyn::from(op); + if let Some(proof) = mode::check_dyn_thread_safe() { + let op = proof.derive(op); let results = rustc_thread_pool::broadcast(|context| op.derive(op(context.index()))); results.into_iter().map(|r| r.into_inner()).collect() } else { diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index 94db421f77e8..71e5e0b412e8 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -55,7 +55,12 @@ pub unsafe trait Tag: Copy { /// Returns the number of bits available for use for tags in a pointer to `T` /// (this is based on `T`'s alignment). pub const fn bits_for() -> u32 { - crate::aligned::align_of::().as_nonzero().trailing_zeros() + let alignment = crate::aligned::align_of::(); + #[cfg(bootstrap)] + let alignment = alignment.as_nonzero(); + #[cfg(not(bootstrap))] + let alignment = alignment.as_nonzero_usize(); + alignment.trailing_zeros() } /// Returns the correct [`Tag::BITS`] constant for a set of tag values. diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index aea5924b8802..6d026bb2c7f7 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -6,12 +6,16 @@ //! //! This is currently used for query caching. -use std::fmt::Debug; +use std::fmt::{self, Debug}; use std::marker::PhantomData; +use std::ops::{Index, IndexMut}; use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicUsize, Ordering}; use rustc_index::Idx; +#[cfg(test)] +mod tests; + struct Slot { // We never construct &Slot so it's fine for this to not be in an UnsafeCell. value: V, @@ -28,7 +32,7 @@ struct Slot { #[derive(Copy, Clone, Debug)] struct SlotIndex { // the index of the bucket in VecCache (0 to 20) - bucket_idx: usize, + bucket_idx: BucketIndex, // the index of the slot within the bucket index_in_bucket: usize, } @@ -42,7 +46,7 @@ struct SlotIndex { let mut key = 0; loop { let si = SlotIndex::from_index(key); - entries[si.bucket_idx] = si.entries(); + entries[si.bucket_idx.to_usize()] = si.bucket_idx.capacity(); if key == 0 { key = 1; } else if key == (1 << 31) { @@ -57,48 +61,24 @@ struct SlotIndex { const BUCKETS: usize = 21; impl SlotIndex { - /// The total possible number of entries in the bucket - const fn entries(&self) -> usize { - if self.bucket_idx == 0 { 1 << 12 } else { 1 << (self.bucket_idx + 11) } - } - - // This unpacks a flat u32 index into identifying which bucket it belongs to and the offset - // within that bucket. As noted in the VecCache docs, buckets double in size with each index. - // Typically that would mean 31 buckets (2^0 + 2^1 ... + 2^31 = u32::MAX - 1), but to reduce - // the size of the VecCache struct and avoid uselessly small allocations, we instead have the - // first bucket have 2**12 entries. To simplify the math, the second bucket also 2**12 entries, - // and buckets double from there. - // - // We assert that [0, 2**32 - 1] uniquely map through this function to individual, consecutive - // slots (see `slot_index_exhaustive` in tests). + /// Unpacks a flat 32-bit index into a [`BucketIndex`] and a slot offset within that bucket. #[inline] const fn from_index(idx: u32) -> Self { - const FIRST_BUCKET_SHIFT: usize = 12; - if idx < (1 << FIRST_BUCKET_SHIFT) { - return SlotIndex { bucket_idx: 0, index_in_bucket: idx as usize }; - } - // We already ruled out idx 0, so this `ilog2` never panics (and the check optimizes away) - let bucket = idx.ilog2() as usize; - let entries = 1 << bucket; - SlotIndex { - bucket_idx: bucket - FIRST_BUCKET_SHIFT + 1, - index_in_bucket: idx as usize - entries, - } + let (bucket_idx, index_in_bucket) = BucketIndex::from_flat_index(idx as usize); + SlotIndex { bucket_idx, index_in_bucket } } // SAFETY: Buckets must be managed solely by functions here (i.e., get/put on SlotIndex) and // `self` comes from SlotIndex::from_index #[inline] unsafe fn get(&self, buckets: &[AtomicPtr>; 21]) -> Option<(V, u32)> { - // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e., - // in-bounds of buckets. See `from_index` for computation. - let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) }; + let bucket = &buckets[self.bucket_idx]; let ptr = bucket.load(Ordering::Acquire); // Bucket is not yet initialized: then we obviously won't find this entry in that bucket. if ptr.is_null() { return None; } - debug_assert!(self.index_in_bucket < self.entries()); + debug_assert!(self.index_in_bucket < self.bucket_idx.capacity()); // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this // must be inbounds. let slot = unsafe { ptr.add(self.index_in_bucket) }; @@ -131,7 +111,7 @@ fn bucket_ptr(&self, bucket: &AtomicPtr>) -> *mut Slot { #[cold] #[inline(never)] - fn initialize_bucket(bucket: &AtomicPtr>, bucket_idx: usize) -> *mut Slot { + fn initialize_bucket(bucket: &AtomicPtr>, bucket_idx: BucketIndex) -> *mut Slot { static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(()); // If we are initializing the bucket, then acquire a global lock. @@ -145,8 +125,8 @@ fn initialize_bucket(bucket: &AtomicPtr>, bucket_idx: usize) -> *mut // OK, now under the allocator lock, if we're still null then it's definitely us that will // initialize this bucket. if ptr.is_null() { - let bucket_len = SlotIndex { bucket_idx, index_in_bucket: 0 }.entries(); - let bucket_layout = std::alloc::Layout::array::>(bucket_len).unwrap(); + let bucket_layout = + std::alloc::Layout::array::>(bucket_idx.capacity()).unwrap(); // This is more of a sanity check -- this code is very cold, so it's safe to pay a // little extra cost here. assert!(bucket_layout.size() > 0); @@ -167,12 +147,10 @@ fn initialize_bucket(bucket: &AtomicPtr>, bucket_idx: usize) -> *mut /// Returns true if this successfully put into the map. #[inline] fn put(&self, buckets: &[AtomicPtr>; 21], value: V, extra: u32) -> bool { - // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e., - // in-bounds of buckets. - let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) }; + let bucket = &buckets[self.bucket_idx]; let ptr = self.bucket_ptr(bucket); - debug_assert!(self.index_in_bucket < self.entries()); + debug_assert!(self.index_in_bucket < self.bucket_idx.capacity()); // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this // must be inbounds. let slot = unsafe { ptr.add(self.index_in_bucket) }; @@ -209,12 +187,10 @@ fn initialize_bucket(bucket: &AtomicPtr>, bucket_idx: usize) -> *mut /// Inserts into the map, given that the slot is unique, so it won't race with other threads. #[inline] unsafe fn put_unique(&self, buckets: &[AtomicPtr>; 21], value: V, extra: u32) { - // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e., - // in-bounds of buckets. - let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) }; + let bucket = &buckets[self.bucket_idx]; let ptr = self.bucket_ptr(bucket); - debug_assert!(self.index_in_bucket < self.entries()); + debug_assert!(self.index_in_bucket < self.bucket_idx.capacity()); // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this // must be inbounds. let slot = unsafe { ptr.add(self.index_in_bucket) }; @@ -254,7 +230,7 @@ pub struct VecCache { // ... // Bucket 19: 1073741824 // Bucket 20: 2147483648 - // The total number of entries if all buckets are initialized is u32::MAX-1. + // The total number of entries if all buckets are initialized is 2^32. buckets: [AtomicPtr>; BUCKETS], // In the compiler's current usage these are only *read* during incremental and self-profiling. @@ -289,7 +265,7 @@ fn drop(&mut self) { assert!(!std::mem::needs_drop::()); assert!(!std::mem::needs_drop::()); - for (idx, bucket) in self.buckets.iter().enumerate() { + for (idx, bucket) in BucketIndex::enumerate_buckets(&self.buckets) { let bucket = bucket.load(Ordering::Acquire); if !bucket.is_null() { let layout = std::alloc::Layout::array::>(ENTRIES_BY_BUCKET[idx]).unwrap(); @@ -299,7 +275,7 @@ fn drop(&mut self) { } } - for (idx, bucket) in self.present.iter().enumerate() { + for (idx, bucket) in BucketIndex::enumerate_buckets(&self.present) { let bucket = bucket.load(Ordering::Acquire); if !bucket.is_null() { let layout = std::alloc::Layout::array::>(ENTRIES_BY_BUCKET[idx]).unwrap(); @@ -365,5 +341,164 @@ pub fn len(&self) -> usize { } } -#[cfg(test)] -mod tests; +/// Index into an array of buckets. +/// +/// Using an enum lets us tell the compiler that values range from 0 to 20, +/// allowing array bounds checks to be optimized away, +/// without having to resort to pattern types or other unstable features. +#[derive(Clone, Copy, PartialEq, Eq)] +#[repr(usize)] +enum BucketIndex { + // tidy-alphabetical-start + Bucket00, + Bucket01, + Bucket02, + Bucket03, + Bucket04, + Bucket05, + Bucket06, + Bucket07, + Bucket08, + Bucket09, + Bucket10, + Bucket11, + Bucket12, + Bucket13, + Bucket14, + Bucket15, + Bucket16, + Bucket17, + Bucket18, + Bucket19, + Bucket20, + // tidy-alphabetical-end +} + +impl Debug for BucketIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.to_usize(), f) + } +} + +impl BucketIndex { + /// Capacity of bucket 0 (and also of bucket 1). + const BUCKET_0_CAPACITY: usize = 1 << (Self::NONZERO_BUCKET_SHIFT_ADJUST + 1); + /// Adjustment factor from the highest-set-bit-position of a flat index, + /// to its corresponding bucket number. + /// + /// For example, the first flat-index in bucket 2 is 8192. + /// Its highest-set-bit-position is `(8192).ilog2() == 13`, and subtracting + /// the adjustment factor of 11 gives the bucket number of 2. + const NONZERO_BUCKET_SHIFT_ADJUST: usize = 11; + + #[inline(always)] + const fn to_usize(self) -> usize { + self as usize + } + + #[inline(always)] + const fn from_raw(raw: usize) -> Self { + match raw { + // tidy-alphabetical-start + 00 => Self::Bucket00, + 01 => Self::Bucket01, + 02 => Self::Bucket02, + 03 => Self::Bucket03, + 04 => Self::Bucket04, + 05 => Self::Bucket05, + 06 => Self::Bucket06, + 07 => Self::Bucket07, + 08 => Self::Bucket08, + 09 => Self::Bucket09, + 10 => Self::Bucket10, + 11 => Self::Bucket11, + 12 => Self::Bucket12, + 13 => Self::Bucket13, + 14 => Self::Bucket14, + 15 => Self::Bucket15, + 16 => Self::Bucket16, + 17 => Self::Bucket17, + 18 => Self::Bucket18, + 19 => Self::Bucket19, + 20 => Self::Bucket20, + // tidy-alphabetical-end + _ => panic!("bucket index out of range"), + } + } + + /// Total number of slots in this bucket. + #[inline(always)] + const fn capacity(self) -> usize { + match self { + Self::Bucket00 => Self::BUCKET_0_CAPACITY, + // Bucket 1 has a capacity of `1 << (1 + 11) == pow(2, 12) == 4096`. + // Bucket 2 has a capacity of `1 << (2 + 11) == pow(2, 13) == 8192`. + _ => 1 << (self.to_usize() + Self::NONZERO_BUCKET_SHIFT_ADJUST), + } + } + + /// Converts a flat index in the range `0..=u32::MAX` into a bucket index, + /// and a slot offset within that bucket. + /// + /// Panics if `flat > u32::MAX`. + #[inline(always)] + const fn from_flat_index(flat: usize) -> (Self, usize) { + if flat > u32::MAX as usize { + panic!(); + } + + // If the index is in bucket 0, the conversion is trivial. + // This also avoids calling `ilog2` when `flat == 0`. + if flat < Self::BUCKET_0_CAPACITY { + return (Self::Bucket00, flat); + } + + // General-case conversion for a non-zero bucket index. + // + // | bucket | slot + // flat | ilog2 | index | offset + // ------------------------------ + // 4096 | 12 | 1 | 0 + // 4097 | 12 | 1 | 1 + // ... + // 8191 | 12 | 1 | 4095 + // 8192 | 13 | 2 | 0 + let highest_bit_pos = flat.ilog2() as usize; + let bucket_index = + BucketIndex::from_raw(highest_bit_pos - Self::NONZERO_BUCKET_SHIFT_ADJUST); + + // Clear the highest-set bit (which selects the bucket) to get the + // slot offset within this bucket. + let slot_offset = flat - (1 << highest_bit_pos); + + (bucket_index, slot_offset) + } + + #[inline(always)] + fn iter_all() -> impl ExactSizeIterator { + (0usize..BUCKETS).map(BucketIndex::from_raw) + } + + #[inline(always)] + fn enumerate_buckets(buckets: &[T; BUCKETS]) -> impl ExactSizeIterator { + BucketIndex::iter_all().zip(buckets) + } +} + +impl Index for [T; BUCKETS] { + type Output = T; + + #[inline(always)] + fn index(&self, index: BucketIndex) -> &Self::Output { + // The optimizer should be able to see that see that a bucket index is + // always in-bounds, and omit the runtime bounds check. + &self[index.to_usize()] + } +} + +impl IndexMut for [T; BUCKETS] { + #[inline(always)] + fn index_mut(&mut self, index: BucketIndex) -> &mut Self::Output { + &mut self[index.to_usize()] + } +} diff --git a/compiler/rustc_data_structures/src/vec_cache/tests.rs b/compiler/rustc_data_structures/src/vec_cache/tests.rs index f588442eee62..f12937ad565d 100644 --- a/compiler/rustc_data_structures/src/vec_cache/tests.rs +++ b/compiler/rustc_data_structures/src/vec_cache/tests.rs @@ -1,10 +1,46 @@ use super::*; +#[test] +#[should_panic(expected = "bucket index out of range")] +fn bucket_index_n_buckets() { + BucketIndex::from_raw(BUCKETS); +} + +#[test] +fn bucket_index_round_trip() { + for i in 0..BUCKETS { + assert_eq!(BucketIndex::from_raw(i).to_usize(), i); + } +} + +#[test] +fn bucket_index_iter_all_len() { + let len = BucketIndex::iter_all().len(); + assert_eq!(len, BUCKETS); + + let len = BucketIndex::iter_all().collect::>().len(); + assert_eq!(len, BUCKETS); + + let len = BucketIndex::enumerate_buckets(&[(); BUCKETS]).len(); + assert_eq!(len, BUCKETS); +} + +#[test] +fn bucket_index_capacity() { + // Check that the combined capacity of all buckets is 2^32 slots. + // That's 1 larger than `u32::MAX`, so store the total as a `u64`. + let mut total = 0u64; + for i in BucketIndex::iter_all() { + total += u64::try_from(i.capacity()).unwrap(); + } + assert_eq!(total, 1 << 32); +} + #[test] #[cfg(not(miri))] -fn vec_cache_empty() { +fn vec_cache_empty_exhaustive() { let cache: VecCache = VecCache::default(); - for key in 0..u32::MAX { + for key in 0..=u32::MAX { assert!(cache.lookup(&key).is_none()); } } @@ -70,8 +106,8 @@ fn slot_entries_table() { #[test] fn bucket_entries_matches() { - for i in 0..BUCKETS { - assert_eq!(SlotIndex { bucket_idx: i, index_in_bucket: 0 }.entries(), ENTRIES_BY_BUCKET[i]); + for i in BucketIndex::iter_all() { + assert_eq!(i.capacity(), ENTRIES_BY_BUCKET[i]); } } @@ -84,13 +120,13 @@ fn slot_index_exhaustive() { } let slot_idx = SlotIndex::from_index(0); assert_eq!(slot_idx.index_in_bucket, 0); - assert_eq!(slot_idx.bucket_idx, 0); + assert_eq!(slot_idx.bucket_idx, BucketIndex::Bucket00); let mut prev = slot_idx; for idx in 1..=u32::MAX { let slot_idx = SlotIndex::from_index(idx); // SAFETY: Ensure indices don't go out of bounds of buckets. - assert!(slot_idx.index_in_bucket < slot_idx.entries()); + assert!(slot_idx.index_in_bucket < slot_idx.bucket_idx.capacity()); if prev.bucket_idx == slot_idx.bucket_idx { assert_eq!(prev.index_in_bucket + 1, slot_idx.index_in_bucket); @@ -98,8 +134,8 @@ fn slot_index_exhaustive() { assert_eq!(slot_idx.index_in_bucket, 0); } - assert_eq!(buckets[slot_idx.bucket_idx], slot_idx.entries() as u32); - assert_eq!(ENTRIES_BY_BUCKET[slot_idx.bucket_idx], slot_idx.entries(), "{}", idx); + assert_eq!(buckets[slot_idx.bucket_idx], slot_idx.bucket_idx.capacity() as u32); + assert_eq!(ENTRIES_BY_BUCKET[slot_idx.bucket_idx], slot_idx.bucket_idx.capacity(), "{idx}",); prev = slot_idx; } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 8fec629161ea..ff7e170543be 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -214,7 +214,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) file_loader: None, lint_caps: Default::default(), psess_created: None, - hash_untracked_state: None, + track_state: None, register_lints: None, override_queries: None, extra_symbols: Vec::new(), @@ -353,16 +353,16 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) }) } -fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) { - let hash = tcxt.crate_hash(LOCAL_CRATE); - let crate_name = tcxt.crate_name(LOCAL_CRATE); +fn dump_feature_usage_metrics(tcx: TyCtxt<'_>, metrics_dir: &Path) { + let hash = tcx.crate_hash(LOCAL_CRATE); + let crate_name = tcx.crate_name(LOCAL_CRATE); let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json"); let metrics_path = metrics_dir.join(metrics_file_name); - if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) { + if let Err(error) = tcx.features().dump_feature_usage_metrics(metrics_path) { // FIXME(yaahc): once metrics can be enabled by default we will want "failure to emit // default metrics" to only produce a warning when metrics are enabled by default and emit // an error only when the user manually enables metrics - tcxt.dcx().emit_err(UnstableFeatureUsage { error }); + tcx.dcx().emit_err(UnstableFeatureUsage { error }); } } diff --git a/compiler/rustc_error_codes/src/error_codes/E0636.md b/compiler/rustc_error_codes/src/error_codes/E0636.md index 41fd701a8ede..18e5af6f87e1 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0636.md +++ b/compiler/rustc_error_codes/src/error_codes/E0636.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + The same feature is enabled multiple times with `#![feature]` attributes Erroneous code example: -```compile_fail,E0636 +```compile_fail #![allow(stable_features)] #![feature(rust1)] #![feature(rust1)] // error: the feature `rust1` has already been enabled diff --git a/compiler/rustc_errors/src/decorate_diag.rs b/compiler/rustc_errors/src/decorate_diag.rs index a11082e29663..61dd8f0493f9 100644 --- a/compiler/rustc_errors/src/decorate_diag.rs +++ b/compiler/rustc_errors/src/decorate_diag.rs @@ -1,7 +1,7 @@ /// This module provides types and traits for buffering lints until later in compilation. use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::sync::DynSend; +use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_error_messages::MultiSpan; use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId}; @@ -10,7 +10,14 @@ /// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its /// variants requires types we don't have yet. So, handle that case separately. pub enum DecorateDiagCompat { - Dynamic(Box FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + 'static>), + Dynamic( + Box< + dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + + DynSync + + DynSend + + 'static, + >, + ), Builtin(BuiltinLintDiag), } @@ -20,7 +27,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { } } -impl Diagnostic<'a, ()> + DynSend + 'static> From for DecorateDiagCompat { +impl Diagnostic<'a, ()> + DynSync + DynSend + 'static> From for DecorateDiagCompat { #[inline] fn from(d: D) -> Self { Self::Dynamic(Box::new(|dcx, level| d.into_diag(dcx, level))) @@ -81,4 +88,21 @@ pub fn buffer_lint( diagnostic: decorate.into(), }); } + + pub fn dyn_buffer_lint< + F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSync + DynSend + 'static, + >( + &mut self, + lint: &'static Lint, + node_id: NodeId, + span: impl Into, + callback: F, + ) { + self.add_early_lint(BufferedEarlyLint { + lint_id: LintId::of(lint), + node_id, + span: Some(span.into()), + diagnostic: DecorateDiagCompat::Dynamic(Box::new(callback)), + }); + } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 631ed54cc024..9525a45d55f1 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -7,12 +7,11 @@ use std::path::PathBuf; use std::thread::panicking; -use rustc_data_structures::sync::DynSend; +use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg}; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_span::{DUMMY_SP, Span, Spanned, Symbol}; use tracing::debug; use crate::{ @@ -121,13 +120,26 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { } impl<'a> Diagnostic<'a, ()> - for Box FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSend + 'static> + for Box< + dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static, + > { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { self(dcx, level) } } +/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait. +pub struct DiagDecorator)>(pub F); + +impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for DiagDecorator { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let mut diag = Diag::new(dcx, level, ""); + (self.0)(&mut diag); + diag + } +} + /// Trait implemented by error types. This should not be implemented manually. Instead, use /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic]. #[rustc_diagnostic_item = "Subdiagnostic"] @@ -923,6 +935,7 @@ pub fn span_suggestion( self } } + with_fn! { with_span_suggestion_with_style, /// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`]. pub fn span_suggestion_with_style( &mut self, @@ -945,7 +958,7 @@ pub fn span_suggestion_with_style( applicability, }); self - } + } } with_fn! { with_span_suggestion_verbose, /// Always show the suggested change. diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 42c605d34814..e50cbbbf06e0 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -59,15 +59,10 @@ fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { } TargetDataLayoutErrors::InvalidAlignment { cause, err } => { Diag::new(dcx, level, msg!( - "invalid alignment for `{$cause}` in \"data-layout\": `{$align}` is {$err_kind -> - [not_power_of_two] not a power of 2 - [too_large] too large - *[other] {\"\"} - }" + "invalid alignment for `{$cause}` in \"data-layout\": {$err}" )) .with_arg("cause", cause) - .with_arg("err_kind", err.diag_ident()) - .with_arg("align", err.align()) + .with_arg("err", err.to_string()) } TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { Diag::new(dcx, level, msg!( diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 0a111538fc89..d17a4d6de42f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -36,8 +36,8 @@ pub use codes::*; pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; pub use diagnostic::{ - BugAbort, Diag, DiagInner, DiagLocation, DiagStyledString, Diagnostic, EmissionGuarantee, - FatalAbort, StringPart, Subdiag, Subdiagnostic, + BugAbort, Diag, DiagDecorator, DiagInner, DiagLocation, DiagStyledString, Diagnostic, + EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic, }; pub use diagnostic_impls::{ DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, @@ -138,6 +138,14 @@ pub fn unwrap_tag(self) -> Vec { Suggestions::Disabled => Vec::new(), } } + + pub fn len(&self) -> usize { + match self { + Suggestions::Enabled(suggestions) => suggestions.len(), + Suggestions::Sealed(suggestions) => suggestions.len(), + Suggestions::Disabled => 0, + } + } } impl Default for Suggestions { @@ -371,8 +379,6 @@ pub enum StashKey { MaybeFruTypo, CallAssocMethod, AssociatedTypeSuggestion, - /// Query cycle detected, stashing in favor of a better error. - Cycle, UndeterminedMacroResolution, /// Used by `Parser::maybe_recover_trailing_expr` ExprInPat, @@ -380,6 +386,7 @@ pub enum StashKey { /// it's a method call without parens. If later on in `hir_typeck` we find out that this is /// the case we suppress this message and we give a better suggestion. GenericInFieldExpr, + ReturnTypeNotation, } fn default_track_diagnostic(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 225906dfba2d..7fd891395fa0 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -149,14 +149,14 @@ pub fn expect_item(self) -> Box { pub fn expect_trait_item(self) -> Box { match self { Annotatable::AssocItem(i, AssocCtxt::Trait) => i, - _ => panic!("expected Item"), + _ => panic!("expected trait item"), } } pub fn expect_impl_item(self) -> Box { match self { Annotatable::AssocItem(i, AssocCtxt::Impl { .. }) => i, - _ => panic!("expected Item"), + _ => panic!("expected impl item"), } } @@ -277,7 +277,8 @@ pub fn from_tts( // Emit the SEMICOLON_IN_EXPRESSIONS_FROM_MACROS deprecation lint. let is_local = true; - let parser = ParserAnyMacro::from_tts(cx, tts, site_span, arm_span, is_local, macro_ident); + let parser = + ParserAnyMacro::from_tts(cx, tts, site_span, arm_span, is_local, macro_ident, &[], &[]); ExpandResult::Ready(Box::new(parser)) } } @@ -377,8 +378,8 @@ fn expand<'cx>( /// Represents a thing that maps token trees to Macro Results pub trait TTMacroExpander: Any { - fn expand<'cx>( - &self, + fn expand<'cx, 'a: 'cx>( + &'a self, ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, @@ -394,8 +395,8 @@ impl TTMacroExpander for F where F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> MacroExpanderResult<'cx>, { - fn expand<'cx>( - &self, + fn expand<'cx, 'a: 'cx>( + &'a self, ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 19a2d65762e8..3680f24707df 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -5,8 +5,7 @@ self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream, }; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, Spanned, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use crate::base::ExtCtxt; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8e4039b32d94..ec5951e50e3a 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -10,9 +10,10 @@ self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, }; -use rustc_attr_parsing as attr; +use rustc_attr_parsing::parser::AllowExprMetavar; use rustc_attr_parsing::{ - AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg, + self as attr, AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, + parse_cfg, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::msg; @@ -402,6 +403,7 @@ pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> Eval emit_errors, parse_cfg, &CFG_TEMPLATE, + AllowExprMetavar::Yes, ) else { // Cfg attribute was not parsable, give up return EvalConfigResult::True; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 76a9a6f9d03d..c8ef295b2a79 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,6 +13,7 @@ TyKind, token, }; use rustc_ast_pretty::pprust; +use rustc_attr_parsing::parser::AllowExprMetavar; use rustc_attr_parsing::{ AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg, validate_attr, @@ -182,8 +183,8 @@ pub(crate) fn to_string(&self) -> String { } } - impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> { - $(fn $make_ast(self: Box>) + impl<'a, 'b> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a, 'b> { + $(fn $make_ast(self: Box>) -> Option<$AstTy> { Some(self.make(AstFragmentKind::$Kind).$make_ast()) })* @@ -2224,6 +2225,7 @@ fn expand_cfg_true( ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, parse_cfg, &CFG_TEMPLATE, + AllowExprMetavar::Yes, ) else { // Cfg attribute was not parsable, give up return EvalConfigResult::True; diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index df6903dc4937..fd2e4e3ec39f 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -222,11 +222,13 @@ fn new(dcx: DiagCtxtHandle<'dcx>, root_span: Span) -> Self { pub(super) fn emit_frag_parse_err( mut e: Diag<'_>, - parser: &Parser<'_>, + parser: &mut Parser<'_>, orig_parser: &mut Parser<'_>, site_span: Span, arm_span: Span, kind: AstFragmentKind, + bindings: &[MacroRule], + matched_rule_bindings: &[MatcherLoc], ) -> ErrorGuaranteed { // FIXME(davidtwco): avoid depending on the error message text if parser.token == token::Eof @@ -285,6 +287,69 @@ pub(super) fn emit_frag_parse_err( }, _ => annotate_err_with_kind(&mut e, kind, site_span), }; + + let mut bindings_rules = vec![]; + for rule in bindings { + let MacroRule::Func { lhs, .. } = rule else { continue }; + for param in lhs { + let MatcherLoc::MetaVarDecl { bind, .. } = param else { continue }; + bindings_rules.push(*bind); + } + } + + let mut matched_rule_bindings_rules = vec![]; + for param in matched_rule_bindings { + let MatcherLoc::MetaVarDecl { bind, .. } = param else { continue }; + matched_rule_bindings_rules.push(*bind); + } + + let matched_rule_bindings_names: Vec<_> = + matched_rule_bindings_rules.iter().map(|bind| bind.name).collect(); + let bindings_name: Vec<_> = bindings_rules.iter().map(|bind| bind.name).collect(); + if parser.token.kind == token::Dollar { + parser.bump(); + if let token::Ident(name, _) = parser.token.kind { + if let Some(matched_name) = rustc_span::edit_distance::find_best_match_for_name( + &matched_rule_bindings_names[..], + name, + None, + ) { + e.span_suggestion_verbose( + parser.token.span, + "there is a macro metavariable with similar name", + format!("{matched_name}"), + Applicability::MaybeIncorrect, + ); + } else if bindings_name.contains(&name) { + e.span_label( + parser.token.span, + format!( + "there is an macro metavariable with this name in another macro matcher" + ), + ); + } else if let Some(matched_name) = + rustc_span::edit_distance::find_best_match_for_name(&bindings_name[..], name, None) + { + e.span_suggestion_verbose( + parser.token.span, + "there is a macro metavariable with a similar name in another macro matcher", + format!("{matched_name}"), + Applicability::MaybeIncorrect, + ); + } else { + let msg = matched_rule_bindings_names + .iter() + .map(|sym| format!("${}", sym)) + .collect::>() + .join(", "); + + e.span_label(parser.token.span, format!("macro metavariable not found")); + if !matched_rule_bindings_names.is_empty() { + e.note(format!("available metavariable names are: {msg}")); + } + } + } + } e.emit() } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 7ff49e040f6f..fd5dac3cd926 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -43,7 +43,7 @@ use crate::mbe::transcribe::transcribe; use crate::mbe::{self, KleeneOp}; -pub(crate) struct ParserAnyMacro<'a> { +pub(crate) struct ParserAnyMacro<'a, 'b> { parser: Parser<'a>, /// Span of the expansion site of the macro this parser is for @@ -55,10 +55,15 @@ pub(crate) struct ParserAnyMacro<'a> { arm_span: Span, /// Whether or not this macro is defined in the current crate is_local: bool, + bindings: &'b [MacroRule], + matched_rule_bindings: &'b [MatcherLoc], } -impl<'a> ParserAnyMacro<'a> { - pub(crate) fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { +impl<'a, 'b> ParserAnyMacro<'a, 'b> { + pub(crate) fn make( + mut self: Box>, + kind: AstFragmentKind, + ) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, @@ -67,13 +72,22 @@ pub(crate) fn make(mut self: Box>, kind: AstFragmentKind) -> arm_span, is_trailing_mac, is_local, + bindings, + matched_rule_bindings, } = *self; let snapshot = &mut parser.create_snapshot_for_diagnostic(); let fragment = match parse_ast_fragment(parser, kind) { Ok(f) => f, Err(err) => { let guar = diagnostics::emit_frag_parse_err( - err, parser, snapshot, site_span, arm_span, kind, + err, + parser, + snapshot, + site_span, + arm_span, + kind, + bindings, + matched_rule_bindings, ); return kind.dummy(site_span, guar); } @@ -100,7 +114,7 @@ pub(crate) fn make(mut self: Box>, kind: AstFragmentKind) -> fragment } - #[instrument(skip(cx, tts))] + #[instrument(skip(cx, tts, bindings, matched_rule_bindings))] pub(crate) fn from_tts<'cx>( cx: &'cx mut ExtCtxt<'a>, tts: TokenStream, @@ -108,6 +122,9 @@ pub(crate) fn from_tts<'cx>( arm_span: Span, is_local: bool, macro_ident: Ident, + // bindings and lhs is for diagnostics + bindings: &'b [MacroRule], + matched_rule_bindings: &'b [MatcherLoc], ) -> Self { Self { parser: Parser::new(&cx.sess.psess, tts, None), @@ -121,11 +138,13 @@ pub(crate) fn from_tts<'cx>( is_trailing_mac: cx.current_expansion.is_trailing_mac, arm_span, is_local, + bindings, + matched_rule_bindings, } } } -pub(super) enum MacroRule { +pub(crate) enum MacroRule { /// A function-style rule, for use with `m!()` Func { lhs: Vec, lhs_span: Span, rhs: mbe::TokenTree }, /// An attr rule, for use with `#[m]` @@ -226,8 +245,8 @@ pub fn expand_derive( } impl TTMacroExpander for MacroRulesMacroExpander { - fn expand<'cx>( - &self, + fn expand<'cx, 'a: 'cx>( + &'a self, cx: &'cx mut ExtCtxt<'_>, sp: Span, input: TokenStream, @@ -337,7 +356,7 @@ fn description() -> &'static str { /// Expands the rules based macro defined by `rules` for a given input `arg`. #[instrument(skip(cx, transparency, arg, rules))] -fn expand_macro<'cx>( +fn expand_macro<'cx, 'a: 'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, def_span: Span, @@ -345,7 +364,7 @@ fn expand_macro<'cx>( name: Ident, transparency: Transparency, arg: TokenStream, - rules: &[MacroRule], + rules: &'a [MacroRule], ) -> Box { let psess = &cx.sess.psess; @@ -359,7 +378,7 @@ fn expand_macro<'cx>( match try_success_result { Ok((rule_index, rule, named_matches)) => { - let MacroRule::Func { rhs, .. } = rule else { + let MacroRule::Func { lhs, rhs, .. } = rule else { panic!("try_match_macro returned non-func rule"); }; let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { @@ -388,7 +407,7 @@ fn expand_macro<'cx>( } // Let the context choose how to interpret the result. Weird, but useful for X-macros. - Box::new(ParserAnyMacro::from_tts(cx, tts, sp, arm_span, is_local, name)) + Box::new(ParserAnyMacro::from_tts(cx, tts, sp, arm_span, is_local, name, rules, lhs)) } Err(CanRetry::No(guar)) => { debug!("Will not retry matching as an error was emitted already"); @@ -724,7 +743,7 @@ pub fn compile_declarative_macro( let args = p.parse_token_tree(); check_args_parens(sess, sym::attr, &args); let args = parse_one_tt(args, RulePart::Pattern, sess, node_id, features, edition); - check_emission(check_lhs(sess, node_id, &args)); + check_emission(check_lhs(sess, features, node_id, &args)); if let Some(guar) = check_no_eof(sess, &p, "expected macro attr body") { return dummy_syn_ext(guar); } @@ -773,7 +792,7 @@ pub fn compile_declarative_macro( }; let lhs_tt = p.parse_token_tree(); let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition); - check_emission(check_lhs(sess, node_id, &lhs_tt)); + check_emission(check_lhs(sess, features, node_id, &lhs_tt)); if let Err(e) = p.expect(exp!(FatArrow)) { return dummy_syn_ext(e.emit()); } @@ -870,21 +889,27 @@ fn check_args_empty(sess: &Session, args: &tokenstream::TokenTree) -> Result<(), } } -fn check_lhs(sess: &Session, node_id: NodeId, lhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed> { - let e1 = check_lhs_nt_follows(sess, node_id, lhs); +fn check_lhs( + sess: &Session, + features: &Features, + node_id: NodeId, + lhs: &mbe::TokenTree, +) -> Result<(), ErrorGuaranteed> { + let e1 = check_lhs_nt_follows(sess, features, node_id, lhs); let e2 = check_lhs_no_empty_seq(sess, slice::from_ref(lhs)); e1.and(e2) } fn check_lhs_nt_follows( sess: &Session, + features: &Features, node_id: NodeId, lhs: &mbe::TokenTree, ) -> Result<(), ErrorGuaranteed> { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. if let mbe::TokenTree::Delimited(.., delimited) = lhs { - check_matcher(sess, node_id, &delimited.tts) + check_matcher(sess, features, node_id, &delimited.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; Err(sess.dcx().span_err(lhs.span(), msg)) @@ -989,12 +1014,13 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed fn check_matcher( sess: &Session, + features: &Features, node_id: NodeId, matcher: &[mbe::TokenTree], ) -> Result<(), ErrorGuaranteed> { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); - check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?; + check_matcher_core(sess, features, node_id, &first_sets, matcher, &empty_suffix)?; Ok(()) } @@ -1331,6 +1357,7 @@ fn add_all(&mut self, other: &Self) { // see `FirstSets::new`. fn check_matcher_core<'tt>( sess: &Session, + features: &Features, node_id: NodeId, first_sets: &FirstSets<'tt>, matcher: &'tt [mbe::TokenTree], @@ -1369,6 +1396,17 @@ fn check_matcher_core<'tt>( | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl { .. } | TokenTree::MetaVarExpr(..) => { + if let TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } = token + && !features.macro_guard_matcher() + { + feature_err( + sess, + sym::macro_guard_matcher, + token.span(), + "`guard` fragments in macro are unstable", + ) + .emit(); + } if token_can_be_followed_by_any(token) { // don't need to track tokens that work with any, last.replace_with_irrelevant(); @@ -1385,7 +1423,7 @@ fn check_matcher_core<'tt>( d.delim.as_close_token_kind(), span.close, )); - check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?; + check_matcher_core(sess, features, node_id, first_sets, &d.tts, &my_suffix)?; // don't track non NT tokens last.replace_with_irrelevant(); @@ -1417,7 +1455,14 @@ fn check_matcher_core<'tt>( // At this point, `suffix_first` is built, and // `my_suffix` is some TokenSet that we can use // for checking the interior of `seq_rep`. - let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?; + let next = check_matcher_core( + sess, + features, + node_id, + first_sets, + &seq_rep.tts, + my_suffix, + )?; if next.maybe_empty { last.add_all(&next); } else { @@ -1609,7 +1654,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } } NonterminalKind::Pat(PatParam { .. }) => { - const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; + const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`if let`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq | Or => IsInFollow::Yes, @@ -1618,11 +1663,12 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } _ => IsInFollow::No(TOKENS), }, + TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } } NonterminalKind::Pat(PatWithOr) => { - const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"]; + const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`if let`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq => IsInFollow::Yes, @@ -1631,6 +1677,17 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } _ => IsInFollow::No(TOKENS), }, + TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } => IsInFollow::Yes, + _ => IsInFollow::No(TOKENS), + } + } + NonterminalKind::Guard => { + const TOKENS: &[&str] = &["`=>`", "`,`", "`{`"]; + match tok { + TokenTree::Token(token) => match token.kind { + FatArrow | Comma | OpenBrace => IsInFollow::Yes, + _ => IsInFollow::No(TOKENS), + }, _ => IsInFollow::No(TOKENS), } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 09f006c3de57..dcf2cd1fa36a 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -12,7 +12,8 @@ use rustc_session::parse::ParseSess; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::{ - Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, sym, with_metavar_spans, + BytePos, Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, kw, sym, + with_metavar_spans, }; use smallvec::{SmallVec, smallvec}; @@ -556,6 +557,19 @@ fn transcribe_pnr<'tx>( ParseNtResult::Vis(vis) => { mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) } + ParseNtResult::Guard(guard) => { + // FIXME(macro_guard_matcher): + // Perhaps it would be better to treat the leading `if` as part of `ast::Guard` during parsing? + // Currently they are separate, but in macros we match and emit the leading `if` for `:guard` matchers, which creates some inconsistency. + + let leading_if_span = + guard.span_with_leading_if.with_hi(guard.span_with_leading_if.lo() + BytePos(2)); + let mut ts = + TokenStream::token_alone(token::Ident(kw::If, IdentIsRaw::No), leading_if_span); + ts.push_stream(TokenStream::from_ast(&guard.cond)); + + mk_delimited(guard.span_with_leading_if, MetaVarKind::Guard, ts) + } }; tscx.result.push(tt); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 839e68d0bb43..037afbb9f550 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -475,14 +475,15 @@ fn injected_env_var(&mut self, var: &str) -> Option { } fn track_env_var(&mut self, var: &str, value: Option<&str>) { - self.psess() + self.ecx + .sess .env_depinfo .borrow_mut() .insert((Symbol::intern(var), value.map(Symbol::intern))); } fn track_path(&mut self, path: &str) { - self.psess().file_depinfo.borrow_mut().insert(Symbol::intern(path)); + self.ecx.sess.file_depinfo.borrow_mut().insert(Symbol::intern(path)); } fn literal_from_str(&mut self, s: &str) -> Result, String> { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3a2f548902d1..acbcba90fbcc 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -773,7 +773,7 @@ pub struct BuiltinAttribute { DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature) ), gated!( - sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding, + sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kernel_hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding, EncodeCrossCrate::No, sanitize, experimental!(sanitize), ), gated!( @@ -1587,6 +1587,7 @@ pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool match sym { sym::on_unimplemented | sym::do_not_recommend => true, sym::on_const => features.diagnostic_on_const(), + sym::on_move => features.diagnostic_on_move(), _ => false, } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c2d7b0e21a7f..224b7273314b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -257,6 +257,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (internal, rustc_attrs, "1.0.0", None), /// Allows using the `#[stable]` and `#[unstable]` attributes. (internal, staged_api, "1.0.0", None), + /// Perma-unstable, only used to test the `incomplete_features` lint. + (incomplete, test_incomplete_feature, "CURRENT_RUSTC_VERSION", None), /// Added for testing unstable lints; perma-unstable. (internal, test_unstable_lint, "1.60.0", None), /// Use for stable + negative coherence and strict coherence depending on trait's @@ -429,7 +431,7 @@ pub fn internal(&self, feature: Symbol) -> bool { /// Allows defining and calling c-variadic functions in const contexts. (unstable, const_c_variadic, "1.95.0", Some(151787)), /// Allows `const || {}` closures in const contexts. - (incomplete, const_closures, "1.68.0", Some(106003)), + (unstable, const_closures, "1.68.0", Some(106003)), /// Allows using `[const] Destruct` bounds and calling drop impls in const contexts. (unstable, const_destruct, "1.85.0", Some(133214)), /// Allows `for _ in _` loops in const contexts. @@ -465,11 +467,13 @@ pub fn internal(&self, feature: Symbol) -> bool { /// Allows having using `suggestion` in the `#[deprecated]` attribute. (unstable, deprecated_suggestion, "1.61.0", Some(94785)), /// Allows deref patterns. - (incomplete, deref_patterns, "1.79.0", Some(87121)), + (unstable, deref_patterns, "1.79.0", Some(87121)), /// Allows deriving the From trait on single-field structs. (unstable, derive_from, "1.91.0", Some(144889)), /// Allows giving non-const impls custom diagnostic messages if attempted to be used as const (unstable, diagnostic_on_const, "1.93.0", Some(143874)), + /// Allows giving on-move borrowck custom diagnostic messages for a type + (unstable, diagnostic_on_move, "CURRENT_RUSTC_VERSION", Some(154181)), /// Allows `#[doc(cfg(...))]`. (unstable, doc_cfg, "1.21.0", Some(43781)), /// Allows `#[doc(masked)]`. @@ -565,6 +569,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (unstable, macro_attr, "1.91.0", Some(143547)), /// Allow `macro_rules!` derive rules (unstable, macro_derive, "1.91.0", Some(143549)), + /// Allow `$x:guard` matcher in macros + (unstable, macro_guard_matcher, "CURRENT_RUSTC_VERSION", Some(153104)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. @@ -687,7 +693,7 @@ pub fn internal(&self, feature: Symbol) -> bool { /// Allows inconsistent bounds in where clauses. (unstable, trivial_bounds, "1.28.0", Some(48214)), /// Allows using `try {...}` expressions. - (unstable, try_blocks, "1.29.0", Some(31436)), + (unstable, try_blocks, "1.29.0", Some(154391)), /// Allows using `try bikeshed TargetType {...}` expressions. (unstable, try_blocks_heterogeneous, "1.94.0", Some(149488)), /// Allows `impl Trait` to be used inside type aliases (RFC 2515). diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e8476c3d8c73..a18ddff94709 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -277,15 +277,15 @@ fn default() -> Self { } #[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] -pub struct StrippedCfgItem { - pub parent_module: ModId, +pub struct StrippedCfgItem { + pub parent_scope: ScopeId, pub ident: Ident, pub cfg: (CfgEntry, Span), } -impl StrippedCfgItem { - pub fn map_mod_id(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem { - StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg } +impl StrippedCfgItem { + pub fn map_scope_id(self, f: impl FnOnce(ScopeId) -> New) -> StrippedCfgItem { + StrippedCfgItem { parent_scope: f(self.parent_scope), ident: self.ident, cfg: self.cfg } } } @@ -1180,13 +1180,18 @@ pub enum AttributeKind { directive: Option>, }, + /// Represents `#[diagnostic::on_move]` + OnMove { + span: Span, + directive: Option>, + }, + /// Represents `#[rustc_on_unimplemented]` and `#[diagnostic::on_unimplemented]`. OnUnimplemented { span: Span, /// None if the directive was malformed in some way. directive: Option>, }, - /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 27128f699637..c19fc6976c6e 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -77,6 +77,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { NoStd(..) => No, NonExhaustive(..) => Yes, // Needed for rustdoc OnConst { .. } => Yes, + OnMove { .. } => Yes, OnUnimplemented { .. } => Yes, Optimize(..) => No, PanicRuntime => No, diff --git a/compiler/rustc_hir/src/attrs/mod.rs b/compiler/rustc_hir/src/attrs/mod.rs index 09fa144a1604..b3c1deaa48fa 100644 --- a/compiler/rustc_hir/src/attrs/mod.rs +++ b/compiler/rustc_hir/src/attrs/mod.rs @@ -13,6 +13,15 @@ mod encode_cross_crate; mod pretty_printing; +/// A trait for types that can provide a list of attributes given a `TyCtxt`. +/// +/// It allows `find_attr!` to accept either a `DefId`, `LocalDefId`, `OwnerId`, or `HirId`. +/// It is defined here with a generic `Tcx` because `rustc_hir` can't depend on `rustc_middle`. +/// The concrete implementations are in `rustc_middle`. +pub trait HasAttrs<'tcx, Tcx> { + fn get_attrs(self, tcx: &Tcx) -> &'tcx [crate::Attribute]; +} + /// Finds attributes in sequences of attributes by pattern matching. /// /// A little like `matches` but for attributes. @@ -34,10 +43,12 @@ /// /// As a convenience, this macro can do that for you! /// -/// Instead of providing an attribute list, provide the `tcx` and a `DefId`. +/// Instead of providing an attribute list, provide the `tcx` and an id +/// (a `DefId`, `LocalDefId`, `OwnerId` or `HirId`). /// /// ```rust,ignore (illustrative) /// find_attr!(tcx, def_id, ) +/// find_attr!(tcx, hir_id, ) /// ``` /// /// Another common case is finding attributes applied to the root of the current crate. @@ -55,13 +66,14 @@ macro_rules! find_attr { $crate::find_attr!($tcx.hir_krate_attrs(), $pattern $(if $guard)? => $e) }; - ($tcx: expr, $def_id: expr, $pattern: pat $(if $guard: expr)?) => { - $crate::find_attr!($tcx, $def_id, $pattern $(if $guard)? => ()).is_some() + ($tcx: expr, $id: expr, $pattern: pat $(if $guard: expr)?) => { + $crate::find_attr!($tcx, $id, $pattern $(if $guard)? => ()).is_some() }; - ($tcx: expr, $def_id: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ - #[allow(deprecated)] { - $crate::find_attr!($tcx.get_all_attrs($def_id), $pattern $(if $guard)? => $e) - } + ($tcx: expr, $id: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ + $crate::find_attr!( + $crate::attrs::HasAttrs::get_attrs($id, &$tcx), + $pattern $(if $guard)? => $e + ) }}; diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 3959ee7f9412..2156c987906c 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -192,7 +192,7 @@ pub enum DefKind { /// These are all represented with the same `ExprKind::Closure` in the AST and HIR, /// which makes it difficult to distinguish these during def collection. Therefore, /// we treat them all the same, and code which needs to distinguish them can match - /// or `hir::ClosureKind` or `type_of`. + /// on `hir::ClosureKind` or `type_of`. Closure, /// The definition of a synthetic coroutine body created by the lowering of a /// coroutine-closure, such as an async closure. @@ -590,6 +590,13 @@ pub enum Res { /// **Belongs to the type namespace.** ToolMod, + /// The resolution for an open module in a namespaced crate. E.g. `my_api` + /// in the namespaced crate `my_api::utils` when `my_api` isn't part of the + /// extern prelude. + /// + /// **Belongs to the type namespace.** + OpenMod(Symbol), + // Macro namespace /// An attribute that is *not* implemented via macro. /// E.g., `#[inline]` and `#[rustfmt::skip]`, which are essentially directives, @@ -838,6 +845,7 @@ pub fn opt_def_id(&self) -> Option { | Res::SelfTyAlias { .. } | Res::SelfCtor(..) | Res::ToolMod + | Res::OpenMod(..) | Res::NonMacroAttr(..) | Res::Err => None, } @@ -869,6 +877,7 @@ pub fn descr(&self) -> &'static str { Res::Local(..) => "local variable", Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => "self type", Res::ToolMod => "tool module", + Res::OpenMod(..) => "namespaced crate", Res::NonMacroAttr(attr_kind) => attr_kind.descr(), Res::Err => "unresolved item", } @@ -895,6 +904,7 @@ pub fn map_id(self, mut map: impl FnMut(Id) -> R) -> Res { Res::SelfTyAlias { alias_to, is_trait_impl } } Res::ToolMod => Res::ToolMod, + Res::OpenMod(sym) => Res::OpenMod(sym), Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), Res::Err => Res::Err, } @@ -911,6 +921,7 @@ pub fn apply_id(self, mut map: impl FnMut(Id) -> Result) -> Result Res::ToolMod, + Res::OpenMod(sym) => Res::OpenMod(sym), Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), Res::Err => Res::Err, }) @@ -936,9 +947,11 @@ pub fn macro_kinds(self) -> Option { pub fn ns(&self) -> Option { match self { Res::Def(kind, ..) => kind.ns(), - Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::ToolMod => { - Some(Namespace::TypeNS) - } + Res::PrimTy(..) + | Res::SelfTyParam { .. } + | Res::SelfTyAlias { .. } + | Res::ToolMod + | Res::OpenMod(..) => Some(Namespace::TypeNS), Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS), Res::NonMacroAttr(..) => Some(Namespace::MacroNS), Res::Err => None, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 45a363b97722..57cf42cc5479 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -23,9 +23,8 @@ use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Spanned; use rustc_span::{ - BytePos, DUMMY_SP, DesugaringKind, ErrorGuaranteed, Ident, Span, Symbol, kw, sym, + BytePos, DUMMY_SP, DesugaringKind, ErrorGuaranteed, Ident, Span, Spanned, Symbol, kw, sym, }; use rustc_target::asm::InlineAsmRegOrRegClass; use smallvec::SmallVec; @@ -398,12 +397,7 @@ pub fn invalid() -> Self { } pub fn args(&self) -> &GenericArgs<'hir> { - if let Some(ref args) = self.args { - args - } else { - const DUMMY: &GenericArgs<'_> = &GenericArgs::none(); - DUMMY - } + if let Some(ref args) = self.args { args } else { GenericArgs::NONE } } } @@ -644,14 +638,12 @@ pub struct GenericArgs<'hir> { } impl<'hir> GenericArgs<'hir> { - pub const fn none() -> Self { - Self { - args: &[], - constraints: &[], - parenthesized: GenericArgsParentheses::No, - span_ext: DUMMY_SP, - } - } + pub const NONE: &'hir GenericArgs<'hir> = &GenericArgs { + args: &[], + constraints: &[], + parenthesized: GenericArgsParentheses::No, + span_ext: DUMMY_SP, + }; /// Obtain the list of input types and the output type if the generic arguments are parenthesized. /// @@ -1265,6 +1257,8 @@ pub struct HashIgnoredAttrId { pub attr_id: AttrId, } +/// Many functions on this type have their documentation in the [`AttributeExt`] trait, +/// since they defer their implementation directly to that trait. #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub enum Attribute { /// A parsed built-in attribute. @@ -1668,19 +1662,6 @@ pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> { } } -/// The top-level data structure that stores the entire contents of -/// the crate currently being compiled. -/// -/// For more details, see the [rustc dev guide]. -/// -/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html -#[derive(Debug)] -pub struct Crate<'hir> { - pub owners: IndexVec>, - // Only present when incr. comp. is enabled. - pub opt_hir_hash: Option, -} - #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Closure<'hir> { pub def_id: LocalDefId, @@ -3779,12 +3760,21 @@ pub struct DelegationGenerics { } #[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)] -pub enum InferDelegationKind<'hir> { +pub enum InferDelegationSig<'hir> { Input(usize), // Place generics info here, as we always specify output type for delegations. Output(&'hir DelegationGenerics), } +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)] +pub enum InferDelegation<'hir> { + /// Infer the type of this `DefId` through `tcx.type_of(def_id).instantiate_identity()`, + /// used for const types propagation. + DefId(DefId), + /// Used during signature inheritance, `DefId` corresponds to the signature function. + Sig(DefId, InferDelegationSig<'hir>), +} + /// The various kinds of types recognized by the compiler. /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: @@ -3794,7 +3784,7 @@ pub enum InferDelegationKind<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TyKind<'hir, Unambig = ()> { /// Actual type should be inherited from `DefId` signature - InferDelegation(DefId, InferDelegationKind<'hir>), + InferDelegation(InferDelegation<'hir>), /// A variable length slice (i.e., `[T]`). Slice(&'hir Ty<'hir>), /// A fixed length array (i.e., `[T; n]`). @@ -3945,7 +3935,7 @@ pub struct FnDecl<'hir> { impl<'hir> FnDecl<'hir> { pub fn opt_delegation_sig_id(&self) -> Option { if let FnRetTy::Return(ty) = self.output - && let TyKind::InferDelegation(sig_id, _) = ty.kind + && let TyKind::InferDelegation(InferDelegation::Sig(sig_id, _)) = ty.kind { return Some(sig_id); } @@ -3954,8 +3944,8 @@ pub fn opt_delegation_sig_id(&self) -> Option { pub fn opt_delegation_generics(&self) -> Option<&'hir DelegationGenerics> { if let FnRetTy::Return(ty) = self.output - && let TyKind::InferDelegation(_, kind) = ty.kind - && let InferDelegationKind::Output(generics) = kind + && let TyKind::InferDelegation(InferDelegation::Sig(_, kind)) = ty.kind + && let InferDelegationSig::Output(generics) = kind { return Some(generics); } diff --git a/compiler/rustc_hir/src/stability.rs b/compiler/rustc_hir/src/stability.rs index 9297f8e6cdcd..d00e1f2d4e8c 100644 --- a/compiler/rustc_hir/src/stability.rs +++ b/compiler/rustc_hir/src/stability.rs @@ -112,7 +112,6 @@ pub enum StabilityLevel { reason: UnstableReason, /// Relevant `rust-lang/rust` issue. issue: Option>, - is_soft: bool, /// If part of a feature is stabilized and a new feature is added for the remaining parts, /// then the `implied_by` attribute is used to indicate which now-stable feature previously /// contained an item. diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index a3f4415ec343..58649a694880 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -3,7 +3,7 @@ use crate::HashIgnoredAttrId; use crate::hir::{ - AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, + AttributeMap, BodyId, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, }; use crate::hir_id::ItemLocalId; use crate::lints::DelayedLints; @@ -94,13 +94,6 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { } } -impl HashStable for Crate<'_> { - fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - let Crate { owners: _, opt_hir_hash } = self; - opt_hir_hash.unwrap().hash_stable(hcx, hasher) - } -} - impl HashStable for HashIgnoredAttrId { fn hash_stable(&self, _hcx: &mut HirCtx, _hasher: &mut StableHasher) { /* we don't hash HashIgnoredAttrId, we ignore them */ diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index dd685c44ec47..07c33eb935f2 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -1,8 +1,4 @@ -//! This module implements some validity checks for attributes. -//! In particular it verifies that `#[inline]` and `#[repr]` attributes are -//! attached to items that actually support them and if there are -//! conflicts between multiple such attributes attached to the same -//! item. +//! This module lists attribute targets, with conversions from other types. use std::fmt::{self, Display}; diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 0ce93561ddd4..0dbd4333ed3c 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -19,7 +19,6 @@ rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } -rustc_lint = { path = "../rustc_lint" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4157b110fbf6..06ccf61a1620 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -24,7 +24,6 @@ TypeVisitable, TypeVisitableExt, fold_regions, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; -use rustc_span::source_map::Spanned; use rustc_target::spec::{AbiMap, AbiMapping}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits; @@ -216,7 +215,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { // SIMD types with invalid layout (e.g., zero-length) should emit an error Err(e @ LayoutError::InvalidSimd { .. }) => { let ty_span = tcx.ty_span(def_id); - tcx.dcx().emit_err(Spanned { span: ty_span, node: e.into_diagnostic() }); + tcx.dcx().span_err(ty_span, e.to_string()); return; } // Generic statics are rejected, but we still reach this case. @@ -953,10 +952,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.ensure_ok().type_of(def_id); tcx.ensure_ok().predicates_of(def_id); check_type_alias_type_params_are_used(tcx, def_id); + let ty = tcx.type_of(def_id).instantiate_identity(); + let span = tcx.def_span(def_id); if tcx.type_alias_is_lazy(def_id) { res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| { - let ty = tcx.type_of(def_id).instantiate_identity(); - let span = tcx.def_span(def_id); let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty); wfcx.register_wf_obligation( span, @@ -967,6 +966,30 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Ok(()) })); check_variances_for_type_defn(tcx, def_id); + } else { + res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| { + // HACK: We sometimes incidentally check that const arguments have the correct + // type as a side effect of the anon const desugaring. To make this "consistent" + // for users we explicitly check `ConstArgHasType` clauses so that const args + // that don't go through an anon const still have their types checked. + // + // We use the unnormalized type as this mirrors the behaviour that we previously + // would have had when all const arguments were anon consts. + // + // Changing this to normalized obligations is a breaking change: + // `type Bar = [(); panic!()];` would become an error + if let Some(unnormalized_obligations) = wfcx.unnormalized_obligations(span, ty) + { + let filtered_obligations = + unnormalized_obligations.into_iter().filter(|o| { + matches!(o.predicate.kind().skip_binder(), + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) + if matches!(ct.kind(), ty::ConstKind::Param(..))) + }); + wfcx.ocx.register_obligations(filtered_obligations) + } + Ok(()) + })); } // Only `Node::Item` and `Node::ForeignItem` still have HIR based @@ -1489,8 +1512,17 @@ fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalab return; } ScalableElt::Container if fields.is_empty() => { - let mut err = - tcx.dcx().struct_span_err(span, "scalable vectors must have a single field"); + let mut err = tcx + .dcx() + .struct_span_err(span, "scalable vector tuples must have at least one field"); + err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type"); + err.emit(); + return; + } + ScalableElt::Container if fields.len() > 8 => { + let mut err = tcx + .dcx() + .struct_span_err(span, "scalable vector tuples can have at most eight fields"); err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type"); err.emit(); return; diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 9443aaac2258..29213058d1d5 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -9,6 +9,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, E0806, struct_span_code_err}; use rustc_hir::attrs::EiiImplResolution; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -37,6 +38,14 @@ pub(crate) fn compare_eii_function_types<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { + // Error recovery can resolve the EII target to another value item with the same name, + // such as a tuple-struct constructor. Skip the comparison in that case and rely on the + // earlier name-resolution error instead of ICEing while building EII diagnostics. + // See . + if !is_foreign_function(tcx, foreign_item) { + return Ok(()); + } + check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?; let external_impl_span = tcx.def_span(external_impl); @@ -442,3 +451,7 @@ fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&' let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id); tcx.hir_fn_sig_by_hir_id(hir_id) } + +fn is_foreign_function(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + tcx.is_foreign_item(def_id) && matches!(tcx.def_kind(def_id), DefKind::Fn) +} diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index a1c8c0150a66..b1dc593331c6 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -111,10 +111,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::expf32 | sym::expf64 | sym::expf128 - | sym::fabsf16 - | sym::fabsf32 - | sym::fabsf64 - | sym::fabsf128 + | sym::fabs | sym::fadd_algebraic | sym::fdiv_algebraic | sym::field_offset @@ -147,22 +144,22 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::logf32 | sym::logf64 | sym::logf128 + | sym::maximum_number_nsz_f16 + | sym::maximum_number_nsz_f32 + | sym::maximum_number_nsz_f64 + | sym::maximum_number_nsz_f128 | sym::maximumf16 | sym::maximumf32 | sym::maximumf64 | sym::maximumf128 - | sym::maxnumf16 - | sym::maxnumf32 - | sym::maxnumf64 - | sym::maxnumf128 + | sym::minimum_number_nsz_f16 + | sym::minimum_number_nsz_f32 + | sym::minimum_number_nsz_f64 + | sym::minimum_number_nsz_f128 | sym::minimumf16 | sym::minimumf32 | sym::minimumf64 | sym::minimumf128 - | sym::minnumf16 - | sym::minnumf32 - | sym::minnumf64 - | sym::minnumf128 | sym::mul_with_overflow | sym::needs_drop | sym::offload @@ -463,25 +460,26 @@ pub(crate) fn check_intrinsic_type( (0, 0, vec![tcx.types.f128, tcx.types.f128, tcx.types.f128], tcx.types.f128) } - sym::fabsf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::fabsf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::fabsf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::fabsf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + sym::fabs => (1, 0, vec![param(0)], param(0)), - sym::minnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::minnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + sym::minimum_number_nsz_f16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::minimum_number_nsz_f32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::minimum_number_nsz_f64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::minimum_number_nsz_f128 => { + (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128) + } sym::minimumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), sym::minimumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), sym::minimumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), sym::minimumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + sym::maximum_number_nsz_f16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::maximum_number_nsz_f32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::maximum_number_nsz_f64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::maximum_number_nsz_f128 => { + (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128) + } sym::maximumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), sym::maximumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), @@ -722,8 +720,8 @@ pub(crate) fn check_intrinsic_type( | sym::simd_and | sym::simd_or | sym::simd_xor - | sym::simd_fmin - | sym::simd_fmax + | sym::simd_minimum_number_nsz + | sym::simd_maximum_number_nsz | sym::simd_saturating_add | sym::simd_saturating_sub | sym::simd_carryless_mul => (1, 0, vec![param(0), param(0)], param(0)), diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 0c611e6c4c9e..e31beca39083 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -11,14 +11,14 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Arm, Block, Expr, LetStmt, Pat, PatKind, Stmt}; use rustc_index::Idx; use rustc_middle::middle::region::*; use rustc_middle::ty::TyCtxt; use rustc_session::lint; -use rustc_span::source_map; +use rustc_span::Spanned; use tracing::debug; #[derive(Debug, Copy, Clone)] @@ -181,7 +181,7 @@ fn resolve_cond<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, cond: &'tcx hi // operands will be terminated). Any temporaries that would need to be dropped will be // dropped before we leave this operator's scope; terminating them here would be redundant. hir::ExprKind::Binary( - source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, + Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, _, _, ) => false, @@ -264,7 +264,7 @@ fn resolve_expr<'tcx>( // scopes, meaning that temporaries cannot outlive them. // This ensures fixed size stacks. hir::ExprKind::Binary( - source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, + Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, left, right, ) => { @@ -293,7 +293,7 @@ fn resolve_expr<'tcx>( // This is purely an optimization to reduce the number of // terminating scopes. hir::ExprKind::Binary( - source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, + Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, .., ) => false, // otherwise: mark it as terminating @@ -849,13 +849,13 @@ fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { /// re-use in incremental scenarios. We may sometimes need to rerun the /// type checker even when the HIR hasn't changed, and in those cases /// we can avoid reconstructing the region scope tree. -pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { - let typeck_root_def_id = tcx.typeck_root_def_id(def_id); +pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &ScopeTree { + let typeck_root_def_id = tcx.typeck_root_def_id_local(def_id); if typeck_root_def_id != def_id { return tcx.region_scope_tree(typeck_root_def_id); } - let scope_tree = if let Some(body) = tcx.hir_maybe_body_owned_by(def_id.expect_local()) { + let scope_tree = if let Some(body) = tcx.hir_maybe_body_owned_by(def_id) { let mut visitor = ScopeResolutionVisitor { tcx, scope_tree: ScopeTree::default(), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 5656c4566d9f..96d0a56f901a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -15,6 +15,7 @@ use rustc_hir::{AmbigArg, ItemKind, find_attr}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt}; +use rustc_infer::traits::PredicateObligations; use rustc_lint_defs::builtin::SHADOWING_SUPERTRAIT_ITEMS; use rustc_macros::Diagnostic; use rustc_middle::mir::interpret::ErrorHandled; @@ -124,6 +125,20 @@ pub(super) fn register_wf_obligation( ty::ClauseKind::WellFormed(term), )); } + + pub(super) fn unnormalized_obligations( + &self, + span: Span, + ty: Ty<'tcx>, + ) -> Option> { + traits::wf::unnormalized_obligations( + self.ocx.infcx, + self.param_env, + ty.into(), + span, + self.body_def_id, + ) + } } pub(super) fn enter_wf_checking_ctxt<'tcx, F>( @@ -140,7 +155,12 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( let mut wfcx = WfCheckingCtxt { ocx, body_def_id, param_env }; - if !tcx.features().trivial_bounds() { + // As of now, bounds are only checked on lazy type aliases, they're ignored for most type + // aliases. So, only check for false global bounds if we're not ignoring bounds altogether. + let ignore_bounds = + tcx.def_kind(body_def_id) == DefKind::TyAlias && !tcx.type_alias_is_lazy(body_def_id); + + if !ignore_bounds && !tcx.features().trivial_bounds() { wfcx.check_false_global_bounds() } f(&mut wfcx)?; @@ -998,7 +1018,7 @@ fn check_type_defn<'tcx>( item: &hir::Item<'tcx>, all_sized: bool, ) -> Result<(), ErrorGuaranteed> { - let _ = tcx.check_representability(item.owner_id.def_id); + tcx.ensure_ok().check_representability(item.owner_id.def_id); let adt_def = tcx.adt_def(item.owner_id); enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 866787a45718..ea98beb95580 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -76,12 +76,12 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { | Node::Ctor(..) | Node::Field(_) => { let parent_id = tcx.hir_get_parent_item(hir_id); - Some(parent_id.to_def_id()) + Some(parent_id.def_id) } // FIXME(#43408) always enable this once `lazy_normalization` is // stable enough and does not need a feature gate anymore. Node::AnonConst(_) => { - let parent_did = tcx.parent(def_id.to_def_id()); + let parent_did = tcx.local_parent(def_id); debug!(?parent_did); let mut in_param_ty = false; @@ -175,7 +175,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { } Node::ConstBlock(_) | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { - Some(tcx.typeck_root_def_id(def_id.to_def_id())) + Some(tcx.typeck_root_def_id_local(def_id)) } Node::OpaqueTy(&hir::OpaqueTy { origin: @@ -188,7 +188,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { } else { assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn); } - Some(fn_def_id.to_def_id()) + Some(fn_def_id) } Node::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty }, @@ -202,7 +202,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent); // Opaque types are always nested within another item, and // inherit the generics of the item. - Some(parent.to_def_id()) + Some(parent) } // All of these nodes have no parent from which to inherit generics. @@ -380,7 +380,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { own_params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { - parent: parent_def_id, + parent: parent_def_id.map(LocalDefId::to_def_id), parent_count, own_params, param_def_id_to_index, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e16fa5492979..8fd3d631962c 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -107,7 +107,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ); return ty::GenericPredicates { - parent: Some(tcx.parent(def_id.to_def_id())), + parent: Some(tcx.local_parent(def_id).to_def_id()), predicates: tcx.arena.alloc_from_iter(predicates), }; } @@ -1069,6 +1069,9 @@ pub(super) fn const_conditions<'tcx>( }, // N.B. Tuple ctors are unconditionally constant. Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(), + Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_), .. }) => { + (hir::Generics::empty(), None, tcx.is_conditionally_const(tcx.local_parent(def_id))) + } _ => bug!("const_conditions called on wrong item: {def_id:?}"), }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 18244d62f2ae..5bb4166bf6cb 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -925,7 +925,7 @@ fn visit_fn( hir::FnRetTy::Return(ty) => Some(ty), }; if let Some(ty) = output - && let hir::TyKind::InferDelegation(sig_id, _) = ty.kind + && let hir::TyKind::InferDelegation(hir::InferDelegation::Sig(sig_id, _)) = ty.kind { let bound_vars: Vec<_> = self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect(); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 23df419d06a7..e65efd6880b8 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -4,8 +4,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::{self as hir, AmbigArg, HirId}; -use rustc_middle::query::plumbing::CyclePlaceholder; -use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_middle::ty::print::{with_forced_trimmed_paths, with_types_for_suggestion}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefiningScopeKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; @@ -183,10 +182,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } }, - Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else( - |CyclePlaceholder(guar)| Ty::new_error(tcx, guar), - |ty| ty.instantiate_identity(), - ), + Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).instantiate_identity(), Node::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { @@ -249,12 +245,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } } -pub(super) fn type_of_opaque( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> Result>, CyclePlaceholder> { +pub(super) fn type_of_opaque(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_, Ty<'_>> { if let Some(def_id) = def_id.as_local() { - Ok(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin { + match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin { hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => { opaque::find_opaque_ty_constraints_for_tait( tcx, @@ -287,11 +280,11 @@ pub(super) fn type_of_opaque( DefiningScopeKind::MirBorrowck, ) } - }) + } } else { // Foreign opaque type will go through the foreign provider // and load the type from metadata. - Ok(tcx.type_of(def_id)) + tcx.type_of(def_id) } } @@ -458,7 +451,7 @@ fn infer_placeholder_type<'tcx>( err.span_suggestion( ty_span, format!("provide a type for the {kind}"), - format!("{colon} {ty}"), + with_types_for_suggestion!(format!("{colon} {ty}")), Applicability::MachineApplicable, ); } else { diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index ad23868fffd6..730288574e76 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -138,7 +138,6 @@ fn create_mapping<'tcx>( tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId, - args: &[ty::GenericArg<'tcx>], ) -> FxHashMap { let mut mapping: FxHashMap = Default::default(); @@ -176,13 +175,6 @@ fn create_mapping<'tcx>( } } - // If there are still unmapped lifetimes left and we are to map types and maybe self - // then skip them, now it is the case when we generated more lifetimes then needed. - // FIXME(fn_delegation): proper support for late bound lifetimes. - while args_index < args.len() && args[args_index].as_region().is_some() { - args_index += 1; - } - // If self after lifetimes insert mapping, relying that self is at 0 in sig parent. if matches!(self_pos_kind, SelfPositionKind::AfterLifetimes) { mapping.insert(0, args_index as u32); @@ -339,10 +331,14 @@ fn create_generic_args<'tcx>( | (FnKind::AssocTrait, FnKind::AssocTrait) => delegation_args, (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { - // Special case, as user specifies Trait args in impl trait header, we want to treat - // them as parent args. + // Special case, as user specifies Trait args in trait impl header, we want to treat + // them as parent args. We always generate a function whose generics match + // child generics in trait. let parent = tcx.local_parent(delegation_id); parent_args = tcx.impl_trait_header(parent).trait_ref.instantiate_identity().args; + + assert!(child_args.is_empty(), "Child args can not be used in trait impl case"); + tcx.mk_args(&delegation_args[delegation_parent_args_count..]) } @@ -507,7 +503,7 @@ fn create_folder_and_args<'tcx>( child_args: &'tcx [ty::GenericArg<'tcx>], ) -> (ParamIndexRemapper<'tcx>, Vec>) { let args = create_generic_args(tcx, sig_id, def_id, parent_args, child_args); - let remap_table = create_mapping(tcx, sig_id, def_id, &args); + let remap_table = create_mapping(tcx, sig_id, def_id); (ParamIndexRemapper { tcx, remap_table }, args) } @@ -597,31 +593,35 @@ fn get_delegation_user_specified_args<'tcx>( .as_slice() }); - let child_args = info.child_args_segment_id.and_then(get_segment).map(|(segment, def_id)| { - let parent_args = if let Some(parent_args) = parent_args { - parent_args - } else { - let parent = tcx.parent(def_id); - if matches!(tcx.def_kind(parent), DefKind::Trait) { - ty::GenericArgs::identity_for_item(tcx, parent).as_slice() + let child_args = info + .child_args_segment_id + .and_then(get_segment) + .filter(|(_, def_id)| matches!(tcx.def_kind(*def_id), DefKind::Fn | DefKind::AssocFn)) + .map(|(segment, def_id)| { + let parent_args = if let Some(parent_args) = parent_args { + parent_args } else { - &[] - } - }; + let parent = tcx.parent(def_id); + if matches!(tcx.def_kind(parent), DefKind::Trait) { + ty::GenericArgs::identity_for_item(tcx, parent).as_slice() + } else { + &[] + } + }; - let args = lowerer - .lower_generic_args_of_path( - segment.ident.span, - def_id, - parent_args, - segment, - None, - GenericArgPosition::Value, - ) - .0; + let args = lowerer + .lower_generic_args_of_path( + segment.ident.span, + def_id, + parent_args, + segment, + None, + GenericArgPosition::Value, + ) + .0; - &args[parent_args.len()..] - }); + &args[parent_args.len()..] + }); (parent_args.unwrap_or_default(), child_args.unwrap_or_default()) } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1c999f1ffc93..fcd4cb938bf7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1807,6 +1807,13 @@ pub(crate) struct CmseImplTrait { pub(crate) struct BadReturnTypeNotation { #[primary_span] pub span: Span, + #[suggestion( + "furthermore, argument types not allowed with return type notation", + applicability = "maybe-incorrect", + code = "(..)", + style = "verbose" + )] + pub suggestion: Option, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 8397ff61a3b3..a498e9740388 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -231,8 +231,9 @@ pub(super) fn lower_trait_object_ty( ordered_associated_items.extend( tcx.associated_items(pred.trait_ref.def_id) .in_definition_order() - // Only associated types & consts can possibly be constrained via a binding. - .filter(|item| item.is_type() || item.is_const()) + // Only associated types & type consts can possibly be + // constrained in a trait object type via a binding. + .filter(|item| item.is_type() || item.is_type_const()) // Traits with RPITITs are simply not dyn compatible (for now). .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| (item.def_id, trait_ref)), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index bf97bfb1ebbc..91660fc65537 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -26,7 +26,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, FatalError, Level, + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, FatalError, Level, StashKey, struct_span_code_err, }; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -2830,6 +2830,7 @@ fn lower_resolved_const_path( | Res::SelfCtor(_) | Res::Local(_) | Res::ToolMod + | Res::OpenMod(..) | Res::NonMacroAttr(_) | Res::Err) => Const::new_error_with_message( tcx, @@ -2874,6 +2875,9 @@ fn lower_const_arg_literal( span: Span, ) -> Const<'tcx> { let tcx = self.tcx(); + + let ty = if !ty.has_infer() { Some(ty) } else { None }; + if let LitKind::Err(guar) = *kind { return ty::Const::new_error(tcx, guar); } @@ -2905,16 +2909,20 @@ fn try_lower_anon_const_lit( }; let lit_input = match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }), + hir::ExprKind::Lit(lit) => { + Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: false }) + } hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }), + hir::ExprKind::Lit(lit) => { + Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: true }) + } _ => None, }, _ => None, }; lit_input.and_then(|l| { - if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) { + if const_lit_matches_ty(tcx, &l.lit, ty, l.neg) { tcx.at(expr.span) .lit_to_const(l) .map(|value| ty::Const::new_value(tcx, value.valtree, value.ty)) @@ -2939,7 +2947,7 @@ fn require_type_const_attribute( ); if def_id.is_local() { let name = tcx.def_path_str(def_id); - err.span_suggestion( + err.span_suggestion_verbose( tcx.def_span(def_id).shrink_to_lo(), format!("add `type` before `const` for `{name}`"), format!("type "), @@ -2952,12 +2960,19 @@ fn require_type_const_attribute( } } - fn lower_delegation_ty(&self, idx: hir::InferDelegationKind<'tcx>) -> Ty<'tcx> { - let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id()); + fn lower_delegation_ty(&self, infer: hir::InferDelegation<'tcx>) -> Ty<'tcx> { + match infer { + hir::InferDelegation::DefId(def_id) => { + self.tcx().type_of(def_id).instantiate_identity() + } + rustc_hir::InferDelegation::Sig(_, idx) => { + let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id()); - match idx { - hir::InferDelegationKind::Input(idx) => delegation_sig[idx], - hir::InferDelegationKind::Output { .. } => *delegation_sig.last().unwrap(), + match idx { + hir::InferDelegationSig::Input(idx) => delegation_sig[idx], + hir::InferDelegationSig::Output { .. } => *delegation_sig.last().unwrap(), + } + } } } @@ -2967,7 +2982,7 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx(); let result_ty = match &hir_ty.kind { - hir::TyKind::InferDelegation(_, idx) => self.lower_delegation_ty(*idx), + hir::TyKind::InferDelegation(infer) => self.lower_delegation_ty(*infer), hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)), hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl), hir::TyKind::Ref(region, mt) => { @@ -3008,7 +3023,9 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { - let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + let guar = self + .dcx() + .emit_err(BadReturnTypeNotation { span: hir_ty.span, suggestion: None }); Ty::new_error(tcx, guar) } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { @@ -3070,12 +3087,95 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { // If we encounter a type relative path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore // it's certainly in an illegal position. - hir::TyKind::Path(hir::QPath::TypeRelative(_, segment)) + hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) if segment.args.is_some_and(|args| { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { - let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + let guar = if let hir::Node::LetStmt(stmt) = tcx.parent_hir_node(hir_ty.hir_id) + && let None = stmt.init + && let hir::TyKind::Path(hir::QPath::Resolved(_, self_ty_path)) = + hir_self_ty.kind + && let Res::Def(DefKind::Enum | DefKind::Struct | DefKind::Union, def_id) = + self_ty_path.res + && let Some(_) = tcx + .inherent_impls(def_id) + .iter() + .flat_map(|imp| { + tcx.associated_items(*imp).filter_by_name_unhygienic(segment.ident.name) + }) + .filter(|assoc| { + matches!(assoc.kind, ty::AssocKind::Fn { has_self: false, .. }) + }) + .next() + { + // `let x: S::new(valid_in_ty_ctxt);` -> `let x = S::new(valid_in_ty_ctxt);` + let err = tcx + .dcx() + .struct_span_err( + hir_ty.span, + "expected type, found associated function call", + ) + .with_span_suggestion_verbose( + stmt.pat.span.between(hir_ty.span), + "use `=` if you meant to assign", + " = ".to_string(), + Applicability::MaybeIncorrect, + ); + self.dcx().try_steal_replace_and_emit_err( + hir_ty.span, + StashKey::ReturnTypeNotation, + err, + ) + } else if let hir::Node::LetStmt(stmt) = tcx.parent_hir_node(hir_ty.hir_id) + && let None = stmt.init + && let hir::TyKind::Path(hir::QPath::Resolved(_, self_ty_path)) = + hir_self_ty.kind + && let Res::PrimTy(_) = self_ty_path.res + && self.dcx().has_stashed_diagnostic(hir_ty.span, StashKey::ReturnTypeNotation) + { + // `let x: i32::something(valid_in_ty_ctxt);` -> `let x = i32::something(valid_in_ty_ctxt);` + // FIXME: Check that `something` is a valid function in `i32`. + let err = tcx + .dcx() + .struct_span_err( + hir_ty.span, + "expected type, found associated function call", + ) + .with_span_suggestion_verbose( + stmt.pat.span.between(hir_ty.span), + "use `=` if you meant to assign", + " = ".to_string(), + Applicability::MaybeIncorrect, + ); + self.dcx().try_steal_replace_and_emit_err( + hir_ty.span, + StashKey::ReturnTypeNotation, + err, + ) + } else { + let suggestion = if self + .dcx() + .has_stashed_diagnostic(hir_ty.span, StashKey::ReturnTypeNotation) + { + // We already created a diagnostic complaining that `foo(bar)` is wrong and + // should have been `foo(..)`. Instead, emit only the current error and + // include that prior suggestion. Changes are that the problems go further, + // but keep the suggestion just in case. Either way, we want a single error + // instead of two. + Some(segment.ident.span.shrink_to_hi().with_hi(hir_ty.span.hi())) + } else { + None + }; + let err = self + .dcx() + .create_err(BadReturnTypeNotation { span: hir_ty.span, suggestion }); + self.dcx().try_steal_replace_and_emit_err( + hir_ty.span, + StashKey::ReturnTypeNotation, + err, + ) + }; Ty::new_error(tcx, guar) } hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 0e8bc9ad5822..937bcee01161 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -85,8 +85,6 @@ use rustc_abi::{CVariadicStatus, ExternAbi}; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::lints::DelayedLint; -use rustc_lint::DecorateAttrLint; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{Const, Ty, TyCtxt}; @@ -147,23 +145,6 @@ pub fn provide(providers: &mut Providers) { }; } -pub fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { - match lint { - DelayedLint::AttributeParsing(attribute_lint) => { - tcx.emit_node_span_lint( - attribute_lint.lint_id.lint, - attribute_lint.id, - attribute_lint.span, - DecorateAttrLint { - sess: tcx.sess, - tcx: Some(tcx), - diagnostic: &attribute_lint.kind, - }, - ); - } - } -} - pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); @@ -182,42 +163,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _: R = tcx.ensure_result().crate_inherent_impls_overlap_check(()); }); - tcx.sess.time("emit_ast_lowering_delayed_lints", || { - // sanity check in debug mode that all lints are really noticed - // and we really will emit them all in the loop right below. - // - // during ast lowering, when creating items, foreign items, trait items and impl items - // we store in them whether they have any lints in their owner node that should be - // picked up by `hir_crate_items`. However, theoretically code can run between that - // boolean being inserted into the item and the owner node being created. - // We don't want any new lints to be emitted there - // (though honestly, you have to really try to manage to do that but still), - // but this check is there to catch that. - #[cfg(debug_assertions)] - { - // iterate over all owners - for owner_id in tcx.hir_crate_items(()).owners() { - // if it has delayed lints - if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { - if !delayed_lints.lints.is_empty() { - // assert that delayed_lint_items also picked up this item to have lints - assert!( - tcx.hir_crate_items(()).delayed_lint_items().any(|i| i == owner_id) - ); - } - } - } - } - - for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { - if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { - for lint in &delayed_lints.lints { - emit_delayed_lint(lint, tcx); - } - } - } - }); - tcx.par_hir_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); // Make sure we evaluate all static and (non-associated) const items, even if unused. diff --git a/compiler/rustc_hir_id/src/lib.rs b/compiler/rustc_hir_id/src/lib.rs index d07bc88e66af..d6deed59b625 100644 --- a/compiler/rustc_hir_id/src/lib.rs +++ b/compiler/rustc_hir_id/src/lib.rs @@ -151,7 +151,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// integers starting at zero, so a mapping that maps all or most nodes within /// an "item-like" to something else can be implemented by a `Vec` instead of a /// tree or hash map. - #[derive(HashStable_Generic)] + #[stable_hash_generic] #[encodable] #[orderable] pub struct ItemLocalId {} diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e806d72d3dd2..82540a932741 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -23,8 +23,8 @@ GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TyFieldPath, TyPatKind, }; -use rustc_span::source_map::{SourceMap, Spanned}; -use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym}; +use rustc_span::source_map::SourceMap; +use rustc_span::{DUMMY_SP, FileName, Ident, Span, Spanned, Symbol, kw, sym}; pub fn id_to_string(cx: &dyn rustc_hir::intravisit::HirTyCtxt<'_>, hir_id: HirId) -> String { to_string(&cx, |s| s.print_node(cx.hir_node(hir_id))) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 82b7c578a1f2..1a9c2a21c7ef 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -72,7 +72,7 @@ pub(crate) fn check_expr_closure( debug!(?bound_sig, ?liberated_sig); let parent_args = - GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id())); + GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id_local(expr_def_id)); let tupled_upvars_ty = self.next_ty_var(expr_span); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 8a73125d6476..bfc677046e0f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -114,6 +114,26 @@ fn success<'tcx>( Ok(InferOk { value: (adj, target), obligations }) } +/// Data extracted from a reference (pinned or not) for coercion to a reference (pinned or not). +struct CoerceMaybePinnedRef<'tcx> { + /// coercion source, must be a pinned (i.e. `Pin<&T>` or `Pin<&mut T>`) or normal reference (`&T` or `&mut T`) + a: Ty<'tcx>, + /// coercion target, must be a pinned (i.e. `Pin<&T>` or `Pin<&mut T>`) or normal reference (`&T` or `&mut T`) + b: Ty<'tcx>, + /// referent type of the source + a_ty: Ty<'tcx>, + /// pinnedness of the source + a_pin: ty::Pinnedness, + /// mutability of the source + a_mut: ty::Mutability, + /// region of the source + a_r: ty::Region<'tcx>, + /// pinnedness of the target + b_pin: ty::Pinnedness, + /// mutability of the target + b_mut: ty::Mutability, +} + /// Whether to force a leak check to occur in `Coerce::unify_raw`. /// Note that leak checks may still occur evn with `ForceLeakCheck::No`. /// @@ -269,16 +289,13 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { return self.coerce_to_raw_ptr(a, b, b_mutbl); } ty::Ref(r_b, _, mutbl_b) => { + if let Some(pin_ref_to_ref) = self.maybe_pin_ref_to_ref(a, b) { + return self.coerce_pin_ref_to_ref(pin_ref_to_ref); + } return self.coerce_to_ref(a, b, r_b, mutbl_b); } - ty::Adt(pin, _) - if self.tcx.features().pin_ergonomics() - && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => - { - let pin_coerce = self.commit_if_ok(|_| self.coerce_to_pin_ref(a, b)); - if pin_coerce.is_ok() { - return pin_coerce; - } + _ if let Some(to_pin_ref) = self.maybe_to_pin_ref(a, b) => { + return self.coerce_to_pin_ref(to_pin_ref); } _ => {} } @@ -790,61 +807,131 @@ fn coerce_unsized_old_solver( Ok(()) } - /// Applies reborrowing for `Pin` + /// Create an obligation for `ty: Unpin`, where . + fn unpin_obligation( + &self, + source: Ty<'tcx>, + target: Ty<'tcx>, + ty: Ty<'tcx>, + ) -> PredicateObligation<'tcx> { + let pred = ty::TraitRef::new( + self.tcx, + self.tcx.require_lang_item(hir::LangItem::Unpin, self.cause.span), + [ty], + ); + let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target }); + PredicateObligation::new(self.tcx, cause, self.param_env, pred) + } + + /// Checks if the given types are compatible for coercion from a pinned reference to a normal reference. + fn maybe_pin_ref_to_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> Option> { + if !self.tcx.features().pin_ergonomics() { + return None; + } + if let Some((a_ty, a_pin @ ty::Pinnedness::Pinned, a_mut, a_r)) = a.maybe_pinned_ref() + && let Some((_, b_pin @ ty::Pinnedness::Not, b_mut, _)) = b.maybe_pinned_ref() + { + return Some(CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut }); + } + debug!("not fitting pinned ref to ref coercion (`{:?}` -> `{:?}`)", a, b); + None + } + + /// Coerces from a pinned reference to a normal reference. + #[instrument(skip(self), level = "trace")] + fn coerce_pin_ref_to_ref( + &self, + CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut }: CoerceMaybePinnedRef< + 'tcx, + >, + ) -> CoerceResult<'tcx> { + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); + debug_assert!(self.tcx.features().pin_ergonomics()); + debug_assert_eq!(a_pin, ty::Pinnedness::Pinned); + debug_assert_eq!(b_pin, ty::Pinnedness::Not); + + coerce_mutbls(a_mut, b_mut)?; + + let unpin_obligation = self.unpin_obligation(a, b, a_ty); + + let a = Ty::new_ref(self.tcx, a_r, a_ty, b_mut); + let mut coerce = self.unify_and( + a, + b, + [Adjustment { kind: Adjust::Deref(DerefAdjustKind::Pin), target: a_ty }], + Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::new(b_mut, self.allow_two_phase))), + ForceLeakCheck::No, + )?; + coerce.obligations.push(unpin_obligation); + Ok(coerce) + } + + /// Checks if the given types are compatible for coercion to a pinned reference. + fn maybe_to_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> Option> { + if !self.tcx.features().pin_ergonomics() { + return None; + } + if let Some((a_ty, a_pin, a_mut, a_r)) = a.maybe_pinned_ref() + && let Some((_, b_pin @ ty::Pinnedness::Pinned, b_mut, _)) = b.maybe_pinned_ref() + { + return Some(CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut }); + } + debug!("not fitting ref to pinned ref coercion (`{:?}` -> `{:?}`)", a, b); + None + } + + /// Applies reborrowing and auto-borrowing that results to `Pin<&T>` or `Pin<&mut T>`: /// - /// We currently only support reborrowing `Pin<&mut T>` as `Pin<&mut T>`. This is accomplished - /// by inserting a call to `Pin::as_mut` during MIR building. + /// Currently we only support the following coercions: + /// - Reborrowing `Pin<&mut T>` -> `Pin<&mut T>` + /// - Reborrowing `Pin<&T>` -> `Pin<&T>` + /// - Auto-borrowing `&mut T` -> `Pin<&mut T>` where `T: Unpin` + /// - Auto-borrowing `&mut T` -> `Pin<&T>` where `T: Unpin` + /// - Auto-borrowing `&T` -> `Pin<&T>` where `T: Unpin` /// /// In the future we might want to support other reborrowing coercions, such as: - /// - `Pin<&mut T>` as `Pin<&T>` - /// - `Pin<&T>` as `Pin<&T>` /// - `Pin>` as `Pin<&T>` /// - `Pin>` as `Pin<&mut T>` #[instrument(skip(self), level = "trace")] - fn coerce_to_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + fn coerce_to_pin_ref( + &self, + CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut }: CoerceMaybePinnedRef< + 'tcx, + >, + ) -> CoerceResult<'tcx> { debug_assert!(self.shallow_resolve(a) == a); debug_assert!(self.shallow_resolve(b) == b); + debug_assert!(self.tcx.features().pin_ergonomics()); + debug_assert_eq!(b_pin, ty::Pinnedness::Pinned); - // We need to make sure the two types are compatible for coercion. - // Then we will build a ReborrowPin adjustment and return that as an InferOk. - - // Right now we can only reborrow if this is a `Pin<&mut T>`. - let extract_pin_mut = |ty: Ty<'tcx>| { - // Get the T out of Pin - let (pin, ty) = match ty.kind() { - ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { - (*pin, args[0].expect_ty()) - } - _ => { - debug!("can't reborrow {:?} as pinned", ty); - return Err(TypeError::Mismatch); - } - }; - // Make sure the T is something we understand (just `&mut U` for now) - match ty.kind() { - ty::Ref(region, ty, mutbl) => Ok((pin, *region, *ty, *mutbl)), - _ => { - debug!("can't reborrow pin of inner type {:?}", ty); - Err(TypeError::Mismatch) - } + // We need to deref the reference first before we reborrow it to a pinned reference. + let (deref, unpin_obligation) = match a_pin { + // no `Unpin` required when reborrowing a pinned reference to a pinned reference + ty::Pinnedness::Pinned => (DerefAdjustKind::Pin, None), + // `Unpin` required when reborrowing a non-pinned reference to a pinned reference + ty::Pinnedness::Not => { + (DerefAdjustKind::Builtin, Some(self.unpin_obligation(a, b, a_ty))) } }; - let (pin, a_region, a_ty, mut_a) = extract_pin_mut(a)?; - let (_, _, _b_ty, mut_b) = extract_pin_mut(b)?; - - coerce_mutbls(mut_a, mut_b)?; + coerce_mutbls(a_mut, b_mut)?; // update a with b's mutability since we'll be coercing mutability - let a = Ty::new_adt( - self.tcx, - pin, - self.tcx.mk_args(&[Ty::new_ref(self.tcx, a_region, a_ty, mut_b).into()]), - ); + let a = Ty::new_pinned_ref(self.tcx, a_r, a_ty, b_mut); // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. - self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b), ForceLeakCheck::No) + let mut coerce = self.unify_and( + a, + b, + [Adjustment { kind: Adjust::Deref(deref), target: a_ty }], + Adjust::Borrow(AutoBorrow::Pin(b_mut)), + ForceLeakCheck::No, + )?; + + coerce.obligations.extend(unpin_obligation); + Ok(coerce) } fn coerce_from_fn_pointer( diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 5c6a66403019..6eef15684697 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -14,8 +14,7 @@ use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; -use rustc_span::source_map::Spanned; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{Ident, Span, Spanned, Symbol}; use crate::FnCtxt; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2de101a1e452..872328535ce6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -34,8 +34,7 @@ use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; -use rustc_span::source_map::Spanned; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Span, Spanned, Symbol, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; use tracing::{debug, instrument, trace}; @@ -1661,14 +1660,6 @@ fn check_expr_array( expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let element_ty = if !args.is_empty() { - // This shouldn't happen unless there's another error - // (e.g., never patterns in inappropriate contexts). - if self.diverges.get() != Diverges::Maybe { - self.dcx() - .struct_span_err(expr.span, "unexpected divergence state in checking array") - .delay_as_bug(); - } - let coerce_to = expected .to_option(self) .and_then(|uty| { @@ -1792,27 +1783,24 @@ fn check_expr_repeat( fn check_expr_tuple( &self, - elts: &'tcx [hir::Expr<'tcx>], + elements: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { - let flds = expected.only_has_type(self).and_then(|ty| { - let ty = self.try_structurally_resolve_type(expr.span, ty); - match ty.kind() { - ty::Tuple(flds) => Some(&flds[..]), - _ => None, - } + let mut expectations = expected + .only_has_type(self) + .and_then(|ty| self.try_structurally_resolve_type(expr.span, ty).opt_tuple_fields()) + .unwrap_or_default() + .iter(); + + let elements = elements.iter().map(|e| { + let ty = expectations.next().unwrap_or_else(|| self.next_ty_var(e.span)); + self.check_expr_coercible_to_type(e, ty, None); + ty }); - let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds { - Some(fs) if i < fs.len() => { - let ety = fs[i]; - self.check_expr_coercible_to_type(e, ety, None); - ety - } - _ => self.check_expr_with_expectation(e, NoExpectation), - }); - let tuple = Ty::new_tup_from_iter(self.tcx, elt_ts_iter); + let tuple = Ty::new_tup_from_iter(self.tcx, elements); + if let Err(guar) = tuple.error_reported() { Ty::new_error(self.tcx, guar) } else { @@ -1883,7 +1871,7 @@ fn check_expr_struct_fields( if !ocx.try_evaluate_obligations().is_empty() { return Err(TypeError::Mismatch); } - Ok(self.resolve_vars_if_possible(adt_ty)) + Ok(adt_ty) }) .ok() }); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 0a492c795b29..b6dfda33142c 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -736,7 +736,7 @@ fn walk_adjustment(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { self.consume_or_copy(&place_with_id, place_with_id.hir_id); } - adjustment::Adjust::Deref(DerefAdjustKind::Builtin) => {} + adjustment::Adjust::Deref(DerefAdjustKind::Builtin | DerefAdjustKind::Pin) => {} // Autoderefs for overloaded Deref calls in fact reference // their receiver. That is, if we have `(*x)` where `x` @@ -791,7 +791,7 @@ fn walk_autoref( ); } - adjustment::AutoBorrow::RawPtr(m) => { + adjustment::AutoBorrow::RawPtr(m) | adjustment::AutoBorrow::Pin(m) => { debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place); self.delegate.borrow_mut().borrow( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index c24d1127d5a6..f817ca842147 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -331,6 +331,9 @@ pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec { // FIXME(const_trait_impl): We *could* enforce `&T: [const] Deref` here. } + Adjust::Deref(DerefAdjustKind::Pin) => { + // FIXME(const_trait_impl): We *could* enforce `Pin<&T>: [const] Deref` here. + } Adjust::Pointer(_pointer_coercion) => { // FIXME(const_trait_impl): We should probably enforce these. } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9faa75e18480..0471fd965cd8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -11,7 +11,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal}; +use rustc_hir::{Expr, ExprKind, FnRetTy, HirId, LangItem, Node, QPath, is_range_literal}; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants}; use rustc_index::IndexVec; @@ -276,12 +276,7 @@ pub(in super::super) fn check_argument_types( // Record all the argument types, with the args // produced from the above subtyping unification. - Ok(Some( - formal_input_tys - .iter() - .map(|&ty| self.resolve_vars_if_possible(ty)) - .collect(), - )) + Ok(Some(formal_input_tys.to_vec())) }) .ok() }) @@ -1587,6 +1582,45 @@ struct MismatchedParam<'a> { } } err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); + if let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(def_id) + && let ty::Param(_) = + self.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output().kind() + && let parent = self.tcx.hir_get_parent_item(call_expr.hir_id).def_id + && let Some((output, body_id)) = match self.tcx.hir_node_by_def_id(parent) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn { sig, body, .. }, + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body)), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(sig, body), + .. + }) => Some((sig.decl.output, body)), + _ => None, + } + && let expr = self.tcx.hir_body(*body_id).value + && (expr.peel_blocks().span == call_expr.span + || matches!( + self.tcx.parent_hir_node(call_expr.hir_id), + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. }) + )) + { + err.span_label( + output.span(), + match output { + FnRetTy::DefaultReturn(_) => format!( + "this implicit `()` return type influences the call expression's return type" + ), + FnRetTy::Return(_) => { + "this return type influences the call expression's return type" + .to_string() + } + }, + ); + } } else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id) && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 801f5acf9d2f..a2f4c57bd442 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -23,8 +23,7 @@ suggest_constraining_type_params, }; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::source_map::Spanned; -use rustc_span::{ExpnKind, Ident, MacroKind, Span, Symbol, sym}; +use rustc_span::{ExpnKind, Ident, MacroKind, Span, Spanned, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 77c95fd55be3..fe8a9a9fb4f7 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -41,7 +41,7 @@ use fn_ctxt::FnCtxt; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; -use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, HirIdMap, Node}; @@ -82,7 +82,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { +fn typeck_root<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { typeck_with_inspect(tcx, def_id, None) } @@ -95,6 +95,13 @@ pub fn inspect_typeck<'tcx>( def_id: LocalDefId, inspect: ObligationInspector<'tcx>, ) -> &'tcx ty::TypeckResults<'tcx> { + // Closures' typeck results come from their outermost function, + // as they are part of the same "inference environment". + let typeck_root_def_id = tcx.typeck_root_def_id_local(def_id); + if typeck_root_def_id != def_id { + return tcx.typeck(typeck_root_def_id); + } + typeck_with_inspect(tcx, def_id, Some(inspect)) } @@ -104,12 +111,7 @@ fn typeck_with_inspect<'tcx>( def_id: LocalDefId, inspector: Option>, ) -> &'tcx ty::TypeckResults<'tcx> { - // Closures' typeck results come from their outermost function, - // as they are part of the same "inference environment". - let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); - if typeck_root_def_id != def_id { - return tcx.typeck(typeck_root_def_id); - } + assert!(!tcx.is_typeck_child(def_id.to_def_id())); let id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(id); @@ -204,7 +206,9 @@ fn typeck_with_inspect<'tcx>( ); } - fcx.check_expr_coercible_to_type(body.value, expected_type, None); + fcx.check_expr_coercible_to_type_or_error(body.value, expected_type, None, |err, _| { + extend_err_with_const_context(err, tcx, node, expected_type); + }); fcx.write_ty(id, expected_type); }; @@ -274,6 +278,126 @@ fn typeck_with_inspect<'tcx>( typeck_results } +fn extend_err_with_const_context( + err: &mut Diag<'_>, + tcx: TyCtxt<'_>, + node: hir::Node<'_>, + expected_ty: Ty<'_>, +) { + match node { + hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, _), .. }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(ty, _, _), .. + }) => { + // Point at the `Type` in `const NAME: Type = value;`. + err.span_label(ty.span, "expected because of the type of the associated constant"); + } + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, ty, _), .. }) => { + // Point at the `Type` in `const NAME: Type = value;`. + err.span_label(ty.span, "expected because of the type of the constant"); + } + hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(_, _, ty, _), .. }) => { + // Point at the `Type` in `static NAME: Type = value;`. + err.span_label(ty.span, "expected because of the type of the static"); + } + hir::Node::AnonConst(anon) + if let hir::Node::ConstArg(parent) = tcx.parent_hir_node(anon.hir_id) + && let hir::Node::Ty(parent) = tcx.parent_hir_node(parent.hir_id) + && let hir::TyKind::Array(_ty, _len) = parent.kind => + { + // `[type; len]` in type context. + err.note("array length can only be `usize`"); + } + hir::Node::AnonConst(anon) + if let hir::Node::ConstArg(parent) = tcx.parent_hir_node(anon.hir_id) + && let hir::Node::Expr(parent) = tcx.parent_hir_node(parent.hir_id) + && let hir::ExprKind::Repeat(_ty, _len) = parent.kind => + { + // `[type; len]` in expr context. + err.note("array length can only be `usize`"); + } + // FIXME: support method calls too. + hir::Node::AnonConst(anon) + if let hir::Node::ConstArg(parent) = tcx.parent_hir_node(anon.hir_id) + && let hir::Node::Expr(expr) = tcx.parent_hir_node(parent.hir_id) + && let hir::ExprKind::Path(path) = expr.kind + && let hir::QPath::Resolved(_, path) = path + && let Res::Def(_, def_id) = path.res => + { + // `foo()` in expression context, point at `foo`'s const parameter. + if let Some(i) = + path.segments.iter().last().and_then(|segment| segment.args).and_then(|args| { + args.args.iter().position(|arg| { + matches!(arg, hir::GenericArg::Const(arg) if arg.hir_id == parent.hir_id) + }) + }) + { + let generics = tcx.generics_of(def_id); + let param = &generics.param_at(i, tcx); + let sp = tcx.def_span(param.def_id); + err.span_note(sp, "expected because of the type of the const parameter"); + } + } + hir::Node::AnonConst(anon) + if let hir::Node::ConstArg(parent) = tcx.parent_hir_node(anon.hir_id) + && let hir::Node::Ty(ty) = tcx.parent_hir_node(parent.hir_id) + && let hir::TyKind::Path(path) = ty.kind + && let hir::QPath::Resolved(_, path) = path + && let Res::Def(_, def_id) = path.res => + { + // `Foo` in type context, point at `Foo`'s const parameter. + if let Some(i) = + path.segments.iter().last().and_then(|segment| segment.args).and_then(|args| { + args.args.iter().position(|arg| { + matches!(arg, hir::GenericArg::Const(arg) if arg.hir_id == parent.hir_id) + }) + }) + { + let generics = tcx.generics_of(def_id); + let param = &generics.param_at(i, tcx); + let sp = tcx.def_span(param.def_id); + err.span_note(sp, "expected because of the type of the const parameter"); + } + } + hir::Node::AnonConst(anon) + if let hir::Node::Variant(_variant) = tcx.parent_hir_node(anon.hir_id) => + { + // FIXME: point at `repr` when present in the type. + err.note( + "enum variant discriminant can only be of a primitive type compatible with the \ + enum's `repr`", + ); + } + hir::Node::AnonConst(anon) + if let hir::Node::ConstArg(parent) = tcx.parent_hir_node(anon.hir_id) + && let hir::Node::GenericParam(param) = tcx.parent_hir_node(parent.hir_id) + && let hir::GenericParamKind::Const { ty, .. } = param.kind => + { + // `fn foo` point at the `usize`. + err.span_label(ty.span, "expected because of the type of the const parameter"); + } + hir::Node::AnonConst(anon) + if let hir::Node::ConstArg(parent) = tcx.parent_hir_node(anon.hir_id) + && let hir::Node::TyPat(ty_pat) = tcx.parent_hir_node(parent.hir_id) + && let hir::Node::Ty(ty) = tcx.parent_hir_node(ty_pat.hir_id) + && let hir::TyKind::Pat(ty, _) = ty.kind => + { + // Point at `char` in `pattern_type!(char is 1..=1)`. + err.span_label(ty.span, "the pattern must match the type"); + } + hir::Node::AnonConst(anon) + if let hir::Node::Field(_) = tcx.parent_hir_node(anon.hir_id) + && let ty::Param(_) = expected_ty.kind() => + { + err.note( + "the type of default fields referencing type parameters can't be assumed inside \ + the struct defining them", + ); + } + _ => {} + } +} + fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Option> { let tcx = fcx.tcx; let def_id = fcx.body_id; @@ -538,7 +662,7 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! { pub fn provide(providers: &mut Providers) { *providers = Providers { method_autoderef_steps: method::probe::method_autoderef_steps, - typeck, + typeck_root, used_trait_imports, check_transmutes: intrinsicck::check_transmutes, ..*providers diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index e77c93641e1a..21b408064fac 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -207,7 +207,7 @@ fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { }; // A `#[const_continue]` must break to a block in a `#[loop_match]`. - if find_attr!(self.tcx.hir_attrs(e.hir_id), ConstContinue(_)) { + if find_attr!(self.tcx, e.hir_id, ConstContinue(_)) { let Some(label) = break_destination.label else { let span = e.span; self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span }); @@ -420,7 +420,7 @@ fn is_loop_match( e: &'hir hir::Expr<'hir>, body: &'hir hir::Block<'hir>, ) -> Option { - if !find_attr!(self.tcx.hir_attrs(e.hir_id), LoopMatch(_)) { + if !find_attr!(self.tcx, e.hir_id, LoopMatch(_)) { return None; } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 608bc7dffd9c..b90d5b40bec6 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -736,12 +736,18 @@ fn lint_ambiguously_glob_imported_traits( let trait_name = self.tcx.item_name(pick.item.container_id(self.tcx)); let import_span = self.tcx.hir_span_if_local(pick.import_ids[0].to_def_id()).unwrap(); - self.tcx.node_lint(AMBIGUOUS_GLOB_IMPORTED_TRAITS, segment.hir_id, |diag| { - diag.primary_message(format!("Use of ambiguously glob imported trait `{trait_name}`")) + self.tcx.emit_node_lint( + AMBIGUOUS_GLOB_IMPORTED_TRAITS, + segment.hir_id, + rustc_errors::DiagDecorator(|diag| { + diag.primary_message(format!( + "Use of ambiguously glob imported trait `{trait_name}`" + )) .span(segment.ident.span) .span_label(import_span, format!("`{trait_name}` imported ambiguously here")) .help(format!("Import `{trait_name}` explicitly")); - }); + }), + ); } fn upcast( diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 1fe82bc7ff6b..c5b3d7065fa9 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -14,7 +14,7 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, MultiSpan, StashKey, listify, pluralize, struct_span_code_err, + Applicability, Diag, MultiSpan, StashKey, StringPart, listify, pluralize, struct_span_code_err, }; use rustc_hir::attrs::diagnostic::OnUnimplementedNote; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -1177,15 +1177,10 @@ fn report_no_match_method_error( let is_method = mode == Mode::MethodCall; let item_kind = if is_method { "method" - } else if rcvr_ty.is_enum() { - "variant or associated item" + } else if rcvr_ty.is_enum() || rcvr_ty.is_fresh_ty() { + "variant, associated function, or constant" } else { - match (item_ident.as_str().chars().next(), rcvr_ty.is_fresh_ty()) { - (Some(name), false) if name.is_lowercase() => "function or associated item", - (Some(_), false) => "associated item", - (Some(_), true) | (None, false) => "variant or associated item", - (None, true) => "variant", - } + "associated function or constant" }; if let Err(guar) = self.report_failed_method_call_on_numerical_infer_var( @@ -1413,33 +1408,45 @@ fn set_not_found_span_label( } }) .collect::>(); - if !inherent_impls_candidate.is_empty() { - inherent_impls_candidate.sort_by_key(|&id| self.tcx.def_path_str(id)); - inherent_impls_candidate.dedup(); - - // number of types to show at most - let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 }; - let type_candidates = inherent_impls_candidate - .iter() - .take(limit) - .map(|impl_item| { - format!( - "- `{}`", - self.tcx.at(span).type_of(*impl_item).instantiate_identity() - ) - }) - .collect::>() - .join("\n"); - let additional_types = if inherent_impls_candidate.len() > limit { - format!("\nand {} more types", inherent_impls_candidate.len() - limit) - } else { - "".to_string() - }; - err.note(format!( - "the {item_kind} was found for\n{type_candidates}{additional_types}" - )); - *find_candidate_for_method = mode == Mode::MethodCall; - } + inherent_impls_candidate.sort_by_key(|&id| self.tcx.def_path_str(id)); + inherent_impls_candidate.dedup(); + let msg = match &inherent_impls_candidate[..] { + [] => return, + [only] => { + vec![ + StringPart::normal(format!("the {item_kind} was found for `")), + StringPart::highlighted( + self.tcx.at(span).type_of(*only).instantiate_identity().to_string(), + ), + StringPart::normal(format!("`")), + ] + } + candidates => { + // number of types to show at most + let limit = if candidates.len() == 5 { 5 } else { 4 }; + let type_candidates = candidates + .iter() + .take(limit) + .map(|impl_item| { + format!( + "- `{}`", + self.tcx.at(span).type_of(*impl_item).instantiate_identity() + ) + }) + .collect::>() + .join("\n"); + let additional_types = if candidates.len() > limit { + format!("\nand {} more types", candidates.len() - limit) + } else { + "".to_string() + }; + vec![StringPart::normal(format!( + "the {item_kind} was found for\n{type_candidates}{additional_types}" + ))] + } + }; + err.highlighted_note(msg); + *find_candidate_for_method = mode == Mode::MethodCall; } } else { let ty_str = if ty_str.len() > 50 { String::new() } else { format!("on `{ty_str}` ") }; @@ -2279,8 +2286,11 @@ pub(crate) fn confusable_method_name( fn_sig, ); let name = inherent_method.name(); + let inputs = fn_sig.inputs(); + let expected_inputs = + if inherent_method.is_method() { &inputs[1..] } else { inputs }; if let Some(ref args) = call_args - && fn_sig.inputs()[1..] + && expected_inputs .iter() .eq_by(args, |expected, found| self.may_coerce(*expected, *found)) { @@ -3448,13 +3458,13 @@ fn consider_suggesting_derives_for_ty( let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id())?; let can_derive = match diagnostic_name { + sym::Copy | sym::Clone => true, + _ if adt.is_union() => false, sym::Default | sym::Eq | sym::PartialEq | sym::Ord | sym::PartialOrd - | sym::Clone - | sym::Copy | sym::Hash | sym::Debug => true, _ => false, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 4b325a7ad14a..cf61728f7c2a 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -13,8 +13,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Spanned, Symbol, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{FulfillmentError, Obligation, ObligationCtxt}; use tracing::debug; diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7b5f5f3f520e..26f7d1ccffc9 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1636,69 +1636,77 @@ fn emit_bad_pat_path( span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}"); }; - if let Some(span) = self.tcx.hir_res_span(pat_res) { + let span = match (self.tcx.hir_res_span(pat_res), res.opt_def_id()) { + (Some(span), _) => span, + (None, Some(def_id)) => self.tcx.def_span(def_id), + (None, None) => { + e.emit(); + return; + } + }; + if let [hir::PathSegment { ident, args: None, .. }] = segments + && e.suggestions.len() == 0 + { e.span_label(span, format!("{} defined here", res.descr())); - if let [hir::PathSegment { ident, .. }] = segments { - e.span_label( - pat_span, - format!( - "`{}` is interpreted as {} {}, not a new binding", - ident, - res.article(), - res.descr(), - ), - ); - match self.tcx.parent_hir_node(hir_id) { - hir::Node::PatField(..) => { + e.span_label( + pat_span, + format!( + "`{}` is interpreted as {} {}, not a new binding", + ident, + res.article(), + res.descr(), + ), + ); + match self.tcx.parent_hir_node(hir_id) { + hir::Node::PatField(..) => { + e.span_suggestion_verbose( + ident.span.shrink_to_hi(), + "bind the struct field to a different name instead", + format!(": other_{}", ident.as_str().to_lowercase()), + Applicability::HasPlaceholders, + ); + } + _ => { + let (type_def_id, item_def_id) = match resolved_pat.ty.kind() { + ty::Adt(def, _) => match res { + Res::Def(DefKind::Const { .. }, def_id) => { + (Some(def.did()), Some(def_id)) + } + _ => (None, None), + }, + _ => (None, None), + }; + + let is_range = matches!( + type_def_id.and_then(|id| self.tcx.as_lang_item(id)), + Some( + LangItem::Range + | LangItem::RangeFrom + | LangItem::RangeTo + | LangItem::RangeFull + | LangItem::RangeInclusiveStruct + | LangItem::RangeToInclusive, + ) + ); + if is_range { + if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { + let msg = "constants only support matching by type, \ + if you meant to match against a range of values, \ + consider using a range pattern like `min ..= max` in the match block"; + e.note(msg); + } + } else { + let msg = "introduce a new binding instead"; + let sugg = format!("other_{}", ident.as_str().to_lowercase()); e.span_suggestion_verbose( - ident.span.shrink_to_hi(), - "bind the struct field to a different name instead", - format!(": other_{}", ident.as_str().to_lowercase()), + ident.span, + msg, + sugg, Applicability::HasPlaceholders, ); } - _ => { - let (type_def_id, item_def_id) = match resolved_pat.ty.kind() { - ty::Adt(def, _) => match res { - Res::Def(DefKind::Const { .. }, def_id) => { - (Some(def.did()), Some(def_id)) - } - _ => (None, None), - }, - _ => (None, None), - }; - - let is_range = matches!( - type_def_id.and_then(|id| self.tcx.as_lang_item(id)), - Some( - LangItem::Range - | LangItem::RangeFrom - | LangItem::RangeTo - | LangItem::RangeFull - | LangItem::RangeInclusiveStruct - | LangItem::RangeToInclusive, - ) - ); - if is_range { - if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { - let msg = "constants only support matching by type, \ - if you meant to match against a range of values, \ - consider using a range pattern like `min ..= max` in the match block"; - e.note(msg); - } - } else { - let msg = "introduce a new binding instead"; - let sugg = format!("other_{}", ident.as_str().to_lowercase()); - e.span_suggestion( - ident.span, - msg, - sugg, - Applicability::HasPlaceholders, - ); - } - } - }; - } + } + }; } e.emit(); } diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs index 3354689d0ca3..a1f4464c7659 100644 --- a/compiler/rustc_incremental/src/errors.rs +++ b/compiler/rustc_incremental/src/errors.rs @@ -192,7 +192,8 @@ pub(crate) struct DeleteFull<'a> { } #[derive(Diagnostic)] -#[diag("error finalizing incremental compilation session directory `{$path}`: {$err}")] +#[diag("did not finalize incremental compilation session directory `{$path}`: {$err}")] +#[help("the next build will not be able to reuse work from this compilation")] pub(crate) struct Finalize<'a> { pub path: &'a Path, pub err: std::io::Error, diff --git a/compiler/rustc_incremental/src/persist/clean.rs b/compiler/rustc_incremental/src/persist/clean.rs index ab336a69737a..e999404c6cc8 100644 --- a/compiler/rustc_incremental/src/persist/clean.rs +++ b/compiler/rustc_incremental/src/persist/clean.rs @@ -49,7 +49,7 @@ label_strs::type_of, // And a big part of compilation (that we eventually want to cache) is type inference // information: - label_strs::typeck, + label_strs::typeck_root, ]; /// DepNodes for Hir, which is pretty much everything diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 9cec2702a417..c47540fe385b 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -12,7 +12,7 @@ use std::borrow::Cow; use std::io::{self, Read}; use std::path::{Path, PathBuf}; -use std::{env, fs}; +use std::{array, env, fs}; use rustc_data_structures::memmap::Mmap; use rustc_serialize::Encoder; @@ -30,12 +30,12 @@ pub(crate) fn write_file_header(stream: &mut FileEncoder, sess: &Session) { stream.emit_raw_bytes(FILE_MAGIC); - stream - .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]); + stream.emit_raw_bytes(&u16::to_le_bytes(HEADER_FORMAT_VERSION)); - let rustc_version = rustc_version(sess.is_nightly_build(), sess.cfg_version); - assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); - stream.emit_raw_bytes(&[rustc_version.len() as u8]); + let rustc_version = rustc_version(sess); + let rustc_version_len = + u8::try_from(rustc_version.len()).expect("version string should not exceed 255 bytes"); + stream.emit_raw_bytes(&[rustc_version_len]); stream.emit_raw_bytes(rustc_version.as_bytes()); } @@ -80,26 +80,47 @@ pub(crate) fn save_in(sess: &Session, path_buf: PathBuf, name: &str, encode: } } -/// Reads the contents of a file with a file header as defined in this module. -/// -/// - Returns `Ok(Some(data, pos))` if the file existed and was generated by a -/// compatible compiler version. `data` is the entire contents of the file -/// and `pos` points to the first byte after the header. -/// - Returns `Ok(None)` if the file did not exist or was generated by an -/// incompatible version of the compiler. -/// - Returns `Err(..)` if some kind of IO error occurred while reading the -/// file. -pub(crate) fn read_file( +pub(crate) struct OpenFile { + /// A read-only mmap view of the file contents. + pub(crate) mmap: Mmap, + /// File position to start reading normal data from, just after the end of the file header. + pub(crate) start_pos: usize, +} + +pub(crate) enum OpenFileError { + /// Either the file was not found, or one of the header checks failed. + /// + /// These conditions prevent us from reading the file contents, but should + /// not trigger an error or even a warning, because they routinely happen + /// during normal operation: + /// - File-not-found occurs in a fresh build, or after clearing the build directory. + /// - Header-mismatch occurs after upgrading or switching compiler versions. + NotFoundOrHeaderMismatch, + + /// An unexpected I/O error occurred while opening or checking the file. + IoError { err: io::Error }, +} + +impl From for OpenFileError { + fn from(err: io::Error) -> Self { + OpenFileError::IoError { err } + } +} + +/// Tries to open a file that was written by the previous incremental-compilation +/// session, and checks that it was produced by a matching compiler version. +pub(crate) fn open_incremental_file( + sess: &Session, path: &Path, - report_incremental_info: bool, - is_nightly_build: bool, - cfg_version: &'static str, -) -> io::Result> { - let file = match fs::File::open(path) { - Ok(file) => file, - Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), - Err(err) => return Err(err), - }; +) -> Result { + let file = fs::File::open(path).map_err(|err| { + if err.kind() == io::ErrorKind::NotFound { + OpenFileError::NotFoundOrHeaderMismatch + } else { + OpenFileError::IoError { err } + } + })?; + // SAFETY: This process must not modify nor remove the backing file while the memory map lives. // For the dep-graph and the work product index, it is as soon as the decoding is done. // For the query result cache, the memory map is dropped in save_dep_graph before calling @@ -116,8 +137,8 @@ pub(crate) fn read_file( let mut file_magic = [0u8; 4]; file.read_exact(&mut file_magic)?; if file_magic != FILE_MAGIC { - report_format_mismatch(report_incremental_info, path, "Wrong FILE_MAGIC"); - return Ok(None); + report_format_mismatch(sess, path, "Wrong FILE_MAGIC"); + return Err(OpenFileError::NotFoundOrHeaderMismatch); } } @@ -126,37 +147,35 @@ pub(crate) fn read_file( debug_assert!(size_of_val(&HEADER_FORMAT_VERSION) == 2); let mut header_format_version = [0u8; 2]; file.read_exact(&mut header_format_version)?; - let header_format_version = - (header_format_version[0] as u16) | ((header_format_version[1] as u16) << 8); + let header_format_version = u16::from_le_bytes(header_format_version); if header_format_version != HEADER_FORMAT_VERSION { - report_format_mismatch(report_incremental_info, path, "Wrong HEADER_FORMAT_VERSION"); - return Ok(None); + report_format_mismatch(sess, path, "Wrong HEADER_FORMAT_VERSION"); + return Err(OpenFileError::NotFoundOrHeaderMismatch); } } // Check RUSTC_VERSION { - let mut rustc_version_str_len = [0u8; 1]; - file.read_exact(&mut rustc_version_str_len)?; - let rustc_version_str_len = rustc_version_str_len[0] as usize; - let mut buffer = vec![0; rustc_version_str_len]; + let mut rustc_version_str_len = 0u8; + file.read_exact(array::from_mut(&mut rustc_version_str_len))?; + let mut buffer = vec![0; usize::from(rustc_version_str_len)]; file.read_exact(&mut buffer)?; - if buffer != rustc_version(is_nightly_build, cfg_version).as_bytes() { - report_format_mismatch(report_incremental_info, path, "Different compiler version"); - return Ok(None); + if buffer != rustc_version(sess).as_bytes() { + report_format_mismatch(sess, path, "Different compiler version"); + return Err(OpenFileError::NotFoundOrHeaderMismatch); } } - let post_header_start_pos = file.position() as usize; - Ok(Some((mmap, post_header_start_pos))) + let start_pos = file.position() as usize; + Ok(OpenFile { mmap, start_pos }) } -fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &str) { +fn report_format_mismatch(sess: &Session, file: &Path, message: &str) { debug!("read_file: {}", message); - if report_incremental_info { + if sess.opts.unstable_opts.incremental_info { eprintln!( "[incremental] ignoring cache artifact `{}`: {}", file.file_name().unwrap().to_string_lossy(), @@ -168,12 +187,13 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: & /// A version string that hopefully is always different for compiler versions /// with different encodings of incremental compilation artifacts. Contains /// the Git commit hash. -fn rustc_version(nightly_build: bool, cfg_version: &'static str) -> Cow<'static, str> { - if nightly_build { - if let Ok(val) = env::var("RUSTC_FORCE_RUSTC_VERSION") { - return val.into(); - } +fn rustc_version(sess: &Session) -> Cow<'static, str> { + // Allow version string overrides so that tests can produce a header-mismatch on demand. + if sess.is_nightly_build() + && let Ok(env_version) = env::var("RUSTC_FORCE_RUSTC_VERSION") + { + Cow::Owned(env_version) + } else { + Cow::Borrowed(sess.cfg_version) } - - cfg_version.into() } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index f73cc4d43e8c..cf80a7ac2c46 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -366,7 +366,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) { } Err(e) => { // Warn about the error. However, no need to abort compilation now. - sess.dcx().emit_warn(errors::Finalize { path: &incr_comp_session_dir, err: e }); + sess.dcx().emit_note(errors::Finalize { path: &incr_comp_session_dir, err: e }); debug!("finalize_session_directory() - error, marking as invalid"); // Drop the file lock, so we can garage collect diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index f7182e3614dc..c0466a4b5211 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -1,9 +1,8 @@ //! Code to load the dep-graph from files. -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::Arc; -use rustc_data_structures::memmap::Mmap; use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProductMap}; @@ -20,6 +19,7 @@ use super::save::build_dep_graph; use super::{file_format, work_product}; use crate::errors; +use crate::persist::file_format::{OpenFile, OpenFileError}; #[derive(Debug)] /// Represents the result of an attempt to load incremental compilation data. @@ -38,19 +38,8 @@ pub enum LoadResult { impl LoadResult { /// Accesses the data returned in [`LoadResult::Ok`]. pub fn open(self, sess: &Session) -> T { - // Check for errors when using `-Zassert-incremental-state` - match (sess.opts.assert_incr_state, &self) { - (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => { - sess.dcx().emit_fatal(errors::AssertNotLoaded); - } - ( - Some(IncrementalStateAssertion::Loaded), - LoadResult::LoadDepGraph(..) | LoadResult::DataOutOfDate, - ) => { - sess.dcx().emit_fatal(errors::AssertLoaded); - } - _ => {} - }; + // Emit a fatal error if `-Zassert-incr-state` is present and unsatisfied. + maybe_assert_incr_state(sess, &self); match self { LoadResult::LoadDepGraph(path, err) => { @@ -69,23 +58,6 @@ pub fn open(self, sess: &Session) -> T { } } -fn load_data(path: &Path, sess: &Session) -> LoadResult<(Mmap, usize)> { - match file_format::read_file( - path, - sess.opts.unstable_opts.incremental_info, - sess.is_nightly_build(), - sess.cfg_version, - ) { - Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, - Ok(None) => { - // The file either didn't exist or was produced by an incompatible - // compiler version. Neither is an error. - LoadResult::DataOutOfDate - } - Err(err) => LoadResult::LoadDepGraph(path.to_path_buf(), err), - } -} - fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) { debug!("delete_dirty_work_product({:?})", swp); work_product::delete_workproduct_files(sess, &swp.work_product); @@ -113,12 +85,12 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc, WorkPr // when trying to load work products. if sess.incr_comp_session_dir_opt().is_some() { let work_products_path = work_products_path(sess); - let load_result = load_data(&work_products_path, sess); - if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { + if let Ok(OpenFile { mmap, start_pos }) = + file_format::open_incremental_file(sess, &work_products_path) + { // Decode the list of work_products - let Ok(mut work_product_decoder) = MemDecoder::new(&work_products_data[..], start_pos) - else { + let Ok(mut work_product_decoder) = MemDecoder::new(&mmap[..], start_pos) else { sess.dcx().emit_warn(errors::CorruptFile { path: &work_products_path }); return LoadResult::DataOutOfDate; }; @@ -147,11 +119,11 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc, WorkPr let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph"); - match load_data(&path, sess) { - LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, - LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err), - LoadResult::Ok { data: (bytes, start_pos) } => { - let Ok(mut decoder) = MemDecoder::new(&bytes, start_pos) else { + match file_format::open_incremental_file(sess, &path) { + Err(OpenFileError::NotFoundOrHeaderMismatch) => LoadResult::DataOutOfDate, + Err(OpenFileError::IoError { err }) => LoadResult::LoadDepGraph(path.to_owned(), err), + Ok(OpenFile { mmap, start_pos }) => { + let Ok(mut decoder) = MemDecoder::new(&mmap, start_pos) else { sess.dcx().emit_warn(errors::CorruptFile { path: &path }); return LoadResult::DataOutOfDate; }; @@ -191,15 +163,43 @@ pub fn load_query_result_cache(sess: &Session) -> Option { let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache"); let path = query_cache_path(sess); - match load_data(&path, sess) { - LoadResult::Ok { data: (bytes, start_pos) } => { - let cache = OnDiskCache::new(sess, bytes, start_pos).unwrap_or_else(|()| { + match file_format::open_incremental_file(sess, &path) { + Ok(OpenFile { mmap, start_pos }) => { + let cache = OnDiskCache::new(sess, mmap, start_pos).unwrap_or_else(|()| { sess.dcx().emit_warn(errors::CorruptFile { path: &path }); OnDiskCache::new_empty() }); Some(cache) } - _ => Some(OnDiskCache::new_empty()), + Err(OpenFileError::NotFoundOrHeaderMismatch | OpenFileError::IoError { .. }) => { + Some(OnDiskCache::new_empty()) + } + } +} + +/// Emits a fatal error if the assertion in `-Zassert-incr-state` doesn't match +/// the outcome of trying to load previous-session state. +fn maybe_assert_incr_state(sess: &Session, load_result: &LoadResult) { + // Return immediately if there's nothing to assert. + let Some(assertion) = sess.opts.unstable_opts.assert_incr_state else { return }; + + // Match exhaustively to make sure we don't miss any cases. + let loaded = match load_result { + LoadResult::Ok { .. } => true, + LoadResult::DataOutOfDate | LoadResult::LoadDepGraph(..) => false, + }; + + match assertion { + IncrementalStateAssertion::Loaded => { + if !loaded { + sess.dcx().emit_fatal(errors::AssertLoaded); + } + } + IncrementalStateAssertion::NotLoaded => { + if loaded { + sess.dcx().emit_fatal(errors::AssertNotLoaded) + } + } } } diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 1de64bb6734d..dc14a8c5e2ec 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -6,6 +6,7 @@ use rustc_middle::dep_graph::{ DepGraph, SerializedDepGraph, WorkProduct, WorkProductId, WorkProductMap, }; +use rustc_middle::query::on_disk_cache; use rustc_middle::ty::TyCtxt; use rustc_serialize::Encodable as RustcEncodable; use rustc_serialize::opaque::FileEncoder; @@ -82,7 +83,7 @@ pub(crate) fn save_dep_graph(tcx: TyCtxt<'_>) { file_format::save_in(sess, query_cache_path, "query cache", |encoder| { tcx.sess.time("incr_comp_serialize_result_cache", || { - on_disk_cache.serialize(tcx, encoder) + on_disk_cache::OnDiskCache::serialize(tcx, encoder) }) }); }); diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 184fa409d960..a2ab99f675ca 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; #[cfg(not(feature = "nightly"))] use std::mem; -use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds, Shl}; +use std::ops::{Bound, Range, RangeBounds}; use std::rc::Rc; use std::{fmt, iter, slice}; @@ -509,14 +509,20 @@ enum Chunk { /// to store the length, which would make this type larger. These excess /// words are always zero, as are any excess bits in the final in-use word. /// - /// The `ChunkSize` field is the count of 1s set in the chunk, and - /// must satisfy `0 < count < chunk_domain_size`. - /// /// The words are within an `Rc` because it's surprisingly common to /// duplicate an entire chunk, e.g. in `ChunkedBitSet::clone_from()`, or /// when a `Mixed` chunk is union'd into a `Zeros` chunk. When we do need /// to modify a chunk we use `Rc::make_mut`. - Mixed(ChunkSize, Rc<[Word; CHUNK_WORDS]>), + Mixed { + /// Count of set bits (1s) in this chunk's words. + /// + /// Invariant: `0 < ones_count < chunk_domain_size`. + /// + /// Tracking this separately allows individual insert/remove calls to + /// know that the chunk has become all-zeroes or all-ones, in O(1) time. + ones_count: ChunkSize, + words: Rc<[Word; CHUNK_WORDS]>, + }, } // This type is used a lot. Make sure it doesn't unintentionally get bigger. @@ -613,7 +619,7 @@ pub fn contains(&self, elem: T) -> bool { match &chunk { Zeros => false, Ones => true, - Mixed(_, words) => { + Mixed { ones_count: _, words } => { let (word_index, mask) = chunk_word_index_and_mask(elem); (words[word_index] & mask) != 0 } @@ -644,19 +650,19 @@ pub fn insert(&mut self, elem: T) -> bool { let (word_index, mask) = chunk_word_index_and_mask(elem); words_ref[word_index] |= mask; - *chunk = Mixed(1, words); + *chunk = Mixed { ones_count: 1, words }; } else { *chunk = Ones; } true } Ones => false, - Mixed(ref mut count, ref mut words) => { + Mixed { ref mut ones_count, ref mut words } => { // We skip all the work if the bit is already set. let (word_index, mask) = chunk_word_index_and_mask(elem); if (words[word_index] & mask) == 0 { - *count += 1; - if *count < chunk_domain_size { + *ones_count += 1; + if *ones_count < chunk_domain_size { let words = Rc::make_mut(words); words[word_index] |= mask; } else { @@ -702,18 +708,18 @@ pub fn remove(&mut self, elem: T) -> bool { ); let (word_index, mask) = chunk_word_index_and_mask(elem); words_ref[word_index] &= !mask; - *chunk = Mixed(chunk_domain_size - 1, words); + *chunk = Mixed { ones_count: chunk_domain_size - 1, words }; } else { *chunk = Zeros; } true } - Mixed(ref mut count, ref mut words) => { + Mixed { ref mut ones_count, ref mut words } => { // We skip all the work if the bit is already clear. let (word_index, mask) = chunk_word_index_and_mask(elem); if (words[word_index] & mask) != 0 { - *count -= 1; - if *count > 0 { + *ones_count -= 1; + if *ones_count > 0 { let words = Rc::make_mut(words); words[word_index] &= !mask; } else { @@ -732,7 +738,7 @@ fn chunk_iter(&self, chunk_index: usize) -> ChunkIter<'_> { match self.chunks.get(chunk_index) { Some(Zeros) => ChunkIter::Zeros, Some(Ones) => ChunkIter::Ones(0..chunk_domain_size as usize), - Some(Mixed(_, words)) => { + Some(Mixed { ones_count: _, words }) => { let num_words = num_words(chunk_domain_size as usize); ChunkIter::Mixed(BitIter::new(&words[0..num_words])) } @@ -765,14 +771,14 @@ fn union(&mut self, other: &ChunkedBitSet) -> bool { match (&mut self_chunk, &other_chunk) { (_, Zeros) | (Ones, _) => {} - (Zeros, _) | (Mixed(..), Ones) => { + (Zeros, _) | (Mixed { .. }, Ones) => { // `other_chunk` fully overwrites `self_chunk` *self_chunk = other_chunk.clone(); changed = true; } ( - Mixed(self_chunk_count, self_chunk_words), - Mixed(_other_chunk_count, other_chunk_words), + Mixed { ones_count: self_chunk_ones, words: self_chunk_words }, + Mixed { ones_count: _, words: other_chunk_words }, ) => { // First check if the operation would change // `self_chunk.words`. If not, we can avoid allocating some @@ -807,8 +813,8 @@ fn union(&mut self, other: &ChunkedBitSet) -> bool { op, ); debug_assert!(has_changed); - *self_chunk_count = count_ones(&self_chunk_words[0..num_words]) as ChunkSize; - if *self_chunk_count == chunk_domain_size { + *self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize; + if *self_chunk_ones == chunk_domain_size { *self_chunk = Ones; } changed = true; @@ -839,11 +845,11 @@ fn subtract(&mut self, other: &ChunkedBitSet) -> bool { match (&mut self_chunk, &other_chunk) { (Zeros, _) | (_, Zeros) => {} - (Ones | Mixed(..), Ones) => { + (Ones | Mixed { .. }, Ones) => { changed = true; *self_chunk = Zeros; } - (Ones, Mixed(other_chunk_count, other_chunk_words)) => { + (Ones, Mixed { ones_count: other_chunk_ones, words: other_chunk_words }) => { changed = true; let num_words = num_words(chunk_domain_size as usize); debug_assert!(num_words > 0 && num_words <= CHUNK_WORDS); @@ -854,16 +860,17 @@ fn subtract(&mut self, other: &ChunkedBitSet) -> bool { *word = !*word & tail_mask; tail_mask = Word::MAX; } - let self_chunk_count = chunk_domain_size - *other_chunk_count; + let self_chunk_ones = chunk_domain_size - *other_chunk_ones; debug_assert_eq!( - self_chunk_count, + self_chunk_ones, count_ones(&self_chunk_words[0..num_words]) as ChunkSize ); - *self_chunk = Mixed(self_chunk_count, Rc::new(self_chunk_words)); + *self_chunk = + Mixed { ones_count: self_chunk_ones, words: Rc::new(self_chunk_words) }; } ( - Mixed(self_chunk_count, self_chunk_words), - Mixed(_other_chunk_count, other_chunk_words), + Mixed { ones_count: self_chunk_ones, words: self_chunk_words }, + Mixed { ones_count: _, words: other_chunk_words }, ) => { // See `ChunkedBitSet::union` for details on what is happening here. let num_words = num_words(chunk_domain_size as usize); @@ -883,8 +890,8 @@ fn subtract(&mut self, other: &ChunkedBitSet) -> bool { op, ); debug_assert!(has_changed); - *self_chunk_count = count_ones(&self_chunk_words[0..num_words]) as ChunkSize; - if *self_chunk_count == 0 { + *self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize; + if *self_chunk_ones == 0 { *self_chunk = Zeros; } changed = true; @@ -915,13 +922,13 @@ fn intersect(&mut self, other: &ChunkedBitSet) -> bool { match (&mut self_chunk, &other_chunk) { (Zeros, _) | (_, Ones) => {} - (Ones, Zeros | Mixed(..)) | (Mixed(..), Zeros) => { + (Ones, Zeros | Mixed { .. }) | (Mixed { .. }, Zeros) => { changed = true; *self_chunk = other_chunk.clone(); } ( - Mixed(self_chunk_count, self_chunk_words), - Mixed(_other_chunk_count, other_chunk_words), + Mixed { ones_count: self_chunk_ones, words: self_chunk_words }, + Mixed { ones_count: _, words: other_chunk_words }, ) => { // See `ChunkedBitSet::union` for details on what is happening here. let num_words = num_words(chunk_domain_size as usize); @@ -941,8 +948,8 @@ fn intersect(&mut self, other: &ChunkedBitSet) -> bool { op, ); debug_assert!(has_changed); - *self_chunk_count = count_ones(&self_chunk_words[0..num_words]) as ChunkSize; - if *self_chunk_count == 0 { + *self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize; + if *self_chunk_ones == 0 { *self_chunk = Zeros; } changed = true; @@ -1023,11 +1030,11 @@ fn assert_valid(&self, chunk_domain_size: ChunkSize) { assert!(chunk_domain_size as usize <= CHUNK_BITS); match *self { Zeros | Ones => {} - Mixed(count, ref words) => { - assert!(0 < count && count < chunk_domain_size); + Mixed { ones_count, ref words } => { + assert!(0 < ones_count && ones_count < chunk_domain_size); // Check the number of set bits matches `count`. - assert_eq!(count_ones(words.as_slice()) as ChunkSize, count); + assert_eq!(count_ones(words.as_slice()) as ChunkSize, ones_count); // Check the not-in-use words are all zeroed. let num_words = num_words(chunk_domain_size as usize); @@ -1043,7 +1050,7 @@ fn count(&self, chunk_domain_size: ChunkSize) -> usize { match *self { Zeros => 0, Ones => chunk_domain_size as usize, - Mixed(count, _) => count as usize, + Mixed { ones_count, words: _ } => usize::from(ones_count), } } } @@ -1316,6 +1323,12 @@ pub fn insert(&mut self, elem: T) -> bool { self.bit_set.insert(elem) } + #[inline] + pub fn insert_range(&mut self, elems: Range) { + self.ensure(elems.end.index()); + self.bit_set.insert_range(elems); + } + /// Returns `true` if the set has changed. #[inline] pub fn remove(&mut self, elem: T) -> bool { @@ -1323,6 +1336,16 @@ pub fn remove(&mut self, elem: T) -> bool { self.bit_set.remove(elem) } + #[inline] + pub fn clear(&mut self) { + self.bit_set.clear(); + } + + #[inline] + pub fn count(&self) -> usize { + self.bit_set.count() + } + #[inline] pub fn is_empty(&self) -> bool { self.bit_set.is_empty() @@ -1334,6 +1357,14 @@ pub fn contains(&self, elem: T) -> bool { self.bit_set.words.get(word_index).is_some_and(|word| (word & mask) != 0) } + #[inline] + pub fn contains_any(&self, elems: Range) -> bool { + elems.start.index() < self.bit_set.domain_size + && self + .bit_set + .contains_any(elems.start..T::new(elems.end.index().min(self.bit_set.domain_size))) + } + #[inline] pub fn iter(&self) -> BitIter<'_, T> { self.bit_set.iter() @@ -1729,114 +1760,3 @@ fn max_bit(word: Word) -> usize { fn count_ones(words: &[Word]) -> usize { words.iter().map(|word| word.count_ones() as usize).sum() } - -/// Integral type used to represent the bit set. -pub trait FiniteBitSetTy: - BitAnd - + BitAndAssign - + BitOrAssign - + Clone - + Copy - + Shl - + Not - + PartialEq - + Sized -{ - /// Size of the domain representable by this type, e.g. 64 for `u64`. - const DOMAIN_SIZE: u32; - - /// Value which represents the `FiniteBitSet` having every bit set. - const FILLED: Self; - /// Value which represents the `FiniteBitSet` having no bits set. - const EMPTY: Self; - - /// Value for one as the integral type. - const ONE: Self; - /// Value for zero as the integral type. - const ZERO: Self; - - /// Perform a checked left shift on the integral type. - fn checked_shl(self, rhs: u32) -> Option; - /// Perform a checked right shift on the integral type. - fn checked_shr(self, rhs: u32) -> Option; -} - -impl FiniteBitSetTy for u32 { - const DOMAIN_SIZE: u32 = 32; - - const FILLED: Self = Self::MAX; - const EMPTY: Self = Self::MIN; - - const ONE: Self = 1u32; - const ZERO: Self = 0u32; - - fn checked_shl(self, rhs: u32) -> Option { - self.checked_shl(rhs) - } - - fn checked_shr(self, rhs: u32) -> Option { - self.checked_shr(rhs) - } -} - -impl std::fmt::Debug for FiniteBitSet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:032b}", self.0) - } -} - -/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range -/// representable by `T` are considered set. -#[cfg_attr(feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext))] -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct FiniteBitSet(pub T); - -impl FiniteBitSet { - /// Creates a new, empty bitset. - pub fn new_empty() -> Self { - Self(T::EMPTY) - } - - /// Sets the `index`th bit. - pub fn set(&mut self, index: u32) { - self.0 |= T::ONE.checked_shl(index).unwrap_or(T::ZERO); - } - - /// Unsets the `index`th bit. - pub fn clear(&mut self, index: u32) { - self.0 &= !T::ONE.checked_shl(index).unwrap_or(T::ZERO); - } - - /// Sets the `i`th to `j`th bits. - pub fn set_range(&mut self, range: Range) { - let bits = T::FILLED - .checked_shl(range.end - range.start) - .unwrap_or(T::ZERO) - .not() - .checked_shl(range.start) - .unwrap_or(T::ZERO); - self.0 |= bits; - } - - /// Is the set empty? - pub fn is_empty(&self) -> bool { - self.0 == T::EMPTY - } - - /// Returns the domain size of the bitset. - pub fn within_domain(&self, index: u32) -> bool { - index < T::DOMAIN_SIZE - } - - /// Returns if the `index`th bit is set. - pub fn contains(&self, index: u32) -> Option { - self.within_domain(index) - .then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE) - } -} - -impl Default for FiniteBitSet { - fn default() -> Self { - Self::new_empty() - } -} diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index 341e0622df75..a0184c5c47f3 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -162,16 +162,16 @@ fn chunked_bitset() { assert!(!b100.contains(20) && b100.contains(30) && !b100.contains(99) && b100.contains(50)); assert_eq!( b100.chunks(), - vec![Mixed( - 97, + vec![Mixed { + ones_count: 97, #[rustfmt::skip] - Rc::new([ + words: Rc::new([ 0b11111111_11111111_11111110_11111111_11111111_11101111_11111111_11111111, 0b00000000_00000000_00000000_00000111_11111111_11111111_11111111_11111111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]) - )], + }], ); b100.assert_valid(); let mut num_removed = 0; @@ -228,14 +228,14 @@ fn chunked_bitset() { b4096.chunks(), #[rustfmt::skip] vec![ - Mixed(1, Rc::new([ + Mixed { ones_count: 1, words:Rc::new([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ])), - Mixed(1, Rc::new([ + ])}, + Mixed { ones_count: 1, words: Rc::new([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x8000_0000_0000_0000 - ])), + ])}, ], ); assert_eq!(b4096.count(), 2); @@ -265,14 +265,14 @@ fn chunked_bitset() { #[rustfmt::skip] vec![ Zeros, - Mixed(1, Rc::new([ + Mixed { ones_count: 1, words: Rc::new([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100_0000_0000_0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ])), - Mixed(1, Rc::new([ + ])}, + Mixed { ones_count: 1, words: Rc::new([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ])), + ])}, Zeros, Zeros, ], diff --git a/compiler/rustc_index_macros/src/lib.rs b/compiler/rustc_index_macros/src/lib.rs index 2b444932f854..96424b0ebcc7 100644 --- a/compiler/rustc_index_macros/src/lib.rs +++ b/compiler/rustc_index_macros/src/lib.rs @@ -34,7 +34,17 @@ /// optimizations. The default max value is 0xFFFF_FF00. /// - `#[gate_rustc_only]`: makes parts of the generated code nightly-only. #[proc_macro] -#[cfg_attr(feature = "nightly", allow_internal_unstable(step_trait, rustc_attrs, trusted_step))] +#[cfg_attr( + feature = "nightly", + allow_internal_unstable( + step_trait, + rustc_attrs, + trusted_step, + pattern_types, + pattern_type_macro, + structural_match, + ) +)] pub fn newtype_index(input: TokenStream) -> TokenStream { newtype::newtype(input) } diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index eedbe630cf2c..282403294db9 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -18,12 +18,14 @@ fn parse(input: ParseStream<'_>) -> Result { braced!(body in input); // Any additional `#[derive]` macro paths to apply - let mut derive_paths: Vec = Vec::new(); let mut debug_format: Option = None; let mut max = None; let mut consts = Vec::new(); let mut encodable = false; let mut ord = false; + let mut stable_hash = false; + let mut stable_hash_generic = false; + let mut stable_hash_no_context = false; let mut gate_rustc_only = quote! {}; let mut gate_rustc_only_cfg = quote! { all() }; @@ -42,6 +44,18 @@ fn parse(input: ParseStream<'_>) -> Result { ord = true; false } + "stable_hash" => { + stable_hash = true; + false + } + "stable_hash_generic" => { + stable_hash_generic = true; + false + } + "stable_hash_no_context" => { + stable_hash_no_context = true; + false + } "max" => { let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta else { @@ -111,12 +125,6 @@ fn encode(&self, e: &mut E) { } else { quote! {} }; - - if ord { - derive_paths.push(parse_quote!(Ord)); - derive_paths.push(parse_quote!(PartialOrd)); - } - let step = if ord { quote! { #gate_rustc_only @@ -139,6 +147,38 @@ fn backward_checked(start: Self, u: usize) -> Option { Self::index(start).checked_sub(u).map(Self::from_usize) } } + impl ::std::cmp::Ord for #name { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_u32().cmp(&other.as_u32()) + } + } + impl ::std::cmp::PartialOrd for #name { + fn partial_cmp(&self, other: &Self) -> Option { + self.as_u32().partial_cmp(&other.as_u32()) + } + } + } + } else { + quote! {} + }; + + let hash_stable = if stable_hash { + quote! { + #gate_rustc_only + impl<'__ctx> ::rustc_data_structures::stable_hasher::HashStable<::rustc_middle::ich::StableHashingContext<'__ctx>> for #name { + fn hash_stable(&self, hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>, hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + self.as_u32().hash_stable(hcx, hasher) + } + } + } + } else if stable_hash_generic || stable_hash_no_context { + quote! { + #gate_rustc_only + impl ::rustc_data_structures::stable_hasher::HashStable for #name { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + self.as_u32().hash_stable(hcx, hasher) + } + } } } else { quote! {} @@ -154,11 +194,13 @@ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { Ok(Self(quote! { #(#attrs)* - #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)] - #[cfg_attr(#gate_rustc_only_cfg, rustc_layout_scalar_valid_range_end(#max))] + #[derive(Clone, Copy)] #[cfg_attr(#gate_rustc_only_cfg, rustc_pass_by_value)] #vis struct #name { + #[cfg(not(#gate_rustc_only_cfg))] private_use_as_methods_instead: u32, + #[cfg(#gate_rustc_only_cfg)] + private_use_as_methods_instead: pattern_type!(u32 is 0..=#max), } #(#consts)* @@ -226,7 +268,7 @@ impl #name { /// Prefer using `from_u32`. #[inline] #vis const unsafe fn from_u32_unchecked(value: u32) -> Self { - Self { private_use_as_methods_instead: value } + Self { private_use_as_methods_instead: unsafe { std::mem::transmute(value) } } } /// Extracts the value of this index as a `usize`. @@ -238,7 +280,7 @@ impl #name { /// Extracts the value of this index as a `u32`. #[inline] #vis const fn as_u32(self) -> u32 { - self.private_use_as_methods_instead + unsafe { std::mem::transmute(self.private_use_as_methods_instead) } } /// Extracts the value of this index as a `usize`. @@ -278,6 +320,8 @@ fn index(self) -> usize { #step + #hash_stable + impl From<#name> for u32 { #[inline] fn from(v: #name) -> u32 { @@ -306,6 +350,23 @@ fn from(value: u32) -> Self { } } + impl ::std::cmp::Eq for #name {} + + impl ::std::cmp::PartialEq for #name { + fn eq(&self, other: &Self) -> bool { + self.as_u32().eq(&other.as_u32()) + } + } + + #gate_rustc_only + impl ::std::marker::StructuralPartialEq for #name {} + + impl ::std::hash::Hash for #name { + fn hash(&self, state: &mut H) { + self.as_u32().hash(state) + } + } + #encodable_impls #debug_impl })) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b57306536260..10e7b1e72f44 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1250,6 +1250,36 @@ pub fn resolve_vars_if_possible(&self, value: T) -> T value.fold_with(&mut r) } + /// Normally, we shallow-resolve unresolved type variables to their root + /// variables. This is mainly done for performance reasons, and in most + /// cases resolving to the root variable (instead of the variable itself) + /// does not affect type inference. + /// + /// However, there is an exceptional case: *fudging*. Fudging is intended + /// to guide inference rather than impose hard requirements. But our current + /// handling here is somewhat janky. + /// + /// In particular, inference variables that are considered equal within the + /// fudging scope may not remain equal outside of it. This makes it observable + /// which inference variable we resolve to. For backwards compatibility, we + /// avoid resolving to the root variable by using this function inside the + /// fudge instead of [`InferCtxt::resolve_vars_if_possible`]. + /// + /// See #153869 for more details. + pub fn resolve_vars_if_possible_for_fudging(&self, value: T) -> T + where + T: TypeFoldable>, + { + if let Err(guar) = value.error_reported() { + self.set_tainted_by_errors(guar); + } + if !value.has_non_region_infer() { + return value; + } + let mut r = resolve::OpportunisticVarResolver::new_for_fudging(self); + value.fold_with(&mut r) + } + pub fn resolve_numeric_literals_with_default(&self, value: T) -> T where T: TypeFoldable>, diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 69c090b662e5..3ab39e83f312 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -61,103 +61,13 @@ pub fn instantiate_ty_var>>( ) -> RelateResult<'tcx, ()> { debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()); - // Generalize `source_ty` depending on the current variance. As an example, assume - // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference - // variable. - // - // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh - // region/type inference variables. - // - // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and - // `?1 <: ?3`. - let Generalization { value_may_be_infer: generalized_ty } = self.generalize( - relation.span(), - relation.structurally_relate_aliases(), - target_vid, + self.instantiate_var( + relation, + target_is_expected, + target_vid.into(), instantiation_variance, - source_ty, - )?; - - // Constrain `b_vid` to the generalized type `generalized_ty`. - if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { - self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid); - } else { - self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); - } - - // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - if generalized_ty.is_ty_var() { - // This happens for cases like `::Assoc == ?0`. - // We can't instantiate `?0` here as that would result in a - // cyclic type. We instead delay the unification in case - // the alias can be normalized to something which does not - // mention `?0`. - if self.next_trait_solver() { - let (lhs, rhs, direction) = match instantiation_variance { - ty::Invariant => { - (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate) - } - ty::Covariant => { - (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype) - } - ty::Contravariant => { - (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype) - } - ty::Bivariant => unreachable!("bivariant generalization"), - }; - - relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]); - } else { - match source_ty.kind() { - &ty::Alias(ty::Projection, data) => { - // FIXME: This does not handle subtyping correctly, we could - // instead create a new inference variable `?normalized_source`, emitting - // `Projection(normalized_source, ?ty_normalized)` and - // `?normalized_source <: generalized_ty`. - relation.register_predicates([ty::ProjectionPredicate { - projection_term: data.into(), - term: generalized_ty.into(), - }]); - } - // The old solver only accepts projection predicates for associated types. - ty::Alias(ty::Inherent | ty::Free | ty::Opaque, _) => { - return Err(TypeError::CyclicTy(source_ty)); - } - _ => bug!("generalized `{source_ty:?} to infer, not an alias"), - } - } - } else { - // NOTE: The `instantiation_variance` is not the same variance as - // used by the relation. When instantiating `b`, `target_is_expected` - // is flipped and the `instantiation_variance` is also flipped. To - // constrain the `generalized_ty` while using the original relation, - // we therefore only have to flip the arguments. - // - // ```ignore (not code) - // ?a rel B - // instantiate_ty_var(?a, B) # expected and variance not flipped - // B' rel B - // ``` - // or - // ```ignore (not code) - // A rel ?b - // instantiate_ty_var(?b, A) # expected and variance flipped - // A rel A' - // ``` - if target_is_expected { - relation.relate(generalized_ty, source_ty)?; - } else { - debug!("flip relation"); - relation.relate(source_ty, generalized_ty)?; - } - } - - Ok(()) + source_ty.into(), + ) } /// Instantiates the const variable `target_vid` with the given constant. @@ -204,54 +114,191 @@ pub(crate) fn instantiate_const_var ) -> RelateResult<'tcx, ()> { // FIXME(generic_const_exprs): Occurs check failures for unevaluated // constants and generic expressions are not yet handled correctly. - let Generalization { value_may_be_infer: generalized_ct } = self.generalize( + debug_assert!( + self.inner.borrow_mut().const_unification_table().probe_value(target_vid).is_unknown() + ); + + self.instantiate_var( + relation, + target_is_expected, + target_vid.into(), + ty::Invariant, + source_ct.into(), + ) + } + + #[instrument(level = "debug", skip(self, relation))] + fn instantiate_var>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: TermVid, + instantiation_variance: ty::Variance, + source_term: Term<'tcx>, + ) -> RelateResult<'tcx, ()> { + // Generalize `source_term` depending on the current variance. As an example, assume + // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference + // variable. + // + // Then the `generalized_term` would be `&'?2 ?3`, where `'?2` and `?3` are fresh + // region/type inference variables. + // + // We then relate `generalized_term <: source_term`, adding constraints like `'x: '?2` and + // `?1 <: ?3`. + let Generalization { value_may_be_infer: generalized_term } = self.generalize( relation.span(), relation.structurally_relate_aliases(), target_vid, - ty::Invariant, - source_ct, + instantiation_variance, + source_term, )?; - debug_assert!(!generalized_ct.is_ct_infer()); + // Constrain `b_vid` to the generalized type `generalized_term`. + self.union_var_term(target_vid, generalized_term); - self.inner - .borrow_mut() - .const_unification_table() - .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct }); + // Finally, relate `generalized_term` to `source_term`, as described in previous comment. + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + if generalized_term.is_infer() { + // This happens for cases like `::Assoc == ?0`. + // We can't instantiate `?0` here as that would result in a + // cyclic type. We instead delay the unification in case + // the alias can be normalized to something which does not + // mention `?0`. + if self.next_trait_solver() { + let (lhs, rhs, direction) = match instantiation_variance { + ty::Invariant => { + (generalized_term, source_term, AliasRelationDirection::Equate) + } + ty::Covariant => { + (generalized_term, source_term, AliasRelationDirection::Subtype) + } + ty::Contravariant => { + (source_term, generalized_term, AliasRelationDirection::Subtype) + } + ty::Bivariant => unreachable!("bivariant generalization"), + }; - // Make sure that the order is correct when relating the - // generalized const and the source. - if target_is_expected { - relation.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - generalized_ct, - source_ct, - )?; + relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]); + } else { + let Some(source_alias) = source_term.to_alias_term() else { + bug!("generalized `{source_term:?} to infer, not an alias"); + }; + match source_alias.kind(self.tcx) { + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { + // FIXME: This does not handle subtyping correctly, we could + // instead create a new inference variable `?normalized_source`, emitting + // `Projection(normalized_source, ?ty_normalized)` and + // `?normalized_source <: generalized_term`. + relation.register_predicates([ty::ProjectionPredicate { + projection_term: source_alias, + term: generalized_term, + }]); + } + // The old solver only accepts projection predicates for associated types. + ty::AliasTermKind::InherentTy + | ty::AliasTermKind::FreeTy + | ty::AliasTermKind::OpaqueTy => { + return Err(TypeError::CyclicTy(source_term.expect_type())); + } + ty::AliasTermKind::InherentConst + | ty::AliasTermKind::FreeConst + | ty::AliasTermKind::UnevaluatedConst => { + return Err(TypeError::CyclicConst(source_term.expect_const())); + } + } + } } else { - relation.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - source_ct, - generalized_ct, - )?; + // NOTE: The `instantiation_variance` is not the same variance as + // used by the relation. When instantiating `b`, `target_is_expected` + // is flipped and the `instantiation_variance` is also flipped. To + // constrain the `generalized_term` while using the original relation, + // we therefore only have to flip the arguments. + // + // ```ignore (not code) + // ?a rel B + // instantiate_ty_var(?a, B) # expected and variance not flipped + // B' rel B + // ``` + // or + // ```ignore (not code) + // A rel ?b + // instantiate_ty_var(?b, A) # expected and variance flipped + // A rel A' + // ``` + match generalized_term.kind() { + ty::TermKind::Ty(_) => { + if target_is_expected { + relation.relate(generalized_term, source_term)?; + } else { + debug!("flip relation"); + relation.relate(source_term, generalized_term)?; + } + } + ty::TermKind::Const(_) => { + // Override consts to always be invariant + if target_is_expected { + relation.relate_with_variance( + ty::Invariant, + ty::VarianceDiagInfo::default(), + generalized_term, + source_term, + )?; + } else { + relation.relate_with_variance( + ty::Invariant, + ty::VarianceDiagInfo::default(), + source_term, + generalized_term, + )?; + } + } + } } Ok(()) } + /// This is a thin wrapper around inserting into the var tables. You probably want + /// [`Self::instantiate_var`] instead, which calls this method. + fn union_var_term(&self, l: TermVid, r: ty::Term<'tcx>) { + match (l, r.kind()) { + (TermVid::Ty(l), ty::TermKind::Ty(r)) => { + if let Some(r) = r.ty_vid() { + self.inner.borrow_mut().type_variables().equate(l, r) + } else { + self.inner.borrow_mut().type_variables().instantiate(l, r) + } + } + (TermVid::Const(l), ty::TermKind::Const(r)) => { + if let Some(r) = r.ct_vid() { + self.inner.borrow_mut().const_unification_table().union(l, r) + } else { + self.inner + .borrow_mut() + .const_unification_table() + .union_value(l, ConstVariableValue::Known { value: r }) + } + } + _ => bug!("mismatched term kinds in generalize: {l:?}, {r:?}"), + } + } + /// Attempts to generalize `source_term` for the type variable `target_vid`. /// This checks for cycles -- that is, whether `source_term` references `target_vid`. - fn generalize> + Relate>>( + fn generalize( &self, span: Span, structurally_relate_aliases: StructurallyRelateAliases, - target_vid: impl Into, + target_vid: TermVid, ambient_variance: ty::Variance, - source_term: T, - ) -> RelateResult<'tcx, Generalization> { + source_term: Term<'tcx>, + ) -> RelateResult<'tcx, Generalization>> { assert!(!source_term.has_escaping_bound_vars()); - let (for_universe, root_vid) = match target_vid.into() { + let (for_universe, root_vid) = match target_vid { TermVid::Ty(ty_vid) => { (self.probe_ty_var(ty_vid).unwrap_err(), TermVid::Ty(self.root_var(ty_vid))) } @@ -267,7 +314,7 @@ fn generalize> + Relate>>( structurally_relate_aliases, root_vid, for_universe, - root_term: source_term.into(), + root_term: source_term, ambient_variance, in_alias: false, cache: Default::default(), @@ -377,8 +424,12 @@ fn cyclic_term_error(&self) -> TypeError<'tcx> { /// Create a new type variable in the universe of the target when /// generalizing an alias. - fn next_ty_var_for_alias(&self) -> Ty<'tcx> { - self.infcx.next_ty_var_in_universe(self.span, self.for_universe) + fn next_var_for_alias_of_kind(&self, alias: ty::AliasTerm<'tcx>) -> ty::Term<'tcx> { + if alias.kind(self.cx()).is_type() { + self.infcx.next_ty_var_in_universe(self.span, self.for_universe).into() + } else { + self.infcx.next_const_var_in_universe(self.span, self.for_universe).into() + } } /// An occurs check failure inside of an alias does not mean @@ -399,10 +450,10 @@ fn next_ty_var_for_alias(&self) -> Ty<'tcx> { /// continue generalizing the alias. This ends up pulling down the universe of the /// inference variable and is incomplete in case the alias would normalize to a type /// which does not mention that inference variable. - fn generalize_alias_ty( + fn generalize_alias_term( &mut self, - alias: ty::AliasTy<'tcx>, - ) -> Result, TypeError<'tcx>> { + alias: ty::AliasTerm<'tcx>, + ) -> Result, TypeError<'tcx>> { // We do not eagerly replace aliases with inference variables if they have // escaping bound vars, see the method comment for details. However, when we // are inside of an alias with escaping bound vars replacing nested aliases @@ -410,12 +461,12 @@ fn generalize_alias_ty( // // cc trait-system-refactor-initiative#110 if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { - return Ok(self.next_ty_var_for_alias()); + return Ok(self.next_var_for_alias_of_kind(alias)); } let is_nested_alias = mem::replace(&mut self.in_alias, true); let result = match self.relate(alias, alias) { - Ok(alias) => Ok(alias.to_ty(self.cx())), + Ok(alias) => Ok(alias.to_term(self.cx())), Err(e) => { if is_nested_alias { return Err(e); @@ -430,7 +481,7 @@ fn generalize_alias_ty( } debug!("generalization failure in alias"); - Ok(self.next_ty_var_for_alias()) + Ok(self.next_var_for_alias_of_kind(alias)) } } }; @@ -585,7 +636,9 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { } ty::Alias(_, data) => match self.structurally_relate_aliases { - StructurallyRelateAliases::No => self.generalize_alias_ty(data), + StructurallyRelateAliases::No => { + self.generalize_alias_term(data.into()).map(|v| v.expect_type()) + } StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t), }, @@ -695,17 +748,26 @@ fn consts( // FIXME: Unevaluated constants are also not rigid, so the current // approach of always relating them structurally is incomplete. // - // FIXME: remove this branch once `structurally_relate_consts` is fully - // structural. - ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { - let args = self.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - args, - args, - )?; - Ok(ty::Const::new_unevaluated(self.cx(), ty::UnevaluatedConst { def, args })) - } + // FIXME: replace the StructurallyRelateAliases::Yes branch with + // `structurally_relate_consts` once it is fully structural. + ty::ConstKind::Unevaluated(uv) => match self.structurally_relate_aliases { + // Hack: Fall back to old behavior if GCE is enabled (it used to just be the Yes + // path), as doing this new No path breaks some GCE things. I expect GCE to be + // ripped out soon so this shouldn't matter soon. + StructurallyRelateAliases::No if !self.cx().features().generic_const_exprs() => { + self.generalize_alias_term(uv.into()).map(|v| v.expect_const()) + } + _ => { + let ty::UnevaluatedConst { def, args } = uv; + let args = self.relate_with_variance( + ty::Invariant, + ty::VarianceDiagInfo::default(), + args, + args, + )?; + Ok(ty::Const::new_unevaluated(self.cx(), ty::UnevaluatedConst { def, args })) + } + }, ty::ConstKind::Placeholder(placeholder) => { if self.for_universe.can_name(placeholder.universe) { Ok(c) diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 13df23a39b96..917d7b6653e0 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -17,6 +17,9 @@ /// points for correctness. pub struct OpportunisticVarResolver<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, + /// If true, we don't resolve ty/const vars to their roots. + /// See comments on [`InferCtxt::resolve_vars_if_possible_for_fudging`] + for_fudging: bool, /// We're able to use a cache here as the folder does /// not have any mutable state. cache: DelayedMap, Ty<'tcx>>, @@ -25,7 +28,12 @@ pub struct OpportunisticVarResolver<'a, 'tcx> { impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> { #[inline] pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - OpportunisticVarResolver { infcx, cache: Default::default() } + OpportunisticVarResolver { infcx, for_fudging: false, cache: Default::default() } + } + + #[inline] + pub fn new_for_fudging(infcx: &'a InferCtxt<'tcx>) -> Self { + OpportunisticVarResolver { infcx, for_fudging: true, cache: Default::default() } } } @@ -43,6 +51,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { } else { let shallow = self.infcx.shallow_resolve(t); let res = shallow.super_fold_with(self); + let res = if self.for_fudging && res.is_ty_var() { t } else { res }; assert!(self.cache.insert(t, res)); res } @@ -52,8 +61,11 @@ fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> { if !ct.has_non_region_infer() { ct // micro-optimize -- if there is nothing in this const that this fold affects... } else { - let ct = self.infcx.shallow_resolve_const(ct); - ct.super_fold_with(self) + let res = self.infcx.shallow_resolve_const(ct); + if self.for_fudging && res.is_ct_infer() { + return ct; + }; + res.super_fold_with(self) } } diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 6709c822dc7b..56cae2c1e396 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -101,7 +101,7 @@ pub fn fudge_inference_if_ok(&self, f: F) -> Result // going to be popped, so we will have to // eliminate any references to them. let snapshot_vars = SnapshotVarData::new(self, variable_lengths); - Ok((snapshot_vars, self.resolve_vars_if_possible(value))) + Ok((snapshot_vars, self.resolve_vars_if_possible_for_fudging(value))) })?; // At this point, we need to replace any of the now-popped diff --git a/compiler/rustc_infer/src/infer/unify_key.rs b/compiler/rustc_infer/src/infer/unify_key.rs index 5e5d0e063a0d..4016054d8974 100644 --- a/compiler/rustc_infer/src/infer/unify_key.rs +++ b/compiler/rustc_infer/src/infer/unify_key.rs @@ -110,6 +110,13 @@ pub(crate) fn known(&self) -> Option> { ConstVariableValue::Known { value } => Some(value), } } + + pub(crate) fn is_unknown(&self) -> bool { + match *self { + ConstVariableValue::Unknown { .. } => true, + ConstVariableValue::Known { .. } => false, + } + } } #[derive(PartialEq, Copy, Clone, Debug)] diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 91b7f234d5f6..fa4d4588caab 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -22,7 +22,6 @@ use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint}; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs}; use rustc_span::{FileName, sym}; -use rustc_target::spec::Target; use tracing::trace; use crate::util; @@ -337,11 +336,14 @@ pub struct Config { /// This is a callback from the driver that is called when [`ParseSess`] is created. pub psess_created: Option>, - /// This is a callback to hash otherwise untracked state used by the caller, if the - /// hash changes between runs the incremental cache will be cleared. + /// This is a callback to track otherwise untracked state used by the caller. /// - /// e.g. used by Clippy to hash its config file - pub hash_untracked_state: Option>, + /// You can write to `sess.env_depinfo` and `sess.file_depinfo` to track env vars and files. + /// To track any other state you can write to the given hasher. If the hash changes between + /// runs the incremental cache will be cleared. + /// + /// The hashing functionality has no known user. FIXME should this be removed? + pub track_state: Option>, /// This is a callback from the driver that is called when we're registering lints; /// it is called during lint loading when we have the LintStore in a non-shared state. @@ -364,8 +366,7 @@ pub struct Config { /// hotswapping branch of cg_clif" for "setting the codegen backend from a /// custom driver where the custom codegen backend has arbitrary data." /// (See #102759.) - pub make_codegen_backend: - Option Box + Send>>, + pub make_codegen_backend: Option Box + Send>>, /// The inner atomic value is set to true when a feature marked as `internal` is /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with @@ -419,20 +420,6 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se // impl `Send`. Creating a new one is fine. let early_dcx = EarlyDiagCtxt::new(config.opts.error_format); - let codegen_backend = match config.make_codegen_backend { - None => util::get_codegen_backend( - &early_dcx, - &config.opts.sysroot, - config.opts.unstable_opts.codegen_backend.as_deref(), - &target, - ), - Some(make_codegen_backend) => { - // N.B. `make_codegen_backend` takes precedence over - // `target.default_codegen_backend`, which is ignored in this case. - make_codegen_backend(&config.opts, &target) - } - }; - let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let mut sess = rustc_session::build_session( @@ -450,6 +437,19 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.using_internal_features, ); + let codegen_backend = match config.make_codegen_backend { + None => util::get_codegen_backend( + &early_dcx, + &sess.opts.sysroot, + sess.opts.unstable_opts.codegen_backend.as_deref(), + &sess.target, + ), + Some(make_codegen_backend) => { + // N.B. `make_codegen_backend` takes precedence over + // `target.default_codegen_backend`, which is ignored in this case. + make_codegen_backend(&sess) + } + }; codegen_backend.init(&sess); sess.replaced_intrinsics = FxHashSet::from_iter(codegen_backend.replaced_intrinsics()); sess.thin_lto_supported = codegen_backend.thin_lto_supported(); @@ -467,9 +467,9 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se psess_created(&mut sess.psess); } - if let Some(hash_untracked_state) = config.hash_untracked_state { + if let Some(track_state) = config.track_state { let mut hasher = StableHasher::new(); - hash_untracked_state(&sess, &mut hasher); + track_state(&sess, &mut hasher); sess.opts.untracked_state_hash = hasher.finish() } diff --git a/compiler/rustc_interface/src/limits.rs b/compiler/rustc_interface/src/limits.rs index e0fc91f3b723..8ae0743886ce 100644 --- a/compiler/rustc_interface/src/limits.rs +++ b/compiler/rustc_interface/src/limits.rs @@ -11,13 +11,13 @@ use rustc_hir::limit::Limit; use rustc_hir::{Attribute, find_attr}; use rustc_middle::query::Providers; -use rustc_session::Limits; +use rustc_session::{Limits, Session}; pub(crate) fn provide(providers: &mut Providers) { providers.limits = |tcx, ()| { let attrs = tcx.hir_krate_attrs(); Limits { - recursion_limit: get_recursion_limit(tcx.hir_krate_attrs()), + recursion_limit: get_recursion_limit(tcx.hir_krate_attrs(), tcx.sess), move_size_limit: find_attr!(attrs, MoveSizeLimit { limit, .. } => *limit) .unwrap_or(Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0))), type_length_limit: find_attr!(attrs, TypeLengthLimit { limit, .. } => *limit) @@ -30,6 +30,13 @@ pub(crate) fn provide(providers: &mut Providers) { } // This one is separate because it must be read prior to macro expansion. -pub(crate) fn get_recursion_limit(attrs: &[Attribute]) -> Limit { - find_attr!(attrs, RecursionLimit { limit, .. } => *limit).unwrap_or(Limit::new(128)) +pub(crate) fn get_recursion_limit(attrs: &[Attribute], sess: &Session) -> Limit { + let limit_from_crate = + find_attr!(attrs, RecursionLimit { limit, .. } => limit.0).unwrap_or(128); + Limit::new( + sess.opts + .unstable_opts + .min_recursion_limit + .map_or(limit_from_crate, |min| min.max(limit_from_crate)), + ) } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a280b2a2a6bf..d7d4f00578d1 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -21,9 +21,12 @@ use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; use rustc_hir::limit::Limit; -use rustc_hir::{Attribute, find_attr}; +use rustc_hir::lints::DelayedLint; +use rustc_hir::{Attribute, MaybeOwner, find_attr}; use rustc_incremental::setup_dep_graph; -use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store}; +use rustc_lint::{ + BufferedEarlyLint, DecorateAttrLint, EarlyCheckNode, LintStore, unerased_lint_store, +}; use rustc_metadata::EncodedMetadata; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; @@ -495,7 +498,7 @@ fn env_var_os<'tcx>(tcx: TyCtxt<'tcx>, key: &'tcx OsStr) -> Option<&'tcx OsStr> // NOTE: This only works for passes run before `write_dep_info`. See that // for extension points for configuring environment variables to be // properly change-tracked. - tcx.sess.psess.env_depinfo.borrow_mut().insert(( + tcx.sess.env_depinfo.borrow_mut().insert(( Symbol::intern(&key.to_string_lossy()), value.as_ref().and_then(|value| value.to_str()).map(|value| Symbol::intern(value)), )); @@ -607,7 +610,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P // Account for explicitly marked-to-track files // (e.g. accessed in proc macros). - let file_depinfo = sess.psess.file_depinfo.borrow(); + let file_depinfo = sess.file_depinfo.borrow(); let normalize_path = |path: PathBuf| escape_dep_filename(&path.to_string_lossy()); @@ -719,7 +722,7 @@ fn hash_iter_files>( } // Emit special comments with information about accessed environment variables. - let env_depinfo = sess.psess.env_depinfo.borrow(); + let env_depinfo = sess.env_depinfo.borrow(); if !env_depinfo.is_empty() { // We will soon sort, so the initial order does not matter. #[allow(rustc::potential_query_instability)] @@ -878,6 +881,10 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) { let providers = &mut Providers::default(); providers.queries.analysis = analysis; providers.queries.hir_crate = rustc_ast_lowering::lower_to_hir; + providers.queries.lower_delayed_owner = rustc_ast_lowering::lower_delayed_owner; + // `delayed_owner` is fed during `lower_delayed_owner`, by default it returns phantom, + // as if this query was not fed it means that `MaybeOwner` does not exist for provided LocalDefId. + providers.queries.delayed_owner = |_, _| MaybeOwner::Phantom; providers.queries.resolver_for_lowering_raw = resolver_for_lowering_raw; providers.queries.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..]; providers.queries.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1; @@ -1021,6 +1028,29 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( ) } +pub fn emit_delayed_lints(tcx: TyCtxt<'_>) { + for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { + if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { + for lint in &delayed_lints.lints { + match lint { + DelayedLint::AttributeParsing(attribute_lint) => { + tcx.emit_node_span_lint( + attribute_lint.lint_id.lint, + attribute_lint.id, + attribute_lint.span, + DecorateAttrLint { + sess: tcx.sess, + tcx: Some(tcx), + diagnostic: &attribute_lint.kind, + }, + ); + } + } + } + } + } +} + /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. /// This function never fails. fn run_required_analyses(tcx: TyCtxt<'_>) { @@ -1070,6 +1100,32 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { ]); }); + sess.time("emit_ast_lowering_delayed_lints", || { + // Sanity check in debug mode that all lints are really noticed and we really will emit + // them all in the loop right below. + // + // During ast lowering, when creating items, foreign items, trait items and impl items, + // we store in them whether they have any lints in their owner node that should be + // picked up by `hir_crate_items`. However, theoretically code can run between that + // boolean being inserted into the item and the owner node being created. We don't want + // any new lints to be emitted there (you have to really try to manage that but still), + // but this check is there to catch that. + #[cfg(debug_assertions)] + { + let hir_items = tcx.hir_crate_items(()); + for owner_id in hir_items.owners() { + if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { + if !delayed_lints.lints.is_empty() { + // Assert that delayed_lint_items also picked up this item to have lints. + assert!(hir_items.delayed_lint_items().any(|i| i == owner_id)); + } + } + } + } + + emit_delayed_lints(tcx); + }); + rustc_hir_analysis::check_crate(tcx); // Freeze definitions as we don't add new ones at this point. // We need to wait until now since we synthesize a by-move body @@ -1429,5 +1485,5 @@ fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit // So, no lints here to avoid duplicates. ShouldEmit::EarlyFatal { also_emit_lints: false }, ); - crate::limits::get_recursion_limit(attr.as_slice()) + crate::limits::get_recursion_limit(attr.as_slice(), sess) } diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 63fed51b020a..eb60c61b0af7 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -7,7 +7,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option { let mut decls = None; for id in tcx.hir_free_items() { - if find_attr!(tcx.hir_attrs(id.hir_id()), RustcProcMacroDecls) { + if find_attr!(tcx, id.hir_id(), RustcProcMacroDecls) { decls = Some(id.owner_id.def_id); } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 88056a0db966..417cde119c21 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -12,12 +12,12 @@ use rustc_session::config::{ AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CoverageLevel, CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, - FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, - LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, - Offload, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, - PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, - SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options, - rustc_optgroups, + FmtDebug, FunctionReturn, IncrementalStateAssertion, InliningThreshold, Input, + InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, + MirIncludeSpans, NextSolverConfig, Offload, Options, OutFileName, OutputType, OutputTypes, + PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, + SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, build_configuration, + build_session_options, rustc_optgroups, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -637,7 +637,6 @@ macro_rules! tracked { tracked!(profile_use, Some(PathBuf::from("abc"))); tracked!(relocation_model, Some(RelocModel::Pic)); tracked!(relro_level, Some(RelroLevel::Full)); - tracked!(soft_float, true); tracked!(split_debuginfo, Some(SplitDebuginfo::Packed)); tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(target_cpu, Some(String::from("abc"))); @@ -687,7 +686,7 @@ macro_rules! untracked { // Make sure that changing an [UNTRACKED] option leaves the hash unchanged. // tidy-alphabetical-start - untracked!(assert_incr_state, Some(String::from("loaded"))); + untracked!(assert_incr_state, Some(IncrementalStateAssertion::Loaded)); untracked!(codegen_source_order, true); untracked!(deduplicate_diagnostics, false); untracked!(dump_dep_graph, true); @@ -822,6 +821,7 @@ macro_rules! tracked { tracked!(maximal_hir_to_mir_coverage, true); tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(min_function_alignment, Some(Align::EIGHT)); + tracked!(min_recursion_limit, Some(256)); tracked!(mir_emit_retag, true); tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]); tracked!(mir_opt_level, Some(4)); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index bacdad25c50b..0cd0275f96bb 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -18,7 +18,7 @@ use rustc_metadata::{DylibError, EncodedMetadata, load_symbol_from_dylib}; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::{CurrentGcx, TyCtxt}; -use rustc_query_impl::collect_active_jobs_from_all_queries; +use rustc_query_impl::{CollectActiveJobsKind, collect_active_query_jobs}; use rustc_session::config::{ Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple, }; @@ -183,7 +183,6 @@ pub(crate) fn run_in_thread_pool_with_globals< use std::process; use rustc_data_structures::defer; - use rustc_data_structures::sync::FromDyn; use rustc_middle::ty::tls; use rustc_query_impl::break_query_cycles; @@ -191,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals< let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap()); - if !sync::is_dyn_thread_safe() { + let Some(proof) = sync::check_dyn_thread_safe() else { return run_in_thread_with_globals( thread_stack_size, edition, @@ -204,9 +203,9 @@ pub(crate) fn run_in_thread_pool_with_globals< f(current_gcx, jobserver_proxy) }, ); - } + }; - let current_gcx = FromDyn::from(CurrentGcx::new()); + let current_gcx = proof.derive(CurrentGcx::new()); let current_gcx2 = current_gcx.clone(); let proxy = Proxy::new(); @@ -253,9 +252,11 @@ pub(crate) fn run_in_thread_pool_with_globals< unsafe { &*(session_globals as *const SessionGlobals) }, || { // Ensure there were no errors collecting all active jobs. - // We need the complete map to ensure we find a cycle to break. - collect_active_jobs_from_all_queries(tcx, false).expect( - "failed to collect active queries in deadlock handler", + // We need the complete map to ensure we find a cycle to + // break. + collect_active_query_jobs( + tcx, + CollectActiveJobsKind::FullNoContention, ) }, ); @@ -276,7 +277,7 @@ pub(crate) fn run_in_thread_pool_with_globals< // `Send` in the parallel compiler. rustc_span::create_session_globals_then(edition, extra_symbols, Some(sm_inputs), || { rustc_span::with_session_globals(|session_globals| { - let session_globals = FromDyn::from(session_globals); + let session_globals = proof.derive(session_globals); builder .build_scoped( // Initialize each new worker thread when created. diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 34049288ea80..910a2918f9f7 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -173,7 +173,7 @@ fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<(Muta Adjust::NeverToAny | Adjust::Pointer(..) | Adjust::ReborrowPin(..) - | Adjust::Deref(DerefAdjustKind::Builtin) - | Adjust::Borrow(AutoBorrow::RawPtr(..)) => None, + | Adjust::Deref(DerefAdjustKind::Builtin | DerefAdjustKind::Pin) + | Adjust::Borrow(AutoBorrow::RawPtr(..) | AutoBorrow::Pin(..)) => None, } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 54c8c75b88fc..af590d98c301 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -39,8 +39,7 @@ use rustc_session::lint::fcw; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Ident, InnerSpan, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, InnerSpan, Span, Spanned, Symbol, kw, sym}; use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d7a0a02f085a..752c2220d414 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -514,9 +514,9 @@ pub trait LintContext { // set the span in their `decorate` function (preferably using set_span). /// Emit a lint at the appropriate level, with an optional associated span. /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature + /// [`emit_lint_base`]: rustc_middle::lint::emit_lint_base#decorate-signature #[track_caller] - fn opt_span_diag_lint>( + fn opt_span_lint>( &self, lint: &'static Lint, span: Option, @@ -532,13 +532,7 @@ fn emit_span_lint>( span: S, decorator: impl for<'a> Diagnostic<'a, ()>, ) { - self.opt_span_diag_lint(lint, Some(span), decorator); - } - - /// Emit a lint from a lint struct (some type that implements `Diagnostic`, typically - /// generated by `#[derive(Diagnostic)]`). - fn emit_diag_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a, ()>) { - self.opt_span_diag_lint(lint, None as Option, decorator); + self.opt_span_lint(lint, Some(span), decorator); } /// This returns the lint level for the given lint at the current location. @@ -594,7 +588,7 @@ fn sess(&self) -> &Session { self.tcx.sess } - fn opt_span_diag_lint>( + fn opt_span_lint>( &self, lint: &'static Lint, span: Option, @@ -619,13 +613,13 @@ fn sess(&self) -> &Session { self.builder.sess() } - fn opt_span_diag_lint>( + fn opt_span_lint>( &self, lint: &'static Lint, span: Option, decorator: impl for<'a> Diagnostic<'a, ()>, ) { - self.builder.opt_span_diag_lint(lint, span.map(|s| s.into()), decorator) + self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator) } fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource { diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index 0db2f6a3565c..9d4b79a45453 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diag}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir as hir; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; @@ -147,50 +147,59 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_ let hir_id = cx.tcx.local_def_id_to_hir_id(impl_id); let span = cx.tcx.hir_span_with_body(hir_id); - cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, span, |diag| { - mk_lint(cx.tcx, diag, type_def_id, orig_fields, fields, span); - }); - } -} - -fn mk_lint( - tcx: TyCtxt<'_>, - diag: &mut Diag<'_, ()>, - type_def_id: DefId, - orig_fields: FxHashMap>, - fields: &[hir::ExprField<'_>], - impl_span: Span, -) { - diag.primary_message("`Default` impl doesn't use the declared default field values"); - - // For each field in the struct expression - // - if the field in the type has a default value, it should be removed - // - elif the field is an expression that could be a default value, it should be used as the - // field's default value (FIXME: not done). - // - else, we wouldn't touch this field, it would remain in the manual impl - let mut removed_all_fields = true; - for field in fields { - if orig_fields.get(&field.ident.name).and_then(|f| f.default).is_some() { - diag.span_label(field.expr.span, "this field has a default value"); - } else { - removed_all_fields = false; - } - } - - if removed_all_fields { - let msg = "to avoid divergence in behavior between `Struct { .. }` and \ - `::default()`, derive the `Default`"; - diag.multipart_suggestion( - msg, - vec![ - (tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()), - (impl_span, String::new()), - ], - Applicability::MachineApplicable, + cx.tcx.emit_node_span_lint( + DEFAULT_OVERRIDES_DEFAULT_FIELDS, + hir_id, + span, + WrongDefaultImpl { tcx: cx.tcx, type_def_id, orig_fields, fields, impl_span: span }, ); - } else { - let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \ - avoid them diverging over time"; - diag.help(msg); + } +} + +struct WrongDefaultImpl<'a, 'hir, 'tcx> { + tcx: TyCtxt<'tcx>, + type_def_id: DefId, + orig_fields: FxHashMap>, + fields: &'a [hir::ExprField<'hir>], + impl_span: Span, +} + +impl<'a, 'b, 'hir, 'tcx> Diagnostic<'a, ()> for WrongDefaultImpl<'b, 'hir, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { tcx, type_def_id, orig_fields, fields, impl_span } = self; + let mut diag = + Diag::new(dcx, level, "`Default` impl doesn't use the declared default field values"); + + // For each field in the struct expression + // - if the field in the type has a default value, it should be removed + // - elif the field is an expression that could be a default value, it should be used as the + // field's default value (FIXME: not done). + // - else, we wouldn't touch this field, it would remain in the manual impl + let mut removed_all_fields = true; + for field in fields { + if orig_fields.get(&field.ident.name).and_then(|f| f.default).is_some() { + diag.span_label(field.expr.span, "this field has a default value"); + } else { + removed_all_fields = false; + } + } + + if removed_all_fields { + diag.multipart_suggestion( + "to avoid divergence in behavior between `Struct { .. }` and \ + `::default()`, derive the `Default`", + vec![ + (tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()), + (impl_span, String::new()), + ], + Applicability::MachineApplicable, + ); + } else { + diag.help( + "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \ + avoid them diverging over time", + ); + } + diag } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 92232c7d230b..c0eca3b5197b 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -39,7 +39,7 @@ fn check_id(&mut self, id: ast::NodeId) { let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; match diagnostic { DecorateDiagCompat::Builtin(b) => { - self.context.opt_span_diag_lint( + self.context.opt_span_lint( lint_id.lint, span, DecorateBuiltinLint { @@ -50,7 +50,7 @@ fn check_id(&mut self, id: ast::NodeId) { ); } DecorateDiagCompat::Dynamic(d) => { - self.context.opt_span_diag_lint(lint_id.lint, span, d); + self.context.opt_span_lint(lint_id.lint, span, d); } } } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 458553fa747c..1cb0f906f730 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,16 +1,13 @@ use std::borrow::Cow; -use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level, elided_lifetime_in_path_suggestion, }; use rustc_hir::lints::{AttributeLintKind, FormatWarning}; -use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::lint::BuiltinLintDiag; -use rustc_span::BytePos; use tracing::debug; use crate::lints; @@ -28,32 +25,6 @@ pub struct DecorateBuiltinLint<'sess, 'tcx> { impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { match self.diagnostic { - BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { - let spans: Vec<_> = content - .char_indices() - .filter_map(|(i, c)| { - TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { - let lo = comment_span.lo() + BytePos(2 + i as u32); - (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) - }) - }) - .collect(); - let characters = spans - .iter() - .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") }) - .collect(); - let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion { - spans: spans.iter().map(|(_c, span)| *span).collect(), - }); - - lints::UnicodeTextFlow { - comment_span, - characters, - suggestions, - num_codepoints: spans.len(), - } - .into_diag(dcx, level) - } BuiltinLintDiag::AbsPathWithModule(mod_span) => { let (replacement, applicability) = match self.sess.source_map().span_to_snippet(mod_span) { @@ -116,87 +87,16 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { } .into_diag(dcx, level) } - BuiltinLintDiag::RedundantImport(spans, ident) => { - let subs = spans - .into_iter() - .map(|(span, is_imported)| match (span.is_dummy(), is_imported) { - (false, true) => lints::RedundantImportSub::ImportedHere { span, ident }, - (false, false) => lints::RedundantImportSub::DefinedHere { span, ident }, - (true, true) => lints::RedundantImportSub::ImportedPrelude { span, ident }, - (true, false) => lints::RedundantImportSub::DefinedPrelude { span, ident }, - }) - .collect(); - lints::RedundantImport { subs, ident }.into_diag(dcx, level) - } - BuiltinLintDiag::DeprecatedMacro { - suggestion, - suggestion_span, - note, - path, - since_kind, - } => { - let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion { - span: suggestion_span, - kind: "macro".to_owned(), - suggestion, - }); - - stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind } - .into_diag(dcx, level) - } - BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { - let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; - if is_foreign { - lints::PatternsInFnsWithoutBody::Foreign { sub } - } else { - lints::PatternsInFnsWithoutBody::Bodiless { sub } - } - .into_diag(dcx, level) - } - BuiltinLintDiag::ReservedPrefix(label_span, prefix) => lints::ReservedPrefix { - label: label_span, - suggestion: label_span.shrink_to_hi(), - prefix, - } - .into_diag(dcx, level), - BuiltinLintDiag::RawPrefix(label_span) => { - lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() } - .into_diag(dcx, level) - } - BuiltinLintDiag::ReservedString { is_string, suggestion } => { - if is_string { - lints::ReservedString { suggestion }.into_diag(dcx, level) - } else { - lints::ReservedMultihash { suggestion }.into_diag(dcx, level) - } - } - BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => lints::BreakWithLabelAndLoop { - sub: lints::BreakWithLabelAndLoopSub { - left: sugg_span.shrink_to_lo(), - right: sugg_span.shrink_to_hi(), - }, - } - .into_diag(dcx, level), - BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { - let suggestion = match sugg { - Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd { - left: left_sp, - right: right_sp, - sugg, - }, - None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }, - }; - lints::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level) - } BuiltinLintDiag::SingleUseLifetime { param_span, - use_span: Some((use_span, elide)), + use_span, + elidable, deletion_span, ident, } => { debug!(?param_span, ?use_span, ?deletion_span); let suggestion = if let Some(deletion_span) = deletion_span { - let (use_span, replace_lt) = if elide { + let (use_span, replace_lt) = if elidable { let use_span = self.sess.source_map().span_extend_while_whitespace(use_span); (use_span, String::new()) @@ -217,9 +117,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { lints::SingleUseLifetime { suggestion, param_span, use_span, ident } .into_diag(dcx, level) } - BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { - lints::UnusedLifetime { deletion_span, ident }.into_diag(dcx, level) - } BuiltinLintDiag::NamedArgumentUsedPositionally { position_sp_to_replace, position_sp_for_msg, @@ -255,63 +152,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { } .into_diag(dcx, level) } - BuiltinLintDiag::AmbiguousGlobReexports { - name, - namespace, - first_reexport_span, - duplicate_reexport_span, - } => lints::AmbiguousGlobReexports { - first_reexport: first_reexport_span, - duplicate_reexport: duplicate_reexport_span, - name, - namespace, - } - .into_diag(dcx, level), - BuiltinLintDiag::HiddenGlobReexports { - name, - namespace, - glob_reexport_span, - private_item_span, - } => lints::HiddenGlobReexports { - glob_reexport: glob_reexport_span, - private_item: private_item_span, - name, - namespace, - } - .into_diag(dcx, level), - BuiltinLintDiag::UnusedQualifications { removal_span } => { - lints::UnusedQualifications { removal_span }.into_diag(dcx, level) - } - BuiltinLintDiag::AssociatedConstElidedLifetime { - elided, - span: lt_span, - lifetimes_in_scope, - } => { - let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; - let code = if elided { "'static " } else { "'static" }; - lints::AssociatedConstElidedLifetime { - span: lt_span, - code, - elided, - lifetimes_in_scope, - } - .into_diag(dcx, level) - } - BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span { - Some(wildcard_span) => { - lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span } - .into_diag(dcx, level) - } - None => lints::UnreachableCfgSelectPredicate { span }.into_diag(dcx, level), - }, - - BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { - lints::UnusedCrateDependency { extern_crate, local_crate }.into_diag(dcx, level) - } - BuiltinLintDiag::UnusedVisibility(span) => { - lints::UnusedVisibility { span }.into_diag(dcx, level) - } BuiltinLintDiag::AttributeLint(kind) => { DecorateAttrLint { sess: self.sess, tcx: self.tcx, diagnostic: &kind } .into_diag(dcx, level) @@ -498,6 +339,18 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { &AttributeLintKind::MissingOptionsForOnConst => { lints::MissingOptionsForOnConstAttr.into_diag(dcx, level) } + &AttributeLintKind::MalformedOnMoveAttr { span } => { + lints::MalformedOnMoveAttrLint { span }.into_diag(dcx, level) + } + &AttributeLintKind::OnMoveMalformedFormatLiterals { name } => { + lints::OnMoveMalformedFormatLiterals { name }.into_diag(dcx, level) + } + &AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter => { + lints::OnMoveMalformedAttrExpectedLiteralOrDelimiter.into_diag(dcx, level) + } + &AttributeLintKind::MissingOptionsForOnMove => { + lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level) + } } } } diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index fe95a682c637..a7c5943c250b 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -49,6 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let Some((pat, arg)) = extract_for_loop(expr) else { return }; + // Do not put suggestions for external macros. + if pat.span.from_expansion() { + return; + } + let arg_span = arg.span.source_callsite(); let ty = cx.typeck_results().expr_ty(arg); @@ -77,6 +82,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { }; let sub = if let Some(recv) = extract_iterator_next_call(cx, arg) + && recv.span.can_be_used_for_suggestions() + && recv.span.between(arg_span.shrink_to_hi()).can_be_used_for_suggestions() && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span) { ForLoopsOverFalliblesLoopSub::RemoveNext { diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 41b670c92c4c..f095d0a6a2f4 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -3,8 +3,7 @@ use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::source_map::Spanned; -use rustc_span::sym; +use rustc_span::{Spanned, sym}; use crate::lints::InvalidFromUtf8Diag; use crate::{LateContext, LateLintPass, LintContext}; diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 6f3a7e945d93..2b859b65c9f8 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -12,7 +12,7 @@ use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ - LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, diag_lint_level, + LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, emit_lint_base, reveal_actual_level, }; use rustc_middle::query::Providers; @@ -981,7 +981,7 @@ fn into_diag( if self.lint_added_lints { let lint = builtin::UNKNOWN_LINTS; let level = self.lint_level(builtin::UNKNOWN_LINTS); - diag_lint_level( + emit_lint_base( self.sess, lint, level, @@ -1001,14 +1001,14 @@ pub fn lint_level(&self, lint: &'static Lint) -> LevelAndSource { /// Used to emit a lint-related diagnostic based on the current state of /// this lint context. #[track_caller] - pub(crate) fn opt_span_diag_lint( + pub(crate) fn opt_span_lint( &self, lint: &'static Lint, span: Option, decorator: impl for<'a> Diagnostic<'a, ()>, ) { let level = self.lint_level(lint); - diag_lint_level(self.sess, lint, level, span, decorator) + emit_lint_base(self.sess, lint, level, span, decorator) } #[track_caller] @@ -1019,13 +1019,13 @@ pub fn emit_span_lint( decorator: impl for<'a> Diagnostic<'a, ()>, ) { let level = self.lint_level(lint); - diag_lint_level(self.sess, lint, level, Some(span), decorator); + emit_lint_base(self.sess, lint, level, Some(span), decorator); } #[track_caller] pub fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a, ()>) { let level = self.lint_level(lint); - diag_lint_level(self.sess, lint, level, None, decorator); + emit_lint_base(self.sess, lint, level, None, decorator); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 1790eac7bef5..2f773b9e166c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -642,6 +642,7 @@ macro_rules! add_lint_group { see for more information", ); store.register_removed("wasm_c_abi", "the wasm C ABI has been fixed"); + store.register_removed("soft_unstable", "the general soft-unstable mechanism has been removed"); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index d8b62e81b0cb..f111f8134499 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -6,8 +6,7 @@ use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, - ElidedLifetimeInPathSubdiag, EmissionGuarantee, Level, MultiSpan, Subdiagnostic, - SuggestionStyle, msg, + ElidedLifetimeInPathSubdiag, EmissionGuarantee, Level, Subdiagnostic, SuggestionStyle, msg, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -2995,14 +2994,6 @@ pub(crate) enum CargoHelp { } } -#[derive(Diagnostic)] -#[diag("extern crate `{$extern_crate}` is unused in crate `{$local_crate}`")] -#[help("remove the dependency or add `use {$extern_crate} as _;` to the crate root")] -pub(crate) struct UnusedCrateDependency { - pub extern_crate: Symbol, - pub local_crate: Symbol, -} - // FIXME(jdonszelmann): duplicated in rustc_attr_parsing, should be moved there completely. #[derive(Diagnostic)] #[diag( @@ -3019,46 +3010,6 @@ pub(crate) struct IllFormedAttributeInput { pub docs: &'static str, } -#[derive(Diagnostic)] -#[diag("unicode codepoint changing visible direction of text present in comment")] -#[note( - "these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen" -)] -pub(crate) struct UnicodeTextFlow { - #[label( - "{$num_codepoints -> - [1] this comment contains an invisible unicode text flow control codepoint - *[other] this comment contains invisible unicode text flow control codepoints - }" - )] - pub comment_span: Span, - #[subdiagnostic] - pub characters: Vec, - #[subdiagnostic] - pub suggestions: Option, - - pub num_codepoints: usize, -} - -#[derive(Subdiagnostic)] -#[label("{$c_debug}")] -pub(crate) struct UnicodeCharNoteSub { - #[primary_span] - pub span: Span, - pub c_debug: String, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - "if their presence wasn't intentional, you can remove them", - applicability = "machine-applicable", - style = "hidden" -)] -pub(crate) struct UnicodeTextFlowSuggestion { - #[suggestion_part(code = "")] - pub spans: Vec, -} - #[derive(Diagnostic)] #[diag( "absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition" @@ -3129,144 +3080,6 @@ pub(crate) enum UnusedImportsSugg { }, } -#[derive(Diagnostic)] -#[diag("the item `{$ident}` is imported redundantly")] -pub(crate) struct RedundantImport { - #[subdiagnostic] - pub subs: Vec, - pub ident: Ident, -} - -#[derive(Subdiagnostic)] -pub(crate) enum RedundantImportSub { - #[label("the item `{$ident}` is already imported here")] - ImportedHere { - #[primary_span] - span: Span, - ident: Ident, - }, - #[label("the item `{$ident}` is already defined here")] - DefinedHere { - #[primary_span] - span: Span, - ident: Ident, - }, - #[label("the item `{$ident}` is already imported by the extern prelude")] - ImportedPrelude { - #[primary_span] - span: Span, - ident: Ident, - }, - #[label("the item `{$ident}` is already defined by the extern prelude")] - DefinedPrelude { - #[primary_span] - span: Span, - ident: Ident, - }, -} - -#[derive(Diagnostic)] -pub(crate) enum PatternsInFnsWithoutBody { - #[diag("patterns aren't allowed in foreign function declarations")] - Foreign { - #[subdiagnostic] - sub: PatternsInFnsWithoutBodySub, - }, - #[diag("patterns aren't allowed in functions without bodies")] - Bodiless { - #[subdiagnostic] - sub: PatternsInFnsWithoutBodySub, - }, -} - -#[derive(Subdiagnostic)] -#[suggestion( - "remove `mut` from the parameter", - code = "{ident}", - applicability = "machine-applicable" -)] -pub(crate) struct PatternsInFnsWithoutBodySub { - #[primary_span] - pub span: Span, - - pub ident: Ident, -} - -#[derive(Diagnostic)] -#[diag("prefix `{$prefix}` is unknown")] -pub(crate) struct ReservedPrefix { - #[label("unknown prefix")] - pub label: Span, - #[suggestion( - "insert whitespace here to avoid this being parsed as a prefix in Rust 2021", - code = " ", - applicability = "machine-applicable" - )] - pub suggestion: Span, - - pub prefix: String, -} - -#[derive(Diagnostic)] -#[diag("prefix `'r` is reserved")] -pub(crate) struct RawPrefix { - #[label("reserved prefix")] - pub label: Span, - #[suggestion( - "insert whitespace here to avoid this being parsed as a prefix in Rust 2021", - code = " ", - applicability = "machine-applicable" - )] - pub suggestion: Span, -} - -#[derive(Diagnostic)] -#[diag( - "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression" -)] -pub(crate) struct BreakWithLabelAndLoop { - #[subdiagnostic] - pub sub: BreakWithLabelAndLoopSub, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion("wrap this expression in parentheses", applicability = "machine-applicable")] -pub(crate) struct BreakWithLabelAndLoopSub { - #[suggestion_part(code = "(")] - pub left: Span, - #[suggestion_part(code = ")")] - pub right: Span, -} - -#[derive(Diagnostic)] -#[diag("where clause not allowed here")] -#[note("see issue #89122 for more information")] -pub(crate) struct DeprecatedWhereClauseLocation { - #[subdiagnostic] - pub suggestion: DeprecatedWhereClauseLocationSugg, -} - -#[derive(Subdiagnostic)] -pub(crate) enum DeprecatedWhereClauseLocationSugg { - #[multipart_suggestion( - "move it to the end of the type declaration", - applicability = "machine-applicable" - )] - MoveToEnd { - #[suggestion_part(code = "")] - left: Span, - #[suggestion_part(code = "{sugg}")] - right: Span, - - sugg: String, - }, - #[suggestion("remove this `where`", code = "", applicability = "machine-applicable")] - RemoveWhere { - #[primary_span] - span: Span, - }, -} - #[derive(Diagnostic)] #[diag("lifetime parameter `{$ident}` only used once")] pub(crate) struct SingleUseLifetime { @@ -3291,15 +3104,6 @@ pub(crate) struct SingleUseLifetimeSugg { pub replace_lt: String, } -#[derive(Diagnostic)] -#[diag("lifetime parameter `{$ident}` never used")] -pub(crate) struct UnusedLifetime { - #[suggestion("elide the unused lifetime", code = "", applicability = "machine-applicable")] - pub deletion_span: Option, - - pub ident: Ident, -} - #[derive(Diagnostic)] #[diag("named argument `{$named_arg_name}` is not used by name")] pub(crate) struct NamedArgumentUsedPositionally { @@ -3319,66 +3123,6 @@ pub(crate) struct NamedArgumentUsedPositionally { pub named_arg_name: String, } -#[derive(Diagnostic)] -#[diag("ambiguous glob re-exports")] -pub(crate) struct AmbiguousGlobReexports { - #[label("the name `{$name}` in the {$namespace} namespace is first re-exported here")] - pub first_reexport: Span, - #[label("but the name `{$name}` in the {$namespace} namespace is also re-exported here")] - pub duplicate_reexport: Span, - - pub name: String, - pub namespace: String, -} - -#[derive(Diagnostic)] -#[diag("private item shadows public glob re-export")] -pub(crate) struct HiddenGlobReexports { - #[note( - "the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here" - )] - pub glob_reexport: Span, - #[note("but the private item here shadows it")] - pub private_item: Span, - - pub name: String, - pub namespace: String, -} - -#[derive(Diagnostic)] -#[diag("unnecessary qualification")] -pub(crate) struct UnusedQualifications { - #[suggestion( - "remove the unnecessary path segments", - style = "verbose", - code = "", - applicability = "machine-applicable" - )] - pub removal_span: Span, -} - -#[derive(Diagnostic)] -#[diag( - "{$elided -> - [true] `&` without an explicit lifetime name cannot be used here - *[false] `'_` cannot be used here - }" -)] -pub(crate) struct AssociatedConstElidedLifetime { - #[suggestion( - "use the `'static` lifetime", - style = "verbose", - code = "{code}", - applicability = "machine-applicable" - )] - pub span: Span, - - pub code: &'static str, - pub elided: bool, - #[note("cannot automatically infer `'static` because of other lifetimes in scope")] - pub lifetimes_in_scope: MultiSpan, -} - #[derive(Diagnostic)] #[diag("creating a {$shared_label}reference to mutable static")] pub(crate) struct RefOfMutStatic<'a> { @@ -3423,28 +3167,6 @@ pub(crate) enum MutRefSugg { #[diag("`use` of a local item without leading `self::`, `super::`, or `crate::`")] pub(crate) struct UnqualifiedLocalImportsDiag; -#[derive(Diagnostic)] -#[diag("will be parsed as a guarded string in Rust 2024")] -pub(crate) struct ReservedString { - #[suggestion( - "insert whitespace here to avoid this being parsed as a guarded string in Rust 2024", - code = " ", - applicability = "machine-applicable" - )] - pub suggestion: Span, -} - -#[derive(Diagnostic)] -#[diag("reserved token in Rust 2024")] -pub(crate) struct ReservedMultihash { - #[suggestion( - "insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024", - code = " ", - applicability = "machine-applicable" - )] - pub suggestion: Span, -} - #[derive(Diagnostic)] #[diag("direct cast of function item into an integer")] pub(crate) struct FunctionCastsAsIntegerDiag<'tcx> { @@ -3752,19 +3474,6 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { pub right: Span, } -#[derive(Diagnostic)] -#[diag("visibility qualifiers have no effect on `const _` declarations")] -#[note("`const _` does not declare a name, so there is nothing for the qualifier to apply to")] -pub(crate) struct UnusedVisibility { - #[suggestion( - "remove the qualifier", - style = "short", - code = "", - applicability = "machine-applicable" - )] - pub span: Span, -} - #[derive(Diagnostic)] #[diag("doc alias is duplicated")] pub(crate) struct DocAliasDuplicated { @@ -3895,23 +3604,6 @@ pub(crate) struct UnknownCrateTypesSuggestion { pub snippet: Symbol, } -#[derive(Diagnostic)] -#[diag("unreachable configuration predicate")] -pub(crate) struct UnreachableCfgSelectPredicate { - #[label("this configuration predicate is never reached")] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag("unreachable configuration predicate")] -pub(crate) struct UnreachableCfgSelectPredicateWildcard { - #[label("this configuration predicate is never reached")] - pub span: Span, - - #[label("always matches")] - pub wildcard_span: Span, -} - #[derive(Diagnostic)] #[diag("positional format arguments are not allowed here")] #[help( @@ -3953,6 +3645,11 @@ pub(crate) struct IgnoredDiagnosticOption { #[help("at least one of the `message`, `note` and `label` options are expected")] pub(crate) struct MissingOptionsForOnConstAttr; +#[derive(Diagnostic)] +#[diag("missing options for `on_move` attribute")] +#[help("at least one of the `message`, `note` and `label` options are expected")] +pub(crate) struct MissingOptionsForOnMoveAttr; + #[derive(Diagnostic)] #[diag("malformed `on_unimplemented` attribute")] #[help("only `message`, `note` and `label` are allowed as options")] @@ -3973,3 +3670,27 @@ pub(crate) struct MalformedOnConstAttrLint { #[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")] #[note("this method was used to add checks to the `Eq` derive macro")] pub(crate) struct EqInternalMethodImplemented; + +#[derive(Diagnostic)] +#[diag("unknown or malformed `on_move` attribute")] +#[help( + "only `message`, `note` and `label` are allowed as options. Their values must be string literals" +)] +pub(crate) struct MalformedOnMoveAttrLint { + #[label("invalid option found here")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("unknown parameter `{$name}`")] +#[help("expect `Self` as format argument")] +pub(crate) struct OnMoveMalformedFormatLiterals { + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag("expected a literal or missing delimiter")] +#[help( + "only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma" +)] +pub(crate) struct OnMoveMalformedAttrExpectedLiteralOrDelimiter; diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index cbb9ca6aa00f..4ee25ac008eb 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -357,15 +357,24 @@ fn check_unnecessary_transmute<'tcx>( _ => return, }; - cx.tcx.node_span_lint(UNNECESSARY_TRANSMUTES, expr.hir_id, expr.span, |diag| { - diag.primary_message("unnecessary transmute"); - if let Some(sugg) = sugg { - diag.multipart_suggestion("replace this with", sugg, Applicability::MachineApplicable); - } - if let Some(help) = help { - diag.help(help); - } - }); + cx.tcx.emit_node_span_lint( + UNNECESSARY_TRANSMUTES, + expr.hir_id, + expr.span, + rustc_errors::DiagDecorator(|diag| { + diag.primary_message("unnecessary transmute"); + if let Some(sugg) = sugg { + diag.multipart_suggestion( + "replace this with", + sugg, + Applicability::MachineApplicable, + ); + } + if let Some(help) = help { + diag.help(help); + } + }), + ); } #[derive(Diagnostic)] diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 03a566efc8a5..2864cf9032a1 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -600,7 +600,7 @@ fn check_unused_delims_expr( && !value.span.from_expansion() && (ctx != UnusedDelimsCtx::LetScrutineeExpr || !matches!(inner.kind, ast::ExprKind::Binary( - rustc_span::source_map::Spanned { node, .. }, + rustc_span::Spanned { node, .. }, _, _, ) if node.is_lazy())) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 38ffecbafa06..22843f664b59 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -39,6 +39,7 @@ DEPRECATED_IN_FUTURE, DEPRECATED_SAFE_2024, DEPRECATED_WHERE_CLAUSE_LOCATION, + DUPLICATE_FEATURES, DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, ELIDED_LIFETIMES_IN_PATHS, @@ -105,7 +106,6 @@ SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, SHADOWING_SUPERTRAIT_ITEMS, SINGLE_USE_LIFETIMES, - SOFT_UNSTABLE, STABLE_FEATURES, TAIL_EXPR_DROP_ORDER, TEST_UNSTABLE_LINT, @@ -1032,8 +1032,8 @@ /// ```rust /// #[warn(unused_macro_rules)] /// macro_rules! unused_empty { - /// (hello) => { println!("Hello, world!") }; // This rule is unused - /// () => { println!("empty") }; // This rule is used + /// (hello) => { println!("Hello, world!") }; // This rule is used + /// () => { println!("empty") }; // This rule is unused /// } /// /// fn main() { @@ -1093,6 +1093,33 @@ "unused features found in crate-level `#[feature]` directives" } +declare_lint! { + /// The `duplicate_features` lint detects duplicate features found in + /// crate-level [`feature` attributes]. + /// + /// Note: This lint used to be a hard error (E0636). + /// + /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(internal_features)] + /// #![feature(rustc_attrs)] + /// #![feature(rustc_attrs)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Enabling a feature more than once is a no-op. + /// To avoid this warning, remove the second `feature()` attribute. + pub DUPLICATE_FEATURES, + Deny, + "duplicate features found in crate-level `#[feature]` directives" +} + declare_lint! { /// The `stable_features` lint detects a [`feature` attribute] that /// has since been made stable. @@ -2317,22 +2344,6 @@ }; } -declare_lint! { - /// The `soft_unstable` lint detects unstable features that were unintentionally allowed on - /// stable. This is a [future-incompatible] lint to transition this to a hard error in the - /// future. See [issue #64266] for more details. - /// - /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub SOFT_UNSTABLE, - Deny, - "a feature gate that doesn't break dependent crates", - @future_incompatible = FutureIncompatibleInfo { - reason: fcw!(FutureReleaseError #64266), - report_in_deps: true, - }; -} - declare_lint! { /// The `inline_no_sanitize` lint detects incompatible use of /// [`#[inline(always)]`][inline] and [`#[sanitize(xyz = "off")]`][sanitize]. diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1492df50a418..0528a0d69324 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -7,7 +7,7 @@ use rustc_data_structures::stable_hasher::{ HashStable, StableCompare, StableHasher, ToStableHashKey, }; -use rustc_error_messages::{DiagArgValue, IntoDiagArg, MultiSpan}; +use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_hir_id::{HashStableContext, HirId, ItemLocalId}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::DefPathHash; @@ -665,30 +665,6 @@ pub enum BuiltinLintDiag { test_module_span: Option, span_snippets: Vec, }, - RedundantImport(Vec<(Span, bool)>, Ident), - DeprecatedMacro { - suggestion: Option, - suggestion_span: Span, - note: Option, - path: String, - since_kind: DeprecatedSinceKind, - }, - PatternsInFnsWithoutBody { - span: Span, - ident: Ident, - is_foreign: bool, - }, - ReservedPrefix(Span, String), - /// `'r#` in edition < 2021. - RawPrefix(Span), - /// `##` or `#"` in edition < 2024. - ReservedString { - is_string: bool, - suggestion: Span, - }, - BreakWithLabelAndLoop(Span), - UnicodeTextFlow(Span, String), - DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), SingleUseLifetime { /// Span of the parameter which declares this lifetime. param_span: Span, @@ -697,7 +673,8 @@ pub enum BuiltinLintDiag { deletion_span: Option, /// Span of the single use, or None if the lifetime is never used. /// If true, the lifetime will be fully elided. - use_span: Option<(Span, bool)>, + use_span: Span, + elidable: bool, ident: Ident, }, NamedArgumentUsedPositionally { @@ -713,45 +690,7 @@ pub enum BuiltinLintDiag { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, - AmbiguousGlobReexports { - /// The name for which collision(s) have occurred. - name: String, - /// The name space for which the collision(s) occurred in. - namespace: String, - /// Span where the name is first re-exported. - first_reexport_span: Span, - /// Span where the same name is also re-exported. - duplicate_reexport_span: Span, - }, - 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, - }, - UnusedQualifications { - /// The span of the unnecessarily-qualified path to remove. - removal_span: Span, - }, - AssociatedConstElidedLifetime { - elided: bool, - span: Span, - lifetimes_in_scope: MultiSpan, - }, - UnusedCrateDependency { - extern_crate: Symbol, - local_crate: Symbol, - }, - UnusedVisibility(Span), AttributeLint(AttributeLintKind), - UnreachableCfg { - span: Span, - wildcard_span: Option, - }, } #[derive(Debug, HashStable_Generic)] @@ -840,6 +779,9 @@ pub enum AttributeLintKind { MalformedOnConstAttr { span: Span, }, + MalformedOnMoveAttr { + span: Span, + }, MalformedDiagnosticFormat { warning: FormatWarning, }, @@ -855,6 +797,11 @@ pub enum AttributeLintKind { }, MissingOptionsForOnUnimplemented, MissingOptionsForOnConst, + MissingOptionsForOnMove, + OnMoveMalformedFormatLiterals { + name: Symbol, + }, + OnMoveMalformedAttrExpectedLiteralOrDelimiter, } #[derive(Debug, Clone, HashStable_Generic)] diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index a47179c14d27..b4f6bb4583c1 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -301,12 +301,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( std::string Error; auto Trip = Triple(Triple::normalize(TripleStr)); - const llvm::Target *TheTarget = -#if LLVM_VERSION_GE(21, 0) - TargetRegistry::lookupTarget(Trip, Error); -#else - TargetRegistry::lookupTarget(Trip.getTriple(), Error); -#endif + const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip, Error); if (TheTarget == nullptr) { LLVMRustSetLastError(Error.c_str()); return nullptr; @@ -367,13 +362,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.EmitStackSizeSection = EmitStackSizeSection; -#if LLVM_VERSION_GE(21, 0) TargetMachine *TM = TheTarget->createTargetMachine(Trip, CPU, Feature, Options, RM, CM, OptLevel); -#else - TargetMachine *TM = TheTarget->createTargetMachine( - Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel); -#endif if (LargeDataThreshold != 0) { TM->setLargeDataThreshold(LargeDataThreshold); @@ -550,6 +540,8 @@ struct LLVMRustSanitizerOptions { bool SanitizeHWAddressRecover; bool SanitizeKernelAddress; bool SanitizeKernelAddressRecover; + bool SanitizeKernelHWAddress; + bool SanitizeKernelHWAddressRecover; }; extern "C" typedef void (*registerEnzymeAndPassPipelineFn)( @@ -701,12 +693,8 @@ extern "C" LLVMRustResult LLVMRustOptimize( if (LintIR) { PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM, OptimizationLevel Level) { -#if LLVM_VERSION_GE(21, 0) MPM.addPass( createModuleToFunctionPassAdaptor(LintPass(/*AbortOnError=*/true))); -#else - MPM.addPass(createModuleToFunctionPassAdaptor(LintPass())); -#endif }); } @@ -781,13 +769,15 @@ extern "C" LLVMRustResult LLVMRustOptimize( !TM->getTargetTriple().isOSWindows())); }); } - if (SanitizerOptions->SanitizeHWAddress) { + if (SanitizerOptions->SanitizeHWAddress || + SanitizerOptions->SanitizeKernelHWAddress) { OptimizerLastEPCallbacks.push_back( [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level, ThinOrFullLTOPhase phase) { HWAddressSanitizerOptions opts( - /*CompileKernel=*/false, - SanitizerOptions->SanitizeHWAddressRecover, + SanitizerOptions->SanitizeKernelHWAddress, + SanitizerOptions->SanitizeHWAddressRecover || + SanitizerOptions->SanitizeKernelHWAddressRecover, /*DisableOptimization=*/false); MPM.addPass(HWAddressSanitizerPass(opts)); }); @@ -1210,12 +1200,8 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, size_t num_modules, // Convert the preserved symbols set from string to GUID, this is then needed // for internalization. for (size_t i = 0; i < num_symbols; i++) { -#if LLVM_VERSION_GE(21, 0) auto GUID = GlobalValue::getGUIDAssumingExternalLinkage(preserved_symbols[i]); -#else - auto GUID = GlobalValue::getGUID(preserved_symbols[i]); -#endif Ret->GUIDPreservedSymbols.insert(GUID); } @@ -1474,21 +1460,12 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, DenseSet CfiFunctionDecls; // Based on the 'InProcessThinBackend' constructor in LLVM -#if LLVM_VERSION_GE(21, 0) for (auto &Name : Data->Index.cfiFunctionDefs().symbols()) CfiFunctionDefs.insert(GlobalValue::getGUIDAssumingExternalLinkage( GlobalValue::dropLLVMManglingEscape(Name))); for (auto &Name : Data->Index.cfiFunctionDecls().symbols()) CfiFunctionDecls.insert(GlobalValue::getGUIDAssumingExternalLinkage( GlobalValue::dropLLVMManglingEscape(Name))); -#else - for (auto &Name : Data->Index.cfiFunctionDefs()) - CfiFunctionDefs.insert( - GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); - for (auto &Name : Data->Index.cfiFunctionDecls()) - CfiFunctionDecls.insert( - GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); -#endif Key = llvm::computeLTOCacheKey(conf, Data->Index, ModId, ImportList, ExportList, ResolvedODR, DefinedGlobals, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index eabc1c94f26e..63ff0b2a0a0d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -137,11 +137,7 @@ extern "C" void LLVMRustSetLastError(const char *Err) { extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *Target) { -#if LLVM_VERSION_GE(21, 0) unwrap(M)->setTargetTriple(Triple(Triple::normalize(Target))); -#else - unwrap(M)->setTargetTriple(Triple::normalize(Target)); -#endif } extern "C" void LLVMRustPrintPassTimings(RustStringRef OutBuf) { @@ -452,11 +448,7 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { case LLVMRustAttributeKind::DeadOnUnwind: return Attribute::DeadOnUnwind; case LLVMRustAttributeKind::DeadOnReturn: -#if LLVM_VERSION_GE(21, 0) return Attribute::DeadOnReturn; -#else - report_fatal_error("DeadOnReturn attribute requires LLVM 21 or later"); -#endif case LLVMRustAttributeKind::CapturesAddress: case LLVMRustAttributeKind::CapturesReadOnly: case LLVMRustAttributeKind::CapturesNone: @@ -514,7 +506,6 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) { extern "C" LLVMAttributeRef LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) { -#if LLVM_VERSION_GE(21, 0) if (RustAttr == LLVMRustAttributeKind::CapturesNone) { return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none())); } @@ -527,7 +518,6 @@ LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) { *unwrap(C), CaptureInfo(CaptureComponents::Address | CaptureComponents::ReadProvenance))); } -#endif #if LLVM_VERSION_GE(23, 0) if (RustAttr == LLVMRustAttributeKind::DeadOnReturn) { return wrap(Attribute::getWithDeadOnReturnInfo(*unwrap(C), @@ -722,6 +712,13 @@ extern "C" void LLVMRustSetAllowReassoc(LLVMValueRef V) { } } +// Enable the NSZ flag on the given instruction. +extern "C" void LLVMRustSetNoSignedZeros(LLVMValueRef V) { + if (auto I = dyn_cast(unwrap(V))) { + I->setHasNoSignedZeros(true); + } +} + extern "C" uint64_t LLVMRustGetArrayNumElements(LLVMTypeRef Ty) { return unwrap(Ty)->getArrayNumElements(); } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 05a28c48f806..b75236b35230 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -140,15 +140,13 @@ struct CacheOnDiskIf { /// See `rustc_middle::query::modifiers` for documentation of each query modifier. struct QueryModifiers { // tidy-alphabetical-start - anon: Option, arena_cache: Option, cache_on_disk_if: Option, - cycle_delay_bug: Option, - cycle_stash: Option, depth_limit: Option, desc: Desc, eval_always: Option, feedable: Option, + no_force: Option, no_hash: Option, separate_provide_extern: Option, // tidy-alphabetical-end @@ -158,10 +156,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut arena_cache = None; let mut cache_on_disk_if = None; let mut desc = None; - let mut cycle_delay_bug = None; - let mut cycle_stash = None; + let mut no_force = None; let mut no_hash = None; - let mut anon = None; let mut eval_always = None; let mut depth_limit = None; let mut separate_provide_extern = None; @@ -193,14 +189,10 @@ macro_rules! try_insert { try_insert!(cache_on_disk_if = CacheOnDiskIf { modifier, block }); } else if modifier == "arena_cache" { try_insert!(arena_cache = modifier); - } else if modifier == "cycle_delay_bug" { - try_insert!(cycle_delay_bug = modifier); - } else if modifier == "cycle_stash" { - try_insert!(cycle_stash = modifier); + } else if modifier == "no_force" { + try_insert!(no_force = modifier); } else if modifier == "no_hash" { try_insert!(no_hash = modifier); - } else if modifier == "anon" { - try_insert!(anon = modifier); } else if modifier == "eval_always" { try_insert!(eval_always = modifier); } else if modifier == "depth_limit" { @@ -220,10 +212,8 @@ macro_rules! try_insert { arena_cache, cache_on_disk_if, desc, - cycle_delay_bug, - cycle_stash, + no_force, no_hash, - anon, eval_always, depth_limit, separate_provide_extern, @@ -253,35 +243,24 @@ fn returns_error_guaranteed(ret_ty: &ReturnType) -> bool { fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { let QueryModifiers { // tidy-alphabetical-start - anon, arena_cache, cache_on_disk_if, - cycle_delay_bug, - cycle_stash, depth_limit, desc: _, eval_always, feedable, + no_force, no_hash, separate_provide_extern, // tidy-alphabetical-end } = &query.modifiers; - let anon = anon.is_some(); let arena_cache = arena_cache.is_some(); let cache_on_disk = cache_on_disk_if.is_some(); - - let cycle_error_handling = if cycle_delay_bug.is_some() { - quote! { DelayBug } - } else if cycle_stash.is_some() { - quote! { Stash } - } else { - quote! { Error } - }; - let depth_limit = depth_limit.is_some(); let eval_always = eval_always.is_some(); let feedable = feedable.is_some(); + let no_force = no_force.is_some(); let no_hash = no_hash.is_some(); let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty); let separate_provide_extern = separate_provide_extern.is_some(); @@ -294,13 +273,12 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { query_name_span => // Search for (QMODLIST) to find all occurrences of this query modifier list. // tidy-alphabetical-start - anon: #anon, arena_cache: #arena_cache, cache_on_disk: #cache_on_disk, - cycle_error_handling: #cycle_error_handling, depth_limit: #depth_limit, eval_always: #eval_always, feedable: #feedable, + no_force: #no_force, no_hash: #no_hash, returns_error_guaranteed: #returns_error_guaranteed, separate_provide_extern: #separate_provide_extern, @@ -409,15 +387,15 @@ macro_rules! doc_link { } doc_link!( + // tidy-alphabetical-start arena_cache, - cycle_delay_bug, - cycle_stash, - no_hash, - anon, - eval_always, depth_limit, - separate_provide_extern, + eval_always, feedable, + no_force, + no_hash, + separate_provide_extern, + // tidy-alphabetical-end ); let name = &query.name; @@ -500,11 +478,6 @@ fn #name(#key_ty) #return_ty }); if let Some(feedable) = &modifiers.feedable { - assert!( - modifiers.anon.is_none(), - feedable.span(), - "Query {name} cannot be both `feedable` and `anon`." - ); assert!( modifiers.eval_always.is_none(), feedable.span(), @@ -522,8 +495,8 @@ fn #name(#key_ty) #return_ty /// Higher-order macro that invokes the specified macro with (a) a list of all query /// signatures (including modifiers), and (b) a list of non-query names. This allows /// multiple simpler macros to each have access to these lists. - #[macro_export] - macro_rules! rustc_with_all_queries { + #[rustc_macro_transparency = "semiopaque"] // Use `macro_rules!` hygiene. + pub macro rustc_with_all_queries { ( // The macro to invoke once, on all queries and non-queries. $macro:ident! diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 4000f12459a9..345ee185156c 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -23,15 +23,14 @@ use rustc_middle::ty::data_structures::IndexSet; use rustc_middle::ty::{TyCtxt, TyCtxtFeed}; use rustc_proc_macro::bridge::client::ProcMacro; -use rustc_session::Session; use rustc_session::config::{ CrateType, ExtendedTargetModifierInfo, ExternLocation, Externs, OptionsTargetModifiers, TargetModifier, }; use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource}; -use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; +use rustc_session::{Session, lint}; use rustc_span::def_id::DefId; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; @@ -1211,7 +1210,7 @@ fn report_unused_deps_in_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, ast::CRATE_NODE_ID, - BuiltinLintDiag::UnusedCrateDependency { + errors::UnusedCrateDependency { extern_crate: name_interned, local_crate: tcx.crate_name(LOCAL_CRATE), }, diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index d4c61441bcea..8b2895d70004 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -688,3 +688,11 @@ pub struct RawDylibMalformed { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag("extern crate `{$extern_crate}` is unused in crate `{$local_crate}`")] +#[help("remove the dependency or add `use {$extern_crate} as _;` to the crate root")] +pub(crate) struct UnusedCrateDependency { + pub extern_crate: Symbol, + pub local_crate: Symbol, +} diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 52b11615c76f..a05366d7147b 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -5,16 +5,21 @@ use rustc_attr_parsing::eval_config_entry; use rustc_data_structures::fx::FxHashSet; use rustc_hir::attrs::{NativeLibKind, PeImportNameType}; +use rustc_hir::def::DefKind; use rustc_hir::find_attr; +use rustc_middle::bug; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::query::LocalCrate; use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::config::CrateType; -use rustc_session::cstore::{DllCallingConvention, DllImport, ForeignModule, NativeLib}; +use rustc_session::cstore::{ + DllCallingConvention, DllImport, DllImportSymbolType, ForeignModule, NativeLib, +}; use rustc_session::search_paths::PathKind; use rustc_span::Symbol; use rustc_span::def_id::{DefId, LOCAL_CRATE}; -use rustc_target::spec::{Abi, Arch, BinaryFormat, Env, LinkSelfContainedComponents, Os}; +use rustc_target::spec::{Arch, BinaryFormat, CfgAbi, Env, LinkSelfContainedComponents, Os}; use crate::errors; @@ -68,14 +73,14 @@ pub fn walk_native_lib_search_dirs( // FIXME: On AIX this also has the side-effect of making the list of library search paths // non-empty, which is needed or the linker may decide to record the LIBPATH env, if // defined, as the search path instead of appending the default search paths. - if sess.target.abi == Abi::Fortanix + if sess.target.cfg_abi == CfgAbi::Fortanix || sess.target.os == Os::Linux || sess.target.os == Os::Fuchsia || sess.target.is_like_aix || sess.target.is_like_darwin && !sess.sanitizers().is_empty() || sess.target.os == Os::Windows && sess.target.env == Env::Gnu - && sess.target.abi == Abi::Llvm + && sess.target.cfg_abi == CfgAbi::Llvm { f(&sess.target_tlib_path.dir, false)?; } @@ -451,12 +456,32 @@ fn build_dll_import( } } - DllImport { - name, - import_name_type, - calling_convention, - span, - is_fn: self.tcx.def_kind(item).is_fn_like(), - } + let def_kind = self.tcx.def_kind(item); + let symbol_type = if def_kind.is_fn_like() { + DllImportSymbolType::Function + } else if matches!(def_kind, DefKind::Static { .. }) { + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + DllImportSymbolType::ThreadLocal + } else { + DllImportSymbolType::Static + } + } else { + bug!("Unexpected type for raw-dylib: {}", def_kind.descr(item)); + }; + + let size = match symbol_type { + // We cannot determine the size of a function at compile time, but it shouldn't matter anyway. + DllImportSymbolType::Function => rustc_abi::Size::ZERO, + DllImportSymbolType::Static | DllImportSymbolType::ThreadLocal => { + let ty = self.tcx.type_of(item).instantiate_identity(); + self.tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + .ok() + .map(|layout| layout.size) + .unwrap_or_else(|| bug!("Non-function symbols must have a size")) + } + }; + + DllImport { name, import_name_type, calling_convention, span, symbol_type, size } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 2fa8e19984b4..fc541f952d22 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1223,7 +1223,7 @@ fn get_stripped_cfg_items<'tcx>( .root .stripped_cfg_items .decode((self, tcx)) - .map(|item| item.map_mod_id(|index| DefId { krate: cnum, index })); + .map(|item| item.map_scope_id(|index| DefId { krate: cnum, index })); tcx.arena.alloc_from_iter(item_names) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index fbc7232f3a27..8bf919dab8e7 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -727,7 +727,7 @@ macro_rules! stat { is_stub: false, }, extra_filename: tcx.sess.opts.cg.extra_filename.clone(), - stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), + stable_crate_id: tcx.stable_crate_id(LOCAL_CRATE), required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE), panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, edition: tcx.sess.edition(), @@ -2145,7 +2145,7 @@ fn encode_stripped_cfg_items(&mut self) -> LazyArray> self.tcx .stripped_cfg_items(LOCAL_CRATE) .into_iter() - .map(|item| item.clone().map_mod_id(|def_id| def_id.index)), + .map(|item| item.clone().map_scope_id(|def_id| def_id.index)), ) } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 80d7ae4e9cb3..9dee913e8389 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -33,7 +33,7 @@ use rustc_middle::mir; use rustc_middle::mir::ConstValue; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::{self, Ty, TyCtxt, UnusedGenericParams}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util::Providers; use rustc_serialize::opaque::FileEncoder; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 5e256438ad95..3b0570dd373a 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -44,16 +44,6 @@ fn is_default(&self) -> bool { } } -impl IsDefault for UnusedGenericParams { - fn is_default(&self) -> bool { - // UnusedGenericParams encodes the *un*usedness as a bitset. - // This means that 0 corresponds to all bits used, which is indeed the default. - let is_default = self.bits() == 0; - debug_assert_eq!(is_default, self.all_used()); - is_default - } -} - /// Helper trait, for encoding to, and decoding from, a fixed number of bytes. /// Used mainly for Lazy positions and lengths. /// diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 6f85dba23dd4..b5f0692b61ce 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -94,10 +94,14 @@ pub const fn as_usize(&self) -> usize { pub struct DepNode { pub kind: DepKind, - /// This is _typically_ a hash of the query key, but sometimes not. + /// If `kind` is a query method, then its "key fingerprint" is always a + /// stable hash of the query key. /// - /// For example, `anon` nodes have a fingerprint that is derived from their - /// dependencies instead of a key. + /// For non-query nodes, the content of this field varies: + /// - Some dep kinds always use a dummy `ZERO` fingerprint. + /// - Some dep kinds use the stable hash of some relevant key-like value. + /// - Some dep kinds use the `with_anon_task` mechanism, and set their key + /// fingerprint to a hash derived from the task's dependencies. /// /// In some cases the key value can be reconstructed from this fingerprint; /// see [`KeyFingerprintStyle`]. @@ -331,7 +335,7 @@ pub mod label_strs { } // Create various data structures for each query, and also for a few things that aren't queries. -rustc_with_all_queries! { define_dep_nodes! } +crate::queries::rustc_with_all_queries! { define_dep_nodes! } // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. // Be very careful changing this type signature! @@ -408,9 +412,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(DepKind, 2); - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] static_assert_size!(DepNode, 18); - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - static_assert_size!(DepNode, 24); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index 963d5f1a53bd..4e789d702ce0 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -18,7 +18,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::Session; use rustc_span::Symbol; -use tracing::{debug, instrument}; +use tracing::instrument; #[cfg(debug_assertions)] use {super::debug::EdgeFilter, std::env}; @@ -164,9 +164,10 @@ pub fn new( ); assert_eq!(red_node_index, DepNodeIndex::FOREVER_RED_NODE); if prev_graph_node_count > 0 { - colors.insert_red(SerializedDepNodeIndex::from_u32( - DepNodeIndex::FOREVER_RED_NODE.as_u32(), - )); + let prev_index = + const { SerializedDepNodeIndex::from_u32(DepNodeIndex::FOREVER_RED_NODE.as_u32()) }; + let result = colors.try_set_color(prev_index, DesiredColor::Red); + assert_matches!(result, TrySetColorResult::Success); } DepGraph { @@ -292,7 +293,7 @@ pub fn with_task<'tcx, A: Debug, R>( pub fn with_anon_task<'tcx, OP, R>( &self, - cx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, dep_kind: DepKind, op: OP, ) -> (R, DepNodeIndex) @@ -301,7 +302,7 @@ pub fn with_anon_task<'tcx, OP, R>( { match self.data() { Some(data) => { - let (result, index) = data.with_anon_task_inner(cx, dep_kind, op); + let (result, index) = data.with_anon_task_inner(tcx, dep_kind, op); self.read_index(index); (result, index) } @@ -375,18 +376,17 @@ pub fn with_task<'tcx, A: Debug, R>( /// incorrectly marked green. /// /// FIXME: This could perhaps return a `WithDepNode` to ensure that the - /// user of this function actually performs the read; we'll have to see - /// how to make that work with `anon` in `execute_job_incr`, though. - pub fn with_anon_task_inner<'tcx, OP, R>( + /// user of this function actually performs the read. + fn with_anon_task_inner<'tcx, OP, R>( &self, - cx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, dep_kind: DepKind, op: OP, ) -> (R, DepNodeIndex) where OP: FnOnce() -> R, { - debug_assert!(!cx.is_eval_always(dep_kind)); + debug_assert!(!tcx.is_eval_always(dep_kind)); // Large numbers of reads are common enough here that pre-sizing `read_set` // to 128 actually helps perf on some benchmarks. @@ -709,7 +709,7 @@ fn encode_side_effect<'tcx>( // side effect. std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), ); - tcx.store_side_effect(dep_node_index, side_effect); + tcx.query_system.side_effects.borrow_mut().insert(dep_node_index, side_effect); dep_node_index } @@ -718,7 +718,13 @@ fn encode_side_effect<'tcx>( #[inline] fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) { with_deps(TaskDepsRef::Ignore, || { - let side_effect = tcx.load_side_effect(prev_index).unwrap(); + let side_effect = tcx + .query_system + .on_disk_cache + .as_ref() + .unwrap() + .load_side_effect(tcx, prev_index) + .unwrap(); // Use `send_and_color` as `promote_node_and_deps_to_current` expects all // green dependencies. `send_and_color` will also prevent multiple nodes @@ -745,7 +751,7 @@ fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNo } // This will just overwrite the same value for concurrent calls. - tcx.store_side_effect(dep_node_index, side_effect); + tcx.query_system.side_effects.borrow_mut().insert(dep_node_index, side_effect); }) } @@ -865,7 +871,7 @@ pub(crate) fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str dep_node_debug.borrow_mut().insert(dep_node, debug_str); } - pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { + pub(crate) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() } @@ -918,94 +924,6 @@ pub fn try_mark_green<'tcx>( } } - #[instrument(skip(self, tcx, parent_dep_node_index, frame), level = "debug")] - fn try_mark_parent_green<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - parent_dep_node_index: SerializedDepNodeIndex, - frame: &MarkFrame<'_>, - ) -> Option<()> { - let get_dep_dep_node = || self.previous.index_to_node(parent_dep_node_index); - - match self.colors.get(parent_dep_node_index) { - DepNodeColor::Green(_) => { - // This dependency has been marked as green before, we are - // still fine and can continue with checking the other - // dependencies. - // - // This path is extremely hot. We don't want to get the - // `dep_dep_node` unless it's necessary. Hence the - // `get_dep_dep_node` closure. - debug!("dependency {:?} was immediately green", get_dep_dep_node()); - return Some(()); - } - DepNodeColor::Red => { - // We found a dependency the value of which has changed - // compared to the previous compilation session. We cannot - // mark the DepNode as green and also don't need to bother - // with checking any of the other dependencies. - debug!("dependency {:?} was immediately red", get_dep_dep_node()); - return None; - } - DepNodeColor::Unknown => {} - } - - let dep_dep_node = get_dep_dep_node(); - - // We don't know the state of this dependency. If it isn't - // an eval_always node, let's try to mark it green recursively. - if !tcx.is_eval_always(dep_dep_node.kind) { - debug!( - "state of dependency {:?} ({}) is unknown, trying to mark it green", - dep_dep_node, dep_dep_node.key_fingerprint, - ); - - let node_index = self.try_mark_previous_green(tcx, parent_dep_node_index, Some(frame)); - - if node_index.is_some() { - debug!("managed to MARK dependency {dep_dep_node:?} as green"); - return Some(()); - } - } - - // We failed to mark it green, so we try to force the query. - debug!("trying to force dependency {dep_dep_node:?}"); - if !tcx.try_force_from_dep_node(*dep_dep_node, parent_dep_node_index, frame) { - // The DepNode could not be forced. - debug!("dependency {dep_dep_node:?} could not be forced"); - return None; - } - - match self.colors.get(parent_dep_node_index) { - DepNodeColor::Green(_) => { - debug!("managed to FORCE dependency {dep_dep_node:?} to green"); - return Some(()); - } - DepNodeColor::Red => { - debug!("dependency {dep_dep_node:?} was red after forcing"); - return None; - } - DepNodeColor::Unknown => {} - } - - if let None = tcx.dcx().has_errors_or_delayed_bugs() { - panic!("try_mark_previous_green() - Forcing the DepNode should have set its color") - } - - // If the query we just forced has resulted in - // some kind of compilation error, we cannot rely on - // the dep-node color having been properly updated. - // This means that the query system has reached an - // invalid state. We let the compiler continue (by - // returning `None`) so it can emit error messages - // and wind down, but rely on the fact that this - // invalid state will not be persisted to the - // incremental compilation cache because of - // compilation errors being present. - debug!("dependency {dep_dep_node:?} resulted in compilation error"); - return None; - } - /// Try to mark a dep-node which existed in the previous compilation session as green. #[instrument(skip(self, tcx, prev_dep_node_index, frame), level = "debug")] fn try_mark_previous_green<'tcx>( @@ -1019,17 +937,58 @@ fn try_mark_previous_green<'tcx>( // We never try to mark eval_always nodes as green debug_assert!(!tcx.is_eval_always(self.previous.index_to_node(prev_dep_node_index).kind)); - let prev_deps = self.previous.edge_targets_from(prev_dep_node_index); + for parent_dep_node_index in self.previous.edge_targets_from(prev_dep_node_index) { + match self.colors.get(parent_dep_node_index) { + // This dependency has been marked as green before, we are still ok and can + // continue checking the remaining dependencies. + DepNodeColor::Green(_) => continue, - for dep_dep_node_index in prev_deps { - self.try_mark_parent_green(tcx, dep_dep_node_index, &frame)?; + // This dependency's result is different to the previous compilation session. We + // cannot mark this dep_node as green, so stop checking. + DepNodeColor::Red => return None, + + // We still need to determine this dependency's colour. + DepNodeColor::Unknown => {} + } + + let parent_dep_node = self.previous.index_to_node(parent_dep_node_index); + + // If this dependency isn't eval_always, try to mark it green recursively. + if !tcx.is_eval_always(parent_dep_node.kind) + && self.try_mark_previous_green(tcx, parent_dep_node_index, Some(&frame)).is_some() + { + continue; + } + + // We failed to mark it green, so we try to force the query. + if !tcx.try_force_from_dep_node(*parent_dep_node, parent_dep_node_index, &frame) { + return None; + } + + match self.colors.get(parent_dep_node_index) { + DepNodeColor::Green(_) => continue, + DepNodeColor::Red => return None, + DepNodeColor::Unknown => {} + } + + if tcx.dcx().has_errors_or_delayed_bugs().is_none() { + panic!("try_mark_previous_green() - forcing failed to set a color"); + } + + // If the query we just forced has resulted in some kind of compilation error, we + // cannot rely on the dep-node color having been properly updated. This means that the + // query system has reached an invalid state. We let the compiler continue (by + // returning `None`) so it can emit error messages and wind down, but rely on the fact + // that this invalid state will not be persisted to the incremental compilation cache + // because of compilation errors being present. + return None; } // If we got here without hitting a `return` that means that all // dependencies of this DepNode could be marked as green. Therefore we // can also mark this DepNode as green. - // There may be multiple threads trying to mark the same dep node green concurrently + // There may be multiple threads trying to mark the same dep node green concurrently. // We allocating an entry for the node in the current dependency graph and // adding all the appropriate edges imported from the previous graph. @@ -1038,12 +997,8 @@ fn try_mark_previous_green<'tcx>( let dep_node_index = self.promote_node_and_deps_to_current(prev_dep_node_index)?; // ... and finally storing a "Green" entry in the color map. - // Multiple threads can all write the same color here + // Multiple threads can all write the same color here. - debug!( - "successfully marked {:?} as green", - self.previous.index_to_node(prev_dep_node_index) - ); Some(dep_node_index) } } @@ -1103,7 +1058,7 @@ pub fn exec_cache_promotions<'tcx>(&self, tcx: TyCtxt<'tcx>) { } } - pub fn finish_encoding(&self) -> FileEncodeResult { + pub(crate) fn finish_encoding(&self) -> FileEncodeResult { if let Some(data) = &self.data { data.current.encoder.finish(&data.current) } else { Ok(0) } } @@ -1416,28 +1371,29 @@ pub(super) fn current(&self, index: SerializedDepNodeIndex) -> Option Result<(), Option> { - let value = &self.values[prev_index]; - match value.compare_exchange( + color: DesiredColor, + ) -> TrySetColorResult { + match self.values[prev_index].compare_exchange( COMPRESSED_UNKNOWN, - if green { index.as_u32() } else { COMPRESSED_RED }, + match color { + DesiredColor::Red => COMPRESSED_RED, + DesiredColor::Green { index } => index.as_u32(), + }, Ordering::Relaxed, Ordering::Relaxed, ) { - Ok(_) => Ok(()), - Err(v) => Err(if v == COMPRESSED_RED { None } else { Some(DepNodeIndex::from_u32(v)) }), + Ok(_) => TrySetColorResult::Success, + Err(COMPRESSED_RED) => TrySetColorResult::AlreadyRed, + Err(index) => TrySetColorResult::AlreadyGreen { index: DepNodeIndex::from_u32(index) }, } } @@ -1455,13 +1411,28 @@ pub(super) fn get(&self, index: SerializedDepNodeIndex) -> DepNodeColor { DepNodeColor::Unknown } } +} - #[inline] - pub(super) fn insert_red(&self, index: SerializedDepNodeIndex) { - let value = self.values[index].swap(COMPRESSED_RED, Ordering::Release); - // Sanity check for duplicate nodes - assert_eq!(value, COMPRESSED_UNKNOWN, "tried to color an already colored node as red"); - } +/// The color that [`DepNodeColorMap::try_set_color`] should try to apply to a node. +#[derive(Clone, Copy, Debug)] +pub(super) enum DesiredColor { + /// Try to mark the node red. + Red, + /// Try to mark the node green, associating it with a current-session node index. + Green { index: DepNodeIndex }, +} + +/// Return value of [`DepNodeColorMap::try_set_color`], indicating success or failure, +/// and (on failure) what the existing color is. +#[derive(Clone, Copy, Debug)] +pub(super) enum TrySetColorResult { + /// The [`DesiredColor`] was freshly applied to the node. + Success, + /// Coloring failed because the node was already marked red. + AlreadyRed, + /// Coloring failed because the node was already marked green, + /// and corresponds to node `index` in the current-session dep graph. + AlreadyGreen { index: DepNodeIndex }, } #[inline(never)] @@ -1533,23 +1504,4 @@ impl<'tcx> TyCtxt<'tcx> { fn is_eval_always(self, kind: DepKind) -> bool { self.dep_kind_vtable(kind).is_eval_always } - - // Interactions with on_disk_cache - fn load_side_effect( - self, - prev_dep_node_index: SerializedDepNodeIndex, - ) -> Option { - self.query_system - .on_disk_cache - .as_ref() - .and_then(|c| c.load_side_effect(self, prev_dep_node_index)) - } - - #[inline(never)] - #[cold] - fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect) { - if let Some(c) = self.query_system.on_disk_cache.as_ref() { - c.store_side_effect(dep_node_index, side_effect) - } - } } diff --git a/compiler/rustc_middle/src/dep_graph/retained.rs b/compiler/rustc_middle/src/dep_graph/retained.rs index 4427982e3708..626b3b782179 100644 --- a/compiler/rustc_middle/src/dep_graph/retained.rs +++ b/compiler/rustc_middle/src/dep_graph/retained.rs @@ -1,6 +1,5 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, LinkedGraph, NodeIndex}; -use rustc_index::IndexVec; use super::{DepNode, DepNodeIndex}; @@ -13,7 +12,6 @@ pub struct RetainedDepGraph { pub inner: LinkedGraph, pub indices: FxHashMap, - pub dep_index_to_index: IndexVec>, } impl RetainedDepGraph { @@ -23,27 +21,22 @@ pub fn new(prev_node_count: usize) -> Self { let inner = LinkedGraph::with_capacity(node_count, edge_count); let indices = FxHashMap::default(); - let dep_index_to_index = IndexVec::new(); - Self { inner, indices, dep_index_to_index } + Self { inner, indices } } pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) { - let source = self.inner.add_node(node); - self.dep_index_to_index.insert(index, source); + let source = NodeIndex(index.as_usize()); + self.inner.add_node_with_idx(source, node); self.indices.insert(node, source); for &target in edges.iter() { - // We may miss the edges that are pushed while the `DepGraphQuery` is being accessed. - // Skip them to issues. - if let Some(&Some(target)) = self.dep_index_to_index.get(target) { - self.inner.add_edge(source, target, ()); - } + self.inner.add_edge(source, NodeIndex(target.as_usize()), ()); } } pub fn nodes(&self) -> Vec<&DepNode> { - self.inner.all_nodes().iter().map(|n| &n.data).collect() + self.inner.all_nodes().iter().map(|n| n.data.as_ref().unwrap()).collect() } pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { diff --git a/compiler/rustc_middle/src/dep_graph/serialized.rs b/compiler/rustc_middle/src/dep_graph/serialized.rs index 8a4ac4b5e5ac..ef5e3d9268ad 100644 --- a/compiler/rustc_middle/src/dep_graph/serialized.rs +++ b/compiler/rustc_middle/src/dep_graph/serialized.rs @@ -43,7 +43,7 @@ use std::cmp::max; use std::sync::Arc; use std::sync::atomic::Ordering; -use std::{iter, mem, u64}; +use std::{iter, mem}; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::FxHashMap; @@ -58,7 +58,7 @@ use rustc_session::Session; use tracing::{debug, instrument}; -use super::graph::{CurrentDepGraph, DepNodeColorMap}; +use super::graph::{CurrentDepGraph, DepNodeColorMap, DesiredColor, TrySetColorResult}; use super::retained::RetainedDepGraph; use super::{DepKind, DepNode, DepNodeIndex}; use crate::dep_graph::edges::EdgesVec; @@ -72,6 +72,15 @@ pub struct SerializedDepNodeIndex {} } +impl SerializedDepNodeIndex { + /// Converts a current-session dep node index to a "serialized" index, + /// for the purpose of serializing data to be loaded by future sessions. + #[inline(always)] + pub fn from_curr_for_serialization(index: DepNodeIndex) -> Self { + SerializedDepNodeIndex::from_u32(index.as_u32()) + } +} + const DEP_NODE_SIZE: usize = size_of::(); /// Amount of padding we need to add to the edge list data so that we can retrieve every /// SerializedDepNodeIndex with a fixed-size read then mask. @@ -905,13 +914,14 @@ pub(crate) fn send_and_color( let mut local = self.status.local.borrow_mut(); let index = self.status.next_index(&mut *local); + let color = if is_green { DesiredColor::Green { index } } else { DesiredColor::Red }; - // Use `try_mark` to avoid racing when `send_promoted` is called concurrently + // Use `try_set_color` to avoid racing when `send_promoted` is called concurrently // on the same index. - match colors.try_mark(prev_index, index, is_green) { - Ok(()) => (), - Err(None) => panic!("dep node {:?} is unexpectedly red", prev_index), - Err(Some(dep_node_index)) => return dep_node_index, + match colors.try_set_color(prev_index, color) { + TrySetColorResult::Success => {} + TrySetColorResult::AlreadyRed => panic!("dep node {prev_index:?} is unexpectedly red"), + TrySetColorResult::AlreadyGreen { index } => return index, } self.status.bump_index(&mut *local); @@ -923,7 +933,8 @@ pub(crate) fn send_and_color( /// from the previous dep graph and expects all edges to already have a new dep node index /// assigned. /// - /// This will also ensure the dep node is marked green if `Some` is returned. + /// Tries to mark the dep node green, and returns Some if it is now green, + /// or None if had already been concurrently marked red. #[inline] pub(crate) fn send_promoted( &self, @@ -935,10 +946,10 @@ pub(crate) fn send_promoted( let mut local = self.status.local.borrow_mut(); let index = self.status.next_index(&mut *local); - // Use `try_mark_green` to avoid racing when `send_promoted` or `send_and_color` + // Use `try_set_color` to avoid racing when `send_promoted` or `send_and_color` // is called concurrently on the same index. - match colors.try_mark(prev_index, index, true) { - Ok(()) => { + match colors.try_set_color(prev_index, DesiredColor::Green { index }) { + TrySetColorResult::Success => { self.status.bump_index(&mut *local); self.status.encode_promoted_node( index, @@ -949,7 +960,8 @@ pub(crate) fn send_promoted( ); Some(index) } - Err(dep_node_index) => dep_node_index, + TrySetColorResult::AlreadyRed => None, + TrySetColorResult::AlreadyGreen { index } => Some(index), } } diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index dfb99fb98513..44ac747726a6 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,8 +1,7 @@ +use std::io; use std::path::Path; -use std::{fmt, io}; use rustc_errors::codes::*; -use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -114,56 +113,6 @@ pub(super) struct ConstNotUsedTraitAlias { pub span: Span, } -pub struct CustomSubdiagnostic<'a> { - pub msg: fn() -> DiagMessage, - pub add_args: Box, -} - -impl<'a> CustomSubdiagnostic<'a> { - pub fn label(x: fn() -> DiagMessage) -> Self { - Self::label_and_then(x, |_| {}) - } - pub fn label_and_then( - msg: fn() -> DiagMessage, - f: F, - ) -> Self { - Self { msg, add_args: Box::new(move |x| f(x)) } - } -} - -impl fmt::Debug for CustomSubdiagnostic<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CustomSubdiagnostic").finish_non_exhaustive() - } -} - -#[derive(Diagnostic)] -pub enum LayoutError<'tcx> { - #[diag("the type `{$ty}` has an unknown layout")] - Unknown { ty: Ty<'tcx> }, - - #[diag("the type `{$ty}` does not have a fixed layout")] - TooGeneric { ty: Ty<'tcx> }, - - #[diag("values of the type `{$ty}` are too big for the target architecture")] - Overflow { ty: Ty<'tcx> }, - - #[diag("the SIMD type `{$ty}` has more elements than the limit {$max_lanes}")] - SimdTooManyLanes { ty: Ty<'tcx>, max_lanes: u64 }, - - #[diag("the SIMD type `{$ty}` has zero elements")] - SimdZeroLength { ty: Ty<'tcx> }, - - #[diag("unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized")] - NormalizationFailure { ty: Ty<'tcx>, failure_ty: String }, - - #[diag("a cycle occurred during layout computation")] - Cycle, - - #[diag("the type has an unknown layout")] - ReferencesError, -} - #[derive(Diagnostic)] #[diag("erroneous constant encountered")] pub(crate) struct ErroneousConstant { diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index cf1b863f754c..499c6dae060b 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in}; +use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; @@ -310,16 +310,18 @@ pub fn hir_body_owner_kind(self, def_id: impl Into) -> BodyOwnerKind { /// This should only be used for determining the context of a body, a return /// value of `Some` does not always suggest that the owner of the body is `const`, /// just that it has to be checked as if it were. - pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option { - let def_id = def_id.into(); + pub fn hir_body_const_context(self, local_def_id: LocalDefId) -> Option { + let def_id = local_def_id.into(); let ccx = match self.hir_body_owner_kind(def_id) { BodyOwnerKind::Const { inline } => ConstContext::Const { inline }, BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability), BodyOwnerKind::Fn if self.is_constructor(def_id) => return None, - BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.is_const_fn(def_id) => { - ConstContext::ConstFn + // Const closures use their parent's const context + BodyOwnerKind::Closure if self.is_const_fn(def_id) => { + return self.hir_body_const_context(self.local_parent(local_def_id)); } + BodyOwnerKind::Fn if self.is_const_fn(def_id) => ConstContext::ConstFn, BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, }; @@ -1243,7 +1245,25 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod } } +fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) { + let krate = tcx.hir_crate(()); + for &id in &krate.delayed_ids { + tcx.ensure_done().lower_delayed_owner(id); + } + + let (_, krate) = krate.delayed_resolver.steal(); + let prof = tcx.sess.prof.clone(); + + // Drop AST to free memory. It can be expensive so try to drop it on a separate thread. + spawn(move || { + let _timer = prof.verbose_generic_activity("drop_ast"); + drop(krate); + }); +} + pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { + force_delayed_owners_lowering(tcx); + let mut collector = ItemCollector::new(tcx, true); // A "crate collector" and "module collector" start at a diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 82f8eb4bbc4a..ad56e462d293 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -6,19 +6,83 @@ pub mod nested_filter; pub mod place; +use std::sync::Arc; + +use rustc_ast::{self as ast}; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lints::DelayedLint; use rustc_hir::*; +use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::{ErrorGuaranteed, ExpnId, Span}; use crate::query::Providers; -use crate::ty::TyCtxt; +use crate::ty::{ResolverAstLowering, TyCtxt}; + +/// The top-level data structure that stores the entire contents of +/// the crate currently being compiled. +/// +/// For more details, see the [rustc dev guide]. +/// +/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html +#[derive(Debug)] +pub struct Crate<'hir> { + // This field is private by intention, access it through `owner` method. + owners: IndexVec>, + // Ids of delayed AST owners which are lowered through `lower_delayed_owner` query. + pub delayed_ids: FxIndexSet, + // The resolver and AST crate which are set in the end of the `hir_crate` query + // and then stolen and dropped in `force_delayed_owners_lowering`. + pub delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc)>, + // Only present when incr. comp. is enabled. + pub opt_hir_hash: Option, +} + +impl<'hir> Crate<'hir> { + pub fn new( + owners: IndexVec>, + delayed_ids: FxIndexSet, + delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc)>, + opt_hir_hash: Option, + ) -> Crate<'hir> { + Crate { owners, delayed_ids, delayed_resolver, opt_hir_hash } + } + + /// Serves as an entry point for getting `MaybeOwner`. As owner can either be in + /// `owners` of `hir_crate` or it can be delayed AST owner (i.e., delegations) + /// we need to firstly check in `hir_crate` and then delayed AST owners. + /// This method can be invoked when not all delayed AST owners are lowered. + pub fn owner(&self, tcx: TyCtxt<'hir>, def_id: LocalDefId) -> MaybeOwner<'hir> { + // Delayed LocalDefId can be in `self.owners` if there exists non-delayed LocalDefId + // which is greater than delayed LocalDefId, we use IndexVec for owners, + // so we will call ensure_contains_elem which will grow it. + if let Some(owner) = self.owners.get(def_id) + && (self.delayed_ids.is_empty() || !matches!(owner, MaybeOwner::Phantom)) + { + return *owner; + } + + if self.delayed_ids.contains(&def_id) { + tcx.ensure_done().lower_delayed_owner(def_id); + } + + tcx.delayed_owner(def_id) + } +} + +impl HashStable for Crate<'_> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + let Crate { opt_hir_hash, .. } = self; + opt_hir_hash.unwrap().hash_stable(hcx, hasher) + } +} /// Gather the LocalDefId for each item-like within a module, including items contained within /// bodies. The Ids are in visitor order. This is used to partition a pass between modules. @@ -372,7 +436,9 @@ fn hir_owner_parent_impl(self, owner_id: OwnerId) -> HirId { let parent_owner_id = self.local_def_id_to_hir_id(parent_def_id).owner; HirId { owner: parent_owner_id, - local_id: self.hir_crate(()).owners[parent_owner_id.def_id] + local_id: self + .hir_crate(()) + .owner(self, parent_owner_id.def_id) .unwrap() .parenting .get(&owner_id.def_id) @@ -406,19 +472,19 @@ pub fn provide(providers: &mut Providers) { providers.hir_crate_items = map::hir_crate_items; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; - providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owners[def_id] { + providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owner(tcx, def_id) { MaybeOwner::Owner(_) => HirId::make_owner(def_id), MaybeOwner::NonOwner(hir_id) => hir_id, MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id), }; providers.opt_hir_owner_nodes = - |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes); + |tcx, id| tcx.hir_crate(()).owner(tcx, id).as_owner().map(|i| &i.nodes); providers.hir_owner_parent_q = |tcx, owner_id| tcx.hir_owner_parent_impl(owner_id); providers.hir_attr_map = |tcx, id| { - tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) + tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; providers.opt_ast_lowering_delayed_lints = - |tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints); + |tcx, id| tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|o| &o.delayed_lints); providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)); providers.def_ident_span = |tcx, def_id| { let hir_id = tcx.local_def_id_to_hir_id(def_id); @@ -459,6 +525,6 @@ pub fn provide(providers: &mut Providers) { providers.expn_that_defined = |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()); providers.in_scope_traits_map = |tcx, id| { - tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map) + tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|owner_info| &owner_info.trait_map) }; } diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 2ab03adf6aaf..c70ceef1d47e 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -9,7 +9,7 @@ use rustc_span::{ExpnHash, ExpnId}; use crate::mir; -use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex}; +use crate::query::on_disk_cache::CacheEncoder; use crate::ty::{Ty, TyCtxt}; macro_rules! declare_hooks { @@ -35,8 +35,10 @@ pub struct Providers { impl Default for Providers { fn default() -> Self { + #[allow(unused)] Providers { - $($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),* + $($name: + |_, $($arg,)*| default_hook(stringify!($name))),* } } } @@ -98,7 +100,7 @@ fn clone(&self) -> Self { *self } /// Trying to execute a query afterwards would attempt to read the result cache we just dropped. hook save_dep_graph() -> (); - hook query_key_hash_verify_all() -> (); + hook verify_query_key_hashes() -> (); /// Ensure the given scalar is valid for the given type. /// This checks non-recursive runtime validity. @@ -109,15 +111,11 @@ fn clone(&self) -> Self { *self } /// Creates the MIR for a given `DefId`, including unreachable code. hook build_mir_inner_impl(def: LocalDefId) -> mir::Body<'tcx>; - hook encode_all_query_results( - encoder: &mut CacheEncoder<'_, 'tcx>, - query_result_index: &mut EncodedDepNodeIndex - ) -> (); + /// Serializes all eligible query return values into the on-disk cache. + hook encode_query_values(encoder: &mut CacheEncoder<'_, 'tcx>) -> (); } #[cold] -fn default_hook(name: &str, args: &dyn std::fmt::Debug) -> ! { - bug!( - "`tcx.{name}{args:?}` cannot be called as `{name}` was never assigned to a provider function" - ) +fn default_hook(name: &str) -> ! { + bug!("`tcx.{name}` cannot be called as `{name}` was never assigned to a provider function") } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 84fe59b3f711..c8702c42c47f 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -67,6 +67,8 @@ #[macro_use] pub mod arena; + +pub mod dep_graph; pub mod error; pub mod hir; pub mod hooks; @@ -76,18 +78,13 @@ pub mod metadata; pub mod middle; pub mod mir; +pub mod queries; +pub mod query; pub mod thir; pub mod traits; pub mod ty; pub mod util; pub mod verify_ich; -#[macro_use] -pub mod query; -#[macro_use] -pub mod queries; -#[macro_use] -pub mod dep_graph; - // Allows macros to refer to this crate as `::rustc_middle` extern crate self as rustc_middle; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index eb1628762ffe..c42783fc77e3 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -293,209 +293,15 @@ fn explain_lint_level_source( } } -/// The innermost function for emitting lints. -/// -/// If you are looking to implement a lint, look for higher level functions, -/// for example: -/// - [`TyCtxt::emit_node_span_lint`] -/// - [`TyCtxt::node_span_lint`] -/// - [`TyCtxt::node_lint`] -/// - `LintContext::opt_span_lint` -/// -/// ## `decorate` -/// -/// It is not intended to call `emit`/`cancel` on the `Diag` passed in the `decorate` callback. -#[track_caller] -pub fn lint_level( - sess: &Session, - lint: &'static Lint, - level: LevelAndSource, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), -) { - // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to - // the "real" work. - #[track_caller] - fn lint_level_impl( - sess: &Session, - lint: &'static Lint, - level: LevelAndSource, - span: Option, - decorate: Box FnOnce(&'b mut Diag<'a, ()>)>, - ) { - let LevelAndSource { level, lint_id, src } = level; - - // Check for future incompatibility lints and issue a stronger warning. - let future_incompatible = lint.future_incompatible; - - let has_future_breakage = future_incompatible.map_or( - // Default allow lints trigger too often for testing. - sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow, - |incompat| incompat.report_in_deps, - ); - - // Convert lint level to error level. - let err_level = match level { - Level::Allow => { - if has_future_breakage { - rustc_errors::Level::Allow - } else { - return; - } - } - Level::Expect => { - // This case is special as we actually allow the lint itself in this context, but - // we can't return early like in the case for `Level::Allow` because we still - // need the lint diagnostic to be emitted to `rustc_error::DiagCtxtInner`. - // - // We can also not mark the lint expectation as fulfilled here right away, as it - // can still be cancelled in the decorate function. All of this means that we simply - // create a `Diag` and continue as we would for warnings. - rustc_errors::Level::Expect - } - Level::ForceWarn => rustc_errors::Level::ForceWarning, - Level::Warn => rustc_errors::Level::Warning, - Level::Deny | Level::Forbid => rustc_errors::Level::Error, - }; - let mut err = Diag::new(sess.dcx(), err_level, ""); - if let Some(span) = span { - err.span(span); - } - if let Some(lint_id) = lint_id { - err.lint_id(lint_id); - } - - // If this code originates in a foreign macro, aka something that this crate - // did not itself author, then it's likely that there's nothing this crate - // can do about it. We probably want to skip the lint entirely. - if err.span.primary_spans().iter().any(|s| s.in_external_macro(sess.source_map())) { - // Any suggestions made here are likely to be incorrect, so anything we - // emit shouldn't be automatically fixed by rustfix. - err.disable_suggestions(); - - // If this is a future incompatible that is not an edition fixing lint - // it'll become a hard error, so we have to emit *something*. Also, - // if this lint occurs in the expansion of a macro from an external crate, - // allow individual lints to opt-out from being reported. - let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none()); - - // In rustc, for the find_attr macro, we want to always emit this. - // This completely circumvents normal lint checking, which usually doesn't happen for macros from other crates. - // However, we kind of want that when using find_attr from another rustc crate. So we cheat a little. - let is_in_find_attr = sess.enable_internal_lints() - && err.span.primary_spans().iter().any(|s| { - s.source_callee().is_some_and( - |i| matches!(i.kind, ExpnKind::Macro(_, name) if name.as_str() == "find_attr") - ) - }); - - if !incompatible && !lint.report_in_external_macro && !is_in_find_attr { - err.cancel(); - - // Don't continue further, since we don't want to have - // `diag_span_note_once` called for a diagnostic that isn't emitted. - return; - } - } - - err.is_lint(lint.name_lower(), has_future_breakage); - - // Lint diagnostics that are covered by the expect level will not be emitted outside - // the compiler. It is therefore not necessary to add any information for the user. - // This will therefore directly call the decorate function which will in turn emit - // the diagnostic. - if let Level::Expect = level { - decorate(&mut err); - err.emit(); - return; - } - - if let Some(future_incompatible) = future_incompatible { - let explanation = match future_incompatible.reason { - FutureIncompatibilityReason::FutureReleaseError(_) => { - "this was previously accepted by the compiler but is being phased out; \ - it will become a hard error in a future release!" - .to_owned() - } - FutureIncompatibilityReason::FutureReleaseSemanticsChange(_) => { - "this will change its meaning in a future release!".to_owned() - } - FutureIncompatibilityReason::EditionError(EditionFcw { edition, .. }) => { - let current_edition = sess.edition(); - format!( - "this is accepted in the current edition (Rust {current_edition}) but is a hard error in Rust {edition}!" - ) - } - FutureIncompatibilityReason::EditionSemanticsChange(EditionFcw { - edition, .. - }) => { - format!("this changes meaning in Rust {edition}") - } - FutureIncompatibilityReason::EditionAndFutureReleaseError(EditionFcw { - edition, - .. - }) => { - format!( - "this was previously accepted by the compiler but is being phased out; \ - it will become a hard error in Rust {edition} and in a future release in all editions!" - ) - } - FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange( - EditionFcw { edition, .. }, - ) => { - format!( - "this changes meaning in Rust {edition} and in a future release in all editions!" - ) - } - FutureIncompatibilityReason::Custom(reason, _) => reason.to_owned(), - FutureIncompatibilityReason::Unreachable => unreachable!(), - }; - - if future_incompatible.explain_reason { - err.warn(explanation); - } - - let citation = - format!("for more information, see {}", future_incompatible.reason.reference()); - err.note(citation); - } - - // Finally, run `decorate`. `decorate` can call `trimmed_path_str` (directly or indirectly), - // so we need to make sure when we do call `decorate` that the diagnostic is eventually - // emitted or we'll get a `must_produce_diag` ICE. - // - // When is a diagnostic *eventually* emitted? Well, that is determined by 2 factors: - // 1. If the corresponding `rustc_errors::Level` is beyond warning, i.e. `ForceWarning(_)` - // or `Error`, then the diagnostic will be emitted regardless of CLI options. - // 2. If the corresponding `rustc_errors::Level` is warning, then that can be affected by - // `-A warnings` or `--cap-lints=xxx` on the command line. In which case, the diagnostic - // will be emitted if `can_emit_warnings` is true. - let skip = err_level == rustc_errors::Level::Warning && !sess.dcx().can_emit_warnings(); - - if !skip { - decorate(&mut err); - } - - explain_lint_level_source(sess, lint, level, src, &mut err); - err.emit() - } - lint_level_impl(sess, lint, level, span, Box::new(decorate)) -} - /// The innermost function for emitting lints implementing the [`trait@Diagnostic`] trait. /// /// If you are looking to implement a lint, look for higher level functions, /// for example: /// /// - [`TyCtxt::emit_node_span_lint`] -/// - [`TyCtxt::node_span_lint`] -/// - [`TyCtxt::node_lint`] /// - `LintContext::opt_span_lint` -/// -/// This function will replace `lint_level` once all its callers have been replaced -/// with `diag_lint_level`. #[track_caller] -pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( +pub fn emit_lint_base<'a, D: Diagnostic<'a, ()> + 'a>( sess: &'a Session, lint: &'static Lint, level: LevelAndSource, @@ -505,7 +311,7 @@ pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to // the "real" work. #[track_caller] - fn diag_lint_level_impl<'a>( + fn emit_lint_base_impl<'a>( sess: &'a Session, lint: &'static Lint, level: LevelAndSource, @@ -689,7 +495,7 @@ fn diag_lint_level_impl<'a>( explain_lint_level_source(sess, lint, level, src, &mut err); err.emit(); } - diag_lint_level_impl( + emit_lint_base_impl( sess, lint, level, diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 990ed8f48fb8..678520e8ce0c 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -159,7 +159,7 @@ pub enum ScopeData { /// /// * The subscope with `first_statement_index == 1` is scope of `c`, /// and thus does not include EXPR_2, but covers the `...`. - #[derive(HashStable)] + #[stable_hash] #[encodable] #[orderable] pub struct FirstStatementIndex {} diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 628d35814684..f9821c92df36 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,15 +4,15 @@ use std::num::NonZero; use rustc_ast::NodeId; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintBuffer, msg}; +use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, LintBuffer, msg}; use rustc_feature::GateIssue; use rustc_hir::attrs::{DeprecatedSince, Deprecation}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, ConstStability, DefaultBodyStability, HirId, Stability}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_session::Session; -use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; -use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint}; +use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE}; +use rustc_session::lint::{DeprecatedSinceKind, Level, Lint}; use rustc_session::parse::feature_err_issue; use rustc_span::{Span, Symbol, sym}; use tracing::debug; @@ -68,9 +68,7 @@ pub fn report_unstable( reason: Option, issue: Option>, suggestion: Option<(Span, String, String, Applicability)>, - is_soft: bool, span: Span, - soft_handler: impl FnOnce(&'static Lint, Span, String), kind: UnstableKind, ) { let qual = match kind { @@ -83,18 +81,14 @@ pub fn report_unstable( None => format!("use of unstable{qual} library feature `{feature}`"), }; - if is_soft { - soft_handler(SOFT_UNSTABLE, span, msg) - } else { - let mut err = feature_err_issue(sess, feature, span, GateIssue::Library(issue), msg); - if let Some((inner_types, msg, sugg, applicability)) = suggestion { - err.span_suggestion(inner_types, msg, sugg, applicability); - } - if let UnstableKind::Const(kw) = kind { - err.span_label(kw, "trait is not stable as const yet"); - } - err.emit(); + let mut err = feature_err_issue(sess, feature, span, GateIssue::Library(issue), msg); + if let Some((inner_types, msg, sugg, applicability)) = suggestion { + err.span_suggestion(inner_types, msg, sugg, applicability); } + if let UnstableKind::Const(kw) = kind { + err.span_label(kw, "trait is not stable as const yet"); + } + err.emit(); } fn deprecation_lint(is_in_effect: bool) -> &'static Lint { @@ -193,23 +187,33 @@ fn deprecated_since_kind(is_in_effect: bool, since: DeprecatedSince) -> Deprecat pub fn early_report_macro_deprecation( lint_buffer: &mut LintBuffer, depr: &Deprecation, - span: Span, + suggestion_span: Span, node_id: NodeId, path: String, ) { - if span.in_derive_expansion() { + if suggestion_span.in_derive_expansion() { return; } let is_in_effect = depr.is_in_effect(); - let diag = BuiltinLintDiag::DeprecatedMacro { - suggestion: depr.suggestion, - suggestion_span: span, - note: depr.note.map(|ident| ident.name), - path, - since_kind: deprecated_since_kind(is_in_effect, depr.since), - }; - lint_buffer.buffer_lint(deprecation_lint(is_in_effect), node_id, span, diag); + let suggestion = depr.suggestion; + let note = depr.note.map(|ident| ident.name); + let since_kind = deprecated_since_kind(is_in_effect, depr.since); + lint_buffer.dyn_buffer_lint( + deprecation_lint(is_in_effect), + node_id, + suggestion_span, + move |dcx, level| { + let sub = suggestion.map(|suggestion| DeprecationSuggestion { + span: suggestion_span, + kind: "macro".to_owned(), + suggestion, + }); + + Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind } + .into_diag(dcx, level) + }, + ); } fn late_report_deprecation( @@ -266,7 +270,6 @@ pub enum EvalResult { reason: Option, issue: Option>, suggestion: Option<(Span, String, String, Applicability)>, - is_soft: bool, }, /// The item does not have the `#[stable]` or `#[unstable]` marker assigned. Unmarked, @@ -386,7 +389,7 @@ pub fn eval_stability_allow_unstable( match stability { Some(Stability { - level: hir::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, + level: hir::StabilityLevel::Unstable { reason, issue, implied_by, .. }, feature, .. }) => { @@ -428,13 +431,7 @@ pub fn eval_stability_allow_unstable( } let suggestion = suggestion_for_allocator_api(self, def_id, span, feature); - EvalResult::Deny { - feature, - reason: reason.to_opt_reason(), - issue, - suggestion, - is_soft, - } + EvalResult::Deny { feature, reason: reason.to_opt_reason(), issue, suggestion } } Some(_) => { // Stable APIs are always ok to call and deprecated APIs are @@ -469,7 +466,7 @@ pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResul match stability { Some(DefaultBodyStability { - level: hir::StabilityLevel::Unstable { reason, issue, is_soft, .. }, + level: hir::StabilityLevel::Unstable { reason, issue, .. }, feature, }) => { if span.allows_unstable(feature) { @@ -485,7 +482,6 @@ pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResul reason: reason.to_opt_reason(), issue, suggestion: None, - is_soft, } } Some(_) => { @@ -563,25 +559,18 @@ pub fn check_optional_stability( allow_unstable: AllowUnstable, unmarked: impl FnOnce(Span, DefId), ) -> bool { - let soft_handler = |lint, span, msg: String| { - self.node_span_lint(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { - lint.primary_message(msg); - }) - }; let eval_result = self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable); let is_allowed = matches!(eval_result, EvalResult::Allow); match eval_result { EvalResult::Allow => {} - EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable( + EvalResult::Deny { feature, reason, issue, suggestion } => report_unstable( self.sess, feature, reason, issue, suggestion, - is_soft, span, - soft_handler, UnstableKind::Regular, ), EvalResult::Unmarked => unmarked(span, def_id), @@ -618,12 +607,10 @@ pub fn check_const_stability(self, def_id: DefId, span: Span, const_kw_span: Spa match stability { Some(ConstStability { - level: hir::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, + level: hir::StabilityLevel::Unstable { reason, issue, implied_by, .. }, feature, .. }) => { - assert!(!is_soft); - if span.allows_unstable(feature) { debug!("body stability: skipping span={:?} since it is internal", span); return; @@ -647,9 +634,7 @@ pub fn check_const_stability(self, def_id: DefId, span: Span, const_kw_span: Spa reason.to_opt_reason(), issue, None, - false, span, - |_, _, _| {}, UnstableKind::Const(const_kw_span), ); } diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index aae815c0be04..bd8c022ef42a 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -65,7 +65,7 @@ pub fn predecessors(&self) -> &Predecessors { /// Returns basic blocks in a reverse postorder. /// - /// See [`traversal::reverse_postorder`]'s docs to learn what is preorder traversal. + /// See [`traversal::reverse_postorder`]'s docs to learn what is postorder traversal. /// /// [`traversal::reverse_postorder`]: crate::mir::traversal::reverse_postorder #[inline] diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index fd4c64b9a61c..0bf5094a27c0 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -10,7 +10,7 @@ rustc_index::newtype_index! { /// Used by [`CoverageKind::BlockMarker`] to mark blocks during THIR-to-MIR /// lowering, so that those blocks can be identified later. - #[derive(HashStable)] + #[stable_hash] #[encodable] #[debug_format = "BlockMarkerId({})"] pub struct BlockMarkerId {} @@ -26,7 +26,7 @@ pub struct BlockMarkerId {} /// /// Note that LLVM handles counter IDs as `uint32_t`, so there is no need /// to use a larger representation on the Rust side. - #[derive(HashStable)] + #[stable_hash] #[encodable] #[orderable] #[debug_format = "CounterId({})"] @@ -43,7 +43,7 @@ pub struct CounterId {} /// /// Note that LLVM handles expression IDs as `uint32_t`, so there is no need /// to use a larger representation on the Rust side. - #[derive(HashStable)] + #[stable_hash] #[encodable] #[orderable] #[debug_format = "ExpressionId({})"] @@ -203,7 +203,7 @@ pub struct CoverageIdsInfo { /// /// After that pass is complete, the coverage graph no longer exists, so a /// BCB is effectively an opaque ID. - #[derive(HashStable)] + #[stable_hash] #[encodable] #[orderable] #[debug_format = "bcb{}"] diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 7fa818ba7d3a..c0dfc18689ba 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -341,13 +341,13 @@ pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpErrorKind<'tcx> { } /// The information that makes up a memory access: offset and size. -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct AllocRange { pub start: Size, pub size: Size, } -impl fmt::Debug for AllocRange { +impl fmt::Display for AllocRange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[{:#x}..{:#x}]", self.start.bytes(), self.end().bytes()) } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 035ffd362a6b..6c7505a7cbbb 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -4,9 +4,9 @@ use std::{convert, fmt, mem, ops}; use either::Either; -use rustc_abi::{Align, Size, VariantIdx, WrappingRange}; +use rustc_abi::{Align, Size, VariantIdx}; use rustc_data_structures::sync::Lock; -use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; +use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_session::CtfeBacktrace; use rustc_span::def_id::DefId; @@ -14,8 +14,9 @@ use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; +use crate::mir::interpret::CtfeProvenance; use crate::mir::{ConstAlloc, ConstValue}; -use crate::ty::{self, Mutability, Ty, TyCtxt, ValTree, layout, tls}; +use crate::ty::{self, Ty, TyCtxt, ValTree, layout, tls}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum ErrorHandled { @@ -240,20 +241,6 @@ fn from(kind: InterpErrorKind<'tcx>) -> Self { } } -/// Error information for when the program we executed turned out not to actually be a valid -/// program. This cannot happen in stand-alone Miri (except for layout errors that are only detect -/// during monomorphization), but it can happen during CTFE/ConstProp where we work on generic code -/// or execution does not have all information available. -#[derive(Debug)] -pub enum InvalidProgramInfo<'tcx> { - /// Resolution can fail if we are in a too generic context. - TooGeneric, - /// Abort in case errors are already reported. - AlreadyReported(ReportedErrorInfo), - /// An error occurred during layout computation. - Layout(layout::LayoutError<'tcx>), -} - /// Details of why a pointer had to be in-bounds. #[derive(Debug, Copy, Clone)] pub enum CheckInAllocMsg { @@ -265,6 +252,17 @@ pub enum CheckInAllocMsg { Dereferenceable, } +impl fmt::Display for CheckInAllocMsg { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use CheckInAllocMsg::*; + match self { + MemoryAccess => write!(f, "memory access failed"), + InboundsPointerArithmetic => write!(f, "in-bounds pointer arithmetic failed"), + Dereferenceable => write!(f, "pointer not dereferenceable"), + } + } +} + /// Details of which pointer is not aligned. #[derive(Debug, Copy, Clone)] pub enum CheckAlignMsg { @@ -314,34 +312,18 @@ pub struct Misalignment { pub required: Align, } -macro_rules! impl_into_diag_arg_through_debug { - ($($ty:ty),*$(,)?) => {$( - impl IntoDiagArg for $ty { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(format!("{self:?}"))) - } - } - )*} -} - -// These types have nice `Debug` output so we can just use them in diagnostics. -impl_into_diag_arg_through_debug! { - AllocId, - Pointer, - AllocRange, -} - /// Error information for when the program caused Undefined Behavior. #[derive(Debug)] pub enum UndefinedBehaviorInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Used by miri Ub(String), - // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically - // dispatched - /// A custom (free-form) fluent-translated error, created by `err_ub_custom!`. - Custom(crate::error::CustomSubdiagnostic<'tcx>), /// Validation error. - ValidationError(ValidationErrorInfo<'tcx>), + ValidationError { + orig_ty: Ty<'tcx>, + path: Option, + msg: String, + ptr_bytes_warning: bool, + }, /// Unreachable code was executed. Unreachable, @@ -446,135 +428,257 @@ pub enum UndefinedBehaviorInfo<'tcx> { CVariadicFixedCountMismatch { caller: u32, callee: u32 }, } -#[derive(Debug, Clone, Copy)] -pub enum PointerKind { - Ref(Mutability), - Box, -} +impl<'tcx> fmt::Display for UndefinedBehaviorInfo<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use UndefinedBehaviorInfo::*; -impl IntoDiagArg for PointerKind { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str( - match self { - Self::Ref(_) => "ref", - Self::Box => "box", + fn fmt_in_alloc_attempt( + f: &mut fmt::Formatter<'_>, + msg: CheckInAllocMsg, + inbounds_size: i64, + ) -> fmt::Result { + let inbounds_size_fmt = if inbounds_size == 1 { + format_args!("1 byte") + } else { + format_args!("{inbounds_size} bytes") + }; + write!(f, "{msg}: ")?; + match msg { + CheckInAllocMsg::MemoryAccess => { + write!(f, "attempting to access {inbounds_size_fmt}") + } + CheckInAllocMsg::InboundsPointerArithmetic => { + write!(f, "attempting to offset pointer by {inbounds_size_fmt}") + } + CheckInAllocMsg::Dereferenceable if inbounds_size == 0 => { + write!(f, "pointer must point to some allocation") + } + CheckInAllocMsg::Dereferenceable => { + write!(f, "pointer must be dereferenceable for {inbounds_size_fmt}") + } } - .into(), - ) - } -} + } -#[derive(Debug)] -pub struct ValidationErrorInfo<'tcx> { - pub path: Option, - pub kind: ValidationErrorKind<'tcx>, -} + match self { + Ub(msg) => write!(f, "{msg}"), -#[derive(Debug)] -pub enum ExpectedKind { - Reference, - Box, - RawPtr, - InitScalar, - Bool, - Char, - Float, - Int, - FnPtr, - EnumTag, - Str, -} + ValidationError { orig_ty, path: None, msg, .. } => { + write!(f, "constructing invalid value of type {orig_ty}: {msg}") + } + ValidationError { orig_ty, path: Some(path), msg, .. } => { + write!(f, "constructing invalid value of type {orig_ty}: at {path}, {msg}") + } -impl From for ExpectedKind { - fn from(x: PointerKind) -> ExpectedKind { - match x { - PointerKind::Box => ExpectedKind::Box, - PointerKind::Ref(_) => ExpectedKind::Reference, + Unreachable => write!(f, "entering unreachable code"), + BoundsCheckFailed { len, index } => { + write!(f, "indexing out of bounds: the len is {len} but the index is {index}") + } + DivisionByZero => write!(f, "dividing by zero"), + RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), + DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"), + RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"), + PointerArithOverflow => write!( + f, + "overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`" + ), + ArithOverflow { intrinsic } => write!(f, "arithmetic overflow in `{intrinsic}`"), + ShiftOverflow { shift_amount, intrinsic } => { + write!(f, "overflowing shift by {shift_amount} in `{intrinsic}`") + } + InvalidMeta(InvalidMetaKind::SliceTooBig) => write!( + f, + "invalid metadata in wide pointer: slice is bigger than largest supported object" + ), + InvalidMeta(InvalidMetaKind::TooBig) => write!( + f, + "invalid metadata in wide pointer: total size is bigger than largest supported object" + ), + UnterminatedCString(ptr) => write!( + f, + "reading a null-terminated string starting at {ptr} with no null found before end of allocation" + ), + PointerUseAfterFree(alloc_id, msg) => { + write!(f, "{msg}: {alloc_id} has been freed, so this pointer is dangling") + } + &PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => { + fmt_in_alloc_attempt(f, msg, inbounds_size)?; + write!(f, ", but got ")?; + // Write pointer. Offset might be negative so we cannot use the normal `impl Display + // for Pointer`. + write!(f, "{}", alloc_id)?; + if ptr_offset > 0 { + write!(f, "+{:#x}", ptr_offset)?; + } else if ptr_offset < 0 { + write!(f, "-{:#x}", ptr_offset.unsigned_abs())?; + } + // Write why it is invalid. + write!(f, " which ")?; + if ptr_offset < 0 { + write!(f, "points to before the beginning of the allocation") + } else if inbounds_size < 0 { + // We expected the ptr to have memory to its left, but it does not. + if ptr_offset == 0 { + write!(f, "is at the beginning of the allocation") + } else { + write!(f, "is only {ptr_offset} bytes from the beginning of the allocation") + } + } else { + let ptr_offset = ptr_offset as u64; + let alloc_size = alloc_size.bytes(); + if ptr_offset >= alloc_size { + let size = if alloc_size == 1 { + format_args!("1 byte") + } else { + format_args!("{alloc_size} bytes") + }; + write!(f, "is at or beyond the end of the allocation of size {size}",) + } else { + let dist_to_end = alloc_size - ptr_offset; + let dist = if dist_to_end == 1 { + format_args!("1 byte") + } else { + format_args!("{dist_to_end} bytes") + }; + write!(f, "is only {dist} from the end of the allocation",) + } + } + } + &DanglingIntPointer { addr: 0, inbounds_size, msg } => { + fmt_in_alloc_attempt(f, msg, inbounds_size)?; + write!(f, ", but got null pointer") + } + &DanglingIntPointer { addr, inbounds_size, msg } => { + fmt_in_alloc_attempt(f, msg, inbounds_size)?; + write!( + f, + ", but got {ptr} which is a dangling pointer (it has no provenance)", + ptr = Pointer::>::without_provenance(addr), + ) + } + AlignmentCheckFailed(misalign, msg) => { + write!( + f, + "{acc} with alignment {has}, but alignment {required} is required", + acc = match msg { + CheckAlignMsg::AccessedPtr => "accessing memory", + CheckAlignMsg::BasedOn => "accessing memory based on pointer", + }, + has = misalign.has.bytes(), + required = misalign.required.bytes(), + ) + } + WriteToReadOnly(alloc) => write!(f, "writing to {alloc} which is read-only"), + DerefFunctionPointer(alloc) => { + write!(f, "accessing {alloc} which contains a function") + } + DerefVTablePointer(alloc) => write!(f, "accessing {alloc} which contains a vtable"), + DerefVaListPointer(alloc) => { + write!(f, "accessing {alloc} which contains a variable argument list") + } + DerefTypeIdPointer(alloc) => write!(f, "accessing {alloc} which contains a `TypeId`"), + InvalidBool(value) => { + write!(f, "interpreting an invalid 8-bit value as a bool: 0x{value:02x}") + } + InvalidChar(value) => { + write!(f, "interpreting an invalid 32-bit value as a char: 0x{value:08x}") + } + InvalidTag(tag) => write!(f, "enum value has invalid tag: {tag:x}"), + InvalidFunctionPointer(ptr) => { + write!(f, "using {ptr} as function pointer but it does not point to a function") + } + InvalidVaListPointer(ptr) => write!( + f, + "using {ptr} as variable argument list pointer but it does not point to a variable argument list" + ), + InvalidVTablePointer(ptr) => { + write!(f, "using {ptr} as vtable pointer but it does not point to a vtable") + } + InvalidVTableTrait { vtable_dyn_type, expected_dyn_type } => write!( + f, + "using vtable for `{vtable_dyn_type}` but `{expected_dyn_type}` was expected" + ), + InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"), + InvalidUninitBytes(None) => { + write!( + f, + "using uninitialized data, but this operation requires initialized memory" + ) + } + InvalidUninitBytes(Some((alloc, info))) => write!( + f, + "reading memory at {alloc}{access}, but memory is uninitialized at {uninit}, and this operation requires initialized memory", + access = info.access, + uninit = info.bad, + ), + DeadLocal => write!(f, "accessing a dead local variable"), + ScalarSizeMismatch(mismatch) => write!( + f, + "scalar size mismatch: expected {target_size} bytes but got {data_size} bytes instead", + target_size = mismatch.target_size, + data_size = mismatch.data_size, + ), + UninhabitedEnumVariantWritten(_) => { + write!(f, "writing discriminant of an uninhabited enum variant") + } + UninhabitedEnumVariantRead(_) => { + write!(f, "read discriminant of an uninhabited enum variant") + } + InvalidNichedEnumVariantWritten { enum_ty } => { + write!( + f, + "trying to set discriminant of a {enum_ty} to the niched variant, but the value does not match" + ) + } + AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => write!( + f, + "calling a function whose parameter #{arg_idx} has type {callee_ty} passing argument of type {caller_ty}", + arg_idx = arg_idx + 1, // adjust for 1-indexed lists in output + ), + AbiMismatchReturn { caller_ty, callee_ty } => write!( + f, + "calling a function with return type {callee_ty} passing return place of type {caller_ty}" + ), + VaArgOutOfBounds => write!(f, "more C-variadic arguments read than were passed"), + CVariadicMismatch { .. } => write!( + f, + "calling a function where the caller and callee disagree on whether the function is C-variadic" + ), + CVariadicFixedCountMismatch { caller, callee } => write!( + f, + "calling a C-variadic function with {caller} fixed arguments, but the function expects {callee}" + ), } } } +/// Error information for when the program we executed turned out not to actually be a valid +/// program. This cannot happen in stand-alone Miri (except for layout errors that are only detect +/// during monomorphization), but it can happen during CTFE/ConstProp where we work on generic code +/// or execution does not have all information available. #[derive(Debug)] -pub enum ValidationErrorKind<'tcx> { - PointerAsInt { - expected: ExpectedKind, - }, - PartialPointer, - PtrToUninhabited { - ptr_kind: PointerKind, - ty: Ty<'tcx>, - }, - MutableRefToImmutable, - UnsafeCellInImmutable, - NullFnPtr { - /// Records whether this pointer is definitely null or just may be null. - maybe: bool, - }, - NeverVal, - NonnullPtrMaybeNull, - PtrOutOfRange { - range: WrappingRange, - max_value: u128, - }, - OutOfRange { - value: String, - range: WrappingRange, - max_value: u128, - }, - UninhabitedVal { - ty: Ty<'tcx>, - }, - InvalidEnumTag { - value: String, - }, - UninhabitedEnumVariant, - Uninit { - expected: ExpectedKind, - }, - InvalidVTablePtr { - value: String, - }, - InvalidMetaWrongTrait { - /// The vtable that was actually referenced by the wide pointer metadata. - vtable_dyn_type: &'tcx ty::List>, - /// The vtable that was expected at the point in MIR that it was accessed. - expected_dyn_type: &'tcx ty::List>, - }, - InvalidMetaSliceTooLarge { - ptr_kind: PointerKind, - }, - InvalidMetaTooLarge { - ptr_kind: PointerKind, - }, - UnalignedPtr { - ptr_kind: PointerKind, - required_bytes: u64, - found_bytes: u64, - }, - NullPtr { - ptr_kind: PointerKind, - /// Records whether this pointer is definitely null or just may be null. - maybe: bool, - }, - DanglingPtrNoProvenance { - ptr_kind: PointerKind, - pointer: String, - }, - DanglingPtrOutOfBounds { - ptr_kind: PointerKind, - }, - DanglingPtrUseAfterFree { - ptr_kind: PointerKind, - }, - InvalidBool { - value: String, - }, - InvalidChar { - value: String, - }, - InvalidFnPtr { - value: String, - }, +pub enum InvalidProgramInfo<'tcx> { + /// Resolution can fail if we are in a too generic context. + TooGeneric, + /// Abort in case errors are already reported. + AlreadyReported(ReportedErrorInfo), + /// An error occurred during layout computation. + Layout(layout::LayoutError<'tcx>), +} + +impl<'tcx> fmt::Display for InvalidProgramInfo<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use InvalidProgramInfo::*; + match self { + TooGeneric => write!(f, "encountered overly generic constant"), + AlreadyReported(_) => { + write!( + f, + "an error has already been reported elsewhere (this should not usually be printed)" + ) + } + Layout(e) => write!(f, "{e}"), + } + } } /// Error information for when the program did something that might (or might not) be correct @@ -604,6 +708,37 @@ pub enum UnsupportedOpInfo { ExternStatic(DefId), } +impl fmt::Display for UnsupportedOpInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use UnsupportedOpInfo::*; + match self { + Unsupported(s) => write!(f, "{s}"), + ExternTypeField => { + write!(f, "`extern type` field does not have a known offset") + } + UnsizedLocal => write!(f, "unsized locals are not supported"), + ReadPartialPointer(ptr) => { + write!(f, "unable to read parts of a pointer from memory at {ptr}") + } + ReadPointerAsInt(_) => write!(f, "unable to turn pointer into integer"), + &ThreadLocalStatic(did) => { + write!( + f, + "cannot access thread local static `{did}`", + did = ty::tls::with(|tcx| tcx.def_path_str(did)) + ) + } + &ExternStatic(did) => { + write!( + f, + "cannot access extern static `{did}`", + did = ty::tls::with(|tcx| tcx.def_path_str(did)) + ) + } + } + } +} + /// Error information for when the program exhausted the resources granted to it /// by the interpreter. #[derive(Debug)] @@ -618,15 +753,27 @@ pub enum ResourceExhaustionInfo { Interrupted, } -/// A trait for machine-specific errors (or other "machine stop" conditions). -pub trait MachineStopType: Any + fmt::Debug + Send { - /// The diagnostic message for this error - fn diagnostic_message(&self) -> DiagMessage; - /// Add diagnostic arguments by passing name and value pairs to `adder`, which are passed to - /// fluent for formatting the translated diagnostic message. - fn add_args(self: Box, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)); +impl fmt::Display for ResourceExhaustionInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use ResourceExhaustionInfo::*; + match self { + StackFrameLimitReached => { + write!(f, "reached the configured maximum number of stack frames") + } + MemoryExhausted => { + write!(f, "tried to allocate more memory than available to compiler") + } + AddressSpaceFull => { + write!(f, "there are no more free addresses in the address space") + } + Interrupted => write!(f, "compilation was interrupted"), + } + } } +/// A trait for machine-specific errors (or other "machine stop" conditions). +pub trait MachineStopType: Any + fmt::Display + fmt::Debug + Send {} + impl dyn MachineStopType { #[inline(always)] pub fn downcast_ref(&self) -> Option<&T> { @@ -639,11 +786,11 @@ pub fn downcast_ref(&self) -> Option<&T> { pub enum InterpErrorKind<'tcx> { /// The program caused undefined behavior. UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), + /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...). + InvalidProgram(InvalidProgramInfo<'tcx>), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo), - /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...). - InvalidProgram(InvalidProgramInfo<'tcx>), /// The program exhausted the interpreter's resources (stack/heap too big, /// execution takes too long, ...). ResourceExhaustion(ResourceExhaustionInfo), @@ -652,6 +799,19 @@ pub enum InterpErrorKind<'tcx> { MachineStop(Box), } +impl<'tcx> fmt::Display for InterpErrorKind<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use InterpErrorKind::*; + match self { + Unsupported(msg) => write!(f, "{msg}"), + InvalidProgram(msg) => write!(f, "{msg}"), + UndefinedBehavior(msg) => write!(f, "{msg}"), + ResourceExhaustion(msg) => write!(f, "{msg}"), + MachineStop(msg) => write!(f, "{msg}"), + } + } +} + impl InterpErrorKind<'_> { /// Some errors do string formatting even if the error is never printed. /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors, @@ -704,25 +864,6 @@ macro_rules! err_ub_format { ($($tt:tt)*) => { $crate::err_ub!(Ub(format!($($tt)*))) }; } -#[macro_export] -macro_rules! err_ub_custom { - ($msg:expr $(, $($name:ident = $value:expr),* $(,)?)?) => {{ - $( - let ($($name,)*) = ($($value,)*); - )? - $crate::err_ub!(Custom( - $crate::error::CustomSubdiagnostic { - msg: || $msg, - add_args: Box::new(move |mut set_arg| { - $($( - set_arg(stringify!($name).into(), rustc_errors::IntoDiagArg::into_diag_arg($name, &mut None)); - )*)? - }) - } - )) - }}; -} - #[macro_export] macro_rules! err_exhaust { ($($tt:tt)*) => { @@ -765,11 +906,6 @@ macro_rules! throw_ub_format { ($($tt:tt)*) => { do yeet $crate::err_ub_format!($($tt)*) }; } -#[macro_export] -macro_rules! throw_ub_custom { - ($($tt:tt)*) => { do yeet $crate::err_ub_custom!($($tt)*) }; -} - #[macro_export] macro_rules! throw_exhaust { ($($tt:tt)*) => { do yeet $crate::err_exhaust!($($tt)*) }; diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 654404f9790c..b3ec4439e354 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -24,9 +24,9 @@ use tracing::{debug, trace}; // Also make the error macros available from this module. pub use { - err_exhaust, err_inval, err_machine_stop, err_ub, err_ub_custom, err_ub_format, err_unsup, - err_unsup_format, throw_exhaust, throw_inval, throw_machine_stop, throw_ub, throw_ub_custom, - throw_ub_format, throw_unsup, throw_unsup_format, + err_exhaust, err_inval, err_machine_stop, err_ub, err_ub_format, err_unsup, err_unsup_format, + throw_exhaust, throw_inval, throw_machine_stop, throw_ub, throw_ub_format, throw_unsup, + throw_unsup_format, }; pub use self::allocation::{ @@ -35,11 +35,10 @@ }; pub use self::error::{ BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult, - EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, - InterpErrorInfo, InterpErrorKind, InterpResult, InvalidMetaKind, InvalidProgramInfo, - MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, - ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValTreeCreationError, - ValidationErrorInfo, ValidationErrorKind, interp_ok, + EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, InterpErrorInfo, + InterpErrorKind, InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, + Misalignment, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, + UndefinedBehaviorInfo, UnsupportedOpInfo, ValTreeCreationError, interp_ok, }; pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; @@ -76,15 +75,21 @@ pub fn display(self, tcx: TyCtxt<'tcx>) -> String { #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct AllocId(pub NonZero); -// We want the `Debug` output to be readable as it is used by `derive(Debug)` for -// all the Miri types. -impl fmt::Debug for AllocId { +// AllocId show up in const-eval error messages +impl fmt::Display for AllocId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { write!(f, "a{}", self.0) } else { write!(f, "alloc{}", self.0) } } } -// No "Display" since AllocIds are not usually user-visible. +// We want the `Debug` output to be readable as it is used by `derive(Debug)` for +// all the Miri types. +impl fmt::Debug for AllocId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Dispatch to `Display` impl. + fmt::Display::fmt(self, f) + } +} #[derive(TyDecodable, TyEncodable)] enum AllocDiscriminant { diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index b6bcc87ff041..e135404f28e7 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -241,6 +241,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } +impl fmt::Display for Pointer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Provenance::fmt(self, f) + } +} + impl fmt::Debug for Pointer> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.provenance { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 89034981cbd6..00ac8e66cda7 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -139,15 +139,15 @@ pub fn const_eval_resolve_for_typeck( let mir_body = self.mir_for_ctfe(cid.instance.def_id()); if mir_body.is_polymorphic { let Some(local_def_id) = ct.def.as_local() else { return }; - self.node_span_lint( + self.emit_node_span_lint( lint::builtin::CONST_EVALUATABLE_UNCHECKED, self.local_def_id_to_hir_id(local_def_id), self.def_span(ct.def), - |lint| { + rustc_errors::DiagDecorator(|lint| { lint.primary_message( "cannot use constants which depend on generic parameters in types", ); - }, + }), ) } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 8ac532ff4863..a3746db65355 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -14,7 +14,7 @@ pub use rustc_ast::{Mutability, Pinnedness}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; +use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{ @@ -24,8 +24,7 @@ use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_serialize::{Decodable, Encodable}; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_span::{DUMMY_SP, Span, Spanned, Symbol}; use tracing::{debug, trace}; pub use self::query::*; @@ -840,7 +839,7 @@ pub fn outermost(span: Span) -> Self { // Variables and temps rustc_index::newtype_index! { - #[derive(HashStable)] + #[stable_hash] #[encodable] #[orderable] #[debug_format = "_{}"] @@ -1264,7 +1263,7 @@ pub struct VarDebugInfo<'tcx> { /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis /// [`CriticalCallEdges`]: ../../rustc_mir_transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ - #[derive(HashStable)] + #[stable_hash] #[encodable] #[orderable] #[debug_format = "bb{}"] @@ -1398,7 +1397,7 @@ pub fn drop_debuginfo(&mut self) { // Scopes rustc_index::newtype_index! { - #[derive(HashStable)] + #[stable_hash] #[encodable] #[debug_format = "scope[{}]"] pub struct SourceScope { @@ -1537,7 +1536,7 @@ pub struct UserTypeProjection { } rustc_index::newtype_index! { - #[derive(HashStable)] + #[stable_hash] #[encodable] #[orderable] #[debug_format = "promoted[{}]"] diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 70954b4cb782..d7d5d63d45a7 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -13,7 +13,7 @@ use crate::ty::{self, CoroutineArgsExt, Ty}; rustc_index::newtype_index! { - #[derive(HashStable)] + #[stable_hash] #[encodable] #[debug_format = "_s{}"] pub struct CoroutineSavedLocal {} diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 48dcef298d66..f66c4755de4d 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -1050,11 +1050,12 @@ pub fn extend(&mut self, debuginfos: &Self) { self.0.extend_from_slice(debuginfos); } - pub fn retain(&mut self, f: F) - where - F: FnMut(&StmtDebugInfo<'tcx>) -> bool, - { - self.0.retain(f); + pub fn retain_locals(&mut self, locals: &DenseBitSet) { + self.retain(|debuginfo| match debuginfo { + StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => { + locals.contains(*local) + } + }); } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index c3da2f039485..455089f285d1 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -11,8 +11,7 @@ use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Spanned, Symbol}; use rustc_target::asm::InlineAsmRegOrRegClass; use smallvec::SmallVec; diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 650c44aa41fb..7931c80bed6c 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -326,36 +326,42 @@ pub fn fmt_assert_args(&self, f: &mut W) -> fmt::Result } } } +} - /// Format the diagnostic message for use in a lint (e.g. when the assertion fails during const-eval). - /// - /// Needs to be kept in sync with the run-time behavior (which is defined by - /// `AssertKind::panic_function` and the lang items mentioned in its docs). - /// Note that we deliberately show more details here than we do at runtime, such as the actual - /// numbers that overflowed -- it is much easier to do so here than at runtime. - pub fn diagnostic_message(&self) -> DiagMessage { +/// Format the diagnostic message for use in a lint (e.g. when the assertion fails during const-eval). +/// +/// Needs to be kept in sync with the run-time behavior (which is defined by +/// `AssertKind::panic_function` and the lang items mentioned in its docs). +/// Note that we deliberately show more details here than we do at runtime, such as the actual +/// numbers that overflowed -- it is much easier to do so here than at runtime. +impl fmt::Display for AssertKind { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { use AssertKind::*; match self { - BoundsCheck { .. } => { - msg!("index out of bounds: the length is {$len} but the index is {$index}") + BoundsCheck { len, index } => { + write!(f, "index out of bounds: the length is {len:?} but the index is {index:?}") } - Overflow(BinOp::Shl, _, _) => { - msg!("attempt to shift left by `{$val}`, which would overflow") + Overflow(BinOp::Shl, _, val) => { + write!(f, "attempt to shift left by `{val:#?}`, which would overflow") } - Overflow(BinOp::Shr, _, _) => { - msg!("attempt to shift right by `{$val}`, which would overflow") + Overflow(BinOp::Shr, _, val) => { + write!(f, "attempt to shift right by `{val:#?}`, which would overflow") } - Overflow(_, _, _) => { - msg!("attempt to compute `{$left} {$op} {$right}`, which would overflow") + Overflow(binop, left, right) => { + write!( + f, + "attempt to compute `{left:#?} {op} {right:#?}`, which would overflow", + op = binop.to_hir_binop().as_str() + ) } - OverflowNeg(_) => msg!("attempt to negate `{$val}`, which would overflow"), - DivisionByZero(_) => msg!("attempt to divide `{$val}` by zero"), - RemainderByZero(_) => { - msg!("attempt to calculate the remainder of `{$val}` with a divisor of zero") + OverflowNeg(val) => write!(f, "attempt to negate `{val:#?}`, which would overflow"), + DivisionByZero(val) => write!(f, "attempt to divide `{val:#?}` by zero"), + RemainderByZero(val) => { + write!(f, "attempt to calculate the remainder of `{val:#?}` with a divisor of zero") } ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { - msg!("`async fn` resumed after completion") + write!(f, "`async fn` resumed after completion") } ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { todo!() @@ -364,84 +370,43 @@ pub fn diagnostic_message(&self) -> DiagMessage { bug!("gen blocks can be resumed after they return and will keep returning `None`") } ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { - msg!("coroutine resumed after completion") + write!(f, "coroutine resumed after completion") } ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { - msg!("`async fn` resumed after panicking") + write!(f, "`async fn` resumed after panicking") } ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { todo!() } ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { - msg!("`gen` fn or block cannot be further iterated on after it panicked") + write!(f, "`gen` fn or block cannot be further iterated on after it panicked") } ResumedAfterPanic(CoroutineKind::Coroutine(_)) => { - msg!("coroutine resumed after panicking") + write!(f, "coroutine resumed after panicking") } - NullPointerDereference => msg!("null pointer dereference occurred"), - InvalidEnumConstruction(_) => { - msg!("trying to construct an enum from an invalid value `{$source}`") + NullPointerDereference => write!(f, "null pointer dereference occurred"), + InvalidEnumConstruction(source) => { + write!(f, "trying to construct an enum from an invalid value `{source:#?}`") } ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { - msg!("`async fn` resumed after async drop") + write!(f, "`async fn` resumed after async drop") } ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { todo!() } ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { - msg!("`gen` fn or block cannot be further iterated on after it async dropped") + write!(f, "`gen` fn or block cannot be further iterated on after it async dropped") } ResumedAfterDrop(CoroutineKind::Coroutine(_)) => { - msg!("coroutine resumed after async drop") + write!(f, "coroutine resumed after async drop") } - MisalignedPointerDereference { .. } => msg!( - "misaligned pointer dereference: address must be a multiple of {$required} but is {$found}" + MisalignedPointerDereference { required, found } => write!( + f, + "misaligned pointer dereference: address must be a multiple of {required:#?} but is {found:#?}" ), } } - - pub fn add_args(self, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) - where - O: fmt::Debug, - { - use AssertKind::*; - - macro_rules! add { - ($name: expr, $value: expr) => { - adder($name.into(), $value.into_diag_arg(&mut None)); - }; - } - - match self { - BoundsCheck { len, index } => { - add!("len", format!("{len:?}")); - add!("index", format!("{index:?}")); - } - Overflow(BinOp::Shl | BinOp::Shr, _, val) - | DivisionByZero(val) - | RemainderByZero(val) - | OverflowNeg(val) => { - add!("val", format!("{val:#?}")); - } - Overflow(binop, left, right) => { - add!("op", binop.to_hir_binop().as_str()); - add!("left", format!("{left:#?}")); - add!("right", format!("{right:#?}")); - } - ResumedAfterReturn(_) - | ResumedAfterPanic(_) - | NullPointerDereference - | ResumedAfterDrop(_) => {} - MisalignedPointerDereference { required, found } => { - add!("required", format!("{required:#?}")); - add!("found", format!("{found:#?}")); - } - InvalidEnumConstruction(source) => { - add!("source", format!("{source:#?}")); - } - } - } } #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] @@ -510,7 +475,6 @@ pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind< } pub use helper::*; -use rustc_errors::msg; mod helper { use super::*; diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 2636fc7024ca..7537a4fc6b0e 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -23,27 +23,10 @@ //! ## Query Modifiers //! //! Query modifiers are special flags that alter the behavior of a query. They are parsed and processed by the `rustc_macros` -//! The main modifiers are: //! -//! - `desc { ... }`: Sets the human-readable description for diagnostics and profiling. Required -//! for every query. The block should contain a `format!`-style string literal followed by -//! optional arguments. The query key identifier is available for use within the block, as is -//! `tcx`. -//! - `arena_cache`: Use an arena for in-memory caching of the query result. -//! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to -//! true. The query key identifier is available for use within the block, as is `tcx`. -//! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately. -//! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling. -//! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed. -//! - `anon`: Make the query anonymous in the dependency graph (no dep node is created). -//! - `eval_always`: Always evaluate the query, ignoring its dependencies and cached results. -//! - `depth_limit`: Impose a recursion depth limit on the query to prevent stack overflows. -//! - `separate_provide_extern`: Use separate provider functions for local and external crates. -//! - `feedable`: Allow the query result to be set from another query ("fed" externally). +//! For the list of modifiers, see [`rustc_middle::query::modifiers`]. //! -//! For the up-to-date list, see the `QueryModifiers` struct in -//! [`rustc_macros/src/query.rs`](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_macros/src/query.rs) -//! and for more details in incremental compilation, see the +//! For more details on incremental compilation, see the //! [Query modifiers in incremental compilation](https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation-in-detail.html#query-modifiers) section of the rustc-dev-guide. //! //! ## Query Expansion and Code Generation @@ -85,7 +68,7 @@ CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId, }; use rustc_hir::lang_items::{LangItem, LanguageItems}; -use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate}; +use rustc_hir::{ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate}; use rustc_index::IndexVec; use rustc_lint_defs::LintId; use rustc_macros::rustc_queries; @@ -96,10 +79,10 @@ }; use rustc_session::lint::LintExpectationId; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, LocalExpnId, Span, Symbol}; +use rustc_span::{DUMMY_SP, LocalExpnId, Span, Spanned, Symbol}; use rustc_target::spec::PanicStrategy; +use crate::hir::Crate; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; use crate::metadata::ModChild; @@ -119,7 +102,7 @@ CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono, }; use crate::query::describe_as_module; -use crate::query::plumbing::CyclePlaceholder; +use crate::query::plumbing::{define_callbacks, maybe_into_query_key}; use crate::traits::query::{ CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal, CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal, @@ -139,7 +122,7 @@ self, CrateInherentImpls, GenericArg, GenericArgsRef, LitToConstInput, PseudoCanonicalInput, SizedTraitKind, Ty, TyCtxt, TyCtxtFeed, }; -use crate::{dep_graph, mir, thir}; +use crate::{mir, thir}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method @@ -148,10 +131,10 @@ // `Providers` that the driver creates (using several `rustc_*` crates). // // The result type of each query must implement `Clone`. Additionally -// `ty::query::from_cycle_error::FromCycleError` can be implemented which produces an appropriate +// `QueryVTable::handle_cycle_error_fn` can be used to produce an appropriate // placeholder (error) value if the query resulted in a query cycle. -// Queries without a `FromCycleError` implementation will raise a fatal error on query -// cycles instead. +// Queries without a custom `handle_cycle_error_fn` implementation will raise a +// fatal error on query cycles instead. rustc_queries! { /// Caches the expansion of a derive proc macro, e.g. `#[derive(Serialize)]`. /// The key is: @@ -228,6 +211,16 @@ desc { "getting the crate HIR" } } + query lower_delayed_owner(def_id: LocalDefId) { + eval_always + desc { "lowering the delayed AST owner `{}`", tcx.def_path_str(def_id) } + } + + query delayed_owner(def_id: LocalDefId) -> hir::MaybeOwner<'tcx> { + feedable + desc { "getting child of lowered delayed AST owner `{}`", tcx.def_path_str(def_id) } + } + /// All items in the crate. query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems { arena_cache @@ -340,22 +333,16 @@ feedable } - /// Returns the *hidden type* of the opaque type given by `DefId` unless a cycle occurred. - /// - /// This is a specialized instance of [`Self::type_of`] that detects query cycles. - /// Unless `CyclePlaceholder` needs to be handled separately, call [`Self::type_of`] instead. - /// This is used to improve the error message in cases where revealing the hidden type - /// for auto-trait leakage cycles. + /// Returns the *hidden type* of the opaque type given by `DefId`. /// /// # Panics /// /// This query will panic if the given definition is not an opaque type. - query type_of_opaque(key: DefId) -> Result>, CyclePlaceholder> { + query type_of_opaque(key: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { desc { "computing type of opaque `{path}`", path = tcx.def_path_str(key), } - cycle_stash } query type_of_opaque_hir_typeck(key: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { desc { @@ -589,26 +576,24 @@ } /// Checks whether a type is representable or infinitely sized - query check_representability(key: LocalDefId) -> rustc_middle::ty::Representability { + // + // Infinitely sized types will cause a cycle. The query's `handle_cycle_error_fn` will print + // a custom error about the infinite size and then abort compilation. (In the past we + // recovered and continued, but in practice that leads to confusing subsequent error + // messages about cycles that then abort.) + query check_representability(key: LocalDefId) { desc { "checking if `{}` is representable", tcx.def_path_str(key) } - // Infinitely sized types will cause a cycle. The custom `FromCycleError` impl for - // `Representability` will print a custom error about the infinite size and then abort - // compilation. (In the past we recovered and continued, but in practice that leads to - // confusing subsequent error messages about cycles that then abort.) - cycle_delay_bug // We don't want recursive representability calls to be forced with // incremental compilation because, if a cycle occurs, we need the - // entire cycle to be in memory for diagnostics. This means we can't - // use `ensure_ok()` with this query. - anon + // entire cycle to be in memory for diagnostics. + no_force } /// An implementation detail for the `check_representability` query. See that query for more /// details, particularly on the modifiers. - query check_representability_adt_ty(key: Ty<'tcx>) -> rustc_middle::ty::Representability { + query check_representability_adt_ty(key: Ty<'tcx>) { desc { "checking if `{}` is representable", key } - cycle_delay_bug - anon + no_force } /// Set of param indexes for type params that are in the type's representation @@ -782,14 +767,10 @@ /// Normally you would just use `tcx.erase_and_anonymize_regions(value)`, /// however, which uses this query as a kind of cache. query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { - // This query is not expected to have input -- as a result, it - // is not a good candidates for "replay" because it is essentially a - // pure function of its input (and hence the expectation is that - // no caller would be green **apart** from just these - // queries). Making it anonymous avoids hashing the result, which - // may save a bit of time. - anon desc { "erasing regions from `{}`", ty } + // Not hashing the return value appears to give marginally better perf for this query, + // which should always be marked green for having no dependencies anyway. + no_hash } query wasm_import_module_map(_: CrateNum) -> &'tcx DefIdMap { @@ -1052,7 +1033,6 @@ desc { "computing the variances of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern - cycle_delay_bug } /// Gets a map with the inferred outlives-predicates of every item in the local crate. @@ -1185,7 +1165,6 @@ desc { "computing function signature of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern - cycle_delay_bug } /// Performs lint checking for the module. @@ -1243,9 +1222,9 @@ separate_provide_extern } - query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { + query typeck_root(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { desc { "type-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { !tcx.is_typeck_child(key.to_def_id()) } + cache_on_disk_if { true } } query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet { @@ -1434,7 +1413,7 @@ /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; /// in the case of closures, this will be redirected to the enclosing function. - query region_scope_tree(def_id: DefId) -> &'tcx crate::middle::region::ScopeTree { + query region_scope_tree(def_id: LocalDefId) -> &'tcx crate::middle::region::ScopeTree { desc { "computing drop scopes for `{}`", tcx.def_path_str(def_id) } } @@ -1776,8 +1755,6 @@ ) -> Result, &'tcx ty::layout::LayoutError<'tcx>> { depth_limit desc { "computing layout of `{}`", key.value } - // we emit our own error during query cycle handling - cycle_delay_bug } /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 4d4833b4943e..81c3c7baa07a 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -7,19 +7,21 @@ use std::ffi::OsStr; use std::intrinsics::transmute_unchecked; +use std::marker::PhantomData; use std::mem::MaybeUninit; use rustc_ast::tokenstream::TokenStream; -use rustc_span::ErrorGuaranteed; -use rustc_span::source_map::Spanned; +use rustc_data_structures::steal::Steal; +use rustc_data_structures::sync::{DynSend, DynSync}; +use rustc_span::{ErrorGuaranteed, Spanned}; -use crate::mir::interpret::EvalToValTreeResult; use crate::mir::mono::{MonoItem, NormalizationErrorInMono}; -use crate::query::plumbing::CyclePlaceholder; -use crate::traits::solve; -use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty, TyCtxt}; -use crate::{mir, traits}; +use crate::{mir, thir, traits}; + +unsafe extern "C" { + type NoAutoTraits; +} /// Internal implementation detail of [`Erased`]. #[derive(Copy, Clone)] @@ -27,8 +29,15 @@ pub struct ErasedData { /// We use `MaybeUninit` here to make sure it's legal to store a transmuted /// value that isn't actually of type `Storage`. data: MaybeUninit, + /// `Storage` is an erased type, so we use an external type here to opt-out of auto traits + /// as those would be incorrect. + no_auto_traits: PhantomData, } +// SAFETY: The bounds on `erase_val` ensure the types we erase are `DynSync` and `DynSend` +unsafe impl DynSync for ErasedData {} +unsafe impl DynSend for ErasedData {} + /// Trait for types that can be erased into [`Erased`]. /// /// Erasing and unerasing values is performed by [`erase_val`] and [`restore_val`]. @@ -58,13 +67,11 @@ pub trait Erasable: Copy { /// /// `Erased` and `Erased` are type-checked as distinct types, but codegen /// can see whether they actually have the same storage type. -/// -/// FIXME: This might have soundness issues with erasable types that don't -/// implement the same auto-traits as `[u8; _]`; see -/// #[inline(always)] #[define_opaque(Erased)] -pub fn erase_val(value: T) -> Erased { +// The `DynSend` and `DynSync` bounds on `T` are used to +// justify the safety of the implementations of these traits for `ErasedData`. +pub fn erase_val(value: T) -> Erased { // Ensure the sizes match const { if size_of::() != size_of::() { @@ -82,6 +89,7 @@ pub fn erase_val(value: T) -> Erased { // // SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes. data: unsafe { transmute_unchecked::>(value) }, + no_auto_traits: PhantomData, } } @@ -92,7 +100,7 @@ pub fn erase_val(value: T) -> Erased { #[inline(always)] #[define_opaque(Erased)] pub fn restore_val(erased_value: Erased) -> T { - let ErasedData { data }: ErasedData<::Storage> = erased_value; + let ErasedData { data, .. }: ErasedData<::Storage> = erased_value; // See comment in `erase_val` for why we use `transmute_unchecked`. // // SAFETY: Due to the use of impl Trait in `Erased` the only way to safely create an instance @@ -104,204 +112,42 @@ pub fn restore_val(erased_value: Erased) -> T { // FIXME(#151565): Using `T: ?Sized` here should let us remove the separate // impls for fat reference types. impl Erasable for &'_ T { - type Storage = [u8; size_of::<&'static ()>()]; + type Storage = [u8; size_of::<&'_ ()>()]; } impl Erasable for &'_ [T] { - type Storage = [u8; size_of::<&'static [()]>()]; -} - -impl Erasable for &'_ OsStr { - type Storage = [u8; size_of::<&'static OsStr>()]; + type Storage = [u8; size_of::<&'_ [()]>()]; } impl Erasable for &'_ ty::List { - type Storage = [u8; size_of::<&'static ty::List<()>>()]; + type Storage = [u8; size_of::<&'_ ty::List<()>>()]; } impl Erasable for &'_ ty::ListWithCachedTypeInfo { - type Storage = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()]; -} - -impl Erasable for &'_ rustc_index::IndexSlice { - type Storage = [u8; size_of::<&'static rustc_index::IndexSlice>()]; + type Storage = [u8; size_of::<&'_ ty::ListWithCachedTypeInfo<()>>()]; } impl Erasable for Result<&'_ T, traits::query::NoSolution> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } -impl Erasable for Result<&'_ [T], traits::query::NoSolution> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Result<&'_ T, rustc_errors::ErrorGuaranteed> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Result<&'_ [T], rustc_errors::ErrorGuaranteed> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Result<&'_ T, traits::CodegenObligationError> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> { - type Storage = [u8; size_of::>>()]; -} - -impl Erasable for Result<(&'_ T, crate::thir::ExprId), rustc_errors::ErrorGuaranteed> { - type Storage = [u8; size_of::< - Result<(&'static (), crate::thir::ExprId), rustc_errors::ErrorGuaranteed>, - >()]; -} - -impl Erasable for Result>, rustc_errors::ErrorGuaranteed> { - type Storage = - [u8; size_of::>, rustc_errors::ErrorGuaranteed>>()]; -} - -impl Erasable for Result { - type Storage = [u8; size_of::>()]; -} - -impl Erasable - for Result>>, rustc_errors::ErrorGuaranteed> -{ - type Storage = [u8; size_of::< - Result>>, rustc_errors::ErrorGuaranteed>, - >()]; -} - -impl Erasable for Result, traits::query::NoSolution> { - type Storage = [u8; size_of::, traits::query::NoSolution>>()]; -} - -impl Erasable for Result> { - type Storage = [u8; size_of::>>()]; -} - -impl Erasable for Result>, &ty::layout::LayoutError<'_>> { - type Storage = [u8; size_of::< - Result< - rustc_abi::TyAndLayout<'static, Ty<'static>>, - &'static ty::layout::LayoutError<'static>, - >, - >()]; -} - -impl Erasable for Result, mir::interpret::ErrorHandled> { - type Storage = - [u8; size_of::, mir::interpret::ErrorHandled>>()]; -} - -impl Erasable for Result { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Option<(mir::ConstValue, Ty<'_>)> { - type Storage = [u8; size_of::)>>()]; -} - -impl Erasable for EvalToValTreeResult<'_> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { - type Storage = - [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; -} - -impl Erasable for Result>, CyclePlaceholder> { - type Storage = [u8; size_of::>, CyclePlaceholder>>()]; -} - -impl Erasable - for Result<(&'_ [Spanned>], &'_ [Spanned>]), NormalizationErrorInMono> -{ - type Storage = [u8; size_of::< - Result< - (&'static [Spanned>], &'static [Spanned>]), - NormalizationErrorInMono, - >, - >()]; -} - -impl Erasable for Result<&'_ TokenStream, ()> { - type Storage = [u8; size_of::>()]; +impl Erasable for Result<&'_ T, ErrorGuaranteed> { + type Storage = [u8; size_of::>()]; } impl Erasable for Option<&'_ T> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Option<&'_ [T]> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Option<&'_ OsStr> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Option> { - type Storage = [u8; size_of::>>()]; -} - -impl Erasable for ty::ImplTraitHeader<'_> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Option>> { - type Storage = [u8; size_of::>>>()]; -} - -impl Erasable for Option> { - type Storage = [u8; size_of::>>()]; -} - -impl Erasable for rustc_hir::MaybeOwner<'_> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for ty::EarlyBinder<'_, T> { type Storage = T::Storage; } -impl Erasable for ty::Binder<'_, ty::FnSig<'_>> { - type Storage = [u8; size_of::>>()]; -} - -impl Erasable for ty::Binder<'_, ty::CoroutineWitnessTypes>> { - type Storage = - [u8; size_of::>>>()]; -} - -impl Erasable for ty::Binder<'_, &'_ ty::List>> { - type Storage = [u8; size_of::>>>()]; -} - impl Erasable for (&'_ T0, &'_ T1) { - type Storage = [u8; size_of::<(&'static (), &'static ())>()]; + type Storage = [u8; size_of::<(&'_ (), &'_ ())>()]; } -impl Erasable for (solve::QueryResult<'_>, &'_ T0) { - type Storage = [u8; size_of::<(solve::QueryResult<'static>, &'static ())>()]; -} - -impl Erasable for (&'_ T0, &'_ [T1]) { - type Storage = [u8; size_of::<(&'static (), &'static [()])>()]; -} - -impl Erasable for (&'_ [T0], &'_ [T1]) { - type Storage = [u8; size_of::<(&'static [()], &'static [()])>()]; -} - -impl Erasable for (&'_ T0, Result<(), ErrorGuaranteed>) { - type Storage = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()]; -} - -macro_rules! impl_erasable_for_simple_types { +macro_rules! impl_erasable_for_types_with_no_type_params { ($($ty:ty),+ $(,)?) => { $( impl Erasable for $ty { @@ -311,172 +157,96 @@ impl Erasable for $ty { } } -// For concrete types with no lifetimes, the erased storage for `Foo` is -// `[u8; size_of::()]`. -impl_erasable_for_simple_types! { - // FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this. +// For types with no type parameters the erased storage for `Foo` is +// `[u8; size_of::()]`. ('_ lifetimes are allowed.) +impl_erasable_for_types_with_no_type_params! { + // tidy-alphabetical-start + (&'_ ty::CrateInherentImpls, Result<(), ErrorGuaranteed>), (), - bool, + (traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe>), + Option<&'_ OsStr>, + Option<&'_ [rustc_hir::PreciseCapturingArgKind]>, + Option<(mir::ConstValue, Ty<'_>)>, Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, + Option, Option, + Option, Option, + Option, Option, Option, - Option, - Option, - Option, - Option, Option, Option, Option, - Option, + Option, Option, + Option, Option, Option, Option, - Option, - Option, Option, + Option>>, + Option>, Option, - Option, - Option, - Result<(), rustc_errors::ErrorGuaranteed>, - Result<(), rustc_middle::traits::query::NoSolution>, + Result<&'_ TokenStream, ()>, + Result<&'_ rustc_target::callconv::FnAbi<'_, Ty<'_>>, &'_ ty::layout::FnAbiError<'_>>, + Result<&'_ traits::ImplSource<'_, ()>, traits::CodegenObligationError>, + Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop>, + Result<(&'_ Steal>, thir::ExprId), ErrorGuaranteed>, + Result<(&'_ [Spanned>], &'_ [Spanned>]), NormalizationErrorInMono>, + Result<(), ErrorGuaranteed>, + Result>>, ErrorGuaranteed>, + Result>, ErrorGuaranteed>, + Result>, + Result, mir::interpret::ErrorHandled>, + Result, + Result>, &ty::layout::LayoutError<'_>>, Result, - rustc_abi::ReprOptions, - rustc_ast::expand::allocator::AllocatorKind, - rustc_hir::DefaultBodyStability, - rustc_hir::attrs::Deprecation, - rustc_hir::attrs::EiiDecl, - rustc_hir::attrs::EiiImpl, + Result, + Result, traits::query::NoSolution>, + Ty<'_>, + bool, rustc_data_structures::svh::Svh, - rustc_errors::ErrorGuaranteed, rustc_hir::Constness, - rustc_hir::ConstStability, - rustc_hir::def_id::DefId, - rustc_hir::def_id::DefIndex, - rustc_hir::def_id::LocalDefId, - rustc_hir::def_id::LocalModDefId, - rustc_hir::def::DefKind, rustc_hir::Defaultness, - rustc_hir::definitions::DefKey, - rustc_hir::CoroutineKind, rustc_hir::HirId, - rustc_hir::IsAsync, - rustc_hir::ItemLocalId, - rustc_hir::LangItem, + rustc_hir::MaybeOwner<'_>, rustc_hir::OpaqueTyOrigin, - rustc_hir::OwnerId, - rustc_hir::Stability, - rustc_hir::Upvar, - rustc_index::bit_set::FiniteBitSet, - rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs, - rustc_middle::middle::dependency_format::Linkage, - rustc_middle::middle::exported_symbols::SymbolExportInfo, + rustc_hir::def::DefKind, + rustc_hir::def_id::DefId, + rustc_middle::middle::codegen_fn_attrs::SanitizerFnAttrs, rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, - rustc_middle::middle::resolve_bound_vars::ResolvedArg, - rustc_middle::middle::stability::DeprecationEntry, rustc_middle::mir::ConstQualifs, rustc_middle::mir::ConstValue, rustc_middle::mir::interpret::AllocId, - rustc_middle::mir::interpret::CtfeProvenance, - rustc_middle::mir::interpret::ErrorHandled, - rustc_middle::thir::ExprId, - rustc_middle::traits::CodegenObligationError, - rustc_middle::traits::EvaluationResult, - rustc_middle::traits::OverflowError, - rustc_middle::traits::query::NoSolution, - rustc_middle::traits::WellFormedLoc, - rustc_middle::ty::adjustment::CoerceUnsizedInfo, - rustc_middle::ty::AssocItem, - rustc_middle::ty::AssocContainer, - rustc_middle::ty::Asyncness, - rustc_middle::ty::AsyncDestructor, + rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'_>, + rustc_middle::mir::interpret::EvalToValTreeResult<'_>, + rustc_middle::mir::mono::MonoItemPartitions<'_>, + rustc_middle::traits::query::MethodAutoderefStepsResult<'_>, + rustc_middle::ty::AdtDef<'_>, rustc_middle::ty::AnonConstKind, - rustc_middle::ty::Destructor, - rustc_middle::ty::fast_reject::SimplifiedType, - rustc_middle::ty::ImplPolarity, - rustc_middle::ty::Representability, - rustc_middle::ty::UnusedGenericParams, - rustc_middle::ty::util::AlwaysRequiresDrop, + rustc_middle::ty::AssocItem, + rustc_middle::ty::Asyncness, + rustc_middle::ty::Binder<'_, ty::CoroutineWitnessTypes>>, + rustc_middle::ty::Binder<'_, ty::FnSig<'_>>, + rustc_middle::ty::ClosureTypeInfo<'_>, + rustc_middle::ty::Const<'_>, + rustc_middle::ty::ConstConditions<'_>, + rustc_middle::ty::GenericPredicates<'_>, + rustc_middle::ty::ImplTraitHeader<'_>, + rustc_middle::ty::ParamEnv<'_>, + rustc_middle::ty::SymbolName<'_>, + rustc_middle::ty::TypingEnv<'_>, rustc_middle::ty::Visibility, - rustc_middle::middle::codegen_fn_attrs::SanitizerFnAttrs, - rustc_session::config::CrateType, - rustc_session::config::EntryFnType, + rustc_middle::ty::inhabitedness::InhabitedPredicate<'_>, + rustc_session::Limits, rustc_session::config::OptLevel, rustc_session::config::SymbolManglingVersion, rustc_session::cstore::CrateDepKind, - rustc_session::cstore::ExternCrate, - rustc_session::cstore::LinkagePreference, - rustc_session::Limits, - rustc_session::lint::LintExpectationId, - rustc_span::def_id::CrateNum, - rustc_span::def_id::DefPathHash, - rustc_span::ExpnHash, rustc_span::ExpnId, rustc_span::Span, rustc_span::Symbol, - rustc_span::Ident, rustc_target::spec::PanicStrategy, - rustc_type_ir::Variance, - u32, usize, -} - -macro_rules! impl_erasable_for_single_lifetime_types { - ($($($fake_path:ident)::+),+ $(,)?) => { - $( - impl<'tcx> Erasable for $($fake_path)::+<'tcx> { - type Storage = [u8; size_of::<$($fake_path)::+<'static>>()]; - } - )* - } -} - -// For types containing a single lifetime and no other generics, e.g. -// `Foo<'tcx>`, the erased storage is `[u8; size_of::>()]`. -// -// FIXME(#151565): Some of the hand-written impls above that only use one -// lifetime can probably be migrated here. -impl_erasable_for_single_lifetime_types! { - // FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this. - rustc_middle::middle::exported_symbols::ExportedSymbol, - rustc_middle::mir::Const, - rustc_middle::mir::DestructuredConstant, - rustc_middle::mir::ConstAlloc, - rustc_middle::mir::interpret::GlobalId, - rustc_middle::mir::interpret::EvalStaticInitializerRawResult, - rustc_middle::mir::mono::MonoItemPartitions, - rustc_middle::traits::query::MethodAutoderefStepsResult, - rustc_middle::traits::query::type_op::AscribeUserType, - rustc_middle::traits::query::type_op::Eq, - rustc_middle::traits::query::type_op::ProvePredicate, - rustc_middle::traits::query::type_op::Subtype, - rustc_middle::ty::AdtDef, - rustc_middle::ty::AliasTy, - rustc_middle::ty::ClauseKind, - rustc_middle::ty::ClosureTypeInfo, - rustc_middle::ty::Const, - rustc_middle::ty::DestructuredAdtConst, - rustc_middle::ty::ExistentialTraitRef, - rustc_middle::ty::FnSig, - rustc_middle::ty::GenericArg, - rustc_middle::ty::GenericPredicates, - rustc_middle::ty::ConstConditions, - rustc_middle::ty::inhabitedness::InhabitedPredicate, - rustc_middle::ty::Instance, - rustc_middle::ty::BoundVariableKind, - rustc_middle::ty::InstanceKind, - rustc_middle::ty::layout::FnAbiError, - rustc_middle::ty::layout::LayoutError, - rustc_middle::ty::LitToConstInput, - rustc_middle::ty::ParamEnv, - rustc_middle::ty::TypingEnv, - rustc_middle::ty::Predicate, - rustc_middle::ty::SymbolName, - rustc_middle::ty::TraitRef, - rustc_middle::ty::Ty, - rustc_middle::ty::UnevaluatedConst, - rustc_middle::ty::ValTree, - rustc_middle::ty::VtblEntry, + // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/query/inner.rs b/compiler/rustc_middle/src/query/inner.rs index 2c3959805d9d..402c448a1fa3 100644 --- a/compiler/rustc_middle/src/query/inner.rs +++ b/compiler/rustc_middle/src/query/inner.rs @@ -4,10 +4,9 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use crate::dep_graph; -use crate::dep_graph::{DepKind, DepNodeKey}; +use crate::dep_graph::DepNodeKey; use crate::query::erase::{self, Erasable, Erased}; -use crate::query::plumbing::QueryVTable; -use crate::query::{EnsureMode, QueryCache, QueryMode}; +use crate::query::{EnsureMode, QueryCache, QueryMode, QueryVTable}; use crate::ty::TyCtxt; /// Checks whether there is already a value for this key in the in-memory @@ -78,46 +77,57 @@ pub(crate) fn query_ensure_result<'tcx, C, T>( C: QueryCache>>, Result: Erasable, { + let convert = |value: Erased>| -> Result<(), ErrorGuaranteed> { + match erase::restore_val(value) { + Ok(_) => Ok(()), + Err(guar) => Err(guar), + } + }; + match try_get_cached(tcx, &query.cache, key) { - Some(value) => erase::restore_val(value).map(drop), - None => (query.execute_query_fn)( - tcx, - DUMMY_SP, - key, - QueryMode::Ensure { ensure_mode: EnsureMode::Ok }, - ) - .map(erase::restore_val) - .map(|value| value.map(drop)) - // Either we actually executed the query, which means we got a full `Result`, - // or we can just assume the query succeeded, because it was green in the - // incremental cache. If it is green, that means that the previous compilation - // that wrote to the incremental cache compiles successfully. That is only - // possible if the cache entry was `Ok(())`, so we emit that here, without - // actually encoding the `Result` in the cache or loading it from there. - .unwrap_or(Ok(())), + Some(value) => convert(value), + None => { + match (query.execute_query_fn)( + tcx, + DUMMY_SP, + key, + QueryMode::Ensure { ensure_mode: EnsureMode::Ok }, + ) { + // We executed the query. Convert the successful result. + Some(res) => convert(res), + + // Reaching here means we didn't execute the query, but we can just assume the + // query succeeded, because it was green in the incremental cache. If it is green, + // that means that the previous compilation that wrote to the incremental cache + // compiles successfully. That is only possible if the cache entry was `Ok(())`, so + // we emit that here, without actually encoding the `Result` in the cache or + // loading it from there. + None => Ok(()), + } + } } } -/// Common implementation of query feeding, used by `define_feedable!`. +/// "Feeds" a feedable query by adding a given key/value pair to its in-memory cache. +/// Called by macro-generated methods of [`rustc_middle::ty::TyCtxtFeed`]. pub(crate) fn query_feed<'tcx, C>( tcx: TyCtxt<'tcx>, - dep_kind: DepKind, - query_vtable: &QueryVTable<'tcx, C>, + query: &'tcx QueryVTable<'tcx, C>, key: C::Key, value: C::Value, ) where C: QueryCache, C::Key: DepNodeKey<'tcx>, { - let format_value = query_vtable.format_value; + let format_value = query.format_value; // Check whether the in-memory cache already has a value for this key. - match try_get_cached(tcx, &query_vtable.cache, key) { + match try_get_cached(tcx, &query.cache, key) { Some(old) => { // The query already has a cached value for this key. // That's OK if both values are the same, i.e. they have the same hash, // so now we check their hashes. - if let Some(hash_value_fn) = query_vtable.hash_value_fn { + if let Some(hash_value_fn) = query.hash_value_fn { let (old_hash, value_hash) = tcx.with_stable_hashing_context(|ref mut hcx| { (hash_value_fn(hcx, &old), hash_value_fn(hcx, &value)) }); @@ -126,7 +136,7 @@ pub(crate) fn query_feed<'tcx, C>( // results is tainted by errors. In this case, delay a bug to // ensure compilation is doomed, and keep the `old` value. tcx.dcx().delayed_bug(format!( - "Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\ + "Trying to feed an already recorded value for query {query:?} key={key:?}:\n\ old value: {old}\nnew value: {value}", old = format_value(&old), value = format_value(&value), @@ -137,7 +147,7 @@ pub(crate) fn query_feed<'tcx, C>( // If feeding the same value multiple times needs to be supported, // the query should not be marked `no_hash`. bug!( - "Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\ + "Trying to feed an already recorded value for query {query:?} key={key:?}:\n\ old value: {old}\nnew value: {value}", old = format_value(&old), value = format_value(&value), @@ -147,15 +157,15 @@ pub(crate) fn query_feed<'tcx, C>( None => { // There is no cached value for this key, so feed the query by // adding the provided value to the cache. - let dep_node = dep_graph::DepNode::construct(tcx, dep_kind, &key); + let dep_node = dep_graph::DepNode::construct(tcx, query.dep_kind, &key); let dep_node_index = tcx.dep_graph.with_feed_task( dep_node, tcx, &value, - query_vtable.hash_value_fn, - query_vtable.format_value, + query.hash_value_fn, + query.format_value, ); - query_vtable.cache.complete(key, value, dep_node_index); + query.cache.complete(key, value, dep_node_index); } } } diff --git a/compiler/rustc_middle/src/query/into_query_key.rs b/compiler/rustc_middle/src/query/into_query_key.rs new file mode 100644 index 000000000000..04bbfd5c3a8a --- /dev/null +++ b/compiler/rustc_middle/src/query/into_query_key.rs @@ -0,0 +1,70 @@ +use rustc_hir::OwnerId; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, ModDefId}; + +/// Argument-conversion trait used by some queries and other `TyCtxt` methods. +/// +/// A function that accepts an `impl IntoQueryKey` argument can be thought +/// of as taking a [`DefId`], except that callers can also pass a [`LocalDefId`] +/// or values of other narrower ID types, as long as they have a trivial conversion +/// to `DefId`. +/// +/// Using a dedicated trait instead of [`Into`] makes the purpose of the conversion +/// more explicit, and makes occurrences easier to search for. +pub trait IntoQueryKey { + /// Argument conversion from `Self` to `K`. + /// This should always be a very cheap conversion, e.g. [`LocalDefId::to_def_id`]. + fn into_query_key(self) -> K; +} + +/// Any type can be converted to itself. +/// +/// This is useful in generic or macro-generated code where we don't know whether +/// conversion is actually needed, so that we can do a conversion unconditionally. +impl IntoQueryKey for K { + #[inline(always)] + fn into_query_key(self) -> K { + self + } +} + +impl IntoQueryKey for OwnerId { + #[inline(always)] + fn into_query_key(self) -> LocalDefId { + self.def_id + } +} + +impl IntoQueryKey for LocalDefId { + #[inline(always)] + fn into_query_key(self) -> DefId { + self.to_def_id() + } +} + +impl IntoQueryKey for OwnerId { + #[inline(always)] + fn into_query_key(self) -> DefId { + self.to_def_id() + } +} + +impl IntoQueryKey for ModDefId { + #[inline(always)] + fn into_query_key(self) -> DefId { + self.to_def_id() + } +} + +impl IntoQueryKey for LocalModDefId { + #[inline(always)] + fn into_query_key(self) -> DefId { + self.to_def_id() + } +} + +impl IntoQueryKey for LocalModDefId { + #[inline(always)] + fn into_query_key(self) -> LocalDefId { + self.into() + } +} diff --git a/compiler/rustc_middle/src/query/job.rs b/compiler/rustc_middle/src/query/job.rs index f1a2b3a34d0e..24c4daf9855d 100644 --- a/compiler/rustc_middle/src/query/job.rs +++ b/compiler/rustc_middle/src/query/job.rs @@ -6,24 +6,9 @@ use parking_lot::{Condvar, Mutex}; use rustc_span::Span; -use crate::query::plumbing::CycleError; -use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra}; +use crate::query::Cycle; use crate::ty::TyCtxt; -/// Represents a span and a query key. -#[derive(Clone, Debug)] -pub struct QueryInfo { - /// The span corresponding to the reason for which this query was required. - pub span: Span, - pub frame: QueryStackFrame, -} - -impl<'tcx> QueryInfo> { - pub(crate) fn lift(&self) -> QueryInfo { - QueryInfo { span: self.span, frame: self.frame.lift() } - } -} - /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct QueryJobId(pub NonZero); @@ -71,28 +56,21 @@ pub fn signal_complete(self) { #[derive(Debug)] pub struct QueryWaiter<'tcx> { - pub query: Option, + pub parent: Option, pub condvar: Condvar, pub span: Span, - pub cycle: Mutex>>>, -} - -#[derive(Debug)] -pub struct QueryLatchInfo<'tcx> { - pub complete: bool, - pub waiters: Vec>>, + pub cycle: Mutex>>, } #[derive(Clone, Debug)] pub struct QueryLatch<'tcx> { - pub info: Arc>>, + /// The `Option` is `Some(..)` when the job is active, and `None` once completed. + pub waiters: Arc>>>>>, } impl<'tcx> QueryLatch<'tcx> { fn new() -> Self { - QueryLatch { - info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), - } + QueryLatch { waiters: Arc::new(Mutex::new(Some(Vec::new()))) } } /// Awaits for the query job to complete. @@ -101,10 +79,36 @@ pub fn wait_on( tcx: TyCtxt<'tcx>, query: Option, span: Span, - ) -> Result<(), CycleError>> { - let waiter = - Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); - self.wait_on_inner(tcx, &waiter); + ) -> Result<(), Cycle<'tcx>> { + let mut waiters_guard = self.waiters.lock(); + let Some(waiters) = &mut *waiters_guard else { + return Ok(()); // already complete + }; + + let waiter = Arc::new(QueryWaiter { + parent: query, + span, + cycle: Mutex::new(None), + condvar: Condvar::new(), + }); + + // We push the waiter on to the `waiters` list. It can be accessed inside + // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. + // Both of these will remove it from the `waiters` list before resuming + // this thread. + waiters.push(Arc::clone(&waiter)); + + // Awaits the caller on this latch by blocking the current thread. + // If this detects a deadlock and the deadlock handler wants to resume this thread + // we have to be in the `wait` call. This is ensured by the deadlock handler + // getting the self.info lock. + rustc_thread_pool::mark_blocked(); + tcx.jobserver_proxy.release_thread(); + waiter.condvar.wait(&mut waiters_guard); + // Release the lock before we potentially block in `acquire_thread` + drop(waiters_guard); + tcx.jobserver_proxy.acquire_thread(); + // FIXME: Get rid of this lock. We have ownership of the QueryWaiter // although another thread may still have a Arc reference so we cannot // use Arc::get_mut @@ -115,35 +119,12 @@ pub fn wait_on( } } - /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, tcx: TyCtxt<'tcx>, waiter: &Arc>) { - let mut info = self.info.lock(); - if !info.complete { - // We push the waiter on to the `waiters` list. It can be accessed inside - // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. - // Both of these will remove it from the `waiters` list before resuming - // this thread. - info.waiters.push(Arc::clone(waiter)); - - // If this detects a deadlock and the deadlock handler wants to resume this thread - // we have to be in the `wait` call. This is ensured by the deadlock handler - // getting the self.info lock. - rustc_thread_pool::mark_blocked(); - tcx.jobserver_proxy.release_thread(); - waiter.condvar.wait(&mut info); - // Release the lock before we potentially block in `acquire_thread` - drop(info); - tcx.jobserver_proxy.acquire_thread(); - } - } - /// Sets the latch and resumes all waiters on it fn set(&self) { - let mut info = self.info.lock(); - debug_assert!(!info.complete); - info.complete = true; + let mut waiters_guard = self.waiters.lock(); + let waiters = waiters_guard.take().unwrap(); // mark the latch as complete let registry = rustc_thread_pool::Registry::current(); - for waiter in info.waiters.drain(..) { + for waiter in waiters { rustc_thread_pool::mark_unblocked(®istry); waiter.condvar.notify_one(); } @@ -152,9 +133,9 @@ fn set(&self) { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. pub fn extract_waiter(&self, waiter: usize) -> Arc> { - let mut info = self.info.lock(); - debug_assert!(!info.complete); + let mut waiters_guard = self.waiters.lock(); + let waiters = waiters_guard.as_mut().expect("non-empty waiters vec"); // Remove the waiter from the list of waiters - info.waiters.remove(waiter) + waiters.remove(waiter) } } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 54b72c5b6714..e5e56b8e28b2 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -45,11 +45,6 @@ pub trait QueryKey: Sized + QueryKeyBounds { fn key_as_def_id(&self) -> Option { None } - - /// Used to detect when ADT def ids are used as keys in a cycle for better error reporting. - fn def_id_for_ty_in_cycle(&self) -> Option { - None - } } pub trait AsLocalQueryKey: QueryKey { @@ -265,14 +260,6 @@ impl<'tcx> QueryKey for Ty<'tcx> { fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } - - fn def_id_for_ty_in_cycle(&self) -> Option { - match *self.kind() { - ty::Adt(adt, _) => Some(adt.did()), - ty::Coroutine(def_id, ..) => Some(def_id), - _ => None, - } - } } impl<'tcx> QueryKey for (Ty<'tcx>, Ty<'tcx>) { @@ -291,10 +278,6 @@ impl<'tcx, T: QueryKey> QueryKey for ty::PseudoCanonicalInput<'tcx, T> { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) } - - fn def_id_for_ty_in_cycle(&self) -> Option { - self.value.def_id_for_ty_in_cycle() - } } impl QueryKey for Symbol { @@ -371,13 +354,6 @@ impl<'tcx> QueryKey for (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty< fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } - - fn def_id_for_ty_in_cycle(&self) -> Option { - match self.1.value.kind() { - ty::Adt(adt, _) => Some(adt.did()), - _ => None, - } - } } impl<'tcx> QueryKey for (ty::Instance<'tcx>, CollectionMode) { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ef96ebb83bff..b7e5e9bcb5e3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1,13 +1,14 @@ use rustc_hir::def_id::LocalDefId; pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; -pub use self::job::{QueryInfo, QueryJob, QueryJobId, QueryLatch, QueryWaiter}; +pub use self::into_query_key::IntoQueryKey; +pub use self::job::{QueryJob, QueryJobId, QueryLatch, QueryWaiter}; pub use self::keys::{AsLocalQueryKey, LocalCrate, QueryKey}; pub use self::plumbing::{ - ActiveKeyStatus, CycleError, CycleErrorHandling, EnsureMode, IntoQueryParam, QueryMode, - QueryState, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk, TyCtxtEnsureResult, + ActiveKeyStatus, Cycle, EnsureMode, QueryMode, QueryState, QuerySystem, QueryVTable, TyCtxtAt, + TyCtxtEnsureDone, TyCtxtEnsureOk, TyCtxtEnsureResult, }; -pub use self::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra}; +pub use self::stack::QueryStackFrame; pub use crate::queries::Providers; use crate::ty::TyCtxt; @@ -15,12 +16,12 @@ mod caches; pub mod erase; pub(crate) mod inner; +mod into_query_key; mod job; mod keys; -pub mod on_disk_cache; -#[macro_use] -pub mod plumbing; pub(crate) mod modifiers; +pub mod on_disk_cache; +pub(crate) mod plumbing; mod stack; pub fn describe_as_module(def_id: impl Into, tcx: TyCtxt<'_>) -> String { diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 2bc70dd588df..50c9136ac6e9 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -4,48 +4,49 @@ //! modifier names in the query list, and to allow find-all-references to list //! all queries that use a particular modifier. #![allow(unused, non_camel_case_types)] -// FIXME: Update and clarify documentation for these modifiers. // tidy-alphabetical-start // -/// # `anon` query modifier -/// -/// Generate a dep node based on the dependencies of the query -pub(crate) struct anon; - /// # `arena_cache` query modifier /// -/// Use this type for the in-memory cache. +/// Query return values must impl `Copy` and be small, but some queries must return values that +/// doesn't meet those criteria. Queries marked with this modifier have their values allocated in +/// an arena and the query returns a reference to the value. There are two cases. +/// - If the provider function returns `T` then the query will return `&'tcx T`. +/// - If the provider function returns `Option` then the query will return `Option<&'tcx T>`. +/// +/// The query plumbing takes care of the arenas and the type manipulations. pub(crate) struct arena_cache; -/// # `cache_on_disk_if` query modifier +/// # `cache_on_disk_if { ... }` query modifier /// -/// Cache the query to disk if the `Block` returns true. +/// Cache the query result to disk if the provided block evaluates to true. The query key +/// identifier is available for use within the block, as is `tcx`. pub(crate) struct cache_on_disk_if; -/// # `cycle_delay_bug` query modifier -/// -/// A cycle error results in a delay_bug call -pub(crate) struct cycle_delay_bug; - -/// # `cycle_stash` query modifier -/// -/// A cycle error results in a stashed cycle error that can be unstashed and canceled later -pub(crate) struct cycle_stash; - /// # `depth_limit` query modifier /// -/// Whether the query has a call depth limit +/// Impose a recursion call depth limit on the query to prevent stack overflow. pub(crate) struct depth_limit; -/// # `desc` query modifier +/// # `desc { ... }` query modifier /// -/// The description of the query. This modifier is required on every query. +/// The human-readable description of the query, for diagnostics and profiling. Required for every +/// query. The block should contain a `format!`-style string literal followed by optional +/// arguments. The query key identifier is available for use within the block, as is `tcx`. pub(crate) struct desc; /// # `eval_always` query modifier /// -/// Always evaluate the query, ignoring its dependencies +/// Queries with this modifier do not track their dependencies, and are treated as always having a +/// red (dirty) dependency instead. This is necessary for queries that interact with state that +/// isn't tracked by the query system. +/// +/// It can also improve performance for queries that are so likely to be dirtied by any change that +/// it's not worth tracking their actual dependencies at all. +/// +/// As with all queries, the return value is still cached in memory for the rest of the compiler +/// session. pub(crate) struct eval_always; /// # `feedable` query modifier @@ -53,14 +54,25 @@ /// Generate a `feed` method to set the query's value from another query. pub(crate) struct feedable; +/// # `no_force` query modifier +/// +/// Dep nodes of queries with this modifier will never be "forced" when trying +/// to mark their dependents green, even if their key is recoverable from the +/// key fingerprint. +/// +/// Used by some queries with custom cycle-handlers to ensure that if a cycle +/// occurs, all of the relevant query calls will be on the query stack. +pub(crate) struct no_force; + /// # `no_hash` query modifier /// -/// Don't hash the result, instead just mark a query red if it runs +/// Do not hash the query's return value for incremental compilation. If the value needs to be +/// recomputed, always mark its node as red (dirty). pub(crate) struct no_hash; /// # `separate_provide_extern` query modifier /// -/// Use a separate query provider for local and extern crates +/// Use separate query provider functions for local and extern crates. pub(crate) struct separate_provide_extern; // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index f2d418fea162..b6fd30647f85 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -2,14 +2,14 @@ use std::sync::Arc; use std::{fmt, mem}; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::sync::{HashMapExt, Lock, RwLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId}; use rustc_hir::definitions::DefPathHash; -use rustc_index::{Idx, IndexVec}; +use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -17,10 +17,9 @@ use rustc_span::hygiene::{ ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextKey, }; -use rustc_span::source_map::Spanned; use rustc_span::{ BlobDecoder, BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, RelativeBytePos, - SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, + SourceFile, Span, SpanDecoder, SpanEncoder, Spanned, StableSourceFileId, Symbol, }; use crate::dep_graph::{DepNodeIndex, QuerySideEffect, SerializedDepNodeIndex}; @@ -54,22 +53,18 @@ pub struct OnDiskCache { // The complete cache data in serialized form. serialized_data: RwLock>, - // Collects all `QuerySideEffect` created during the current compilation - // session. - current_side_effects: Lock>, - file_index_to_stable_id: FxHashMap, // Caches that are populated lazily during decoding. file_index_to_file: Lock>>, - // A map from dep-node to the position of the cached query result in - // `serialized_data`. - query_result_index: FxHashMap, + /// For query dep nodes that have a disk-cached return value, maps the node + /// index to the position of its serialized value in `serialized_data`. + query_values_index: FxHashMap, - // A map from dep-node to the position of any associated `QuerySideEffect` in - // `serialized_data`. - prev_side_effects_index: FxHashMap, + /// For `DepKind::SideEffect` dep nodes, maps the node index to the position + /// of its serialized [`QuerySideEffect`] in `serialized_data`. + side_effects_index: FxHashMap, alloc_decoding_state: AllocDecodingState, @@ -102,8 +97,8 @@ pub struct OnDiskCache { #[derive(Encodable, Decodable)] struct Footer { file_index_to_stable_id: FxHashMap, - query_result_index: EncodedDepNodeIndex, - side_effects_index: EncodedDepNodeIndex, + query_values_index: Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>, + side_effects_index: Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>, // The location of all allocations. // Most uses only need values up to u32::MAX, but benchmarking indicates that we can use a u64 // without measurable overhead. This permits larger const allocations without ICEing. @@ -115,8 +110,6 @@ struct Footer { foreign_expn_data: UnhashMap, } -pub type EncodedDepNodeIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)] struct SourceFileIndex(u32); @@ -175,9 +168,8 @@ pub fn new(sess: &Session, data: Mmap, start_pos: usize) -> Result { serialized_data: RwLock::new(Some(data)), file_index_to_stable_id: footer.file_index_to_stable_id, file_index_to_file: Default::default(), - current_side_effects: Default::default(), - query_result_index: footer.query_result_index.into_iter().collect(), - prev_side_effects_index: footer.side_effects_index.into_iter().collect(), + query_values_index: footer.query_values_index.into_iter().collect(), + side_effects_index: footer.side_effects_index.into_iter().collect(), alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), syntax_contexts: footer.syntax_contexts, expn_data: footer.expn_data, @@ -191,9 +183,8 @@ pub fn new_empty() -> Self { serialized_data: RwLock::new(None), file_index_to_stable_id: Default::default(), file_index_to_file: Default::default(), - current_side_effects: Default::default(), - query_result_index: Default::default(), - prev_side_effects_index: Default::default(), + query_values_index: Default::default(), + side_effects_index: Default::default(), alloc_decoding_state: AllocDecodingState::new(Vec::new()), syntax_contexts: FxHashMap::default(), expn_data: UnhashMap::default(), @@ -208,7 +199,9 @@ pub fn close_serialized_data_mmap(&self) { *self.serialized_data.write() = None; } - pub fn serialize(&self, tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult { + /// Serialize the current-session data that will be loaded by [`OnDiskCache`] + /// in a subsequent incremental compilation session. + pub fn serialize(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -242,30 +235,19 @@ pub fn serialize(&self, tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResu file_to_file_index, hygiene_context: &hygiene_encode_context, symbol_index_table: Default::default(), + query_values_index: Default::default(), + side_effects_index: Default::default(), }; - // Encode query results. - let mut query_result_index = EncodedDepNodeIndex::new(); - - tcx.sess.time("encode_query_results", || { - let enc = &mut encoder; - let qri = &mut query_result_index; - tcx.encode_all_query_results(enc, qri); + // Encode query return values. + tcx.sess.time("encode_query_values", || { + tcx.encode_query_values(&mut encoder); }); // Encode side effects. - let side_effects_index: EncodedDepNodeIndex = self - .current_side_effects - .borrow() - .iter() - .map(|(dep_node_index, side_effect)| { - let pos = AbsoluteBytePos::new(encoder.position()); - let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index()); - encoder.encode_tagged(dep_node_index, side_effect); - - (dep_node_index, pos) - }) - .collect(); + for (&dep_node_index, side_effect) in tcx.query_system.side_effects.borrow().iter() { + encoder.encode_side_effect(dep_node_index, side_effect); + } let interpret_alloc_index = { let mut interpret_alloc_index = Vec::new(); @@ -316,11 +298,13 @@ pub fn serialize(&self, tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResu // Encode the file footer. let footer_pos = encoder.position() as u64; + let query_values_index = mem::take(&mut encoder.query_values_index); + let side_effects_index = mem::take(&mut encoder.side_effects_index); encoder.encode_tagged( TAG_FILE_FOOTER, &Footer { file_index_to_stable_id, - query_result_index, + query_values_index, side_effects_index, interpret_alloc_index, syntax_contexts, @@ -341,35 +325,25 @@ pub fn serialize(&self, tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResu } /// Loads a `QuerySideEffect` created during the previous compilation session. - pub fn load_side_effect( + pub(crate) fn load_side_effect( &self, tcx: TyCtxt<'_>, dep_node_index: SerializedDepNodeIndex, ) -> Option { let side_effect: Option = - self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index); + self.load_indexed(tcx, dep_node_index, &self.side_effects_index); side_effect } - /// Stores a `QuerySideEffect` emitted during the current compilation session. - /// Anything stored like this will be available via `load_side_effect` in - /// the next compilation session. - pub fn store_side_effect(&self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect) { - let mut current_side_effects = self.current_side_effects.borrow_mut(); - let prev = current_side_effects.insert(dep_node_index, side_effect); - debug_assert!(prev.is_none()); - } - - /// Return whether the cached query result can be decoded. + /// Returns true if there is a disk-cached query return value for the given node. #[inline] pub fn loadable_from_disk(&self, dep_node_index: SerializedDepNodeIndex) -> bool { - self.query_result_index.contains_key(&dep_node_index) + self.query_values_index.contains_key(&dep_node_index) // with_decoder is infallible, so we can stop here } - /// Returns the cached query result if there is something in the cache for - /// the given `SerializedDepNodeIndex`; otherwise returns `None`. - pub fn try_load_query_result<'tcx, T>( + /// Returns the disk-cached query return value for the given node, if there is one. + pub fn try_load_query_value<'tcx, T>( &self, tcx: TyCtxt<'tcx>, dep_node_index: SerializedDepNodeIndex, @@ -377,9 +351,7 @@ pub fn try_load_query_result<'tcx, T>( where T: for<'a> Decodable>, { - let opt_value = self.load_indexed(tcx, dep_node_index, &self.query_result_index); - debug_assert_eq!(opt_value.is_some(), self.loadable_from_disk(dep_node_index)); - opt_value + self.load_indexed(tcx, dep_node_index, &self.query_values_index) } fn load_indexed<'tcx, T>( @@ -816,6 +788,9 @@ pub struct CacheEncoder<'a, 'tcx> { hygiene_context: &'a HygieneEncodeContext, // Used for both `Symbol`s and `ByteSymbol`s. symbol_index_table: FxHashMap, + + query_values_index: Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>, + side_effects_index: Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>, } impl<'a, 'tcx> fmt::Debug for CacheEncoder<'a, 'tcx> { @@ -836,7 +811,7 @@ fn source_file_index(&mut self, source_file: Arc) -> SourceFileIndex /// encode the specified tag, then the given value, then the number of /// bytes taken up by tag and value. On decoding, we can then verify that /// we get the expected tag and read the expected number of bytes. - pub fn encode_tagged, V: Encodable>(&mut self, tag: T, value: &V) { + fn encode_tagged, V: Encodable>(&mut self, tag: T, value: &V) { let start_pos = self.position(); tag.encode(self); @@ -846,6 +821,20 @@ pub fn encode_tagged, V: Encodable>(&mut self, tag: T, ((end_pos - start_pos) as u64).encode(self); } + pub fn encode_query_value>(&mut self, index: DepNodeIndex, value: &V) { + let index = SerializedDepNodeIndex::from_curr_for_serialization(index); + + self.query_values_index.push((index, AbsoluteBytePos::new(self.position()))); + self.encode_tagged(index, value); + } + + fn encode_side_effect(&mut self, index: DepNodeIndex, side_effect: &QuerySideEffect) { + let index = SerializedDepNodeIndex::from_curr_for_serialization(index); + + self.side_effects_index.push((index, AbsoluteBytePos::new(self.position()))); + self.encode_tagged(index, side_effect); + } + // copy&paste impl from rustc_metadata fn encode_symbol_or_byte_symbol( &mut self, diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index ad0b6f7c335e..e5c7d994b6c8 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -2,22 +2,20 @@ use std::ops::Deref; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::hash_table::HashTable; use rustc_data_structures::sharded::Sharded; -use rustc_data_structures::sync::{AtomicU64, WorkerLocal}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::hir_id::OwnerId; -use rustc_macros::HashStable; -use rustc_span::{ErrorGuaranteed, Span}; -pub use sealed::IntoQueryParam; +use rustc_data_structures::sync::{AtomicU64, Lock, WorkerLocal}; +use rustc_errors::Diag; +use rustc_hir::def_id::LocalDefId; +use rustc_span::Span; -use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex}; +use crate::dep_graph::{DepKind, DepNodeIndex, QuerySideEffect, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; -use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables}; +use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables, TaggedQueryKey}; use crate::query::on_disk_cache::OnDiskCache; -use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra}; -use crate::query::{QueryCache, QueryInfo, QueryJob}; -use crate::ty::TyCtxt; +use crate::query::{IntoQueryKey, QueryCache, QueryJob, QueryStackFrame}; +use crate::ty::{self, TyCtxt}; /// For a particular query, keeps track of "active" keys, i.e. keys whose /// evaluation has started but has not yet finished successfully. @@ -50,31 +48,13 @@ pub enum ActiveKeyStatus<'tcx> { Poisoned, } -/// How a particular query deals with query cycle errors. -/// -/// Inspected by the code that actually handles cycle errors, to decide what -/// approach to use. -#[derive(Copy, Clone)] -pub enum CycleErrorHandling { - Error, - DelayBug, - Stash, -} - -#[derive(Clone, Debug)] -pub struct CycleError { +#[derive(Debug)] +pub struct Cycle<'tcx> { /// The query and related span that uses the cycle. - pub usage: Option<(Span, QueryStackFrame)>, - pub cycle: Vec>, -} + pub usage: Option>, -impl<'tcx> CycleError> { - pub fn lift(&self) -> CycleError { - CycleError { - usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift())), - cycle: self.cycle.iter().map(|info| info.lift()).collect(), - } - } + /// The span here corresponds to the reason for which this query was required. + pub frames: Vec>, } #[derive(Debug)] @@ -99,8 +79,6 @@ pub enum EnsureMode { pub struct QueryVTable<'tcx, C: QueryCache> { pub name: &'static str, - /// True if this query has the `anon` modifier. - pub anon: bool, /// True if this query has the `eval_always` modifier. pub eval_always: bool, /// True if this query has the `depth_limit` modifier. @@ -109,8 +87,6 @@ pub struct QueryVTable<'tcx, C: QueryCache> { pub feedable: bool, pub dep_kind: DepKind, - /// How this query deals with query cycle errors. - pub cycle_error_handling: CycleErrorHandling, pub state: QueryState<'tcx, C::Key>, pub cache: C, @@ -130,23 +106,21 @@ pub struct QueryVTable<'tcx, C: QueryCache> { index: DepNodeIndex, ) -> Option, - pub is_loadable_from_disk_fn: - fn(tcx: TyCtxt<'tcx>, key: C::Key, index: SerializedDepNodeIndex) -> bool, - /// Function pointer that hashes this query's result values. /// /// For `no_hash` queries, this function pointer is None. pub hash_value_fn: Option, &C::Value) -> Fingerprint>, - pub value_from_cycle_error: - fn(tcx: TyCtxt<'tcx>, cycle_error: CycleError, guar: ErrorGuaranteed) -> C::Value, + /// Function pointer that handles a cycle error. `error` must be consumed, e.g. with `emit` (if + /// it should be emitted) or `delay_as_bug` (if it need not be emitted because an alternative + /// error is created and emitted). A value may be returned, or (more commonly) the function may + /// just abort after emitting the error. + pub handle_cycle_error_fn: + fn(tcx: TyCtxt<'tcx>, key: C::Key, cycle: Cycle<'tcx>, error: Diag<'_>) -> C::Value, + pub format_value: fn(&C::Value) -> String, - /// Formats a human-readable description of this query and its key, as - /// specified by the `desc` query modifier. - /// - /// Used when reporting query cycle errors and similar problems. - pub description_fn: fn(TyCtxt<'tcx>, C::Key) -> String, + pub create_tagged_key: fn(C::Key) -> TaggedQueryKey<'tcx>, /// Function pointer that is called by the query methods on [`TyCtxt`] and /// friends[^1], after they have checked the in-memory cache and found no @@ -176,6 +150,13 @@ pub struct QuerySystem<'tcx> { pub arenas: WorkerLocal>, pub query_vtables: QueryVTables<'tcx>, + /// Side-effect associated with each [`DepKind::SideEffect`] node in the + /// current incremental-compilation session. Side effects will be written + /// to disk, and loaded by [`OnDiskCache`] in the next session. + /// + /// Always empty if incremental compilation is off. + pub side_effects: Lock>, + /// This provides access to the incremental compilation on-disk cache for query results. /// Do not access this directly. It is only meant to be used by /// `DepGraph::try_mark_green()` and the query infrastructure. @@ -220,7 +201,28 @@ pub struct TyCtxtEnsureDone<'tcx> { pub tcx: TyCtxt<'tcx>, } +impl<'tcx> TyCtxtEnsureOk<'tcx> { + pub fn typeck(self, def_id: impl IntoQueryKey) { + self.typeck_root( + self.tcx.typeck_root_def_id(def_id.into_query_key().to_def_id()).expect_local(), + ) + } +} + impl<'tcx> TyCtxt<'tcx> { + pub fn typeck(self, def_id: impl IntoQueryKey) -> &'tcx ty::TypeckResults<'tcx> { + self.typeck_root( + self.typeck_root_def_id(def_id.into_query_key().to_def_id()).expect_local(), + ) + } + + /// Returns a transparent wrapper for `TyCtxt` which uses + /// `span` as the location of queries performed through it. + #[inline(always)] + pub fn at(self, span: Span) -> TyCtxtAt<'tcx> { + TyCtxtAt { tcx: self, span } + } + /// FIXME: `ensure_ok`'s effects are subtle. Is this comment fully accurate? /// /// Wrapper that calls queries in a special "ensure OK" mode, for callers @@ -278,38 +280,30 @@ pub fn ensure_result(self) -> TyCtxtEnsureResult<'tcx> { pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> { TyCtxtEnsureDone { tcx: self } } - - /// Returns a transparent wrapper for `TyCtxt` which uses - /// `span` as the location of queries performed through it. - #[inline(always)] - pub fn at(self, span: Span) -> TyCtxtAt<'tcx> { - TyCtxtAt { tcx: self, span } - } } -macro_rules! query_helper_param_ty { - (DefId) => { impl $crate::query::IntoQueryParam }; - (LocalDefId) => { impl $crate::query::IntoQueryParam }; +macro_rules! maybe_into_query_key { + (DefId) => { impl $crate::query::IntoQueryKey }; + (LocalDefId) => { impl $crate::query::IntoQueryKey }; ($K:ty) => { $K }; } macro_rules! define_callbacks { ( // You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that - // `query_helper_param_ty!` can match on specific type names. + // `maybe_into_query_key!` can match on specific type names. queries { $( $(#[$attr:meta])* fn $name:ident($($K:tt)*) -> $V:ty { // Search for (QMODLIST) to find all occurrences of this query modifier list. - anon: $anon:literal, arena_cache: $arena_cache:literal, cache_on_disk: $cache_on_disk:literal, - cycle_error_handling: $cycle_error_handling:ident, depth_limit: $depth_limit:literal, eval_always: $eval_always:literal, feedable: $feedable:literal, + no_force: $no_force:literal, no_hash: $no_hash:literal, returns_error_guaranteed: $returns_error_guaranteed:literal, separate_provide_extern: $separate_provide_extern:literal, @@ -320,7 +314,6 @@ fn $name:ident($($K:tt)*) -> $V:ty non_queries { $($_:tt)* } ) => { $( - #[allow(unused_lifetimes)] pub mod $name { use super::*; use $crate::query::erase::{self, Erased}; @@ -345,6 +338,9 @@ pub mod $name { #[cfg(not($arena_cache))] pub type ProvidedValue<'tcx> = Value<'tcx>; + pub type Cache<'tcx> = + as $crate::query::QueryKey>::Cache>>; + /// This helper function takes a value returned by the query provider /// (or loaded from disk, or supplied by query feeding), allocates /// it in an arena if requested by the `arena_cache` modifier, and @@ -376,9 +372,6 @@ pub fn provided_to_erased<'tcx>( erase::erase_val(value) } - pub type Cache<'tcx> = - as $crate::query::QueryKey>::Cache>>; - // Ensure that keys grow no larger than 88 bytes by accident. // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] @@ -412,6 +405,97 @@ pub fn provided_to_erased<'tcx>( } )* + /// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a + /// number. + #[allow(non_camel_case_types)] + #[derive(Clone, Copy, Debug)] + pub enum TaggedQueryKey<'tcx> { + $( + $name($name::Key<'tcx>), + )* + } + + impl<'tcx> TaggedQueryKey<'tcx> { + /// Returns the name of the query this key is tagged with. + /// + /// This is useful for error/debug output, but don't use it to check for + /// specific query names. Instead, match on the `TaggedQueryKey` variant. + pub fn query_name(&self) -> &'static str { + match self { + $( + TaggedQueryKey::$name(_) => stringify!($name), + )* + } + } + + /// Formats a human-readable description of this query and its key, as + /// specified by the `desc` query modifier. + /// + /// Used when reporting query cycle errors and similar problems. + pub fn description(&self, tcx: TyCtxt<'tcx>) -> String { + let (name, description) = ty::print::with_no_queries!(match self { + $( + TaggedQueryKey::$name(key) => + (stringify!($name), _description_fns::$name(tcx, *key)), + )* + }); + if tcx.sess.verbose_internals() { + format!("{description} [{name:?}]") + } else { + description + } + } + + /// Returns the default span for this query if `span` is a dummy span. + pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span { + if !span.is_dummy() { + return span + } + if let TaggedQueryKey::def_span(..) = self { + // The `def_span` query is used to calculate `default_span`, + // so exit to avoid infinite recursion. + return DUMMY_SP + } + match self { + $( + TaggedQueryKey::$name(key) => + $crate::query::QueryKey::default_span(key, tcx), + )* + } + } + + pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option { + // This is used to reduce code generation as it + // can be reused for queries with the same key type. + fn inner<'tcx>(key: &impl $crate::query::QueryKey, tcx: TyCtxt<'tcx>) + -> Option + { + key + .key_as_def_id() + .and_then(|def_id| def_id.as_local()) + .map(|def_id| tcx.def_kind(def_id)) + } + + if let TaggedQueryKey::def_kind(..) = self { + // Try to avoid infinite recursion. + return None + } + + match self { + $( + TaggedQueryKey::$name(key) => inner(key, tcx), + )* + } + } + } + + /// Holds a `QueryVTable` for each query. + pub struct QueryVTables<'tcx> { + $( + pub $name: $crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>, + )* + } + /// Holds per-query arenas for queries with the `arena_cache` modifier. #[derive(Default)] pub struct QueryArenas<'tcx> { @@ -424,111 +508,6 @@ pub struct QueryArenas<'tcx> { )* } - impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) { - crate::query::inner::query_ensure_ok_or_done( - self.tcx, - &self.tcx.query_system.query_vtables.$name, - $crate::query::IntoQueryParam::into_query_param(key), - $crate::query::EnsureMode::Ok, - ) - } - )* - } - - // Only defined when the `ensure_result` modifier is present. - impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> { - $( - #[cfg($returns_error_guaranteed)] - $(#[$attr])* - #[inline(always)] - pub fn $name( - self, - key: query_helper_param_ty!($($K)*), - ) -> Result<(), rustc_errors::ErrorGuaranteed> { - crate::query::inner::query_ensure_result( - self.tcx, - &self.tcx.query_system.query_vtables.$name, - $crate::query::IntoQueryParam::into_query_param(key), - ) - } - )* - } - - impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) { - crate::query::inner::query_ensure_ok_or_done( - self.tcx, - &self.tcx.query_system.query_vtables.$name, - $crate::query::IntoQueryParam::into_query_param(key), - $crate::query::EnsureMode::Done, - ); - } - )* - } - - impl<'tcx> TyCtxt<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - #[must_use] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { - self.at(DUMMY_SP).$name(key) - } - )* - } - - impl<'tcx> $crate::query::TyCtxtAt<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { - use $crate::query::{erase, inner}; - - erase::restore_val::<$V>(inner::query_get_at( - self.tcx, - self.span, - &self.tcx.query_system.query_vtables.$name, - $crate::query::IntoQueryParam::into_query_param(key), - )) - } - )* - } - - $( - #[cfg($feedable)] - impl<'tcx, K: $crate::query::IntoQueryParam<$name::Key<'tcx>> + Copy> - TyCtxtFeed<'tcx, K> - { - $(#[$attr])* - #[inline(always)] - pub fn $name(self, value: $name::ProvidedValue<'tcx>) { - let key = self.key().into_query_param(); - let erased_value = $name::provided_to_erased(self.tcx, value); - $crate::query::inner::query_feed( - self.tcx, - dep_graph::DepKind::$name, - &self.tcx.query_system.query_vtables.$name, - key, - erased_value, - ); - } - } - )* - - /// Holds a `QueryVTable` for each query. - pub struct QueryVTables<'tcx> { - $( - pub $name: ::rustc_middle::query::plumbing::QueryVTable<'tcx, $name::Cache<'tcx>>, - )* - } - pub struct Providers { $( /// This is the provider for the query. Use `Find references` on this to @@ -585,74 +564,108 @@ impl Copy for ExternProviders {} impl Clone for ExternProviders { fn clone(&self) -> Self { *self } } + + impl<'tcx> TyCtxt<'tcx> { + $( + $(#[$attr])* + #[inline(always)] + #[must_use] + pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V { + self.at(DUMMY_SP).$name(key) + } + )* + } + + impl<'tcx> $crate::query::TyCtxtAt<'tcx> { + $( + $(#[$attr])* + #[inline(always)] + pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V { + use $crate::query::{erase, inner}; + + erase::restore_val::<$V>(inner::query_get_at( + self.tcx, + self.span, + &self.tcx.query_system.query_vtables.$name, + $crate::query::IntoQueryKey::into_query_key(key), + )) + } + )* + } + + impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> { + $( + $(#[$attr])* + #[inline(always)] + pub fn $name(self, key: maybe_into_query_key!($($K)*)) { + $crate::query::inner::query_ensure_ok_or_done( + self.tcx, + &self.tcx.query_system.query_vtables.$name, + $crate::query::IntoQueryKey::into_query_key(key), + $crate::query::EnsureMode::Ok, + ) + } + )* + } + + // Only defined when the `returns_error_guaranteed` modifier is present. + impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> { + $( + #[cfg($returns_error_guaranteed)] + $(#[$attr])* + #[inline(always)] + pub fn $name( + self, + key: maybe_into_query_key!($($K)*), + ) -> Result<(), rustc_errors::ErrorGuaranteed> { + $crate::query::inner::query_ensure_result( + self.tcx, + &self.tcx.query_system.query_vtables.$name, + $crate::query::IntoQueryKey::into_query_key(key), + ) + } + )* + } + + impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> { + $( + $(#[$attr])* + #[inline(always)] + pub fn $name(self, key: maybe_into_query_key!($($K)*)) { + $crate::query::inner::query_ensure_ok_or_done( + self.tcx, + &self.tcx.query_system.query_vtables.$name, + $crate::query::IntoQueryKey::into_query_key(key), + $crate::query::EnsureMode::Done, + ); + } + )* + } + + $( + // Only defined when the `feedable` modifier is present. + #[cfg($feedable)] + impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy> + TyCtxtFeed<'tcx, K> + { + $(#[$attr])* + #[inline(always)] + pub fn $name(self, value: $name::ProvidedValue<'tcx>) { + $crate::query::inner::query_feed( + self.tcx, + &self.tcx.query_system.query_vtables.$name, + self.key().into_query_key(), + $name::provided_to_erased(self.tcx, value), + ); + } + } + )* }; } -mod sealed { - use rustc_hir::def_id::{LocalModDefId, ModDefId}; - - use super::{DefId, LocalDefId, OwnerId}; - - /// An analogue of the `Into` trait that's intended only for query parameters. - /// - /// This exists to allow queries to accept either `DefId` or `LocalDefId` while requiring that the - /// user call `to_def_id` to convert between them everywhere else. - pub trait IntoQueryParam

{ - fn into_query_param(self) -> P; - } - - impl

IntoQueryParam

for P { - #[inline(always)] - fn into_query_param(self) -> P { - self - } - } - - impl IntoQueryParam for OwnerId { - #[inline(always)] - fn into_query_param(self) -> LocalDefId { - self.def_id - } - } - - impl IntoQueryParam for LocalDefId { - #[inline(always)] - fn into_query_param(self) -> DefId { - self.to_def_id() - } - } - - impl IntoQueryParam for OwnerId { - #[inline(always)] - fn into_query_param(self) -> DefId { - self.to_def_id() - } - } - - impl IntoQueryParam for ModDefId { - #[inline(always)] - fn into_query_param(self) -> DefId { - self.to_def_id() - } - } - - impl IntoQueryParam for LocalModDefId { - #[inline(always)] - fn into_query_param(self) -> DefId { - self.to_def_id() - } - } - - impl IntoQueryParam for LocalModDefId { - #[inline(always)] - fn into_query_param(self) -> LocalDefId { - self.into() - } - } -} - -#[derive(Copy, Clone, Debug, HashStable)] -pub struct CyclePlaceholder(pub ErrorGuaranteed); +// Re-export `macro_rules!` macros as normal items, so that they can be imported normally. +pub(crate) use define_callbacks; +pub(crate) use maybe_into_query_key; #[cold] pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! { diff --git a/compiler/rustc_middle/src/query/stack.rs b/compiler/rustc_middle/src/query/stack.rs index fd80c7edd602..9465fc87edf0 100644 --- a/compiler/rustc_middle/src/query/stack.rs +++ b/compiler/rustc_middle/src/query/stack.rs @@ -1,106 +1,18 @@ -use std::fmt::Debug; -use std::marker::PhantomData; -use std::mem::transmute; -use std::sync::Arc; - -use rustc_data_structures::sync::{DynSend, DynSync}; -use rustc_hir::def::DefKind; use rustc_span::Span; -use rustc_span::def_id::DefId; -use crate::dep_graph::DepKind; +use crate::queries::TaggedQueryKey; /// Description of a frame in the query stack. /// /// This is mostly used in case of cycles for error reporting. -#[derive(Clone, Debug)] -pub struct QueryStackFrame { - /// This field initially stores a `QueryStackDeferred` during collection, - /// but can later be changed to `QueryStackFrameExtra` containing concrete information - /// by calling `lift`. This is done so that collecting query does not need to invoke - /// queries, instead `lift` will call queries in a more appropriate location. - pub info: I, +#[derive(Debug)] +pub struct QueryStackFrame<'tcx> { + pub span: Span, - pub dep_kind: DepKind, - pub def_id: Option, - /// A def-id that is extracted from a `Ty` in a query key - pub def_id_for_ty_in_cycle: Option, -} - -impl<'tcx> QueryStackFrame> { - #[inline] - pub fn new( - info: QueryStackDeferred<'tcx>, - dep_kind: DepKind, - def_id: Option, - def_id_for_ty_in_cycle: Option, - ) -> Self { - Self { info, def_id, dep_kind, def_id_for_ty_in_cycle } - } - - pub fn lift(&self) -> QueryStackFrame { - QueryStackFrame { - info: self.info.extract(), - dep_kind: self.dep_kind, - def_id: self.def_id, - def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle, - } - } -} - -#[derive(Clone, Debug)] -pub struct QueryStackFrameExtra { - pub description: String, - pub span: Option, - pub def_kind: Option, -} - -impl QueryStackFrameExtra { - #[inline] - pub fn new(description: String, span: Option, def_kind: Option) -> Self { - Self { description, span, def_kind } - } - - // FIXME(eddyb) Get more valid `Span`s on queries. - #[inline] - pub fn default_span(&self, span: Span) -> Span { - if !span.is_dummy() { - return span; - } - self.span.unwrap_or(span) - } -} - -/// Track a 'side effect' for a particular query. -/// This is used to hold a closure which can create `QueryStackFrameExtra`. -#[derive(Clone)] -pub struct QueryStackDeferred<'tcx> { - _dummy: PhantomData<&'tcx ()>, - - // `extract` may contain references to 'tcx, but we can't tell drop checking that it won't - // access it in the destructor. - extract: Arc QueryStackFrameExtra + DynSync + DynSend>, -} - -impl<'tcx> QueryStackDeferred<'tcx> { - pub fn new( - context: C, - extract: fn(C) -> QueryStackFrameExtra, - ) -> Self { - let extract: Arc QueryStackFrameExtra + DynSync + DynSend + 'tcx> = - Arc::new(move || extract(context)); - // SAFETY: The `extract` closure does not access 'tcx in its destructor as the only - // captured variable is `context` which is Copy and cannot have a destructor. - Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } } - } - - pub fn extract(&self) -> QueryStackFrameExtra { - (self.extract)() - } -} - -impl<'tcx> Debug for QueryStackDeferred<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("QueryStackDeferred") - } + /// The query and key of the query method call that this stack frame + /// corresponds to. + /// + /// Code that doesn't care about the specific key can still use this to + /// check which query it's for, or obtain the query's name. + pub tagged_key: TaggedQueryKey<'tcx>, } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 18456e763078..51f33691bb7d 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -44,7 +44,7 @@ macro_rules! thir_with_elements { ) => { $( newtype_index! { - #[derive(HashStable)] + #[stable_hash] #[debug_format = $format] pub struct $id {} } @@ -866,6 +866,13 @@ pub enum PatKind<'tcx> { pats: Box<[Pat<'tcx>]>, }, + /// A guard pattern, e.g. `x if guard(x)` + Guard { + subpattern: Box>, + #[type_visitable(ignore)] + condition: ExprId, + }, + /// A never pattern `!`. Never, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index c17e15513cdf..aa1b6b1663bf 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -247,6 +247,12 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, pat: &'thir Pat<'tcx>, ) { + if let PatKind::Guard { subpattern, condition } = &pat.kind { + visitor.visit_pat(subpattern); + visitor.visit_expr(&visitor.thir()[*condition]); + return; + }; + for_each_immediate_subpat(pat, |p| visitor.visit_pat(p)); } @@ -287,5 +293,9 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( callback(pat); } } + + PatKind::Guard { subpattern, .. } => { + callback(subpattern); + } } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 2fca85c9f2f1..a940365b9008 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -633,10 +633,6 @@ pub enum SelectionError<'tcx> { NotConstEvaluatable(NotConstEvaluatable), /// Exceeded the recursion depth during type projection. Overflow(OverflowError), - /// Computing an opaque type's hidden type caused an error (e.g. a cycle error). - /// We can thus not know whether the hidden type implements an auto trait, so - /// we should not presume anything about it. - OpaqueTypeAutoTraitLeakageUnknown(DefId), /// Error for a `ConstArgHasType` goal ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> }, } diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 3a32029c60bd..8499e61ee485 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -163,9 +163,6 @@ pub enum SelectionCandidate<'tcx> { /// types generated for a fn pointer type (e.g., `fn(int) -> int`) FnPointerCandidate, - /// Builtin impl of the `PointerLike` trait. - PointerLikeCandidate, - TraitAliasCandidate, /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 6d546aede4cf..58687be7440b 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -105,6 +105,7 @@ pub enum Adjust { Pointer(PointerCoercion), /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`. + // FIXME(pin_ergonomics): This can be replaced with a `Deref(Pin)` followed by a `Borrow(Pin)` ReborrowPin(hir::Mutability), } @@ -112,6 +113,7 @@ pub enum Adjust { pub enum DerefAdjustKind { Builtin, Overloaded(OverloadedDeref), + Pin, } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` @@ -196,6 +198,9 @@ pub enum AutoBorrow { /// Converts from T to *T. RawPtr(hir::Mutability), + + /// Converts from T to Pin<&T>. + Pin(hir::Mutability), } /// Information for `CoerceUnsized` impls, storing information we diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index ac51e5bd2289..ae3c45877900 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -751,8 +751,3 @@ pub fn sizedness_constraint( if self.is_struct() { tcx.adt_sizedness_constraint((self.did(), sizedness)) } else { None } } } - -/// This type exists just so a `FromCycleError` impl can be made for the `check_representability` -/// query. -#[derive(Clone, Copy, Debug, HashStable)] -pub struct Representability; diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 4cc255cba635..cabe8514ae4b 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -137,8 +137,8 @@ pub fn as_def_kind(&self) -> DefKind { self.kind.as_def_kind() } - pub fn is_const(&self) -> bool { - matches!(self.kind, ty::AssocKind::Const { .. }) + pub fn is_type_const(&self) -> bool { + matches!(self.kind, ty::AssocKind::Const { is_type_const: true, .. }) } pub fn is_fn(&self) -> bool { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index d1987f51f6e0..6652c5a758da 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -15,8 +15,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::Const; use rustc_serialize::{Decodable, Encodable}; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, SpanDecoder, SpanEncoder}; +use rustc_span::{Span, SpanDecoder, SpanEncoder, Spanned}; use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarKind, CanonicalVarKinds}; diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index aade274bfc98..d342e4ba5efa 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -323,6 +323,13 @@ pub fn is_ct_infer(self) -> bool { matches!(self.kind(), ty::ConstKind::Infer(_)) } + pub fn ct_vid(self) -> Option { + match self.kind() { + ConstKind::Infer(ty::InferConst::Var(vid)) => Some(vid), + _ => None, + } + } + /// Iterator that walks `self` and any types reachable from /// `self`, in depth-first order. Note that just walks the types /// that appear in `self`, it does not descend into the fields of diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index eaf67ae23ad2..180ccd9301c4 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -4,7 +4,6 @@ use rustc_abi::Size; use rustc_apfloat::Float; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; -use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use crate::ty::TyCtxt; @@ -137,14 +136,6 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { } } -impl IntoDiagArg for ConstInt { - // FIXME this simply uses the Debug impl, but we could probably do better by converting both - // to an inherent method that returns `Cow`. - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(format!("{self:?}").into()) - } -} - /// The raw bytes of a simple value. /// /// This is a packed struct in order to allow this type to be optimally embedded in enums diff --git a/compiler/rustc_middle/src/ty/consts/lit.rs b/compiler/rustc_middle/src/ty/consts/lit.rs index be6dfb20e043..7be225a9e921 100644 --- a/compiler/rustc_middle/src/ty/consts/lit.rs +++ b/compiler/rustc_middle/src/ty/consts/lit.rs @@ -10,7 +10,10 @@ pub struct LitToConstInput<'tcx> { /// The absolute value of the resultant constant. pub lit: LitKind, /// The type of the constant. - pub ty: Ty<'tcx>, + /// + /// `None` is used by const generics when the type of the constant is unknown, e.g. + /// if there are inference variables + pub ty: Option>, /// If the constant is negative. pub neg: bool, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 64af9e7f0998..28688bcbfafc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -36,8 +36,9 @@ use rustc_hir::intravisit::VisitorExt; use rustc_hir::lang_items::LangItem; use rustc_hir::limit::Limit; -use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, Node, TraitCandidate, find_attr}; +use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, MaybeOwner, Node, TraitCandidate, find_attr}; use rustc_index::IndexVec; +use rustc_macros::Diagnostic; use rustc_session::Session; use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; @@ -54,14 +55,13 @@ use crate::dep_graph::{DepGraph, DepKindVTable, DepNodeIndex}; use crate::ich::StableHashingContext; use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind}; -use crate::lint::{diag_lint_level, lint_level}; +use crate::lint::emit_lint_base; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature}; use crate::middle::resolve_bound_vars; use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; -use crate::query::plumbing::QuerySystem; -use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt}; +use crate::query::{IntoQueryKey, LocalCrate, Providers, QuerySystem, TyCtxtAt}; use crate::thir::Thir; use crate::traits; use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData, PredefinedOpaques}; @@ -657,6 +657,11 @@ pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<'tcx, debug_assert_eq!(self.def_kind(key), DefKind::AnonConst); TyCtxtFeed { tcx: self, key }.type_of(value) } + + /// Feeds the HIR delayed owner during AST -> HIR delayed lowering. + pub fn feed_delayed_owner(self, key: LocalDefId, owner: MaybeOwner<'tcx>) { + TyCtxtFeed { tcx: self, key }.delayed_owner(owner); + } } impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> { @@ -894,12 +899,8 @@ impl<'tcx> TyCtxt<'tcx> { pub fn has_typeck_results(self, def_id: LocalDefId) -> bool { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". - let typeck_root_def_id = self.typeck_root_def_id(def_id.to_def_id()); - if typeck_root_def_id != def_id.to_def_id() { - return self.has_typeck_results(typeck_root_def_id.expect_local()); - } - - self.hir_node_by_def_id(def_id).body_id().is_some() + let root = self.typeck_root_def_id_local(def_id); + self.hir_node_by_def_id(root).body_id().is_some() } /// Expects a body and returns its codegen attributes. @@ -1111,10 +1112,9 @@ pub fn type_const_span(self, def_id: DefId) -> Option { } /// Check if the given `def_id` is a `type const` (mgca) - pub fn is_type_const>(self, def_id: I) -> bool { - // No need to call the query directly in this case always false. - let def_kind = self.def_kind(def_id.into_query_param()); - match def_kind { + pub fn is_type_const(self, def_id: impl IntoQueryKey) -> bool { + let def_id = def_id.into_query_key(); + match self.def_kind(def_id) { DefKind::Const { is_type_const } | DefKind::AssocConst { is_type_const } => { is_type_const } @@ -1168,8 +1168,8 @@ pub fn features(self) -> &'tcx rustc_feature::Features { self.features_query(()) } - pub fn def_key(self, id: impl IntoQueryParam) -> rustc_hir::definitions::DefKey { - let id = id.into_query_param(); + pub fn def_key(self, id: impl IntoQueryKey) -> rustc_hir::definitions::DefKey { + let id = id.into_query_key(); // Accessing the DefKey is ok, since it is part of DefPathHash. if let Some(id) = id.as_local() { self.definitions_untracked().def_key(id) @@ -1677,7 +1677,7 @@ pub fn finish(self) { self.alloc_self_profile_query_strings(); self.save_dep_graph(); - self.query_key_hash_verify_all(); + self.verify_query_key_hashes(); if let Err((path, error)) = self.dep_graph.finish_encoding() { self.sess.dcx().emit_fatal(crate::error::FailedWritingFile { path: &path, error }); @@ -1685,6 +1685,12 @@ pub fn finish(self) { } pub fn report_unused_features(self) { + #[derive(Diagnostic)] + #[diag("feature `{$feature}` is declared but not used")] + struct UnusedFeature { + feature: Symbol, + } + // Collect first to avoid holding the lock while linting. let used_features = self.sess.used_features.lock(); let unused_features = self @@ -1703,13 +1709,11 @@ pub fn report_unused_features(self) { .collect::>(); for (feature, span) in unused_features { - self.node_span_lint( + self.emit_node_span_lint( rustc_session::lint::builtin::UNUSED_FEATURES, CRATE_HIR_ID, span, - |lint| { - lint.primary_message(format!("feature `{}` is declared but not used", feature)); - }, + UnusedFeature { feature }, ); } } @@ -2534,22 +2538,7 @@ pub fn emit_node_span_lint( decorator: impl for<'a> Diagnostic<'a, ()>, ) { let level = self.lint_level_at_node(lint, hir_id); - diag_lint_level(self.sess, lint, level, Some(span.into()), decorator) - } - - /// Emit a lint at the appropriate level for a hir node, with an associated span. - /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature - #[track_caller] - pub fn node_span_lint( - self, - lint: &'static Lint, - hir_id: HirId, - span: impl Into, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - let level = self.lint_level_at_node(lint, hir_id); - lint_level(self.sess, lint, level, Some(span.into()), decorate); + emit_lint_base(self.sess, lint, level, Some(span.into()), decorator) } /// Find the appropriate span where `use` and outer attributes can be inserted at. @@ -2592,21 +2581,7 @@ pub fn emit_node_lint( decorator: impl for<'a> Diagnostic<'a, ()>, ) { let level = self.lint_level_at_node(lint, id); - diag_lint_level(self.sess, lint, level, None, decorator); - } - - /// Emit a lint at the appropriate level for a hir node. - /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature - #[track_caller] - pub fn node_lint( - self, - lint: &'static Lint, - id: HirId, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - let level = self.lint_level_at_node(lint, id); - lint_level(self.sess, lint, level, None, decorate); + emit_lint_base(self.sess, lint, level, None, decorator); } pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate<'tcx>]> { @@ -2730,7 +2705,8 @@ pub fn is_sdylib_interface_build(self) -> bool { self.sess.opts.unstable_opts.build_sdylib_interface } - pub fn intrinsic(self, def_id: impl IntoQueryParam + Copy) -> Option { + pub fn intrinsic(self, def_id: impl IntoQueryKey) -> Option { + let def_id = def_id.into_query_key(); match self.def_kind(def_id) { DefKind::Fn | DefKind::AssocFn => self.intrinsic_raw(def_id), _ => None, @@ -2799,10 +2775,8 @@ pub fn do_not_recommend_impl(self, def_id: DefId) -> bool { find_attr!(self, def_id, DoNotRecommend { .. }) } - pub fn is_trivial_const

(self, def_id: P) -> bool - where - P: IntoQueryParam, - { + pub fn is_trivial_const(self, def_id: impl IntoQueryKey) -> bool { + let def_id = def_id.into_query_key(); self.trivial_const(def_id).is_some() } diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index e59573976af5..7bbfb11698fe 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -14,7 +14,6 @@ use crate::dep_graph::{DepKind, DepNodeIndex}; use crate::infer::canonical::CanonicalVarKinds; -use crate::query::IntoQueryParam; use crate::traits::cache::WithDepNode; use crate::traits::solve::{ self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, QueryResult, inspect, @@ -402,6 +401,11 @@ fn fn_is_const(self, def_id: DefId) -> bool { self.is_conditionally_const(def_id) } + fn closure_is_const(self, def_id: DefId) -> bool { + debug_assert_matches!(self.def_kind(def_id), DefKind::Closure); + self.constness(def_id) == hir::Constness::Const + } + fn alias_has_const_conditions(self, def_id: DefId) -> bool { debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::OpaqueTy); self.is_conditionally_const(def_id) @@ -715,7 +719,6 @@ fn evaluate_root_goal_for_proof_tree_raw( } fn item_name(self, id: DefId) -> Symbol { - let id = id.into_query_param(); self.opt_item_name(id).unwrap_or_else(|| { bug!("item_name: no name for {:?}", self.def_path(id)); }) diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index b454689e243d..5bb11c917502 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -61,7 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) { /// requires calling [`InhabitedPredicate::instantiate`] fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { if let Some(def_id) = def_id.as_local() { - let _ = tcx.check_representability(def_id); + tcx.ensure_ok().check_representability(def_id); } let adt = tcx.adt_def(def_id); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4cea8b62f0b6..9759e376c058 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -6,8 +6,7 @@ use rustc_hir::def::{CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::FiniteBitSet; -use rustc_macros::{Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable}; +use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; @@ -941,50 +940,3 @@ fn needs_fn_once_adapter_shim( (ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce, _) => Err(()), } } - -// Set bits represent unused generic parameters. -// An empty set indicates that all parameters are used. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Decodable, Encodable, HashStable)] -pub struct UnusedGenericParams(FiniteBitSet); - -impl Default for UnusedGenericParams { - fn default() -> Self { - UnusedGenericParams::new_all_used() - } -} - -impl UnusedGenericParams { - pub fn new_all_unused(amount: u32) -> Self { - let mut bitset = FiniteBitSet::new_empty(); - bitset.set_range(0..amount); - Self(bitset) - } - - pub fn new_all_used() -> Self { - Self(FiniteBitSet::new_empty()) - } - - pub fn mark_used(&mut self, idx: u32) { - self.0.clear(idx); - } - - pub fn is_unused(&self, idx: u32) -> bool { - self.0.contains(idx).unwrap_or(false) - } - - pub fn is_used(&self, idx: u32) -> bool { - !self.is_unused(idx) - } - - pub fn all_used(&self) -> bool { - self.0.is_empty() - } - - pub fn bits(&self) -> u32 { - self.0.0 - } - - pub fn from_bits(bits: u32) -> UnusedGenericParams { - UnusedGenericParams(FiniteBitSet(bits)) - } -} diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index fe8f8abf7f57..4ca51c078bef 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -7,9 +7,8 @@ PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, TyAbiInterface, VariantIdx, Variants, }; -use rustc_error_messages::DiagMessage; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg, + Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; use rustc_hir as hir; use rustc_hir::LangItem; @@ -265,53 +264,6 @@ pub enum LayoutError<'tcx> { Cycle(ErrorGuaranteed), } -impl<'tcx> LayoutError<'tcx> { - pub fn diagnostic_message(&self) -> DiagMessage { - use LayoutError::*; - - match self { - Unknown(_) => msg!("the type `{$ty}` has an unknown layout"), - SizeOverflow(_) => { - msg!("values of the type `{$ty}` are too big for the target architecture") - } - InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => { - msg!("the SIMD type `{$ty}` has more elements than the limit {$max_lanes}") - } - InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => { - msg!("the SIMD type `{$ty}` has zero elements") - } - TooGeneric(_) => msg!("the type `{$ty}` does not have a fixed layout"), - NormalizationFailure(_, _) => msg!( - "unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized" - ), - Cycle(_) => msg!("a cycle occurred during layout computation"), - ReferencesError(_) => msg!("the type has an unknown layout"), - } - } - - pub fn into_diagnostic(self) -> crate::error::LayoutError<'tcx> { - use LayoutError::*; - - use crate::error::LayoutError as E; - match self { - Unknown(ty) => E::Unknown { ty }, - SizeOverflow(ty) => E::Overflow { ty }, - InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => { - E::SimdTooManyLanes { ty, max_lanes } - } - InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty }, - TooGeneric(ty) => E::TooGeneric { ty }, - NormalizationFailure(ty, e) => { - E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() } - } - Cycle(_) => E::Cycle, - ReferencesError(_) => E::ReferencesError, - } - } -} - -// FIXME: Once the other errors that embed this error have been converted to translatable -// diagnostics, this Display impl should be removed. impl<'tcx> fmt::Display for LayoutError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -1333,7 +1285,7 @@ pub enum FnAbiError<'tcx> { impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { match self { - Self::Layout(e) => e.into_diagnostic().into_diag(dcx, level), + Self::Layout(e) => Diag::new(dcx, level, e.to_string()), } } } diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 0cf5820959ee..82c23abefce4 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -264,7 +264,10 @@ unsafe impl DynSync for RawList {} // Layouts of `ListSkeleton` and `RawList` are the same, modulo opaque tail, // thus aligns of `ListSkeleton` and `RawList` must be the same. unsafe impl Aligned for RawList { + #[cfg(bootstrap)] const ALIGN: ptr::Alignment = align_of::>(); + #[cfg(not(bootstrap))] + const ALIGN: mem::Alignment = align_of::>(); } /// A [`List`] that additionally stores type information inline to speed up diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6abe7d146699..674799cb41ba 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,7 +27,6 @@ Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx, }; use rustc_ast as ast; -use rustc_ast::AttrVec; use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; @@ -85,7 +84,7 @@ CtxtInterners, CurrentGcx, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, tls, }; pub use self::fold::*; -pub use self::instance::{Instance, InstanceKind, ReifyReason, UnusedGenericParams}; +pub use self::instance::{Instance, InstanceKind, ReifyReason}; pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::opaque_types::OpaqueTypeKey; pub use self::pattern::{Pattern, PatternKind}; @@ -117,7 +116,7 @@ use crate::metadata::{AmbigModChild, ModChild}; use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, CoroutineLayout, CoroutineSavedLocal, SourceInfo}; -use crate::query::{IntoQueryParam, Providers}; +use crate::query::{IntoQueryKey, Providers}; use crate::ty; use crate::ty::codec::{TyDecoder, TyEncoder}; pub use crate::ty::diagnostics::*; @@ -221,43 +220,15 @@ pub struct ResolverAstLowering<'tcx> { /// Lints that were emitted by the resolver and early lints. pub lint_buffer: Steal, - /// Information about functions signatures for delegation items expansion - pub delegation_fn_sigs: LocalDefIdMap, // Information about delegations which is used when handling recursive delegations pub delegation_infos: LocalDefIdMap, } -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] - pub struct DelegationFnSigAttrs: u8 { - const TARGET_FEATURE = 1 << 0; - const MUST_USE = 1 << 1; - } -} - -pub const DELEGATION_INHERIT_ATTRS_START: DelegationFnSigAttrs = DelegationFnSigAttrs::MUST_USE; - #[derive(Debug)] pub struct DelegationInfo { // NodeId (either delegation.id or item_id in case of a trait impl) for signature resolution, // for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914 pub resolution_node: ast::NodeId, - pub attrs: DelegationAttrs, -} - -#[derive(Debug)] -pub struct DelegationAttrs { - pub flags: DelegationFnSigAttrs, - pub to_inherit: AttrVec, -} - -#[derive(Debug)] -pub struct DelegationFnSig { - pub header: ast::FnHeader, - pub param_count: usize, - pub has_self: bool, - pub c_variadic: bool, - pub attrs: DelegationAttrs, } #[derive(Clone, Copy, Debug, HashStable)] @@ -1031,12 +1002,14 @@ pub fn fully_monomorphized() -> TypingEnv<'tcx> { /// converted to use proper canonical inputs instead. pub fn non_body_analysis( tcx: TyCtxt<'tcx>, - def_id: impl IntoQueryParam, + def_id: impl IntoQueryKey, ) -> TypingEnv<'tcx> { + let def_id = def_id.into_query_key(); TypingEnv { typing_mode: TypingMode::non_body_analysis(), param_env: tcx.param_env(def_id) } } - pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam) -> TypingEnv<'tcx> { + pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey) -> TypingEnv<'tcx> { + let def_id = def_id.into_query_key(); tcx.typing_env_normalized_for_post_analysis(def_id) } @@ -1528,8 +1501,8 @@ pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions { } /// Look up the name of a definition across crates. This does not look at HIR. - pub fn opt_item_name(self, def_id: impl IntoQueryParam) -> Option { - let def_id = def_id.into_query_param(); + pub fn opt_item_name(self, def_id: impl IntoQueryKey) -> Option { + let def_id = def_id.into_query_key(); if let Some(cnum) = def_id.as_crate_root() { Some(self.crate_name(cnum)) } else { @@ -1549,8 +1522,8 @@ pub fn opt_item_name(self, def_id: impl IntoQueryParam) -> Option /// [`opt_item_name`] instead. /// /// [`opt_item_name`]: Self::opt_item_name - pub fn item_name(self, id: impl IntoQueryParam) -> Symbol { - let id = id.into_query_param(); + pub fn item_name(self, id: impl IntoQueryKey) -> Symbol { + let id = id.into_query_key(); self.opt_item_name(id).unwrap_or_else(|| { bug!("item_name: no name for {:?}", self.def_path(id)); }) @@ -1559,8 +1532,8 @@ pub fn item_name(self, id: impl IntoQueryParam) -> Symbol { /// Look up the name and span of a definition. /// /// See [`item_name`][Self::item_name] for more information. - pub fn opt_item_ident(self, def_id: impl IntoQueryParam) -> Option { - let def_id = def_id.into_query_param(); + pub fn opt_item_ident(self, def_id: impl IntoQueryKey) -> Option { + let def_id = def_id.into_query_key(); let def = self.opt_item_name(def_id)?; let span = self .def_ident_span(def_id) @@ -1571,8 +1544,8 @@ pub fn opt_item_ident(self, def_id: impl IntoQueryParam) -> Option /// Look up the name and span of a definition. /// /// See [`item_name`][Self::item_name] for more information. - pub fn item_ident(self, def_id: impl IntoQueryParam) -> Ident { - let def_id = def_id.into_query_param(); + pub fn item_ident(self, def_id: impl IntoQueryKey) -> Ident { + let def_id = def_id.into_query_key(); self.opt_item_ident(def_id).unwrap_or_else(|| { bug!("item_ident: no name for {:?}", self.def_path(def_id)); }) @@ -1902,8 +1875,9 @@ pub fn assoc_parent(self, def_id: DefId) -> Option<(DefId, DefKind)> { } /// Returns the trait item that is implemented by the given item `DefId`. - pub fn trait_item_of(self, def_id: impl IntoQueryParam) -> Option { - self.opt_associated_item(def_id.into_query_param())?.trait_item_def_id() + pub fn trait_item_of(self, def_id: impl IntoQueryKey) -> Option { + let def_id = def_id.into_query_key(); + self.opt_associated_item(def_id)?.trait_item_def_id() } /// If the given `DefId` is an associated item of a trait, @@ -1915,8 +1889,8 @@ pub fn trait_of_assoc(self, def_id: DefId) -> Option { } } - pub fn impl_is_of_trait(self, def_id: impl IntoQueryParam) -> bool { - let def_id = def_id.into_query_param(); + pub fn impl_is_of_trait(self, def_id: impl IntoQueryKey) -> bool { + let def_id = def_id.into_query_key(); let DefKind::Impl { of_trait } = self.def_kind(def_id) else { panic!("expected Impl for {def_id:?}"); }; @@ -1950,15 +1924,17 @@ pub fn trait_impl_of_assoc(self, def_id: DefId) -> Option { } } - pub fn impl_polarity(self, def_id: impl IntoQueryParam) -> ty::ImplPolarity { + pub fn impl_polarity(self, def_id: impl IntoQueryKey) -> ty::ImplPolarity { + let def_id = def_id.into_query_key(); self.impl_trait_header(def_id).polarity } /// Given an `impl_id`, return the trait it implements. pub fn impl_trait_ref( self, - def_id: impl IntoQueryParam, + def_id: impl IntoQueryKey, ) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> { + let def_id = def_id.into_query_key(); self.impl_trait_header(def_id).trait_ref } @@ -1966,21 +1942,22 @@ pub fn impl_trait_ref( /// Returns `None` if it is an inherent impl. pub fn impl_opt_trait_ref( self, - def_id: impl IntoQueryParam, + def_id: impl IntoQueryKey, ) -> Option>> { - let def_id = def_id.into_query_param(); + let def_id = def_id.into_query_key(); self.impl_is_of_trait(def_id).then(|| self.impl_trait_ref(def_id)) } /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements. - pub fn impl_trait_id(self, def_id: impl IntoQueryParam) -> DefId { + pub fn impl_trait_id(self, def_id: impl IntoQueryKey) -> DefId { + let def_id = def_id.into_query_key(); self.impl_trait_ref(def_id).skip_binder().def_id } /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements. /// Returns `None` if it is an inherent impl. - pub fn impl_opt_trait_id(self, def_id: impl IntoQueryParam) -> Option { - let def_id = def_id.into_query_param(); + pub fn impl_opt_trait_id(self, def_id: impl IntoQueryKey) -> Option { + let def_id = def_id.into_query_key(); self.impl_is_of_trait(def_id).then(|| self.impl_trait_id(def_id)) } @@ -2118,11 +2095,7 @@ pub fn is_conditionally_const(self, def_id: impl Into) -> bool { // FIXME(const_trait_impl): ATPITs could be conditionally const? hir::OpaqueTyOrigin::TyAlias { .. } => false, }, - DefKind::Closure => { - // Closures and RPITs will eventually have const conditions - // for `[const]` bounds. - false - } + DefKind::Closure => self.constness(def_id) == hir::Constness::Const, DefKind::Ctor(_, CtorKind::Const) | DefKind::Mod | DefKind::Struct @@ -2199,6 +2172,36 @@ pub fn fn_abi_of_instance( } } +// `HasAttrs` impls: allow `find_attr!(tcx, id, ...)` to work with both DefId-like types and HirId. + +impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for DefId { + fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [hir::Attribute] { + if let Some(did) = self.as_local() { + tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)) + } else { + tcx.attrs_for_def(self) + } + } +} + +impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for LocalDefId { + fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [hir::Attribute] { + tcx.hir_attrs(tcx.local_def_id_to_hir_id(self)) + } +} + +impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for hir::OwnerId { + fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [hir::Attribute] { + hir::attrs::HasAttrs::get_attrs(self.def_id, tcx) + } +} + +impl<'tcx> hir::attrs::HasAttrs<'tcx, TyCtxt<'tcx>> for hir::HirId { + fn get_attrs(self, tcx: &TyCtxt<'tcx>) -> &'tcx [hir::Attribute] { + tcx.hir_attrs(self) + } +} + pub fn provide(providers: &mut Providers) { closure::provide(providers); context::provide(providers); diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 0fd68e74e044..20e40dd6b2fe 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -133,8 +133,15 @@ fn print_coroutine_with_kind( self.print_path_with_generic_args(|p| p.print_def_path(def_id, parent_args), &[kind.into()]) } - // Defaults (should not be overridden): + fn reset_path(&mut self) -> Result<(), PrintError> { + Ok(()) + } + fn should_omit_parent_def_path(&self, _parent_def_id: DefId) -> bool { + false + } + + // Defaults (should not be overridden): #[instrument(skip(self), level = "debug")] fn default_print_def_path( &mut self, @@ -210,9 +217,15 @@ fn default_print_def_path( && self.tcx().generics_of(parent_def_id).parent_count == 0; } + let omit_parent = matches!(key.disambiguated_data.data, DefPathData::TypeNs(..)) + && self.should_omit_parent_def_path(parent_def_id); + self.print_path_with_simple( |p: &mut Self| { - if trait_qualify_parent { + if omit_parent { + p.reset_path()?; + Ok(()) + } else if trait_qualify_parent { let trait_ref = ty::TraitRef::new( p.tcx(), parent_def_id, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8b8fe522842a..b196327763f0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -23,7 +23,7 @@ // `pretty` is a separate module only for organization. use super::*; use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; -use crate::query::{IntoQueryParam, Providers}; +use crate::query::{IntoQueryKey, Providers}; use crate::ty::{ ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TraitPredicate, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -2180,17 +2180,18 @@ fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace { impl<'t> TyCtxt<'t> { /// Returns a string identifying this `DefId`. This string is /// suitable for user output. - pub fn def_path_str(self, def_id: impl IntoQueryParam) -> String { + pub fn def_path_str(self, def_id: impl IntoQueryKey) -> String { + let def_id = def_id.into_query_key(); self.def_path_str_with_args(def_id, &[]) } /// For this one we determine the appropriate namespace for the `def_id`. pub fn def_path_str_with_args( self, - def_id: impl IntoQueryParam, + def_id: impl IntoQueryKey, args: &'t [GenericArg<'t>], ) -> String { - let def_id = def_id.into_query_param(); + let def_id = def_id.into_query_key(); let ns = guess_def_namespace(self, def_id); debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns); @@ -2200,10 +2201,10 @@ pub fn def_path_str_with_args( /// For this one we always use value namespace. pub fn value_path_str_with_args( self, - def_id: impl IntoQueryParam, + def_id: impl IntoQueryKey, args: &'t [GenericArg<'t>], ) -> String { - let def_id = def_id.into_query_param(); + let def_id = def_id.into_query_key(); let ns = Namespace::ValueNS; debug!("value_path_str: def_id={:?}, ns={:?}", def_id, ns); @@ -2223,6 +2224,19 @@ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx } + fn reset_path(&mut self) -> Result<(), PrintError> { + self.empty_path = true; + Ok(()) + } + + fn should_omit_parent_def_path(&self, parent_def_id: DefId) -> bool { + RTN_MODE.with(|mode| mode.get()) == RtnMode::ForSuggestion + && matches!( + self.tcx().def_key(parent_def_id).disambiguated_data.data, + DefPathData::ValueNs(..) | DefPathData::Closure | DefPathData::AnonConst + ) + } + fn print_def_path( &mut self, def_id: DefId, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 04985dd3acde..68e43bbbea20 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -8,7 +8,7 @@ use rustc_abi::TyAndLayout; use rustc_hir::def::Namespace; use rustc_hir::def_id::LocalDefId; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit}; use super::{GenericArg, GenericArgKind, Pattern, Region}; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d0d8fad4b120..0d047b348d9e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -753,7 +753,7 @@ pub fn new_dynamic( .map(|principal| { tcx.associated_items(principal.def_id()) .in_definition_order() - .filter(|item| item.is_type() || item.is_const()) + .filter(|item| item.is_type() || item.is_type_const()) .filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .count() @@ -1365,6 +1365,14 @@ pub fn pinned_ty(self) -> Option> { } } + /// Returns the type, pinnedness, mutability, and the region of a reference (`&T` or `&mut T`) + /// or a pinned-reference type (`Pin<&T>` or `Pin<&mut T>`). + /// + /// Regarding the [`pin_ergonomics`] feature, one of the goals is to make pinned references + /// (`Pin<&T>` and `Pin<&mut T>`) behaves similar to normal references (`&T` and `&mut T`). + /// This function is useful when references and pinned references are processed similarly. + /// + /// [`pin_ergonomics`]: https://github.com/rust-lang/rust/issues/130494 pub fn maybe_pinned_ref( self, ) -> Option<(Ty<'tcx>, ty::Pinnedness, ty::Mutability, Region<'tcx>)> { @@ -1592,7 +1600,8 @@ pub fn ty_adt_def(self) -> Option> { } } - /// Iterates over tuple fields. + /// Returns a list of tuple type arguments. + /// /// Panics when called on anything but a tuple. #[inline] pub fn tuple_fields(self) -> &'tcx List> { @@ -1602,6 +1611,15 @@ pub fn tuple_fields(self) -> &'tcx List> { } } + /// Returns a list of tuple type arguments, or `None` if `self` isn't a tuple. + #[inline] + pub fn opt_tuple_fields(self) -> Option<&'tcx List>> { + match self.kind() { + Tuple(args) => Some(args), + _ => None, + } + } + /// If the type contains variants, returns the valid range of variant indices. // // FIXME: This requires the optimized MIR in the case of coroutines. diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 2c5e4957d0ae..b8399215cf81 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -716,7 +716,7 @@ pub fn remove(&mut self, id: hir::HirId) -> bool { } rustc_index::newtype_index! { - #[derive(HashStable)] + #[stable_hash] #[encodable] #[debug_format = "UserType({})"] pub struct UserTypeAnnotationIndex { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e7c7d5924870..d0cbdff366df 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -650,6 +650,20 @@ pub fn typeck_root_def_id(self, def_id: DefId) -> DefId { def_id } + /// Given the `LocalDefId`, returns the `LocalDefId` of the innermost item that + /// has its own type-checking context or "inference environment". + /// + /// For example, a closure has its own `LocalDefId`, but it is type-checked + /// with the containing item. Therefore, when we fetch the `typeck` of the closure, + /// for example, we really wind up fetching the `typeck` of the enclosing fn item. + pub fn typeck_root_def_id_local(self, def_id: LocalDefId) -> LocalDefId { + let mut def_id = def_id; + while self.is_typeck_child(def_id.to_def_id()) { + def_id = self.local_parent(def_id); + } + def_id + } + /// Given the `DefId` and args a closure, creates the type of /// `self` argument that the closure expects. For example, for a /// `Fn` closure, this would return a reference type `&T` where diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index edb1eaea3027..8a376e542945 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -101,7 +101,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let layout = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) { Ok(layout) => layout, - Err(e) => tcx.dcx().emit_fatal(e.into_diagnostic()), + Err(e) => tcx.dcx().fatal(e.to_string()), }; assert!(layout.is_sized(), "can't create a vtable for an unsized type"); let size = layout.size.bytes(); diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index f05183d7c068..fa22e07612cf 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -15,7 +15,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } -rustc_lint = { path = "../rustc_lint" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 13082d408ec0..a47a2e08c9f4 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -4,8 +4,7 @@ use rustc_middle::thir::*; use rustc_middle::ty; use rustc_middle::ty::cast::mir_cast_kind; -use rustc_span::Span; -use rustc_span::source_map::Spanned; +use rustc_span::{Span, Spanned}; use super::{PResult, ParseCtxt, parse_by_kind}; use crate::builder::custom::ParseError; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index ad6c1f7dce5b..c67d99a8eb7d 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -50,7 +50,8 @@ pub(crate) fn as_constant_inner<'tcx>( match *kind { ExprKind::Literal { lit, neg } => { - let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg }); + let const_ = + lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty: Some(ty), neg }); ConstOperand { span, user_ty: None, const_ } } @@ -109,6 +110,8 @@ pub(crate) fn as_constant_inner<'tcx>( fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> { let LitToConstInput { lit, ty, neg } = lit_input; + let ty = ty.expect("type of literal must be known at this point"); + if let Err(guar) = ty.error_reported() { return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)); } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 0f206c1f01ec..a1b41510f1e1 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -11,8 +11,7 @@ use rustc_middle::ty::cast::{CastTy, mir_cast_kind}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Ty, UpvarArgs}; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, Spanned}; use tracing::debug; use crate::builder::expr::as_place::PlaceBase; diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 24d184121ffd..446b2939e370 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -10,8 +10,7 @@ use rustc_middle::span_bug; use rustc_middle::thir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, sym}; +use rustc_span::{DUMMY_SP, Spanned, sym}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; diff --git a/compiler/rustc_mir_build/src/builder/expr/stmt.rs b/compiler/rustc_mir_build/src/builder/expr/stmt.rs index 3d603afbaa4a..99e16d182a97 100644 --- a/compiler/rustc_mir_build/src/builder/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/builder/expr/stmt.rs @@ -2,7 +2,7 @@ use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::thir::*; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use tracing::debug; use crate::builder::scope::{BreakableTarget, LintLevel}; diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 7698af4cd38b..cbe31fd7d132 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -360,6 +360,11 @@ pub(super) fn for_pattern( Some(TestableCase::Deref { temp, mutability }) } + PatKind::Guard { .. } => { + // FIXME(guard_patterns) + None + } + PatKind::Never => Some(TestableCase::Never), }; diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index d7edf82ae4af..d4f5fe84e0ff 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -944,6 +944,9 @@ fn visit_primary_bindings_special( visit_subpat(self, subpattern, user_tys, f); } } + PatKind::Guard { ref subpattern, .. } => { + visit_subpat(self, subpattern, user_tys, f); + } } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 5c3173a7b148..d8911870d3ad 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -14,8 +14,7 @@ use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt}; use rustc_span::def_id::DefId; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym}; use tracing::{debug, instrument}; use crate::builder::Builder; diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index bcac45199437..01c1e2e79b50 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -491,7 +491,7 @@ fn construct_fn<'tcx>( }; if let Some((dialect, phase)) = - find_attr!(tcx.hir_attrs(fn_id), CustomMir(dialect, phase, _) => (dialect, phase)) + find_attr!(tcx, fn_id, CustomMir(dialect, phase, _) => (dialect, phase)) { return custom::build_custom_mir( tcx, diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index b10df60e0f75..91610e768d01 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -94,8 +94,7 @@ use rustc_middle::{bug, span_bug}; use rustc_pattern_analysis::rustc::RustcPatCtxt; use rustc_session::lint::Level; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, Spanned}; use tracing::{debug, instrument}; use super::matches::BuiltMatchTree; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index f79adb2eb598..aed0c6e6085d 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -103,9 +103,7 @@ fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool let guarantee = format!("that {}", suggestion); let suggestion = sm .indentation_before(span) - .map(|indent| { - format!("{}// TODO: Audit that {}.\n", indent, suggestion) // ignore-tidy-todo - }) + .map(|indent| format!("{}// FIXME: Audit that {}.\n", indent, suggestion)) .unwrap_or_default(); self.tcx.emit_node_span_lint( @@ -317,6 +315,7 @@ fn visit_pat(&mut self, pat: &'a Pat<'tcx>) { | PatKind::Range { .. } | PatKind::Slice { .. } | PatKind::Array { .. } + | PatKind::Guard { .. } // Never constitutes a witness of uninhabitedness. | PatKind::Never => { self.requires_unsafe(pat.span, AccessToUnionField); diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index c362badd033c..793d9ef18eb6 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1053,17 +1053,115 @@ pub(crate) struct TypeNotStructural<'tcx> { #[primary_span] #[label("constant of non-structural type")] pub(crate) span: Span, - #[label("`{$ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns")] + #[label( + "{$is_local -> + *[true] `{$ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns + [false] `{$ty}` is not usable in patterns + }" + )] pub(crate) ty_def_span: Span, pub(crate) ty: Ty<'tcx>, #[note( - "the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details" + "the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see \ + https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details" )] pub(crate) manual_partialeq_impl_span: Option, #[note( "see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details" )] pub(crate) manual_partialeq_impl_note: bool, + #[subdiagnostic] + pub(crate) suggestion: Option>, + pub(crate) is_local: bool, +} + +#[derive(Subdiagnostic)] +pub(crate) enum SuggestEq<'tcx> { + #[multipart_suggestion( + "{$manual_partialeq_impl -> + [false] if `{$ty}` manually implemented `PartialEq`, you could add + *[true] add + } a condition to the match arm checking for equality", + applicability = "maybe-incorrect", + style = "verbose" + )] + AddIf { + #[suggestion_part(code = "binding")] + pat_span: Span, + #[suggestion_part(code = " if binding == {name}")] + if_span: Span, + name: String, + ty: Ty<'tcx>, + manual_partialeq_impl: bool, + }, + #[multipart_suggestion( + "{$manual_partialeq_impl -> + [false] if `{$ty}` manually implemented `PartialEq`, you could add + *[true] add + } a check for equality to the condition of the match arm", + applicability = "maybe-incorrect", + style = "verbose" + )] + AddToIf { + #[suggestion_part(code = "binding")] + pat_span: Span, + #[suggestion_part(code = " && binding == {name}")] + span: Span, + name: String, + ty: Ty<'tcx>, + manual_partialeq_impl: bool, + }, + #[multipart_suggestion( + "{$manual_partialeq_impl -> + [false] if `{$ty}` manually implemented `PartialEq`, you could check + *[true] check + } for equality instead of pattern matching", + applicability = "maybe-incorrect", + style = "verbose" + )] + AddToLetChain { + #[suggestion_part(code = "binding")] + pat_span: Span, + #[suggestion_part(code = " && binding == {name}")] + span: Span, + name: String, + ty: Ty<'tcx>, + manual_partialeq_impl: bool, + }, + #[multipart_suggestion( + "{$manual_partialeq_impl -> + [false] if `{$ty}` manually implemented `PartialEq`, you could check + *[true] check + } for equality instead of pattern matching", + applicability = "maybe-incorrect", + style = "verbose" + )] + ReplaceWithEq { + #[suggestion_part(code = "")] + removal: Span, + #[suggestion_part(code = " == ")] + eq: Span, + ty: Ty<'tcx>, + manual_partialeq_impl: bool, + }, + #[multipart_suggestion( + "{$manual_partialeq_impl -> + [false] if `{$ty}` manually implemented `PartialEq`, you could check + *[true] check + } for equality instead of pattern matching", + applicability = "maybe-incorrect", + style = "verbose" + )] + ReplaceLetElseWithIf { + #[suggestion_part(code = "if ")] + if_span: Span, + #[suggestion_part(code = " == ")] + eq: Span, + #[suggestion_part(code = " ")] + else_span: Span, + ty: Ty<'tcx>, + manual_partialeq_impl: bool, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b4eedb15033c..019af2461354 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -31,25 +31,27 @@ pub(crate) fn lit_to_const<'tcx>( .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)) }; - let (valtree, valtree_ty) = match (lit, expected_ty.kind()) { + let (valtree, valtree_ty) = match (lit, expected_ty.map(|ty| ty.kind())) { (ast::LitKind::Str(s, _), _) => { let str_bytes = s.as_str().as_bytes(); let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_); (ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty) } - (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) + (ast::LitKind::ByteStr(byte_sym, _), Some(ty::Ref(_, inner_ty, _))) if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() && let ty::Uint(UintTy::U8) = ty.kind() => { - (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty) + (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap()) } - (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) - if tcx.features().deref_patterns() - && let ty::Uint(UintTy::U8) = inner_ty.kind() => + ( + ast::LitKind::ByteStr(byte_sym, _), + Some(ty::Slice(inner_ty) | ty::Array(inner_ty, _)), + ) if tcx.features().deref_patterns() + && let ty::Uint(UintTy::U8) = inner_ty.kind() => { // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is // enabled, in order to allow, e.g., `deref!(b"..."): Vec`. - (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty) + (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap()) } (ast::LitKind::ByteStr(byte_sym, _), _) => { let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); @@ -79,11 +81,11 @@ pub(crate) fn lit_to_const<'tcx>( trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned()); (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i)) } - (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => { + (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Uint(ui))) if !neg => { let scalar_int = trunc(n.get(), *ui); (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui)) } - (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => { + (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Int(i))) => { // Unsigned "negation" has the same bitwise effect as signed negation, // which gets the result we want without additional casts. let scalar_int = @@ -101,7 +103,7 @@ pub(crate) fn lit_to_const<'tcx>( let bits = parse_float_into_scalar(n, fty, neg)?; (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty)) } - (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => { + (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), Some(ty::Float(fty))) => { let bits = parse_float_into_scalar(n, *fty, neg)?; (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty)) } diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index b108dff5555f..ea27252ad6ce 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -83,6 +83,7 @@ fn mirror_stmts( } Some(_) | None => local.span, }; + let initializer = local.init.map(|init| self.mirror_expr(init)); let stmt = Stmt { kind: StmtKind::Let { remainder_scope, @@ -91,7 +92,7 @@ fn mirror_stmts( data: region::ScopeData::Node, }, pattern, - initializer: local.init.map(|init| self.mirror_expr(init)), + initializer, else_block, hir_id: local.hir_id, span, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index c5eeb8b1aa85..7e6f30378a49 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -143,6 +143,19 @@ fn apply_adjustment( adjust_span(&mut expr); ExprKind::Deref { arg: self.thir.exprs.push(expr) } } + Adjust::Deref(DerefAdjustKind::Pin) => { + adjust_span(&mut expr); + // pointer = ($expr).pointer + let pin_ty = expr.ty.pinned_ty().expect("Deref(Pin) with non-Pin type"); + let pointer_target = ExprKind::Field { + lhs: self.thir.exprs.push(expr), + variant_index: FIRST_VARIANT, + name: FieldIdx::ZERO, + }; + let expr = Expr { temp_scope_id, ty: pin_ty, span, kind: pointer_target }; + // expr = *pointer + ExprKind::Deref { arg: self.thir.exprs.push(expr) } + } Adjust::Deref(DerefAdjustKind::Overloaded(deref)) => { // We don't need to do call adjust_span here since // deref coercions always start with a built-in deref. @@ -177,6 +190,37 @@ fn apply_adjustment( Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => { ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) } } + Adjust::Borrow(AutoBorrow::Pin(mutbl)) => { + // expr = &pin (mut|const|) arget + let borrow_kind = match mutbl { + hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, + hir::Mutability::Not => BorrowKind::Shared, + }; + let new_pin_target = + Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, expr.ty, mutbl); + let arg = self.thir.exprs.push(expr); + let expr = self.thir.exprs.push(Expr { + temp_scope_id, + ty: new_pin_target, + span, + kind: ExprKind::Borrow { borrow_kind, arg }, + }); + + // kind = Pin { pointer } + let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span); + let args = self.tcx.mk_args(&[new_pin_target.into()]); + let kind = ExprKind::Adt(Box::new(AdtExpr { + adt_def: self.tcx.adt_def(pin_did), + variant_index: FIRST_VARIANT, + args, + fields: Box::new([FieldExpr { name: FieldIdx::ZERO, expr }]), + user_ty: None, + base: AdtExprBase::None, + })); + + debug!(?kind); + kind + } Adjust::ReborrowPin(mutbl) => { debug!("apply ReborrowPin adjustment"); // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }` @@ -772,8 +816,8 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> } hir::InlineAsmOperand::Const { ref anon_const } => { let ty = self.typeck_results.node_type(anon_const.hir_id); - let did = anon_const.def_id.to_def_id(); - let typeck_root_def_id = tcx.typeck_root_def_id(did); + let did = anon_const.def_id; + let typeck_root_def_id = tcx.typeck_root_def_id_local(did); let parent_args = tcx.erase_and_anonymize_regions( GenericArgs::identity_for_item(tcx, typeck_root_def_id), ); @@ -781,7 +825,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }) .args; - let uneval = mir::UnevaluatedConst::new(did, args); + let uneval = mir::UnevaluatedConst::new(did.to_def_id(), args); let value = mir::Const::Unevaluated(uneval, ty); InlineAsmOperand::Const { value, span: tcx.def_span(did) } } @@ -832,7 +876,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> }; let indices = self.typeck_results.offset_of_data().get(expr.hir_id).unwrap(); - let mut expr = None::>; + let mut expr = None::>; for &(container, variant, field) in indices.iter() { let next = mk_call(&mut self.thir, container, variant, field); @@ -851,15 +895,15 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> hir::ExprKind::ConstBlock(ref anon_const) => { let ty = self.typeck_results.node_type(anon_const.hir_id); - let did = anon_const.def_id.to_def_id(); - let typeck_root_def_id = tcx.typeck_root_def_id(did); + let did = anon_const.def_id; + let typeck_root_def_id = tcx.typeck_root_def_id_local(did); let parent_args = tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item( tcx, typeck_root_def_id, )); let args = InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }).args; - ExprKind::ConstBlock { did, args } + ExprKind::ConstBlock { did: did.to_def_id(), args } } // Now comes the rote stuff: hir::ExprKind::Repeat(v, _) => { @@ -873,7 +917,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> hir::ExprKind::Ret(v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) }, hir::ExprKind::Become(call) => ExprKind::Become { value: self.mirror_expr(call) }, hir::ExprKind::Break(dest, ref value) => { - if find_attr!(self.tcx.hir_attrs(expr.hir_id), ConstContinue(_)) { + if find_attr!(self.tcx, expr.hir_id, ConstContinue(_)) { match dest.target_id { Ok(target_id) => { let (Some(value), Some(_)) = (value, dest.label) else { @@ -938,7 +982,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> match_source, }, hir::ExprKind::Loop(body, ..) => { - if find_attr!(self.tcx.hir_attrs(expr.hir_id), LoopMatch(_)) { + if find_attr!(self.tcx, expr.hir_id, LoopMatch(_)) { let dcx = self.tcx.dcx(); // Accept either `state = expr` or `state = expr;`. diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 60cb509ee9dd..f22ff92c0178 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -13,14 +13,14 @@ use rustc_middle::ty::{self, TyCtxt}; /// Query implementation for [`TyCtxt::thir_body`]. -pub(crate) fn thir_body( - tcx: TyCtxt<'_>, +pub(crate) fn thir_body<'tcx>( + tcx: TyCtxt<'tcx>, owner_def: LocalDefId, -) -> Result<(&Steal>, ExprId), ErrorGuaranteed> { +) -> Result<(&'tcx Steal>, ExprId), ErrorGuaranteed> { debug_assert!(!tcx.is_type_const(owner_def.to_def_id()), "thir_body queried for type_const"); let body = tcx.hir_body_owned_by(owner_def); - let mut cx = ThirBuildCx::new(tcx, owner_def); + let mut cx: ThirBuildCx<'tcx> = ThirBuildCx::new(tcx, owner_def); if let Some(reported) = cx.typeck_results.tainted_by_errors { return Err(reported); } @@ -50,7 +50,7 @@ pub(crate) fn thir_body( } /// Context for lowering HIR to THIR for a single function body (or other kind of body). -struct ThirBuildCx<'tcx> { +pub(crate) struct ThirBuildCx<'tcx> { tcx: TyCtxt<'tcx>, /// The THIR data that this context is building. thir: Thir<'tcx>, @@ -104,7 +104,7 @@ fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self { typing_env: ty::TypingEnv::non_body_analysis(tcx, def), typeck_results, body_owner: def.to_def_id(), - apply_adjustments: !find_attr!(tcx.hir_attrs(hir_id), CustomMir(..) => ()).is_some(), + apply_adjustments: !find_attr!(tcx, hir_id, CustomMir(..)), } } @@ -118,6 +118,7 @@ fn pattern_from_hir_with_annotation( let_stmt_type: Option<&hir::Ty<'tcx>>, ) -> Box> { crate::thir::pattern::pat_from_hir( + self, self.tcx, self.typing_env, self.typeck_results, @@ -201,7 +202,7 @@ fn explicit_params( fn_sig.inputs()[index] }; - let pat = self.pattern_from_hir(param.pat); + let pat: Box> = self.pattern_from_hir(param.pat); Param { pat: Some(pat), ty, ty_span, self_kind, hir_id: Some(param.hir_id) } }) } 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 e844f1114d61..baabc1afe3fa 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_lint::Level; +use rustc_lint_defs::Level; use rustc_middle::bug; use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; @@ -101,8 +101,7 @@ struct MatchVisitor<'p, 'tcx> { error: Result<(), ErrorGuaranteed>, } -// Visitor for a thir body. This calls `check_match`, `check_let` and `check_let_chain` as -// appropriate. +// Visitor for a thir body. This calls `check_match` and `check_let` as appropriate. impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { fn thir(&self) -> &'p Thir<'tcx> { self.thir diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ff9d456f7e70..630770115a35 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -22,10 +22,10 @@ use super::PatCtxt; use crate::errors::{ ConstPatternDependsOnGenericParameter, CouldNotEvalConstPattern, InvalidPattern, NaNPattern, - PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern, + PointerPattern, SuggestEq, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern, }; -impl<'tcx> PatCtxt<'tcx> { +impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { /// Converts a constant to a pattern (if possible). /// This means aggregate values (like structs and enums) are converted /// to a pattern that matches the value (as if you'd compared via structural equality). @@ -61,7 +61,7 @@ struct ConstToPat<'tcx> { } impl<'tcx> ConstToPat<'tcx> { - fn new(pat_ctxt: &PatCtxt<'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self { + fn new(pat_ctxt: &PatCtxt<'tcx, '_>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self { trace!(?pat_ctxt.typeck_results.hir_owner); ConstToPat { tcx: pat_ctxt.tcx, typing_env: pat_ctxt.typing_env, span, id, c } } @@ -224,13 +224,93 @@ fn valtree_to_pat(&self, value: ty::Value<'tcx>) -> Box> { } _ => (None, true), }; + let manual_partialeq_impl = + manual_partialeq_impl_note || manual_partialeq_impl_span.is_some(); + let is_local = adt_def.did().is_local(); let ty_def_span = tcx.def_span(adt_def.did()); + let suggestion = if let Ok(name) = tcx.sess.source_map().span_to_snippet(self.span) + && (is_local || manual_partialeq_impl) + { + let mut hir_id = self.id; + while let hir::Node::Pat(pat) = tcx.parent_hir_node(hir_id) { + hir_id = pat.hir_id; + } + match tcx.parent_hir_node(hir_id) { + hir::Node::Arm(hir::Arm { pat, guard: None, .. }) => { + // Add an if condition to the match arm. + Some(SuggestEq::AddIf { + if_span: pat.span.shrink_to_hi(), + pat_span: self.span, + name, + ty, + manual_partialeq_impl, + }) + } + hir::Node::Arm(hir::Arm { guard: Some(guard), .. }) => { + // Modify the the match arm if condition and add a check for equality. + Some(SuggestEq::AddToIf { + span: guard.span.shrink_to_hi(), + pat_span: self.span, + name, + ty, + manual_partialeq_impl, + }) + } + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Let(let_expr), + span, + .. + }) => { + if let_expr.pat.span == self.span { + // `if let CONST = expr` -> `if CONST == expr`. + Some(SuggestEq::ReplaceWithEq { + removal: span.until(self.span), + eq: self.span.between(let_expr.init.span), + ty, + manual_partialeq_impl, + }) + } else if tcx.sess.edition().at_least_rust_2024() { + // `if let Some(CONST) = expr` -> + // `if let Some(binding) = expr && binding == CONST`. + Some(SuggestEq::AddToLetChain { + span: span.shrink_to_hi(), + pat_span: self.span, + name, + ty, + manual_partialeq_impl, + }) + } else { + None + } + } + hir::Node::LetStmt(let_stmt) + if let Some(init) = let_stmt.init + && let Some(els) = let_stmt.els + && init.span.ctxt().is_root() + && els.span.ctxt().is_root() => + { + // `let PAT = expr else {` -> `if PAT == expr {`. + Some(SuggestEq::ReplaceLetElseWithIf { + if_span: let_stmt.span.until(let_stmt.pat.span), + eq: let_stmt.pat.span.between(init.span), + else_span: init.span.between(els.span), + ty, + manual_partialeq_impl, + }) + } + _ => None, + } + } else { + None + }; let err = TypeNotStructural { span, ty, ty_def_span, manual_partialeq_impl_span, manual_partialeq_impl_note, + is_local, + suggestion, }; return self.mk_err(tcx.dcx().create_err(err), ty); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index 9a5cc08e6c4c..75e23c3a2ff1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, pluralize}; use rustc_hir::{BindingMode, ByRef, HirId, Mutability}; -use rustc_lint as lint; +use rustc_lint_defs::builtin::RUST_2024_INCOMPATIBLE_PAT; use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt}; use rustc_span::{Ident, Span}; @@ -55,10 +55,15 @@ pub(super) fn emit<'tcx>(self, tcx: TyCtxt<'tcx>, pat_id: HirId) { self.format_subdiagnostics(&mut err); err.emit(); } else { - tcx.node_span_lint(lint::builtin::RUST_2024_INCOMPATIBLE_PAT, pat_id, spans, |diag| { - diag.primary_message(primary_message); - self.format_subdiagnostics(diag); - }); + tcx.emit_node_span_lint( + RUST_2024_INCOMPATIBLE_PAT, + pat_id, + spans, + rustc_errors::DiagDecorator(|diag| { + diag.primary_message(primary_message); + self.format_subdiagnostics(diag); + }), + ); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 67cde0e2c886..7d4e25cd814b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -30,9 +30,11 @@ pub(crate) use self::check_match::check_match; use self::migration::PatMigration; use crate::errors::*; +use crate::thir::cx::ThirBuildCx; /// Context for lowering HIR patterns to THIR patterns. -struct PatCtxt<'tcx> { +struct PatCtxt<'tcx, 'ptcx> { + upper: &'ptcx mut ThirBuildCx<'tcx>, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, @@ -41,8 +43,9 @@ struct PatCtxt<'tcx> { rust_2024_migration: Option>, } -#[instrument(level = "debug", skip(tcx, typing_env, typeck_results), ret)] -pub(super) fn pat_from_hir<'tcx>( +#[instrument(level = "debug", skip(upper, tcx, typing_env, typeck_results), ret)] +pub(super) fn pat_from_hir<'tcx, 'ptcx>( + upper: &'ptcx mut ThirBuildCx<'tcx>, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, @@ -51,6 +54,7 @@ pub(super) fn pat_from_hir<'tcx>( let_stmt_type: Option<&hir::Ty<'tcx>>, ) -> Box> { let mut pcx = PatCtxt { + upper, tcx, typing_env, typeck_results, @@ -87,7 +91,7 @@ pub(super) fn pat_from_hir<'tcx>( thir_pat } -impl<'tcx> PatCtxt<'tcx> { +impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { let adjustments: &[PatAdjustment<'tcx>] = self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v); @@ -443,8 +447,10 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box PatKind::Or { pats: self.lower_patterns(pats) }, - // FIXME(guard_patterns): implement guard pattern lowering - hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind, + hir::PatKind::Guard(pat, condition) => PatKind::Guard { + subpattern: self.lower_pattern(pat), + condition: self.upper.mirror_expr(condition), + }, hir::PatKind::Err(guar) => PatKind::Error(guar), }; @@ -696,7 +702,7 @@ fn lower_pat_expr( // patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`. let pat_ty = self.typeck_results.node_type(pat.hir_id); - let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; + let lit_input = LitToConstInput { lit: lit.node, ty: Some(pat_ty), neg: *negated }; let constant = const_lit_matches_ty(self.tcx, &lit.node, pat_ty, *negated) .then(|| self.tcx.at(expr.span).lit_to_const(lit_input)) .flatten() diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 27dec99696f5..ea34e5f4d97d 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -844,6 +844,14 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) { print_indented!(self, "]", depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } + PatKind::Guard { subpattern, condition } => { + print_indented!(self, "Guard pattern: {", depth_lvl + 1); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, "guard: ", depth_lvl + 2); + self.print_expr(*condition, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } PatKind::Error(_) => { print_indented!(self, "Error", depth_lvl + 1); } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index dee08d34427f..a59798dafbda 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -109,21 +109,21 @@ fn new( /// ```rust /// struct S; /// #[rustfmt::skip] -/// fn foo(pred: bool) { // maybe-init: -/// // {} -/// let a = S; let mut b = S; let c; let d; // {a, b} +/// fn foo(p: bool) { // maybe-init: +/// // {p} +/// let a = S; let mut b = S; let c; let d; // {p, a, b} /// -/// if pred { -/// drop(a); // { b} -/// b = S; // { b} +/// if p { +/// drop(a); // {p, b} +/// b = S; // {p, b} /// /// } else { -/// drop(b); // {a} -/// d = S; // {a, d} +/// drop(b); // {p, a} +/// d = S; // {p, a, d} /// -/// } // {a, b, d} +/// } // {p, a, b, d} /// -/// c = S; // {a, b, c, d} +/// c = S; // {p, a, b, c, d} /// } /// ``` /// @@ -199,11 +199,11 @@ fn move_data(&self) -> &MoveData<'tcx> { /// ```rust /// struct S; /// #[rustfmt::skip] -/// fn foo(pred: bool) { // maybe-uninit: +/// fn foo(p: bool) { // maybe-uninit: /// // {a, b, c, d} /// let a = S; let mut b = S; let c; let d; // { c, d} /// -/// if pred { +/// if p { /// drop(a); // {a, c, d} /// b = S; // {a, c, d} /// @@ -279,34 +279,36 @@ fn move_data(&self) -> &MoveData<'tcx> { } } -/// `EverInitializedPlaces` tracks all places that might have ever been -/// initialized upon reaching a particular point in the control flow -/// for a function, without an intervening `StorageDead`. +/// `EverInitializedPlaces` tracks all initializations that may have occurred +/// upon reaching a particular point in the control flow for a function, +/// without an intervening `StorageDead`. /// /// This dataflow is used to determine if an immutable local variable may /// be assigned to. /// /// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. +/// dataflow information shown in the right-hand comments. Underscored indices +/// are used to distinguish between multiple initializations of the same local +/// variable, e.g. `b_0` and `b_1`. /// /// ```rust /// struct S; /// #[rustfmt::skip] -/// fn foo(pred: bool) { // ever-init: -/// // { } -/// let a = S; let mut b = S; let c; let d; // {a, b } +/// fn foo(p: bool) { // ever-init: +/// // {p, } +/// let a = S; let mut b = S; let c; let d; // {p, a, b_0, } /// -/// if pred { -/// drop(a); // {a, b, } -/// b = S; // {a, b, } +/// if p { +/// drop(a); // {p, a, b_0, } +/// b = S; // {p, a, b_0, b_1, } /// /// } else { -/// drop(b); // {a, b, } -/// d = S; // {a, b, d } +/// drop(b); // {p, a, b_0, b_1, } +/// d = S; // {p, a, b_0, b_1, d} /// -/// } // {a, b, d } +/// } // {p, a, b_0, b_1, d} /// -/// c = S; // {a, b, c, d } +/// c = S; // {p, a, b_0, b_1, c, d} /// } /// ``` pub struct EverInitializedPlaces<'a, 'tcx> { diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 89ee96317ac9..e04cb26e8990 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -58,7 +58,8 @@ fn is_required(&self) -> bool { } } -/// Utility to help performing substitution of `*pattern` by `target`. +/// Utility to help performing substitution: for all key-value pairs in `copy_classes`, +/// all occurrences of the key get replaced by the value. struct Replacer<'a, 'tcx> { tcx: TyCtxt<'tcx>, unified: DenseBitSet, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index c83b10a5e583..332196e3afee 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -83,8 +83,7 @@ Analysis, Results, ResultsCursor, ResultsVisitor, visit_reachable_results, }; use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_span::source_map::dummy_spanned; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, dummy_spanned}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt as _; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 19ffffdd1eca..53aa5f450dbb 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -35,11 +35,6 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return true; } - // FIXME(autodiff): replace this as per discussion in https://github.com/rust-lang/rust/pull/149033#discussion_r2535465880 - if find_attr!(tcx, def_id, RustcAutodiff(..)) { - return true; - } - if find_attr!(tcx, def_id, RustcIntrinsic) { // Intrinsic fallback bodies are always cross-crate inlineable. // To ensure that the MIR inliner doesn't cluelessly try to inline fallback diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index e17629215b79..1fe745a5d519 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -9,8 +9,7 @@ use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt}; use rustc_middle::{bug, span_bug, traits}; -use rustc_span::DUMMY_SP; -use rustc_span::source_map::{Spanned, dummy_spanned}; +use rustc_span::{DUMMY_SP, Spanned, dummy_spanned}; use tracing::{debug, instrument}; use crate::patch::MirPatch; diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 6f0f9cc23a55..daee8de96513 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -19,11 +19,11 @@ pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( caller_def_id: DefId, callee_only: &[&'a str], ) { - tcx.node_span_lint( + tcx.emit_node_span_lint( lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()), call_span, - |lint| { + rustc_errors::DiagDecorator(|lint| { let callee = tcx.def_path_str(callee_def_id); let caller = tcx.def_path_str(caller_def_id); @@ -46,7 +46,7 @@ pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( format!("#[target_feature(enable = \"{feats}\")]\n"), lint::Applicability::MaybeIncorrect, ); - }, + }), ); } @@ -145,11 +145,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { } }, ); - let label = self.assert_kind.diagnostic_message(); - self.assert_kind.add_args(&mut |name, value| { - diag.arg(name, value); - }); - diag.span_label(self.span, label); + diag.span_label(self.span, self.assert_kind.to_string()); diag } } diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 2ae8f43cf6c8..0216e0d4cfbc 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -5,8 +5,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt}; use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Spanned, sym}; use crate::errors; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 517bc61e5eb0..e9a20aa01655 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -48,8 +48,15 @@ //! # Handling of references //! //! We handle references by assigning a different "provenance" index to each Ref/RawPtr rvalue. -//! This ensure that we do not spuriously merge borrows that should not be merged. Meanwhile, we -//! consider all the derefs of an immutable reference to a freeze type to give the same value: +//! This ensure that we do not spuriously merge borrows that should not be merged. For instance: +//! ```ignore (MIR) +//! _x = &_a; +//! _a = 0; +//! _y = &_a; // cannot be turned into `_y = _x`! +//! ``` +//! +//! On top of that, we consider all the derefs of an immutable reference to a freeze type to give +//! the same value: //! ```ignore (MIR) //! _a = *_b // _b is &Freeze //! _c = *_b // replaced by _c = _a @@ -1699,7 +1706,7 @@ fn transmute_may_have_niche_of_interest_to_backend( !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx) } BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } + | BackendRepr::SimdScalableVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 9069f279e981..afcea3236dbd 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -15,7 +15,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; use rustc_session::config::{DebugInfo, OptLevel}; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use tracing::{debug, instrument, trace, trace_span}; use crate::cost_checker::{CostChecker, is_call_like}; diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 9e8de4926c6e..a1e5d810afc0 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -161,7 +161,7 @@ struct TOFinder<'a, 'tcx> { } rustc_index::newtype_index! { - #[derive(Ord, PartialOrd)] + #[orderable] #[debug_format = "_c{}"] struct ConditionIndex {} } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index c4994417ed7e..8d0922db8f40 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -241,7 +241,7 @@ fn use_ecx(&mut self, f: F) -> Option assert!( !err.kind().formatted_string(), "known panics lint encountered formatting error: {}", - format_interp_error(self.ecx.tcx.dcx(), err), + format_interp_error(err), ); err }) diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 89bd91e7013d..2f812358fcfe 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -1,4 +1,5 @@ use rustc_abi::{HasDataLayout, Size, TagEncoding, Variants}; +use rustc_const_eval::interpret::{Scalar, alloc_range}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::*; @@ -23,7 +24,8 @@ /// /// In summary, what this does is at runtime determine which enum variant is active, /// and instead of copying all the bytes of the largest possible variant, -/// copy only the bytes for the currently active variant. +/// copy only the bytes for the currently active variant. The number of bytes to copy is determined +/// by a lookup table: a discriminant-indexed array indicating the size of each variant. pub(super) struct EnumSizeOpt { pub(crate) discrepancy: u64, } @@ -32,8 +34,8 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { fn is_enabled(&self, sess: &Session) -> bool { // There are some differences in behavior on wasm and ARM that are not properly // understood, so we conservatively treat this optimization as unsound: - // https://github.com/rust-lang/rust/pull/85158#issuecomment-1101836457 - sess.opts.unstable_opts.unsound_mir_opts || sess.mir_opt_level() >= 3 + // https://github.com/rust-lang/rust/issues/154413 + sess.opts.unstable_opts.unsound_mir_opts && sess.mir_opt_level() >= 3 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -202,45 +204,23 @@ fn candidate<'tcx>( return Some((*adt_def, num_discrs, *alloc_id)); } + // Construct an in-memory array mapping discriminant idx to variant size. let data_layout = tcx.data_layout(); - let ptr_sized_int = data_layout.ptr_sized_integer(); - let target_bytes = ptr_sized_int.size().bytes() as usize; - let mut data = vec![0; target_bytes * num_discrs]; - - // We use a macro because `$bytes` can be u32 or u64. - macro_rules! encode_store { - ($curr_idx: expr, $endian: expr, $bytes: expr) => { - let bytes = match $endian { - rustc_abi::Endian::Little => $bytes.to_le_bytes(), - rustc_abi::Endian::Big => $bytes.to_be_bytes(), - }; - for (i, b) in bytes.into_iter().enumerate() { - data[$curr_idx + i] = b; - } - }; - } - - for (var_idx, layout) in variants.iter_enumerated() { - let curr_idx = - target_bytes * adt_def.discriminant_for_variant(tcx, var_idx).val as usize; - let sz = layout.size; - match ptr_sized_int { - rustc_abi::Integer::I32 => { - encode_store!(curr_idx, data_layout.endian, sz.bytes() as u32); - } - rustc_abi::Integer::I64 => { - encode_store!(curr_idx, data_layout.endian, sz.bytes()); - } - _ => unreachable!(), - }; - } - let alloc = interpret::Allocation::from_bytes( - data, + let ptr_size = data_layout.pointer_size(); + let mut alloc = interpret::Allocation::from_bytes( + vec![0; ptr_size.bytes_usize() * num_discrs], tcx.data_layout.ptr_sized_integer().align(&tcx.data_layout).abi, - Mutability::Not, + Mutability::Mut, (), ); + for (var_idx, layout) in variants.iter_enumerated() { + let curr_idx = ptr_size * adt_def.discriminant_for_variant(tcx, var_idx).val as u64; + let val = Scalar::from_target_usize(layout.size.bytes(), &tcx); + alloc.write_scalar(&tcx, alloc_range(curr_idx, val.size()), val).unwrap(); + } + alloc.mutability = Mutability::Not; let alloc = tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc)); + Some((*adt_def, num_discrs, *alloc_cache.entry(ty).or_insert(alloc))) } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 6bf4221d9ab7..9273c2103d44 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -27,8 +27,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::util::Providers; use rustc_middle::{bug, query, span_bug}; -use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, sym}; +use rustc_span::{DUMMY_SP, Spanned, sym}; use tracing::debug; #[macro_use] @@ -527,7 +526,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & // We only need to borrowck non-synthetic MIR. let tainted_by_errors = if !tcx.is_synthetic_mir(def) { - tcx.mir_borrowck(tcx.typeck_root_def_id(def.to_def_id()).expect_local()).err() + tcx.mir_borrowck(tcx.typeck_root_def_id_local(def)).err() } else { None }; @@ -555,14 +554,14 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & // // We do this check here and not during `mir_promoted` because that may result // in borrowck cycles if WF requires looking into an opaque hidden type. - let root = tcx.typeck_root_def_id(def.to_def_id()); + let root = tcx.typeck_root_def_id_local(def); match tcx.def_kind(root) { DefKind::Fn | DefKind::AssocFn | DefKind::Static { .. } | DefKind::Const { .. } | DefKind::AssocConst { .. } => { - if let Err(guar) = tcx.ensure_result().check_well_formed(root.expect_local()) { + if let Err(guar) = tcx.ensure_result().check_well_formed(root) { body.tainted_by_errors = Some(guar); } } @@ -841,7 +840,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Den } // Don't run unused pass for #[derive] - let parent = tcx.parent(tcx.typeck_root_def_id(def_id.to_def_id())); + let parent = tcx.local_parent(tcx.typeck_root_def_id_local(def_id)); if let DefKind::Impl { of_trait: true } = tcx.def_kind(parent) && find_attr!(tcx, parent, AutomaticallyDerived(..)) { diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index a9f2c32171c3..c98ca2f4da52 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::Session; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; pub(super) struct MentionedItems; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 3f5a630a2174..a47b3ce64ed2 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -23,8 +23,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, GenericArgs, List, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, mir, span_bug}; -use rustc_span::Span; -use rustc_span::source_map::Spanned; +use rustc_span::{Span, Spanned}; use tracing::{debug, instrument}; /// A `MirPass` for promotion. diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 1abbfed1a822..4fd0629befec 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -12,8 +12,7 @@ self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt, }; use rustc_middle::{bug, span_bug}; -use rustc_span::source_map::{Spanned, dummy_spanned}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, Spanned, dummy_spanned}; use tracing::{debug, instrument}; use crate::deref_separator::deref_finder; diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs index 6d33736d64ec..91e040d5cbc8 100644 --- a/compiler/rustc_mir_transform/src/single_use_consts.rs +++ b/compiler/rustc_mir_transform/src/single_use_consts.rs @@ -5,6 +5,8 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use crate::strip_debuginfo::drop_invalid_debuginfos; + /// Various parts of MIR building introduce temporaries that are commonly not needed. /// /// Notably, `if CONST` and `match CONST` end up being used-once temporaries, which @@ -82,6 +84,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { ); } } + + drop_invalid_debuginfos(body); } fn is_required(&self) -> bool { diff --git a/compiler/rustc_mir_transform/src/strip_debuginfo.rs b/compiler/rustc_mir_transform/src/strip_debuginfo.rs index 7fec25ccb521..5931a4666024 100644 --- a/compiler/rustc_mir_transform/src/strip_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/strip_debuginfo.rs @@ -32,24 +32,21 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { ) }); - let debuginfo_locals = debuginfo_locals(body); - for data in body.basic_blocks.as_mut_preserves_cfg() { - for stmt in data.statements.iter_mut() { - stmt.debuginfos.retain(|debuginfo| match debuginfo { - StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => { - debuginfo_locals.contains(*local) - } - }); - } - data.after_last_stmt_debuginfos.retain(|debuginfo| match debuginfo { - StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => { - debuginfo_locals.contains(*local) - } - }); - } + drop_invalid_debuginfos(body); } fn is_required(&self) -> bool { true } } + +// Drop invalid debuginfos when strip locals in `var_debug_info`. +pub(super) fn drop_invalid_debuginfos(body: &mut Body<'_>) { + let debuginfo_locals = debuginfo_locals(body); + for data in body.basic_blocks.as_mut_preserves_cfg() { + for stmt in data.statements.iter_mut() { + stmt.debuginfos.retain_locals(&debuginfo_locals); + } + data.after_last_stmt_debuginfos.retain_locals(&debuginfo_locals); + } +} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 3aa55cc8eb9f..4698e054daf6 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,13 +205,11 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. -mod autodiff; - use std::cell::OnceCell; use std::ops::ControlFlow; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::sync::{MTLock, par_for_each_in}; +use rustc_data_structures::sync::{Lock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::attrs::InlineAttr; @@ -236,11 +234,9 @@ use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; use rustc_session::config::{DebugInfo, EntryFnType}; -use rustc_span::source_map::{Spanned, dummy_spanned, respan}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, Spanned, dummy_spanned, respan}; use tracing::{debug, instrument, trace}; -use crate::collector::autodiff::collect_autodiff_fn; use crate::errors::{ self, EncounteredErrorWhileInstantiating, EncounteredErrorWhileInstantiatingGlobalAsm, NoOptimizedMir, RecursionLimit, @@ -255,12 +251,12 @@ pub(crate) enum MonoItemCollectionStrategy { /// The state that is shared across the concurrent threads that are doing collection. struct SharedState<'tcx> { /// Items that have been or are currently being recursively collected. - visited: MTLock>>, + visited: Lock>>, /// Items that have been or are currently being recursively treated as "mentioned", i.e., their /// consts are evaluated but nothing is added to the collection. - mentioned: MTLock>>, + mentioned: Lock>>, /// Which items are being used where, for better errors. - usage_map: MTLock>, + usage_map: Lock>, } pub(crate) struct UsageMap<'tcx> { @@ -363,7 +359,7 @@ fn collect_items_root<'tcx>( state: &SharedState<'tcx>, recursion_limit: Limit, ) { - if !state.visited.lock_mut().insert(starting_item.node) { + if !state.visited.lock().insert(starting_item.node) { // We've been here already, no need to search again. return; } @@ -572,7 +568,7 @@ fn collect_items_rec<'tcx>( // This is part of the output of collection and hence only relevant for "used" items. // ("Mentioned" items are only considered internally during collection.) if mode == CollectionMode::UsedItems { - state.usage_map.lock_mut().record_used(starting_item.node, &used_items); + state.usage_map.lock().record_used(starting_item.node, &used_items); } { @@ -580,13 +576,13 @@ fn collect_items_rec<'tcx>( if mode == CollectionMode::UsedItems { used_items .items - .retain(|k, _| visited.get_mut_or_init(|| state.visited.lock_mut()).insert(*k)); + .retain(|k, _| visited.get_mut_or_init(|| state.visited.lock()).insert(*k)); } let mut mentioned = OnceCell::default(); mentioned_items.items.retain(|k, _| { !visited.get_or_init(|| state.visited.lock()).contains(k) - && mentioned.get_mut_or_init(|| state.mentioned.lock_mut()).insert(*k) + && mentioned.get_mut_or_init(|| state.mentioned.lock()).insert(*k) }); } if mode == CollectionMode::MentionedItems { @@ -990,8 +986,6 @@ fn visit_instance_use<'tcx>( return; } if let Some(intrinsic) = tcx.intrinsic(instance.def_id()) { - collect_autodiff_fn(tcx, instance, intrinsic, output); - if let Some(_requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { // The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any @@ -1621,7 +1615,7 @@ fn process_nested_body(&mut self, def_id: LocalDefId) { if (self.strategy == MonoItemCollectionStrategy::Eager || is_pub_fn_coroutine) && !self .tcx - .generics_of(self.tcx.typeck_root_def_id(def_id.to_def_id())) + .generics_of(self.tcx.typeck_root_def_id_local(def_id)) .requires_monomorphization(self.tcx) { let instance = match *self.tcx.type_of(def_id).instantiate_identity().kind() { @@ -1816,9 +1810,9 @@ pub(crate) fn collect_crate_mono_items<'tcx>( debug!("building mono item graph, beginning at roots"); let state = SharedState { - visited: MTLock::new(UnordSet::default()), - mentioned: MTLock::new(UnordSet::default()), - usage_map: MTLock::new(UsageMap::new()), + visited: Lock::new(UnordSet::default()), + mentioned: Lock::new(UnordSet::default()), + usage_map: Lock::new(UsageMap::new()), }; let recursion_limit = tcx.recursion_limit(); diff --git a/compiler/rustc_monomorphize/src/collector/autodiff.rs b/compiler/rustc_monomorphize/src/collector/autodiff.rs deleted file mode 100644 index 67d4b8c8afff..000000000000 --- a/compiler/rustc_monomorphize/src/collector/autodiff.rs +++ /dev/null @@ -1,50 +0,0 @@ -use rustc_middle::bug; -use rustc_middle::ty::{self, GenericArg, IntrinsicDef, TyCtxt}; - -use crate::collector::{MonoItems, create_fn_mono_item}; - -// Here, we force both primal and diff function to be collected in -// mono so this does not interfere in `autodiff` intrinsics -// codegen process. If they are unused, LLVM will remove them when -// compiling with O3. -// FIXME(autodiff): Remove this whole file, as per discussion in -// https://github.com/rust-lang/rust/pull/149033#discussion_r2535465880 -pub(crate) fn collect_autodiff_fn<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::Instance<'tcx>, - intrinsic: IntrinsicDef, - output: &mut MonoItems<'tcx>, -) { - if intrinsic.name != rustc_span::sym::autodiff { - return; - }; - - collect_autodiff_fn_from_arg(instance.args[0], tcx, output); -} - -fn collect_autodiff_fn_from_arg<'tcx>( - arg: GenericArg<'tcx>, - tcx: TyCtxt<'tcx>, - output: &mut MonoItems<'tcx>, -) { - let (instance, span) = match arg.kind() { - ty::GenericArgKind::Type(ty) => match *ty.kind() { - ty::FnDef(def_id, substs) => { - let span = tcx.def_span(def_id); - let instance = ty::Instance::expect_resolve( - tcx, - ty::TypingEnv::non_body_analysis(tcx, def_id), - def_id, - substs, - span, - ); - - (instance, span) - } - _ => bug!("expected autodiff function"), - }, - _ => bug!("expected type when matching autodiff arg"), - }; - - output.push(create_fn_mono_item(tcx, instance, span)); -} diff --git a/compiler/rustc_monomorphize/src/graph_checks/statics.rs b/compiler/rustc_monomorphize/src/graph_checks/statics.rs index a764d307b3d4..90993e55906f 100644 --- a/compiler/rustc_monomorphize/src/graph_checks/statics.rs +++ b/compiler/rustc_monomorphize/src/graph_checks/statics.rs @@ -30,7 +30,7 @@ fn from(value: usize) -> Self { } newtype_index! { - #[derive(Ord, PartialOrd)] + #[orderable] struct StaticSccIdx {} } diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index a5f2ba2f1ced..0921e57844b0 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -36,7 +36,7 @@ fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorReg UsesVectorRegisters::FixedVector } PassMode::Direct(..) | PassMode::Pair(..) - if matches!(repr, BackendRepr::ScalableVector { .. }) => + if matches!(repr, BackendRepr::SimdScalableVector { .. }) => { UsesVectorRegisters::ScalableVector } diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs index a8f3104c0d98..a24b0443d39c 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs @@ -6,8 +6,7 @@ use rustc_middle::mir::{self, Location, traversal}; use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; -use rustc_span::source_map::Spanned; -use rustc_span::{Ident, Span, sym}; +use rustc_span::{Ident, Span, Spanned, sym}; use tracing::{debug, trace}; use crate::errors::LargeAssignmentsLint; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 038168ca638b..32b1e93bf98b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -9,6 +9,7 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::SolverTraitLangItem; use rustc_type_ir::search_graph::CandidateHeadUsages; +use rustc_type_ir::solve::Certainty::Maybe; use rustc_type_ir::solve::{AliasBoundKind, SizedTraitKind}; use rustc_type_ir::{ self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, @@ -138,8 +139,10 @@ fn probe_and_consider_param_env_candidate( .enter_single_candidate(|ecx| { Self::match_assumption(ecx, goal, assumption, |ecx| { ecx.try_evaluate_added_goals()?; - source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + let (src, certainty) = + ecx.characterize_param_env_assumption(goal.param_env, assumption)?; + source.set(src); + ecx.evaluate_added_goals_and_make_canonical_response(certainty) }) }); @@ -1228,21 +1231,26 @@ fn characterize_param_env_assumption( &mut self, param_env: I::ParamEnv, assumption: I::Clause, - ) -> Result, NoSolution> { + ) -> Result<(CandidateSource, Certainty), NoSolution> { // FIXME: This should be fixed, but it also requires changing the behavior // in the old solver which is currently relied on. if assumption.has_bound_vars() { - return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)); + return Ok((CandidateSource::ParamEnv(ParamEnvSource::NonGlobal), Certainty::Yes)); } match assumption.visit_with(&mut FindParamInClause { ecx: self, param_env, universes: vec![], + recursion_depth: 0, }) { ControlFlow::Break(Err(NoSolution)) => Err(NoSolution), - ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)), - ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)), + ControlFlow::Break(Ok(certainty)) => { + Ok((CandidateSource::ParamEnv(ParamEnvSource::NonGlobal), certainty)) + } + ControlFlow::Continue(()) => { + Ok((CandidateSource::ParamEnv(ParamEnvSource::Global), Certainty::Yes)) + } } } } @@ -1251,6 +1259,7 @@ struct FindParamInClause<'a, 'b, D: SolverDelegate, I: Interner> { ecx: &'a mut EvalCtxt<'b, D>, param_env: I::ParamEnv, universes: Vec>, + recursion_depth: usize, } impl TypeVisitor for FindParamInClause<'_, '_, D, I> @@ -1258,7 +1267,11 @@ impl TypeVisitor for FindParamInClause<'_, '_, D, I> D: SolverDelegate, I: Interner, { - type Result = ControlFlow>; + // - `Continue(())`: no generic parameter was found, the type is global + // - `Break(Ok(Certainty::Yes))`: a generic parameter was found, the type is non-global + // - `Break(Ok(Certainty::Maybe(_)))`: the recursion limit reached, assume that the type is non-global + // - `Break(Err(NoSolution))`: normalization failed + type Result = ControlFlow>; fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { self.universes.push(None); @@ -1275,12 +1288,24 @@ fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { if let ty::Placeholder(p) = ty.kind() { if p.universe() == ty::UniverseIndex::ROOT { - ControlFlow::Break(Ok(())) + ControlFlow::Break(Ok(Certainty::Yes)) } else { ControlFlow::Continue(()) } } else if ty.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) { - ty.super_visit_with(self) + self.recursion_depth += 1; + if self.recursion_depth > self.ecx.cx().recursion_limit() { + return ControlFlow::Break(Ok(Maybe { + cause: MaybeCause::Overflow { + suggest_increasing_limit: true, + keep_constraints: false, + }, + opaque_types_jank: OpaqueTypesJank::AllGood, + })); + } + let result = ty.super_visit_with(self); + self.recursion_depth -= 1; + result } else { ControlFlow::Continue(()) } @@ -1294,7 +1319,7 @@ fn visit_const(&mut self, ct: I::Const) -> Self::Result { if let ty::ConstKind::Placeholder(p) = ct.kind() { if p.universe() == ty::UniverseIndex::ROOT { - ControlFlow::Break(Ok(())) + ControlFlow::Break(Ok(Certainty::Yes)) } else { ControlFlow::Continue(()) } @@ -1310,12 +1335,12 @@ fn visit_region(&mut self, r: I::Region) -> Self::Result { ty::ReStatic | ty::ReError(_) | ty::ReBound(..) => ControlFlow::Continue(()), ty::RePlaceholder(p) => { if p.universe() == ty::UniverseIndex::ROOT { - ControlFlow::Break(Ok(())) + ControlFlow::Break(Ok(Certainty::Yes)) } else { ControlFlow::Continue(()) } } - ty::ReVar(_) => ControlFlow::Break(Ok(())), + ty::ReVar(_) => ControlFlow::Break(Ok(Certainty::Yes)), ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) => { unreachable!("unexpected region in param-env clause") } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 05ea217c1de0..433cad188bb6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -661,10 +661,11 @@ fn coroutine_closure_to_ambiguous_coroutine( /// /// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable` /// would be wasteful. +#[instrument(level = "trace", skip(cx), ret)] pub(in crate::solve) fn extract_fn_def_from_const_callable( cx: I, self_ty: I::Ty, -) -> Result<(ty::Binder, I::FunctionId, I::GenericArgs), NoSolution> { +) -> Result<(ty::Binder, I::DefId, I::GenericArgs), NoSolution> { match self_ty.kind() { ty::FnDef(def_id, args) => { let sig = cx.fn_sig(def_id); @@ -675,7 +676,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( Ok(( sig.instantiate(cx, args) .map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())), - def_id, + def_id.into(), args, )) } else { @@ -686,9 +687,19 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( ty::FnPtr(..) => { return Err(NoSolution); } - // `Closure`s are not const for now. - ty::Closure(..) => { - return Err(NoSolution); + ty::Closure(def, args) => { + if cx.closure_is_const(def) { + let closure_args = args.as_closure(); + Ok(( + closure_args + .sig() + .map_bound(|sig| (sig.inputs().get(0).unwrap(), sig.output())), + def.into(), + args, + )) + } else { + return Err(NoSolution); + } } // `CoroutineClosure`s are not const for now. ty::CoroutineClosure(..) => { @@ -786,12 +797,16 @@ pub(in crate::solve) fn const_conditions_for_destruct( | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) | ty::Error(_) => Ok(vec![]), - // Coroutines and closures could implement `[const] Drop`, + // Closures are [const] Destruct when all of their upvars (captures) are [const] Destruct. + ty::Closure(_, args) => { + let closure_args = args.as_closure(); + Ok(vec![ty::TraitRef::new(cx, destruct_def_id, [closure_args.tupled_upvars_ty()])]) + } + // Coroutines could implement `[const] Drop`, // but they don't really need to right now. - ty::Closure(_, _) - | ty::CoroutineClosure(_, _) - | ty::Coroutine(_, _) - | ty::CoroutineWitness(_, _) => Err(NoSolution), + ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(_, _) => { + Err(NoSolution) + } // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop` // if their inner type implements it. diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 4da76b88b5de..4b1e4b2de571 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -272,6 +272,7 @@ fn consider_builtin_fn_ptr_trait_candidate( todo!("Fn* are not yet const") } + #[instrument(level = "trace", skip_all, ret)] fn consider_builtin_fn_trait_candidates( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -289,7 +290,7 @@ fn consider_builtin_fn_trait_candidates( let output_is_sized_pred = ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]); let requirements = cx - .const_conditions(def_id.into()) + .const_conditions(def_id) .iter_instantiated(cx, args) .map(|trait_ref| { ( diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index f4f718292205..6faaafcc0100 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -4344,7 +4344,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { pub(crate) enum HiddenUnicodeCodepointsDiagSub { Escape { spans: Vec<(char, Span)> }, - NoEscape { spans: Vec<(char, Span)> }, + NoEscape { spans: Vec<(char, Span)>, is_doc_comment: bool }, } // Used because of multiple multipart_suggestion and note @@ -4370,7 +4370,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { Applicability::MachineApplicable, ); } - HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => { + HiddenUnicodeCodepointsDiagSub::NoEscape { spans, is_doc_comment } => { // FIXME: in other suggestions we've reversed the inner spans of doc comments. We // should do the same here to provide the same good suggestions as we do for // literals above. @@ -4383,7 +4383,11 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { .join(", "), ); diag.note(msg!("if their presence wasn't intentional, you can remove them")); - diag.note(msg!("if you want to keep them but make them visible in your source code, you can escape them: {$escaped}")); + if is_doc_comment { + diag.note(msg!(r#"if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as {$escaped}"#)); + } else { + diag.note(msg!("if you want to keep them but make them visible in your source code, you can escape them: {$escaped}")); + } } } } @@ -4499,3 +4503,111 @@ pub(super) fn from_token(token: &Token) -> Option { } } } + +#[derive(Diagnostic)] +#[diag( + "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression" +)] +pub(crate) struct BreakWithLabelAndLoop { + #[subdiagnostic] + pub sub: BreakWithLabelAndLoopSub, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("wrap this expression in parentheses", applicability = "machine-applicable")] +pub(crate) struct BreakWithLabelAndLoopSub { + #[suggestion_part(code = "(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} + +#[derive(Diagnostic)] +#[diag("prefix `'r` is reserved")] +pub(crate) struct RawPrefix { + #[label("reserved prefix")] + pub label: Span, + #[suggestion( + "insert whitespace here to avoid this being parsed as a prefix in Rust 2021", + code = " ", + applicability = "machine-applicable" + )] + pub suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("unicode codepoint changing visible direction of text present in comment")] +#[note( + "these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen" +)] +pub(crate) struct UnicodeTextFlow { + #[label( + "{$num_codepoints -> + [1] this comment contains an invisible unicode text flow control codepoint + *[other] this comment contains invisible unicode text flow control codepoints + }" + )] + pub comment_span: Span, + #[subdiagnostic] + pub characters: Vec, + #[subdiagnostic] + pub suggestions: Option, + + pub num_codepoints: usize, +} + +#[derive(Subdiagnostic)] +#[label("{$c_debug}")] +pub(crate) struct UnicodeCharNoteSub { + #[primary_span] + pub span: Span, + pub c_debug: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + "if their presence wasn't intentional, you can remove them", + applicability = "machine-applicable", + style = "hidden" +)] +pub(crate) struct UnicodeTextFlowSuggestion { + #[suggestion_part(code = "")] + pub spans: Vec, +} + +#[derive(Diagnostic)] +#[diag("prefix `{$prefix}` is unknown")] +pub(crate) struct ReservedPrefix { + #[label("unknown prefix")] + pub label: Span, + #[suggestion( + "insert whitespace here to avoid this being parsed as a prefix in Rust 2021", + code = " ", + applicability = "machine-applicable" + )] + pub suggestion: Span, + + pub prefix: String, +} + +#[derive(Diagnostic)] +#[diag("will be parsed as a guarded string in Rust 2024")] +pub(crate) struct ReservedStringLint { + #[suggestion( + "insert whitespace here to avoid this being parsed as a guarded string in Rust 2024", + code = " ", + applicability = "machine-applicable" + )] + pub suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("reserved token in Rust 2024")] +pub(crate) struct ReservedMultihashLint { + #[suggestion( + "insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024", + code = " ", + applicability = "machine-applicable" + )] + pub suggestion: Span, +} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index cd90655125b2..5766d25bc86c 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -4,12 +4,11 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::{TEXT_FLOW_CONTROL_CHARS, contains_text_flow_control_chars}; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, StashKey}; use rustc_lexer::{ Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_horizontal_whitespace, }; use rustc_literal_escaper::{EscapeError, Mode, check_for_errors}; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TEXT_DIRECTION_CODEPOINT_IN_LITERAL, @@ -388,7 +387,10 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) { RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, prefix_span, ast::CRATE_NODE_ID, - BuiltinLintDiag::RawPrefix(prefix_span), + errors::RawPrefix { + label: prefix_span, + suggestion: prefix_span.shrink_to_hi() + }, ); // Reset the state so we just lex the `'r`. @@ -498,11 +500,41 @@ fn lint_unicode_text_flow(&self, start: BytePos) { let content = self.str_from(content_start); if contains_text_flow_control_chars(content) { let span = self.mk_sp(start, self.pos); - self.psess.buffer_lint( + let content = content.to_string(); + self.psess.dyn_buffer_lint( TEXT_DIRECTION_CODEPOINT_IN_COMMENT, span, ast::CRATE_NODE_ID, - BuiltinLintDiag::UnicodeTextFlow(span, content.to_string()), + move |dcx, level| { + let spans: Vec<_> = content + .char_indices() + .filter_map(|(i, c)| { + TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { + let lo = span.lo() + BytePos(2 + i as u32); + (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) + }) + }) + .collect(); + let characters = spans + .iter() + .map(|&(c, span)| errors::UnicodeCharNoteSub { + span, + c_debug: format!("{c:?}"), + }) + .collect(); + let suggestions = + (!spans.is_empty()).then_some(errors::UnicodeTextFlowSuggestion { + spans: spans.iter().map(|(_c, span)| *span).collect(), + }); + + errors::UnicodeTextFlow { + comment_span: span, + characters, + suggestions, + num_codepoints: spans.len(), + } + .into_diag(dcx, level) + }, ); } } @@ -514,6 +546,7 @@ fn lint_doc_comment_unicode_text_flow(&mut self, start: BytePos, content: &str) self.mk_sp(start, self.pos), 0, false, + true, "doc comment", ); } @@ -548,6 +581,7 @@ fn lint_literal_unicode_text_flow( span, padding, point_at_inner_spans, + false, label, ); } @@ -558,6 +592,7 @@ fn report_text_direction_codepoint( span: Span, padding: u32, point_at_inner_spans: bool, + is_doc_comment: bool, label: &str, ) { // Obtain the `Span`s for each of the forbidden chars. @@ -578,7 +613,7 @@ fn report_text_direction_codepoint( let sub = if point_at_inner_spans && !spans.is_empty() { errors::HiddenUnicodeCodepointsDiagSub::Escape { spans } } else { - errors::HiddenUnicodeCodepointsDiagSub::NoEscape { spans } + errors::HiddenUnicodeCodepointsDiagSub::NoEscape { spans, is_doc_comment } }; self.psess.buffer_lint( @@ -1038,7 +1073,11 @@ fn report_unknown_prefix(&self, start: BytePos) { RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, prefix_span, ast::CRATE_NODE_ID, - BuiltinLintDiag::ReservedPrefix(prefix_span, prefix.to_string()), + errors::ReservedPrefix { + label: prefix_span, + suggestion: prefix_span.shrink_to_hi(), + prefix: prefix.to_string(), + }, ); } } @@ -1112,11 +1151,18 @@ fn maybe_report_guarded_str(&mut self, start: BytePos, str_before: &'src str) -> }) } else { // Before Rust 2024, only emit a lint for migration. - self.psess.buffer_lint( + self.psess.dyn_buffer_lint( RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, span, ast::CRATE_NODE_ID, - BuiltinLintDiag::ReservedString { is_string, suggestion: space_span }, + move |dcx, level| { + if is_string { + errors::ReservedStringLint { suggestion: space_span }.into_diag(dcx, level) + } else { + errors::ReservedMultihashLint { suggestion: space_span } + .into_diag(dcx, level) + } + }, ); // For backwards compatibility, roll back to after just the first `#` diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 284e651d94ad..47ac91feefd4 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -16,9 +16,8 @@ pluralize, }; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::source_map::Spanned; use rustc_span::symbol::used_keywords; -use rustc_span::{BytePos, DUMMY_SP, Ident, Span, SpanSnippetError, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, SpanSnippetError, Spanned, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, trace}; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4297086983b4..c18e8c631fec 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,18 +15,16 @@ use rustc_ast::{ self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, - FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits, - StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, + FnRetTy, Guard, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, + RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; use rustc_literal_escaper::unescape_char; use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error}; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_span::edition::Edition; -use rustc_span::source_map::{self, Spanned}; -use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Spanned, Symbol, kw, respan, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::instrument; @@ -296,12 +294,12 @@ pub(super) fn parse_expr_assoc_rest_with( let span = self.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span); lhs = match op { AssocOp::Binary(ast_op) => { - let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); + let binary = self.mk_binary(respan(cur_op_span, ast_op), lhs, rhs); self.mk_expr(span, binary) } AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)), AssocOp::AssignOp(aop) => { - let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs); + let aopexpr = self.mk_assign_op(respan(cur_op_span, aop), lhs, rhs); self.mk_expr(span, aopexpr) } AssocOp::Cast | AssocOp::Range(_) => { @@ -409,7 +407,7 @@ pub(super) fn check_assoc_op(&self) -> Option> { } _ => return None, }; - Some(source_map::respan(span, op)) + Some(respan(span, op)) } /// Checks if this expression is a successfully parsed statement. @@ -1922,11 +1920,17 @@ fn parse_expr_break(&mut self) -> PResult<'a, Box> { _ => false, } { + let span = expr.span; self.psess.buffer_lint( BREAK_WITH_LABEL_AND_LOOP, lo.to(expr.span), ast::CRATE_NODE_ID, - BuiltinLintDiag::BreakWithLabelAndLoop(expr.span), + errors::BreakWithLabelAndLoop { + sub: errors::BreakWithLabelAndLoopSub { + left: span.shrink_to_lo(), + right: span.shrink_to_hi(), + }, + }, ); } @@ -2763,7 +2767,7 @@ pub fn parse_expr_cond( /// Parses a `let $pat = $expr` pseudo-expression. fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box> { - let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) { + let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) { let err = errors::ExpectedExpressionFoundLet { span: self.token.span, reason: errors::ForbiddenLetReason::OtherForbidden, @@ -3459,20 +3463,54 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { }) } - fn parse_match_arm_guard(&mut self) -> PResult<'a, Option>> { + pub(crate) fn eat_metavar_guard(&mut self) -> Option> { + self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Guard), + |this| this.parse_match_arm_guard(), + ) + .flatten() + } + + fn parse_match_arm_guard(&mut self) -> PResult<'a, Option>> { + if let Some(guard) = self.eat_metavar_guard() { + return Ok(Some(guard)); + } + if !self.eat_keyword(exp!(If)) { // No match arm guard present. return Ok(None); } + self.expect_match_arm_guard_cond(ForceCollect::No).map(Some) + } - let mut cond = self.parse_match_guard_condition()?; + pub(crate) fn expect_match_arm_guard( + &mut self, + force_collect: ForceCollect, + ) -> PResult<'a, Box> { + if let Some(guard) = self.eat_metavar_guard() { + return Ok(guard); + } + + self.expect_keyword(exp!(If))?; + self.expect_match_arm_guard_cond(force_collect) + } + + fn expect_match_arm_guard_cond( + &mut self, + force_collect: ForceCollect, + ) -> PResult<'a, Box> { + let leading_if_span = self.prev_token.span; + + let mut cond = self.parse_match_guard_condition(force_collect)?; + let cond_span = cond.span; CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond); - Ok(Some(cond)) + let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) }; + Ok(Box::new(guard)) } - fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option>)> { + fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option>)> { if self.token == token::OpenParen { let left = self.token.span; let pat = self.parse_pat_no_top_guard( @@ -3488,10 +3526,10 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option PResult<'a, (Pat, Option PResult<'a, (Pat, Option PResult<'a, Box> { + fn parse_match_guard_condition( + &mut self, + force_collect: ForceCollect, + ) -> PResult<'a, Box> { let attrs = self.parse_outer_attributes()?; - match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) { - Ok((expr, _)) => Ok(expr), - Err(mut err) => { - if self.prev_token == token::OpenBrace { - let sugg_sp = self.prev_token.span.shrink_to_lo(); - // Consume everything within the braces, let's avoid further parse - // errors. - self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); - let msg = "you might have meant to start a match arm after the match guard"; - if self.eat(exp!(CloseBrace)) { - let applicability = if self.token != token::FatArrow { - // We have high confidence that we indeed didn't have a struct - // literal in the match guard, but rather we had some operation - // that ended in a path, immediately followed by a block that was - // meant to be the match arm. - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability); + let expr = self.collect_tokens( + None, + AttrWrapper::empty(), + force_collect, + |this, _empty_attrs| { + match this + .parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) + { + Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)), + Err(mut err) => { + if this.prev_token == token::OpenBrace { + let sugg_sp = this.prev_token.span.shrink_to_lo(); + // Consume everything within the braces, let's avoid further parse + // errors. + this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); + let msg = + "you might have meant to start a match arm after the match guard"; + if this.eat(exp!(CloseBrace)) { + let applicability = if this.token != token::FatArrow { + // We have high confidence that we indeed didn't have a struct + // literal in the match guard, but rather we had some operation + // that ended in a path, immediately followed by a block that was + // meant to be the match arm. + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability); + } + } + Err(err) } } - Err(err) - } - } + }, + )?; + Ok(expr) } pub(crate) fn is_builtin(&self) -> bool { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index db5be5feaeb6..0f4927432f6f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -13,7 +13,7 @@ use rustc_session::lint::builtin::VARARGS_WITHOUT_PATTERN; use rustc_span::edit_distance::edit_distance; use rustc_span::edition::Edition; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, source_map, sym}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, respan, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::debug; @@ -3557,7 +3557,7 @@ fn parse_self_param(&mut self) -> PResult<'a, Option> { _ => return Ok(None), }; - let eself = source_map::respan(eself_lo.to(eself_hi), eself); + let eself = respan(eself_lo.to(eself_hi), eself); Ok(Some(Param::from_self(AttrVec::default(), eself, eself_ident))) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 36ca8a7d6133..8c1c3c7025f5 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1788,4 +1788,5 @@ pub enum ParseNtResult { Meta(Box), Path(Box), Vis(Box), + Guard(Box), } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 706b454835fa..ddf1b10e5235 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -31,7 +31,8 @@ fn may_be_ident(kind: MetaVarKind) -> bool { MetaVarKind::Item | MetaVarKind::Block - | MetaVarKind::Vis => false, + | MetaVarKind::Vis + | MetaVarKind::Guard => false, MetaVarKind::Ident | MetaVarKind::Lifetime @@ -86,7 +87,8 @@ fn may_be_ident(kind: MetaVarKind) -> bool { | MetaVarKind::Ty { .. } | MetaVarKind::Meta { .. } | MetaVarKind::Path - | MetaVarKind::Vis => false, + | MetaVarKind::Vis + | MetaVarKind::Guard => false, MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => { unreachable!() } @@ -103,6 +105,7 @@ fn may_be_ident(kind: MetaVarKind) -> bool { token::Lifetime(..) | token::NtLifetime(..) => true, _ => false, }, + NonterminalKind::Guard => token.is_keyword(kw::If), NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => { token.kind.close_delim().is_none() } @@ -196,6 +199,9 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN })) } } + NonterminalKind::Guard => { + Ok(ParseNtResult::Guard(self.expect_match_arm_guard(ForceCollect::Yes)?)) + } } } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 528b69abbf1a..bdcbb1eb42a8 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -6,14 +6,14 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ - self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability, - Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind, + self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, Guard, LocalKind, MacCall, + Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, + StmtKind, }; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey}; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{BytePos, ErrorGuaranteed, Ident, Span, kw, sym}; +use rustc_span::{BytePos, ErrorGuaranteed, Ident, Span, Spanned, kw, respan, sym}; use thin_vec::{ThinVec, thin_vec}; use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, UsePreAttrPos}; @@ -111,11 +111,19 @@ pub fn parse_pat_allow_top_guard( let pat = self.parse_pat_no_top_guard(expected, rc, ra, rt)?; if self.eat_keyword(exp!(If)) { - let cond = self.parse_expr()?; + let guard = if let Some(guard) = self.eat_metavar_guard() { + guard + } else { + let leading_if_span = self.prev_token.span; + let cond = self.parse_expr()?; + let cond_span = cond.span; + Box::new(Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) }) + }; + // Feature-gate guard patterns - self.psess.gated_spans.gate(sym::guard_patterns, cond.span); - let span = pat.span.to(cond.span); - Ok(self.mk_pat(span, PatKind::Guard(Box::new(pat), cond))) + self.psess.gated_spans.gate(sym::guard_patterns, guard.span()); + let span = pat.span.to(guard.span()); + Ok(self.mk_pat(span, PatKind::Guard(Box::new(pat), guard))) } else { Ok(pat) } @@ -602,17 +610,18 @@ fn maybe_add_suggestions_then_emit( } Some(guard) => { // Are parentheses required around the old guard? - let wrap_guard = guard.precedence() <= ExprPrecedence::LAnd; + let wrap_guard = + guard.cond.precedence() <= ExprPrecedence::LAnd; err.subdiagnostic( UnexpectedExpressionInPatternSugg::UpdateGuard { ident_span, guard_lo: if wrap_guard { - Some(guard.span.shrink_to_lo()) + Some(guard.span().shrink_to_lo()) } else { None }, - guard_hi: guard.span.shrink_to_hi(), + guard_hi: guard.span().shrink_to_hi(), guard_hi_paren: if wrap_guard { ")" } else { "" }, ident, expr, @@ -1740,6 +1749,9 @@ fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> } else { // Parsing a pattern of the form `(box) (ref) (mut) fieldname`. let is_box = self.eat_keyword(exp!(Box)); + if is_box { + self.psess.gated_spans.gate(sym::box_patterns, self.prev_token.span); + } let boxed_span = self.token.span; let mutability = self.parse_mutability(); let by_ref = self.parse_byref(); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 3b2102484bdf..5bd2ca313922 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -362,7 +362,7 @@ fn parse_local(&mut self, super_: Option, attrs: AttrVec) -> PResult<'a, B // init parsed, ty error // Could parse the type as if it were the initializer, it is likely there was a // typo in the code: `:` instead of `=`. Add suggestion and emit the error. - err.span_suggestion_short( + err.span_suggestion_verbose( colon_sp, "use `=` if you meant to assign", " =", @@ -1133,11 +1133,11 @@ pub fn parse_full_stmt( } else { false }; - if suggest_eq { - e.span_suggestion_short( - colon_sp, + if suggest_eq && let Some(ty) = &local.ty { + e.span_suggestion_verbose( + local.pat.span.between(ty.span), "use `=` if you meant to assign", - "=", + " = ", Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 3da0978e5ff8..35bfad3a877f 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -6,7 +6,6 @@ use rustc_middle::ty::layout::{FnAbiError, LayoutError}; use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt}; use rustc_span::Span; -use rustc_span::source_map::Spanned; use rustc_target::callconv::FnAbi; use super::layout_test::ensure_wf; @@ -45,10 +44,7 @@ fn unwrap_fn_abi<'tcx>( match abi { Ok(abi) => abi, Err(FnAbiError::Layout(layout_error)) => { - tcx.dcx().emit_fatal(Spanned { - node: layout_error.into_diagnostic(), - span: tcx.def_span(item_def_id), - }); + tcx.dcx().span_fatal(tcx.def_span(item_def_id), layout_error.to_string()); } } } @@ -66,11 +62,7 @@ fn dump_abi_of_fn_item( Ok(None) => { // Not sure what to do here, but `LayoutError::Unknown` seems reasonable? let ty = tcx.type_of(item_def_id).instantiate_identity(); - tcx.dcx().emit_fatal(Spanned { - node: LayoutError::Unknown(ty).into_diagnostic(), - - span: tcx.def_span(item_def_id), - }); + tcx.dcx().span_fatal(tcx.def_span(item_def_id), LayoutError::Unknown(ty).to_string()); } Err(_guaranteed) => return, }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bec6ab7e8355..26ba2b0e8f42 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -15,23 +15,19 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey, msg}; -use rustc_feature::{ - ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, - BuiltinAttribute, -}; +use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, msg}; +use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_hir::attrs::diagnostic::Directive; use rustc_hir::attrs::{ AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr, - MirDialect, MirPhase, ReprAttr, SanitizerSet, + ReprAttr, SanitizerSet, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ self as hir, Attribute, CRATE_HIR_ID, Constness, FnSig, ForeignItem, GenericParamKind, HirId, - Item, ItemKind, MethodKind, Node, ParamName, PartialConstStability, Safety, Stability, - StabilityLevel, Target, TraitItem, find_attr, + Item, ItemKind, MethodKind, Node, ParamName, Safety, Target, TraitItem, find_attr, }; use rustc_macros::Diagnostic; use rustc_middle::hir::nested_filter; @@ -49,7 +45,7 @@ }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; -use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; @@ -74,6 +70,10 @@ struct DiagnosticOnConstOnlyForNonConstTraitImpls { item_span: Span, } +#[derive(Diagnostic)] +#[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")] +struct DiagnosticOnMoveOnlyForAdt; + fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target { match impl_item.kind { hir::ImplItemKind::Const(..) => Target::AssocConst, @@ -152,16 +152,6 @@ fn check_attributes( Attribute::Parsed(AttributeKind::ProcMacroDerive { .. }) => { self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) } - Attribute::Parsed( - AttributeKind::Stability { - span: attr_span, - stability: Stability { level, feature }, - } - | AttributeKind::RustcConstStability { - span: attr_span, - stability: PartialConstStability { level, feature, .. }, - }, - ) => self.check_stability(*attr_span, span, level, *feature), Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => { self.check_inline(hir_id, *attr_span, kind, target) @@ -208,9 +198,6 @@ fn check_attributes( Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { self.check_may_dangle(hir_id, *attr_span) } - &Attribute::Parsed(AttributeKind::CustomMir(dialect, phase, attr_span)) => { - self.check_custom_mir(dialect, phase, attr_span) - } &Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, rtsan: _, span: attr_span}) => { self.check_sanitize(attr_span, on_set | off_set, span, target); }, @@ -233,6 +220,9 @@ fn check_attributes( Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)}, Attribute::Parsed(AttributeKind::OnUnimplemented{span, directive}) => {self.check_diagnostic_on_unimplemented(*span, hir_id, target,directive.as_deref())}, Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)} + Attribute::Parsed(AttributeKind::OnMove { span, directive }) => { + self.check_diagnostic_on_move(*span, hir_id, target, directive.as_deref()) + }, Attribute::Parsed( // tidy-alphabetical-start AttributeKind::RustcAllowIncoherentImpl(..) @@ -247,6 +237,7 @@ fn check_attributes( | AttributeKind::Coverage (..) | AttributeKind::CrateName { .. } | AttributeKind::CrateType(..) + | AttributeKind::CustomMir(..) | AttributeKind::DebuggerVisualizer(..) | AttributeKind::DefaultLibAllocator // `#[doc]` is actually a lot more than just doc comments, so is checked below @@ -307,6 +298,7 @@ fn check_attributes( | AttributeKind::RustcCoherenceIsCore(..) | AttributeKind::RustcCoinductive(..) | AttributeKind::RustcConfusables { .. } + | AttributeKind::RustcConstStability { .. } | AttributeKind::RustcConstStableIndirect | AttributeKind::RustcConversionSuggestion | AttributeKind::RustcDeallocator @@ -379,6 +371,7 @@ fn check_attributes( | AttributeKind::RustcTrivialFieldReads | AttributeKind::RustcUnsafeSpecializationMarker(..) | AttributeKind::ShouldPanic { .. } + | AttributeKind::Stability { .. } | AttributeKind::TestRunner(..) | AttributeKind::ThreadLocal | AttributeKind::TypeLengthLimit { .. } @@ -684,6 +677,56 @@ fn check_diagnostic_on_const( // The traits' or the impls'? } + /// Checks if `#[diagnostic::on_move]` is applied to an ADT definition + fn check_diagnostic_on_move( + &self, + attr_span: Span, + hir_id: HirId, + target: Target, + directive: Option<&Directive>, + ) { + if !matches!(target, Target::Enum | Target::Struct | Target::Union) { + self.tcx.emit_node_span_lint( + MISPLACED_DIAGNOSTIC_ATTRIBUTES, + hir_id, + attr_span, + DiagnosticOnMoveOnlyForAdt, + ); + } + + if let Some(directive) = directive { + if let Node::Item(Item { + kind: + ItemKind::Struct(_, generics, _) + | ItemKind::Enum(_, generics, _) + | ItemKind::Union(_, generics, _), + .. + }) = self.tcx.hir_node(hir_id) + { + directive.visit_params(&mut |argument_name, span| { + let has_generic = generics.params.iter().any(|p| { + if !matches!(p.kind, GenericParamKind::Lifetime { .. }) + && let ParamName::Plain(name) = p.name + && name.name == argument_name + { + true + } else { + false + } + }); + if !has_generic { + self.tcx.emit_node_span_lint( + MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, + hir_id, + span, + errors::OnMoveMalformedFormatLiterals { name: argument_name }, + ) + } + }); + } + } + } + /// Checks if an `#[inline]` is applied to a function or a closure. fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) { match target { @@ -1515,24 +1558,6 @@ fn check_rustc_allow_const_fn_unstable( } } - fn check_stability( - &self, - attr_span: Span, - item_span: Span, - level: &StabilityLevel, - feature: Symbol, - ) { - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if level.is_unstable() - && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() - { - self.tcx - .dcx() - .emit_err(errors::UnstableAttrForAlreadyStableFeature { attr_span, item_span }); - } - } - fn check_deprecated(&self, hir_id: HirId, attr_span: Span, target: Target) { match target { Target::AssocConst | Target::Method(..) | Target::AssocTy @@ -1856,48 +1881,6 @@ fn check_const_continue(&self, hir_id: HirId, attr_span: Span, target: Target) { self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span }); }; } - - fn check_custom_mir( - &self, - dialect: Option<(MirDialect, Span)>, - phase: Option<(MirPhase, Span)>, - attr_span: Span, - ) { - let Some((dialect, dialect_span)) = dialect else { - if let Some((_, phase_span)) = phase { - self.dcx() - .emit_err(errors::CustomMirPhaseRequiresDialect { attr_span, phase_span }); - } - return; - }; - - match dialect { - MirDialect::Analysis => { - if let Some((MirPhase::Optimized, phase_span)) = phase { - self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase { - dialect, - phase: MirPhase::Optimized, - attr_span, - dialect_span, - phase_span, - }); - } - } - - MirDialect::Built => { - if let Some((phase, phase_span)) = phase { - self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase { - dialect, - phase, - attr_span, - dialect_span, - phase_span, - }); - } - } - MirDialect::Runtime => {} - } - } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { @@ -1924,27 +1907,6 @@ fn visit_item(&mut self, item: &'tcx Item<'tcx>) { } fn visit_where_predicate(&mut self, where_predicate: &'tcx hir::WherePredicate<'tcx>) { - // FIXME(where_clause_attrs): Currently, as the following check shows, - // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed - // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`) - // in where clauses. After that, only `self.check_attributes` should be enough. - let spans = self - .tcx - .hir_attrs(where_predicate.hir_id) - .iter() - // FIXME: We shouldn't need to special-case `doc`! - .filter(|attr| { - matches!( - attr, - Attribute::Parsed(AttributeKind::DocComment { .. } | AttributeKind::Doc(_)) - | Attribute::Unparsed(_) - ) - }) - .map(|attr| attr.span()) - .collect::>(); - if !spans.is_empty() { - self.tcx.dcx().emit_err(errors::UnsupportedAttributesInWhere { span: spans.into() }); - } self.check_attributes( where_predicate.hir_id, where_predicate.span, @@ -2042,64 +2004,6 @@ fn is_c_like_enum(item: &Item<'_>) -> bool { } } -// FIXME: Fix "Cannot determine resolution" error and remove built-in macros -// from this check. -fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { - // Check for builtin attributes at the crate level - // which were unsuccessfully resolved due to cannot determine - // resolution for the attribute macro error. - const ATTRS_TO_CHECK: &[Symbol] = - &[sym::derive, sym::test, sym::test_case, sym::global_allocator, sym::bench]; - - for attr in attrs { - // FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day. - let (span, name) = if let Some(a) = - ATTRS_TO_CHECK.iter().find(|attr_to_check| attr.has_name(**attr_to_check)) - { - (attr.span(), *a) - } else if let Attribute::Parsed(AttributeKind::Repr { - reprs: _, - first_span: first_attr_span, - }) = attr - { - (*first_attr_span, sym::repr) - } else { - continue; - }; - - let item = tcx - .hir_free_items() - .map(|id| tcx.hir_item(id)) - .find(|item| !item.span.is_dummy()) // Skip prelude `use`s - .map(|item| errors::ItemFollowingInnerAttr { - span: if let Some(ident) = item.kind.ident() { ident.span } else { item.span }, - kind: tcx.def_descr(item.owner_id.to_def_id()), - }); - let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel { - span, - sugg_span: tcx - .sess - .source_map() - .span_to_snippet(span) - .ok() - .filter(|src| src.starts_with("#![")) - .map(|_| span.with_lo(span.lo() + BytePos(1)).with_hi(span.lo() + BytePos(2))), - name, - item, - }); - - if let Attribute::Unparsed(p) = attr { - tcx.dcx().try_steal_replace_and_emit_err( - p.path.span, - StashKey::UndeterminedMacroResolution, - err, - ); - } else { - err.emit(); - } - } -} - fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) { let attrs = tcx.hir_attrs(item.hir_id()); @@ -2115,7 +2019,6 @@ fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { tcx.hir_visit_item_likes_in_module(module_def_id, check_attr_visitor); if module_def_id.to_local_def_id().is_top_level_module() { check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); - check_invalid_crate_level_attr(tcx, tcx.hir_krate_attrs()); } if check_attr_visitor.abort.get() { tcx.dcx().abort_if_errors() diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 15c91deef247..d5ef9ee9335c 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -157,7 +157,7 @@ fn handle_res(&mut self, res: Res) { Res::Def(_, def_id) => self.check_def_id(def_id), Res::SelfTyParam { trait_: t } => self.check_def_id(t), Res::SelfTyAlias { alias_to: i, .. } => self.check_def_id(i), - Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {} + Res::ToolMod | Res::NonMacroAttr(..) | Res::OpenMod(..) | Res::Err => {} } } @@ -380,8 +380,8 @@ fn mark_live_symbols(&mut self) -> as Visitor<'tcx>>::R /// for discussion). fn should_ignore_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) -> bool { if let hir::ImplItemImplKind::Trait { .. } = impl_item.impl_kind - && let impl_of = self.tcx.parent(impl_item.owner_id.to_def_id()) - && self.tcx.is_automatically_derived(impl_of) + && let impl_of = self.tcx.local_parent(impl_item.owner_id.def_id) + && self.tcx.is_automatically_derived(impl_of.to_def_id()) && let trait_ref = self.tcx.impl_trait_ref(impl_of).instantiate_identity() && find_attr!(self.tcx, trait_ref.def_id, RustcTrivialFieldReads) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7c7698ac3bb8..f9dc696f320e 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -3,11 +3,9 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, msg, + Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, msg, }; use rustc_hir::Target; -use rustc_hir::attrs::{MirDialect, MirPhase}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{MainDefinition, Ty}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; @@ -448,44 +446,6 @@ pub(crate) struct LangItemOnIncorrectTarget { pub actual_target: Target, } -pub(crate) struct InvalidAttrAtCrateLevel { - pub span: Span, - pub sugg_span: Option, - pub name: Symbol, - pub item: Option, -} - -#[derive(Clone, Copy)] -pub(crate) struct ItemFollowingInnerAttr { - pub span: Span, - pub kind: &'static str, -} - -impl Diagnostic<'_, G> for InvalidAttrAtCrateLevel { - #[track_caller] - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { - let mut diag = - Diag::new(dcx, level, msg!("`{$name}` attribute cannot be used at crate level")); - diag.span(self.span); - diag.arg("name", self.name); - // Only emit an error with a suggestion if we can create a string out - // of the attribute span - if let Some(span) = self.sugg_span { - diag.span_suggestion_verbose( - span, - msg!("perhaps you meant to use an outer attribute"), - String::new(), - Applicability::MachineApplicable, - ); - } - if let Some(item) = self.item { - diag.arg("kind", item.kind); - diag.span_label(item.span, msg!("the inner attribute doesn't annotate this {$kind}")); - } - diag - } -} - #[derive(Diagnostic)] #[diag("duplicate diagnostic item in crate `{$crate_name}`: `{$name}`")] pub(crate) struct DuplicateDiagnosticItemInCrate { @@ -872,17 +832,6 @@ pub(crate) struct CannotStabilizeDeprecated { pub item_sp: Span, } -#[derive(Diagnostic)] -#[diag("can't mark as unstable using an already stable feature")] -pub(crate) struct UnstableAttrForAlreadyStableFeature { - #[primary_span] - #[label("this feature is already stable")] - #[help("consider removing the attribute")] - pub attr_span: Span, - #[label("the stability attribute annotates this item")] - pub item_span: Span, -} - #[derive(Diagnostic)] #[diag("{$descr} has missing stability attribute")] pub(crate) struct MissingStabilityAttr<'a> { @@ -987,14 +936,6 @@ pub(crate) struct ImpliedFeatureNotExist { pub implied_by: Symbol, } -#[derive(Diagnostic)] -#[diag("the feature `{$feature}` has already been enabled", code = E0636)] -pub(crate) struct DuplicateFeatureErr { - #[primary_span] - pub span: Span, - pub feature: Symbol, -} - #[derive(Diagnostic)] #[diag( "attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`" @@ -1144,6 +1085,12 @@ pub(crate) struct ProcMacroBadSig { pub kind: ProcMacroKind, } +#[derive(Diagnostic)] +#[diag("the feature `{$feature}` has already been enabled")] +pub(crate) struct DuplicateFeature { + pub feature: Symbol, +} + #[derive(Diagnostic)] #[diag( "the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable" @@ -1203,14 +1150,6 @@ pub(crate) struct RustcConstStableIndirectPairing { pub span: Span, } -#[derive(Diagnostic)] -#[diag("most attributes are not supported in `where` clauses")] -#[help("only `#[cfg]` and `#[cfg_attr]` are supported")] -pub(crate) struct UnsupportedAttributesInWhere { - #[primary_span] - pub span: MultiSpan, -} - #[derive(Diagnostic)] pub(crate) enum UnexportableItem<'a> { #[diag("{$descr}'s are not exportable")] @@ -1276,28 +1215,6 @@ pub(crate) struct ReprAlignShouldBeAlignStatic { pub item: &'static str, } -#[derive(Diagnostic)] -#[diag("`dialect` key required")] -pub(crate) struct CustomMirPhaseRequiresDialect { - #[primary_span] - pub attr_span: Span, - #[label("`phase` argument requires a `dialect` argument")] - pub phase_span: Span, -} - -#[derive(Diagnostic)] -#[diag("the {$dialect} dialect is not compatible with the {$phase} phase")] -pub(crate) struct CustomMirIncompatibleDialectAndPhase { - pub dialect: MirDialect, - pub phase: MirPhase, - #[primary_span] - pub attr_span: Span, - #[label("this dialect...")] - pub dialect_span: Span, - #[label("... is not compatible with this phase")] - pub phase_span: Span, -} - #[derive(Diagnostic)] #[diag("`eii_macro_for` is only valid on functions")] pub(crate) struct EiiImplNotFunction { @@ -1434,3 +1351,10 @@ pub(crate) struct UnknownFormatParameterForOnUnimplementedAttr { #[help(r#"expect either a generic argument name or {"`{Self}`"} as format argument"#)] pub help: bool, } + +#[derive(Diagnostic)] +#[diag("unknown parameter `{$name}`")] +#[help(r#"expect either a generic argument name or {"`{Self}`"} as format argument"#)] +pub(crate) struct OnMoveMalformedFormatLiterals { + pub name: Symbol, +} diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 68834cf7d55a..1a9054a51ca3 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -7,7 +7,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; -use rustc_span::source_map::Spanned; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits; @@ -116,7 +115,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attrs: &[RustcLayout } Err(layout_error) => { - tcx.dcx().emit_err(Spanned { node: layout_error.into_diagnostic(), span }); + tcx.dcx().span_err(span, layout_error.to_string()); } } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index ec6d48cbea2e..220cb57ddd39 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -131,7 +131,6 @@ fn inherit_stability(def_kind: DefKind) -> bool { level: StabilityLevel::Unstable { reason: UnstableReason::Default, issue: NonZero::new(27812), - is_soft: false, implied_by: None, old_name: None, }, @@ -964,12 +963,15 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let mut lang_features = UnordSet::default(); for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features { if let Some(version) = stable_since { + // Mark the feature as enabled, to ensure that it is not marked as unused. + let _ = tcx.features().enabled(*gate_name); + // Warn if the user has enabled an already-stable lang feature. unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version); } if !lang_features.insert(gate_name) { // Warn if the user enables a lang feature multiple times. - tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name }); + duplicate_feature_lint(tcx, *attr_sp, *gate_name); } } @@ -978,7 +980,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features { if remaining_lib_features.contains_key(gate_name) { // Warn if the user enables a lib feature multiple times. - tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name }); + duplicate_feature_lint(tcx, *attr_sp, *gate_name); } remaining_lib_features.insert(*gate_name, *attr_sp); } @@ -1021,6 +1023,9 @@ fn check_features<'tcx>( if let FeatureStability::AcceptedSince(since) = stability && let Some(span) = remaining_lib_features.get(&feature) { + // Mark the feature as enabled, to ensure that it is not marked as unused. + let _ = tcx.features().enabled(feature); + // Warn if the user has enabled an already-stable lib feature. if let Some(implies) = all_implications.get(&feature) { unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since); @@ -1160,3 +1165,12 @@ fn unnecessary_stable_feature_lint( errors::UnnecessaryStableFeature { feature, since }, ); } + +fn duplicate_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol) { + tcx.emit_node_span_lint( + lint::builtin::DUPLICATE_FEATURES, + hir::CRATE_HIR_ID, + span, + errors::DuplicateFeature { feature }, + ); +} diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index dc38f2d8bc70..0226c54db58c 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -462,7 +462,8 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { let arity; let fields: Vec<_>; match &pat.kind { - PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), + PatKind::Binding { subpattern: Some(subpat), .. } + | PatKind::Guard { subpattern: subpat, .. } => return self.lower_pat(subpat), PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; fields = vec![]; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 63860dfdd1a6..663f8727724e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1595,13 +1595,14 @@ fn check_assoc_item( let mut check = self.check(item.def_id.expect_local(), vis, effective_vis); let is_assoc_ty = item.is_type(); - check.hard_error = is_assoc_ty && !item.is_impl_trait_in_trait(); + check.hard_error = is_assoc_ty; check.generics().predicates(); if assoc_has_type_of(self.tcx, item) { - check.hard_error = check.hard_error && item.defaultness(self.tcx).has_value(); check.ty(); } if is_assoc_ty && item.container == AssocContainer::Trait { + // FIXME: too much breakage from reporting hard errors here, better wait for a fix + // from proper associated type normalization. check.hard_error = false; check.bounds(); } diff --git a/compiler/rustc_public/src/compiler_interface.rs b/compiler/rustc_public/src/compiler_interface.rs index b0ea1e0f5b84..30fbc5c5233d 100644 --- a/compiler/rustc_public/src/compiler_interface.rs +++ b/compiler/rustc_public/src/compiler_interface.rs @@ -20,7 +20,8 @@ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef, ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, - TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx, + TraitDecl, TraitDef, TraitRef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx, + VtblEntry, }; use crate::unstable::{RustcInternal, Stable, new_item_kind}; use crate::{ @@ -838,6 +839,25 @@ pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems { let did = tables[def_id]; cx.associated_items(did).iter().map(|assoc| assoc.stable(&mut *tables, cx)).collect() } + + /// Get all vtable entries of a trait. + pub(crate) fn vtable_entries(&self, trait_ref: &TraitRef) -> Vec { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + cx.vtable_entries(trait_ref.internal(&mut *tables, cx.tcx)) + .iter() + .map(|v| v.stable(&mut *tables, cx)) + .collect() + } + + /// Returns the vtable entry at the given index. + /// + /// Returns `None` if the index is out of bounds. + pub(crate) fn vtable_entry(&self, trait_ref: &TraitRef, idx: usize) -> Option { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + cx.vtable_entry(trait_ref.internal(&mut *tables, cx.tcx), idx).stable(&mut *tables, cx) + } } // A thread local variable that stores a pointer to [`CompilerInterface`]. diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index 8205d29c4534..7ec8b688402a 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -9,7 +9,7 @@ use crate::abi::{FnAbi, Layout}; use crate::crate_def::{CrateDef, CrateDefType}; use crate::mir::alloc::{AllocId, read_target_int, read_target_uint}; -use crate::mir::mono::StaticDef; +use crate::mir::mono::{Instance, StaticDef}; use crate::target::MachineInfo; use crate::{AssocItems, Filename, IndexedVal, Opaque, ThreadLocalIndex}; @@ -1440,6 +1440,18 @@ pub fn self_ty(&self) -> Ty { }; self_ty } + + /// Retrieve all vtable entries. + pub fn vtable_entries(&self) -> Vec { + with(|cx| cx.vtable_entries(self)) + } + + /// Returns the vtable entry at the given index. + /// + /// Returns `None` if the index is out of bounds. + pub fn vtable_entry(&self, idx: usize) -> Option { + with(|cx| cx.vtable_entry(self, idx)) + } } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] @@ -1656,3 +1668,19 @@ pub fn is_impl_trait_in_trait(&self) -> bool { matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) }) } } + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum VtblEntry { + /// destructor of this type (used in vtable header) + MetadataDropInPlace, + /// layout size of this type (used in vtable header) + MetadataSize, + /// layout align of this type (used in vtable header) + MetadataAlign, + /// non-dispatchable associated function that is excluded from trait object + Vacant, + /// dispatchable associated function + Method(Instance), + /// pointer to a separate supertrait vtable, can be used by trait upcasting coercion + TraitVPtr(TraitRef), +} diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 582a02e91824..b3edc6194c30 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -265,7 +265,7 @@ fn stable<'cx>( rustc_abi::BackendRepr::SimdVector { element, count } => { ValueAbi::Vector { element: element.stable(tables, cx), count } } - rustc_abi::BackendRepr::ScalableVector { element, count } => { + rustc_abi::BackendRepr::SimdScalableVector { element, count } => { ValueAbi::ScalableVector { element: element.stable(tables, cx), count } } rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 4bf98c4f0731..31cc6bd46959 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -1139,3 +1139,25 @@ fn stable<'cx>( crate::ty::Discr { val: self.val, ty: self.ty.stable(tables, cx) } } } + +impl<'tcx> Stable<'tcx> for rustc_middle::ty::VtblEntry<'tcx> { + type T = crate::ty::VtblEntry; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &CompilerCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::VtblEntry; + match self { + ty::VtblEntry::MetadataDropInPlace => VtblEntry::MetadataDropInPlace, + ty::VtblEntry::MetadataSize => VtblEntry::MetadataSize, + ty::VtblEntry::MetadataAlign => VtblEntry::MetadataAlign, + ty::VtblEntry::Vacant => VtblEntry::Vacant, + ty::VtblEntry::Method(instance) => VtblEntry::Method(instance.stable(tables, cx)), + ty::VtblEntry::TraitVPtr(trait_ref) => { + VtblEntry::TraitVPtr(trait_ref.stable(tables, cx)) + } + } + } +} diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs index 4418d68c5c3a..359769d4cfe4 100644 --- a/compiler/rustc_public_bridge/src/context/impls.rs +++ b/compiler/rustc_public_bridge/src/context/impls.rs @@ -18,7 +18,7 @@ AdtDef, AdtKind, AssocItem, Binder, ClosureKind, CoroutineArgsExt, EarlyBinder, ExistentialTraitRef, FnSig, GenericArgsRef, Instance, InstanceKind, IntrinsicDef, List, PolyFnSig, ScalarInt, TraitDef, TraitRef, Ty, TyCtxt, TyKind, TypeVisitableExt, UintTy, - ValTree, VariantDef, + ValTree, VariantDef, VtblEntry, }; use rustc_middle::{mir, ty}; use rustc_session::cstore::ForeignModule; @@ -757,4 +757,16 @@ pub fn associated_items(&self, def_id: DefId) -> Vec { }; assoc_items } + + /// Get all vtable entries of a trait. + pub fn vtable_entries(&self, trait_ref: TraitRef<'tcx>) -> Vec> { + self.tcx.vtable_entries(trait_ref).to_vec() + } + + /// Returns the vtable entry at the given index. + /// + /// Returns `None` if the index is out of bounds. + pub fn vtable_entry(&self, trait_ref: TraitRef<'tcx>, idx: usize) -> Option> { + self.vtable_entries(trait_ref).get(idx).copied() + } } diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 449d2ed5334a..02d3b0110cb8 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -10,11 +10,9 @@ rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } -rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } -rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_thread_pool = { path = "../rustc_thread_pool" } tracing = "0.1" diff --git a/compiler/rustc_query_impl/src/dep_kind_vtables.rs b/compiler/rustc_query_impl/src/dep_kind_vtables.rs index 3bc2e35b02bc..b70fe3008cb1 100644 --- a/compiler/rustc_query_impl/src/dep_kind_vtables.rs +++ b/compiler/rustc_query_impl/src/dep_kind_vtables.rs @@ -4,7 +4,7 @@ use rustc_middle::query::QueryCache; use crate::GetQueryVTable; -use crate::plumbing::{force_from_dep_node_inner, promote_from_disk_inner}; +use crate::plumbing::promote_from_disk_inner; /// [`DepKindVTable`] constructors for special dep kinds that aren't queries. #[expect(non_snake_case, reason = "use non-snake case to avoid collision with query names")] @@ -96,32 +96,31 @@ pub(crate) fn Metadata<'tcx>() -> DepKindVTable<'tcx> { /// Shared implementation of the [`DepKindVTable`] constructor for queries. /// Called from macro-generated code for each query. pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>( - is_anon: bool, is_cache_on_disk: bool, is_eval_always: bool, + is_no_force: bool, ) -> DepKindVTable<'tcx> where Q: GetQueryVTable<'tcx>, { - let key_fingerprint_style = if is_anon { - KeyFingerprintStyle::Opaque - } else { - ::Key::key_fingerprint_style() - }; - // A query dep-node can only be forced or promoted if it can recover a key // from its key fingerprint. + let key_fingerprint_style = ::Key::key_fingerprint_style(); let can_recover = key_fingerprint_style.is_maybe_recoverable(); - if is_anon { - assert!(!can_recover); - } DepKindVTable { is_eval_always, key_fingerprint_style, - force_from_dep_node_fn: can_recover.then_some(force_from_dep_node_inner::), - promote_from_disk_fn: (can_recover && is_cache_on_disk) - .then_some(promote_from_disk_inner::), + force_from_dep_node_fn: (can_recover && !is_no_force).then_some( + |tcx, dep_node, _prev_index| { + let query = Q::query_vtable(tcx); + crate::execution::force_query_dep_node(tcx, query, dep_node) + }, + ), + promote_from_disk_fn: (can_recover && is_cache_on_disk).then_some(|tcx, dep_node| { + let query = Q::query_vtable(tcx); + promote_from_disk_inner(tcx, query, dep_node) + }), } } @@ -133,13 +132,12 @@ macro_rules! define_dep_kind_vtables { fn $name:ident($K:ty) -> $V:ty { // Search for (QMODLIST) to find all occurrences of this query modifier list. - anon: $anon:literal, arena_cache: $arena_cache:literal, cache_on_disk: $cache_on_disk:literal, - cycle_error_handling: $cycle_error_handling:ident, depth_limit: $depth_limit:literal, eval_always: $eval_always:literal, feedable: $feedable:literal, + no_force: $no_force:literal, no_hash: $no_hash:literal, returns_error_guaranteed: $returns_error_guaranteed:literal, separate_provide_extern: $separate_provide_extern:literal, @@ -166,9 +164,9 @@ fn $name:ident($K:ty) -> $V:ty $crate::dep_kind_vtables::make_dep_kind_vtable_for_query::< $crate::query_impl::$name::VTableGetter, >( - $anon, $cache_on_disk, $eval_always, + $no_force, ) ),* ]; @@ -180,7 +178,7 @@ fn $name:ident($K:ty) -> $V:ty // Create an array of vtables, one for each dep kind (non-query and query). pub fn make_dep_kind_vtables<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindVTable<'tcx>] { let (nq_vtables, q_vtables) = - rustc_middle::rustc_with_all_queries! { define_dep_kind_vtables! }; + rustc_middle::queries::rustc_with_all_queries! { define_dep_kind_vtables! }; // Non-query vtables must come before query vtables, to match the order of `DepKind`. arena.alloc_from_iter(nq_vtables.into_iter().chain(q_vtables.into_iter())) diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 11749f3fb82d..8844d40f49cf 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -1,107 +1,121 @@ use std::hash::Hash; -use std::mem; +use std::mem::ManuallyDrop; use rustc_data_structures::hash_table::{Entry, HashTable}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::{outline, sharded, sync}; -use rustc_errors::{FatalError, StashKey}; +use rustc_errors::FatalError; use rustc_middle::dep_graph::{DepGraphData, DepNodeKey, SerializedDepNodeIndex}; -use rustc_middle::query::plumbing::QueryVTable; use rustc_middle::query::{ - ActiveKeyStatus, CycleError, CycleErrorHandling, EnsureMode, QueryCache, QueryJob, QueryJobId, - QueryKey, QueryLatch, QueryMode, QueryState, + ActiveKeyStatus, Cycle, EnsureMode, QueryCache, QueryJob, QueryJobId, QueryKey, QueryLatch, + QueryMode, QueryState, QueryVTable, }; use rustc_middle::ty::TyCtxt; use rustc_middle::verify_ich::incremental_verify_ich; use rustc_span::{DUMMY_SP, Span}; +use tracing::warn; -use crate::collect_active_jobs_from_all_queries; use crate::dep_graph::{DepNode, DepNodeIndex}; -use crate::job::{QueryJobInfo, QueryJobMap, find_cycle_in_stack, report_cycle}; -use crate::plumbing::{current_query_job, next_job_id, start_query}; +use crate::job::{QueryJobInfo, QueryJobMap, create_cycle_error, find_cycle_in_stack}; +use crate::plumbing::{current_query_job, loadable_from_disk, next_job_id, start_query}; +use crate::query_impl::for_each_query_vtable; #[inline] fn equivalent_key(k: K) -> impl Fn(&(K, V)) -> bool { move |x| x.0 == k } -/// Obtains the enclosed [`QueryJob`], or panics if this query evaluation -/// was poisoned by a panic. -fn expect_job<'tcx>(status: ActiveKeyStatus<'tcx>) -> QueryJob<'tcx> { - match status { - ActiveKeyStatus::Started(job) => job, - ActiveKeyStatus::Poisoned => { - panic!("job for query failed to start and was poisoned") - } - } -} - pub(crate) fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool { state.active.lock_shards().all(|shard| shard.is_empty()) } +#[derive(Clone, Copy)] +pub enum CollectActiveJobsKind { + /// We need the full query job map, and we are willing to wait to obtain the query state + /// shard lock(s). + Full, + + /// We need the full query job map, and we shouldn't need to wait to obtain the shard lock(s), + /// because we are in a place where nothing else could hold the shard lock(s). + FullNoContention, + + /// We can get by without the full query job map, so we won't bother waiting to obtain the + /// shard lock(s) if they're not already unlocked. + PartialAllowed, +} + +/// Returns a map of currently active query jobs, collected from all queries. +pub fn collect_active_query_jobs<'tcx>( + tcx: TyCtxt<'tcx>, + collect_kind: CollectActiveJobsKind, +) -> QueryJobMap<'tcx> { + let mut job_map = QueryJobMap::default(); + + for_each_query_vtable!(ALL, tcx, |query| { + collect_active_query_jobs_inner(query, collect_kind, &mut job_map); + }); + + job_map +} + /// Internal plumbing for collecting the set of active jobs for this query. /// -/// Should only be called from `collect_active_jobs_from_all_queries`. -/// -/// (We arbitrarily use the word "gather" when collecting the jobs for -/// each individual query, so that we have distinct function names to -/// grep for.) -pub(crate) fn gather_active_jobs<'tcx, C>( +/// Aborts if jobs can't be gathered as specified by `collect_kind`. +fn collect_active_query_jobs_inner<'tcx, C>( query: &'tcx QueryVTable<'tcx, C>, - tcx: TyCtxt<'tcx>, - require_complete: bool, - job_map_out: &mut QueryJobMap<'tcx>, // Out-param; job info is gathered into this map -) -> Option<()> -where + collect_kind: CollectActiveJobsKind, + job_map: &mut QueryJobMap<'tcx>, +) where C: QueryCache, QueryVTable<'tcx, C>: DynSync, { - let mut active = Vec::new(); - - // Helper to gather active jobs from a single shard. - let mut gather_shard_jobs = |shard: &HashTable<(C::Key, ActiveKeyStatus<'tcx>)>| { - for (k, v) in shard.iter() { - if let ActiveKeyStatus::Started(ref job) = *v { - active.push((*k, job.clone())); + let mut collect_shard_jobs = |shard: &HashTable<(C::Key, ActiveKeyStatus<'tcx>)>| { + for (key, status) in shard.iter() { + if let ActiveKeyStatus::Started(job) = status { + // It's fine to call `create_tagged_key` with the shard locked, + // because it's just a `TaggedQueryKey` variant constructor. + let tagged_key = (query.create_tagged_key)(*key); + job_map.insert(job.id, QueryJobInfo { tagged_key, job: job.clone() }); } } }; - // Lock shards and gather jobs from each shard. - if require_complete { - for shard in query.state.active.lock_shards() { - gather_shard_jobs(&shard); + match collect_kind { + CollectActiveJobsKind::Full => { + for shard in query.state.active.lock_shards() { + collect_shard_jobs(&shard); + } } - } else { - // We use try_lock_shards here since we are called from the - // deadlock handler, and this shouldn't be locked. - for shard in query.state.active.try_lock_shards() { - // This can be called during unwinding, and the function has a `try_`-prefix, so - // don't `unwrap()` here, just manually check for `None` and do best-effort error - // reporting. - match shard { - None => { - tracing::warn!( - "Failed to collect active jobs for query with name `{}`!", - query.name - ); - return None; + CollectActiveJobsKind::FullNoContention => { + for shard in query.state.active.try_lock_shards() { + match shard { + Some(shard) => collect_shard_jobs(&shard), + None => panic!("Failed to collect active jobs for query `{}`!", query.name), + } + } + } + CollectActiveJobsKind::PartialAllowed => { + for shard in query.state.active.try_lock_shards() { + match shard { + Some(shard) => collect_shard_jobs(&shard), + None => warn!("Failed to collect active jobs for query `{}`!", query.name), } - Some(shard) => gather_shard_jobs(&shard), } } } +} - // Call `make_frame` while we're not holding a `state.active` lock as `make_frame` may call - // queries leading to a deadlock. - for (key, job) in active { - let frame = crate::plumbing::create_deferred_query_stack_frame(tcx, query, key); - job_map_out.insert(job.id, QueryJobInfo { frame, job }); - } - - Some(()) +#[cold] +#[inline(never)] +fn handle_cycle<'tcx, C: QueryCache>( + query: &'tcx QueryVTable<'tcx, C>, + tcx: TyCtxt<'tcx>, + key: C::Key, + cycle: Cycle<'tcx>, +) -> C::Value { + let error = create_cycle_error(tcx, &cycle); + (query.handle_cycle_error_fn)(tcx, key, cycle, error) } /// Guard object representing the responsibility to execute a query job and @@ -118,69 +132,51 @@ struct ActiveJobGuard<'tcx, K> key_hash: u64, } -#[cold] -#[inline(never)] -fn mk_cycle<'tcx, C: QueryCache>( - query: &'tcx QueryVTable<'tcx, C>, - tcx: TyCtxt<'tcx>, - cycle_error: CycleError, -) -> C::Value { - let error = report_cycle(tcx.sess, &cycle_error); - match query.cycle_error_handling { - CycleErrorHandling::Error => { - let guar = error.emit(); - (query.value_from_cycle_error)(tcx, cycle_error, guar) - } - CycleErrorHandling::DelayBug => { - let guar = error.delay_as_bug(); - (query.value_from_cycle_error)(tcx, cycle_error, guar) - } - CycleErrorHandling::Stash => { - let guar = if let Some(root) = cycle_error.cycle.first() - && let Some(span) = root.frame.info.span - { - error.stash(span, StashKey::Cycle).unwrap() - } else { - error.emit() - }; - (query.value_from_cycle_error)(tcx, cycle_error, guar) - } - } -} - impl<'tcx, K> ActiveJobGuard<'tcx, K> where K: Eq + Hash + Copy, { /// Completes the query by updating the query cache with the `result`, /// signals the waiter, and forgets the guard so it won't poison the query. - fn complete(self, cache: &C, result: C::Value, dep_node_index: DepNodeIndex) + fn complete(self, cache: &C, value: C::Value, dep_node_index: DepNodeIndex) where C: QueryCache, { - // Forget ourself so our destructor won't poison the query. - // (Extract fields by value first to make sure we don't leak anything.) - let Self { state, key, key_hash }: Self = self; - mem::forget(self); - // Mark as complete before we remove the job from the active state // so no other thread can re-execute this query. - cache.complete(key, result, dep_node_index); + cache.complete(self.key, value, dep_node_index); - let job = { - // don't keep the lock during the `unwrap()` of the retrieved value, or we taint the - // underlying shard. - // since unwinding also wants to look at this map, this can also prevent a double - // panic. - let mut shard = state.active.lock_shard_by_hash(key_hash); - match shard.find_entry(key_hash, equivalent_key(key)) { - Err(_) => None, - Ok(occupied) => Some(occupied.remove().0.1), + let mut this = ManuallyDrop::new(self); + + // Drop everything without poisoning the query. + this.drop_and_maybe_poison(/* poison */ false); + } + + fn drop_and_maybe_poison(&mut self, poison: bool) { + let status = { + let mut shard = self.state.active.lock_shard_by_hash(self.key_hash); + match shard.find_entry(self.key_hash, equivalent_key(self.key)) { + Err(_) => { + // Note: we must not panic while holding the lock, because unwinding also looks + // at this map, which can result in a double panic. So drop it first. + drop(shard); + panic!(); + } + Ok(occupied) => { + let ((key, status), vacant) = occupied.remove(); + if poison { + vacant.insert((key, ActiveKeyStatus::Poisoned)); + } + status + } } }; - let job = expect_job(job.expect("active query job entry")); - job.signal_complete(); + // Also signal the completion of the job, so waiters will continue execution. + match status { + ActiveKeyStatus::Started(job) => job.signal_complete(), + ActiveKeyStatus::Poisoned => panic!(), + } } } @@ -192,40 +188,25 @@ impl<'tcx, K> Drop for ActiveJobGuard<'tcx, K> #[cold] fn drop(&mut self) { // Poison the query so jobs waiting on it panic. - let Self { state, key, key_hash } = *self; - let job = { - let mut shard = state.active.lock_shard_by_hash(key_hash); - match shard.find_entry(key_hash, equivalent_key(key)) { - Err(_) => panic!(), - Ok(occupied) => { - let ((key, value), vacant) = occupied.remove(); - vacant.insert((key, ActiveKeyStatus::Poisoned)); - expect_job(value) - } - } - }; - // Also signal the completion of the job, so waiters - // will continue execution. - job.signal_complete(); + self.drop_and_maybe_poison(/* poison */ true); } } #[cold] #[inline(never)] -fn cycle_error<'tcx, C: QueryCache>( +fn find_and_handle_cycle<'tcx, C: QueryCache>( query: &'tcx QueryVTable<'tcx, C>, tcx: TyCtxt<'tcx>, + key: C::Key, try_execute: QueryJobId, span: Span, ) -> (C::Value, Option) { - // Ensure there was no errors collecting all active jobs. + // Ensure there were no errors collecting all active jobs. // We need the complete map to ensure we find a cycle to break. - let job_map = collect_active_jobs_from_all_queries(tcx, false) - .ok() - .expect("failed to collect active queries"); + let job_map = collect_active_query_jobs(tcx, CollectActiveJobsKind::FullNoContention); - let error = find_cycle_in_stack(try_execute, job_map, ¤t_query_job(), span); - (mk_cycle(query, tcx, error.lift()), None) + let cycle = find_cycle_in_stack(try_execute, job_map, ¤t_query_job(), span); + (handle_cycle(query, tcx, key, cycle), None) } #[inline(always)] @@ -234,6 +215,7 @@ fn wait_for_query<'tcx, C: QueryCache>( tcx: TyCtxt<'tcx>, span: Span, key: C::Key, + key_hash: u64, latch: QueryLatch<'tcx>, current: Option, ) -> (C::Value, Option) { @@ -242,8 +224,7 @@ fn wait_for_query<'tcx, C: QueryCache>( // self-profiler. let query_blocked_prof_timer = tcx.prof.query_blocked(); - // With parallel queries we might just have to wait on some other - // thread. + // With parallel queries we might just have to wait on some other thread. let result = latch.wait_on(tcx, current, span); match result { @@ -252,7 +233,6 @@ fn wait_for_query<'tcx, C: QueryCache>( outline(|| { // We didn't find the query result in the query cache. Check if it was // poisoned due to a panic instead. - let key_hash = sharded::make_hash(&key); let shard = query.state.active.lock_shard_by_hash(key_hash); match shard.find(key_hash, equivalent_key(key)) { // The query we waited on panicked. Continue unwinding here. @@ -270,7 +250,7 @@ fn wait_for_query<'tcx, C: QueryCache>( (v, Some(index)) } - Err(cycle) => (mk_cycle(query, tcx, cycle.lift()), None), + Err(cycle) => (handle_cycle(query, tcx, key, cycle), None), } } @@ -281,9 +261,7 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>( tcx: TyCtxt<'tcx>, span: Span, key: C::Key, - // If present, some previous step has already created a `DepNode` for this - // query+key, which we should reuse instead of creating a new one. - dep_node: Option, + dep_node: Option, // `None` for non-incremental, `Some` for incremental ) -> (C::Value, Option) { let key_hash = sharded::make_hash(&key); let mut state_lock = query.state.active.lock_shard_by_hash(key_hash); @@ -305,16 +283,35 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>( match state_lock.entry(key_hash, equivalent_key(key), |(k, _)| sharded::make_hash(k)) { Entry::Vacant(entry) => { - // Nothing has computed or is computing the query, so we start a new job and insert it in the - // state map. + // Nothing has computed or is computing the query, so we start a new job and insert it + // in the state map. let id = next_job_id(tcx); let job = QueryJob::new(id, span, current_job_id); entry.insert((key, ActiveKeyStatus::Started(job))); - // Drop the lock before we start executing the query + // Drop the lock before we start executing the query. drop(state_lock); - execute_job::(query, tcx, key, key_hash, id, dep_node) + // Set up a guard object that will automatically poison the query if a + // panic occurs while executing the query (or any intermediate plumbing). + let job_guard = ActiveJobGuard { state: &query.state, key, key_hash }; + + // Delegate to another function to actually execute the query job. + let (value, dep_node_index) = if INCR { + execute_job_incr(query, tcx, key, dep_node.unwrap(), id) + } else { + execute_job_non_incr(query, tcx, key, id) + }; + + if query.feedable { + check_feedable_consistency(tcx, query, key, &value); + } + + // Tell the guard to insert `value` in the cache and remove the status entry from + // `query.state`. + job_guard.complete(&query.cache, value, dep_node_index); + + (value, Some(dep_node_index)) } Entry::Occupied(mut entry) => { match &mut entry.get_mut().1 { @@ -326,14 +323,14 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>( // Only call `wait_for_query` if we're using a Rayon thread pool // as it will attempt to mark the worker thread as blocked. - wait_for_query(query, tcx, span, key, latch, current_job_id) + wait_for_query(query, tcx, span, key, key_hash, latch, current_job_id) } else { let id = job.id; drop(state_lock); // If we are single-threaded we know that we have cycle error, // so we just return the error. - cycle_error(query, tcx, id, span) + find_and_handle_cycle(query, tcx, key, id, span) } } ActiveKeyStatus::Poisoned => FatalError.raise(), @@ -343,67 +340,44 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>( } #[inline(always)] -fn execute_job<'tcx, C: QueryCache, const INCR: bool>( - query: &'tcx QueryVTable<'tcx, C>, +fn check_feedable_consistency<'tcx, C: QueryCache>( tcx: TyCtxt<'tcx>, + query: &'tcx QueryVTable<'tcx, C>, key: C::Key, - key_hash: u64, - id: QueryJobId, - dep_node: Option, -) -> (C::Value, Option) { - // Set up a guard object that will automatically poison the query if a - // panic occurs while executing the query (or any intermediate plumbing). - let job_guard = ActiveJobGuard { state: &query.state, key, key_hash }; + value: &C::Value, +) { + // We should not compute queries that also got a value via feeding. + // This can't happen, as query feeding adds the very dependencies to the fed query + // as its feeding query had. So if the fed query is red, so is its feeder, which will + // get evaluated first, and re-feed the query. + let Some((cached_value, _)) = query.cache.lookup(&key) else { return }; - debug_assert_eq!(tcx.dep_graph.is_fully_enabled(), INCR); - - // Delegate to another function to actually execute the query job. - let (value, dep_node_index) = if INCR { - execute_job_incr(query, tcx, key, dep_node, id) - } else { - execute_job_non_incr(query, tcx, key, id) + let Some(hash_value_fn) = query.hash_value_fn else { + panic!( + "no_hash fed query later has its value computed.\n\ + Remove `no_hash` modifier to allow recomputation.\n\ + The already cached value: {}", + (query.format_value)(&cached_value) + ); }; - let cache = &query.cache; - if query.feedable { - // We should not compute queries that also got a value via feeding. - // This can't happen, as query feeding adds the very dependencies to the fed query - // as its feeding query had. So if the fed query is red, so is its feeder, which will - // get evaluated first, and re-feed the query. - if let Some((cached_value, _)) = cache.lookup(&key) { - let Some(hash_value_fn) = query.hash_value_fn else { - panic!( - "no_hash fed query later has its value computed.\n\ - Remove `no_hash` modifier to allow recomputation.\n\ - The already cached value: {}", - (query.format_value)(&cached_value) - ); - }; - - let (old_hash, new_hash) = tcx.with_stable_hashing_context(|mut hcx| { - (hash_value_fn(&mut hcx, &cached_value), hash_value_fn(&mut hcx, &value)) - }); - let formatter = query.format_value; - if old_hash != new_hash { - // We have an inconsistency. This can happen if one of the two - // results is tainted by errors. - assert!( - tcx.dcx().has_errors().is_some(), - "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ - computed={:#?}\nfed={:#?}", - query.dep_kind, - key, - formatter(&value), - formatter(&cached_value), - ); - } - } + let (old_hash, new_hash) = tcx.with_stable_hashing_context(|mut hcx| { + (hash_value_fn(&mut hcx, &cached_value), hash_value_fn(&mut hcx, value)) + }); + let formatter = query.format_value; + if old_hash != new_hash { + // We have an inconsistency. This can happen if one of the two + // results is tainted by errors. + assert!( + tcx.dcx().has_errors().is_some(), + "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ + computed={:#?}\nfed={:#?}", + query.dep_kind, + key, + formatter(value), + formatter(&cached_value), + ); } - - // Tell the guard to perform completion bookkeeping, and also to not poison the query. - job_guard.complete(cache, value, dep_node_index); - - (value, Some(dep_node_index)) } // Fast path for when incr. comp. is off. @@ -440,27 +414,23 @@ fn execute_job_incr<'tcx, C: QueryCache>( query: &'tcx QueryVTable<'tcx, C>, tcx: TyCtxt<'tcx>, key: C::Key, - mut dep_node_opt: Option, + dep_node: DepNode, job_id: QueryJobId, ) -> (C::Value, DepNodeIndex) { let dep_graph_data = tcx.dep_graph.data().expect("should always be present in incremental mode"); - if !query.anon && !query.eval_always { - // `to_dep_node` is expensive for some `DepKind`s. - let dep_node = - dep_node_opt.get_or_insert_with(|| DepNode::construct(tcx, query.dep_kind, &key)); - + if !query.eval_always { // The diagnostics for this query will be promoted to the current session during // `try_mark_green()`, so we can ignore them here. if let Some(ret) = start_query(job_id, false, || try { - let (prev_index, dep_node_index) = dep_graph_data.try_mark_green(tcx, dep_node)?; + let (prev_index, dep_node_index) = dep_graph_data.try_mark_green(tcx, &dep_node)?; let value = load_from_disk_or_invoke_provider_green( tcx, dep_graph_data, query, key, - dep_node, + &dep_node, prev_index, dep_node_index, ); @@ -473,17 +443,6 @@ fn execute_job_incr<'tcx, C: QueryCache>( let prof_timer = tcx.prof.query_provider(); let (result, dep_node_index) = start_query(job_id, query.depth_limit, || { - if query.anon { - // Call the query provider inside an anon task. - return dep_graph_data.with_anon_task_inner(tcx, query.dep_kind, || { - (query.invoke_provider_fn)(tcx, key) - }); - } - - // `to_dep_node` is expensive for some `DepKind`s. - let dep_node = - dep_node_opt.unwrap_or_else(|| DepNode::construct(tcx, query.dep_kind, &key)); - // Call the query provider. dep_graph_data.with_task( dep_node, @@ -517,94 +476,62 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>( debug_assert!(dep_graph_data.is_index_green(prev_index)); - // First we try to load the result from the on-disk cache. - // Some things are never cached on disk. - if let Some(value) = (query.try_load_from_disk_fn)(tcx, key, prev_index, dep_node_index) { - if std::intrinsics::unlikely(tcx.sess.opts.unstable_opts.query_dep_graph) { - dep_graph_data.mark_debug_loaded_from_disk(*dep_node) - } + // First try to load the result from the on-disk cache. Some things are never cached on disk. + let value; + let verify; + match (query.try_load_from_disk_fn)(tcx, key, prev_index, dep_node_index) { + Some(loaded_value) => { + if std::intrinsics::unlikely(tcx.sess.opts.unstable_opts.query_dep_graph) { + dep_graph_data.mark_debug_loaded_from_disk(*dep_node) + } - let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_index); - // If `-Zincremental-verify-ich` is specified, re-hash results from - // the cache and make sure that they have the expected fingerprint. + value = loaded_value; + + let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_index); + // If `-Zincremental-verify-ich` is specified, re-hash results from + // the cache and make sure that they have the expected fingerprint. + // + // If not, we still seek to verify a subset of fingerprints loaded + // from disk. Re-hashing results is fairly expensive, so we can't + // currently afford to verify every hash. This subset should still + // give us some coverage of potential bugs. + verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32) + || tcx.sess.opts.unstable_opts.incremental_verify_ich; + } + None => { + // We could not load a result from the on-disk cache, so recompute. The dep-graph for + // this computation is already in-place, so we can just call the query provider. + let prof_timer = tcx.prof.query_provider(); + value = tcx.dep_graph.with_ignore(|| (query.invoke_provider_fn)(tcx, key)); + prof_timer.finish_with_query_invocation_id(dep_node_index.into()); + + verify = true; + } + }; + + if verify { + // Verify that re-running the query produced a result with the expected hash. + // This catches bugs in query implementations, turning them into ICEs. + // For example, a query might sort its result by `DefId` - since `DefId`s are + // not stable across compilation sessions, the result could get up getting sorted + // in a different order when the query is re-run, even though all of the inputs + // (e.g. `DefPathHash` values) were green. // - // If not, we still seek to verify a subset of fingerprints loaded - // from disk. Re-hashing results is fairly expensive, so we can't - // currently afford to verify every hash. This subset should still - // give us some coverage of potential bugs though. - let try_verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32); - if std::intrinsics::unlikely( - try_verify || tcx.sess.opts.unstable_opts.incremental_verify_ich, - ) { - incremental_verify_ich( - tcx, - dep_graph_data, - &value, - prev_index, - query.hash_value_fn, - query.format_value, - ); - } - - return value; + // See issue #82920 for an example of a miscompilation that would get turned into + // an ICE by this check + incremental_verify_ich( + tcx, + dep_graph_data, + &value, + prev_index, + query.hash_value_fn, + query.format_value, + ); } - // We always expect to find a cached result for things that - // can be forced from `DepNode`. - debug_assert!( - !(query.will_cache_on_disk_for_key_fn)(tcx, key) - || !tcx.key_fingerprint_style(dep_node.kind).is_maybe_recoverable(), - "missing on-disk cache entry for {dep_node:?}" - ); - - // Sanity check for the logic in `ensure`: if the node is green and the result loadable, - // we should actually be able to load it. - debug_assert!( - !(query.is_loadable_from_disk_fn)(tcx, key, prev_index), - "missing on-disk cache entry for loadable {dep_node:?}" - ); - - // We could not load a result from the on-disk cache, so - // recompute. - let prof_timer = tcx.prof.query_provider(); - - // The dep-graph for this computation is already in-place. - // Call the query provider. - let value = tcx.dep_graph.with_ignore(|| (query.invoke_provider_fn)(tcx, key)); - - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - // Verify that re-running the query produced a result with the expected hash - // This catches bugs in query implementations, turning them into ICEs. - // For example, a query might sort its result by `DefId` - since `DefId`s are - // not stable across compilation sessions, the result could get up getting sorted - // in a different order when the query is re-run, even though all of the inputs - // (e.g. `DefPathHash` values) were green. - // - // See issue #82920 for an example of a miscompilation that would get turned into - // an ICE by this check - incremental_verify_ich( - tcx, - dep_graph_data, - &value, - prev_index, - query.hash_value_fn, - query.format_value, - ); - value } -/// Return value struct for [`check_if_ensure_can_skip_execution`]. -struct EnsureCanSkip { - /// If true, the current `tcx.ensure_ok()` or `tcx.ensure_done()` query - /// can return early without actually trying to execute. - skip_execution: bool, - /// A dep node that was prepared while checking whether execution can be - /// skipped, to be reused by execution itself if _not_ skipped. - dep_node: Option, -} - /// Checks whether a `tcx.ensure_ok()` or `tcx.ensure_done()` query call can /// return early without actually trying to execute. /// @@ -612,23 +539,19 @@ struct EnsureCanSkip { /// on having the dependency graph (and in some cases a disk-cached value) /// from the previous incr-comp session. #[inline(never)] -fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>( +fn ensure_can_skip_execution<'tcx, C: QueryCache>( query: &'tcx QueryVTable<'tcx, C>, tcx: TyCtxt<'tcx>, key: C::Key, + dep_node: DepNode, ensure_mode: EnsureMode, -) -> EnsureCanSkip { +) -> bool { // Queries with `eval_always` should never skip execution. if query.eval_always { - return EnsureCanSkip { skip_execution: false, dep_node: None }; + return false; } - // Ensuring an anonymous query makes no sense - assert!(!query.anon); - - let dep_node = DepNode::construct(tcx, query.dep_kind, &key); - - let serialized_dep_node_index = match tcx.dep_graph.try_mark_green(tcx, &dep_node) { + match tcx.dep_graph.try_mark_green(tcx, &dep_node) { None => { // A None return from `try_mark_green` means that this is either // a new dep node or that the dep node has already been marked red. @@ -636,28 +559,27 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>( // DepNodeIndex. We must invoke the query itself. The performance cost // this introduces should be negligible as we'll immediately hit the // in-memory cache, or another query down the line will. - return EnsureCanSkip { skip_execution: false, dep_node: Some(dep_node) }; + false } Some((serialized_dep_node_index, dep_node_index)) => { tcx.dep_graph.read_index(dep_node_index); tcx.prof.query_cache_hit(dep_node_index.into()); - serialized_dep_node_index - } - }; + match ensure_mode { + // In ensure-ok mode, we can skip execution for this key if the + // node is green. It must have succeeded in the previous + // session, and therefore would succeed in the current session + // if executed. + EnsureMode::Ok => true, - match ensure_mode { - EnsureMode::Ok => { - // In ensure-ok mode, we can skip execution for this key if the node - // is green. It must have succeeded in the previous session, and - // therefore would succeed in the current session if executed. - EnsureCanSkip { skip_execution: true, dep_node: None } - } - EnsureMode::Done => { - // In ensure-done mode, we can only skip execution for this key if - // there's a disk-cached value available to load later if needed, - // which guarantees the query provider will never run for this key. - let is_loadable = (query.is_loadable_from_disk_fn)(tcx, key, serialized_dep_node_index); - EnsureCanSkip { skip_execution: is_loadable, dep_node: Some(dep_node) } + // In ensure-done mode, we can only skip execution for this key + // if there's a disk-cached value available to load later if + // needed, which guarantees the query provider will never run + // for this key. + EnsureMode::Done => { + (query.will_cache_on_disk_for_key_fn)(tcx, key) + && loadable_from_disk(tcx, serialized_dep_node_index) + } + } } } } @@ -671,8 +593,6 @@ pub(super) fn execute_query_non_incr_inner<'tcx, C: QueryCache>( span: Span, key: C::Key, ) -> C::Value { - debug_assert!(!tcx.dep_graph.is_fully_enabled()); - ensure_sufficient_stack(|| try_execute_query::(query, tcx, span, key, None).0) } @@ -686,48 +606,44 @@ pub(super) fn execute_query_incr_inner<'tcx, C: QueryCache>( key: C::Key, mode: QueryMode, ) -> Option { - debug_assert!(tcx.dep_graph.is_fully_enabled()); + let dep_node = DepNode::construct(tcx, query.dep_kind, &key); // Check if query execution can be skipped, for `ensure_ok` or `ensure_done`. - // This might have the side-effect of creating a suitable DepNode, which - // we should reuse for execution instead of creating a new one. - let dep_node: Option = match mode { - QueryMode::Ensure { ensure_mode } => { - let EnsureCanSkip { skip_execution, dep_node } = - check_if_ensure_can_skip_execution(query, tcx, key, ensure_mode); - if skip_execution { - // Return early to skip execution. - return None; - } - dep_node - } - QueryMode::Get => None, - }; + if let QueryMode::Ensure { ensure_mode } = mode + && ensure_can_skip_execution(query, tcx, key, dep_node, ensure_mode) + { + return None; + } - let (result, dep_node_index) = - ensure_sufficient_stack(|| try_execute_query::(query, tcx, span, key, dep_node)); + let (result, dep_node_index) = ensure_sufficient_stack(|| { + try_execute_query::(query, tcx, span, key, Some(dep_node)) + }); if let Some(dep_node_index) = dep_node_index { tcx.dep_graph.read_index(dep_node_index) } Some(result) } -pub(crate) fn force_query<'tcx, C: QueryCache>( - query: &'tcx QueryVTable<'tcx, C>, +/// Inner implementation of [`DepKindVTable::force_from_dep_node_fn`][force_fn] +/// for query nodes. +/// +/// [force_fn]: rustc_middle::dep_graph::DepKindVTable::force_from_dep_node_fn +pub(crate) fn force_query_dep_node<'tcx, C: QueryCache>( tcx: TyCtxt<'tcx>, - key: C::Key, + query: &'tcx QueryVTable<'tcx, C>, dep_node: DepNode, -) { - // We may be concurrently trying both execute and force a query. - // Ensure that only one of them runs the query. - if let Some((_, index)) = query.cache.lookup(&key) { - tcx.prof.query_cache_hit(index.into()); - return; - } - - debug_assert!(!query.anon); +) -> bool { + let Some(key) = C::Key::try_recover_key(tcx, &dep_node) else { + // We couldn't recover a key from the node's key fingerprint. + // Tell the caller that we couldn't force the node. + return false; + }; ensure_sufficient_stack(|| { try_execute_query::(query, tcx, DUMMY_SP, key, Some(dep_node)) }); + + // We did manage to recover a key and force the node, though it's up to + // the caller to check whether the node ended up marked red or green. + true } diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs deleted file mode 100644 index eb6942ba491f..000000000000 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ /dev/null @@ -1,407 +0,0 @@ -use std::collections::VecDeque; -use std::fmt::Write; -use std::ops::ControlFlow; - -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::codes::*; -use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_middle::dep_graph::DepKind; -use rustc_middle::query::CycleError; -use rustc_middle::query::plumbing::CyclePlaceholder; -use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; -use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::LocalDefId; -use rustc_span::{ErrorGuaranteed, Span}; - -use crate::job::report_cycle; - -pub(crate) trait FromCycleError<'tcx>: Sized { - /// Try to produce a `Self` value that represents an error form (e.g. `TyKind::Error`). - /// - /// Note: the default impl calls `raise_fatal`, ending compilation immediately! Only a few - /// types override this with a non-fatal impl. - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle_error: CycleError, guar: ErrorGuaranteed) -> Self; -} - -impl<'tcx, T> FromCycleError<'tcx> for T { - default fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle_error: CycleError, - _guar: ErrorGuaranteed, - ) -> T { - let Some(guar) = tcx.sess.dcx().has_errors() else { - bug!( - "<{} as FromCycleError>::from_cycle_error called without errors: {:#?}", - std::any::type_name::(), - cycle_error.cycle, - ); - }; - guar.raise_fatal(); - } -} - -impl<'tcx> FromCycleError<'tcx> for Ty<'_> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: CycleError, guar: ErrorGuaranteed) -> Self { - // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. - // FIXME: Represent the above fact in the trait system somehow. - unsafe { std::mem::transmute::, Ty<'_>>(Ty::new_error(tcx, guar)) } - } -} - -impl<'tcx> FromCycleError<'tcx> for Result>, CyclePlaceholder> { - fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: CycleError, guar: ErrorGuaranteed) -> Self { - Err(CyclePlaceholder(guar)) - } -} - -impl<'tcx> FromCycleError<'tcx> for ty::Binder<'_, ty::FnSig<'_>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle_error: CycleError, guar: ErrorGuaranteed) -> Self { - let err = Ty::new_error(tcx, guar); - - let arity = if let Some(info) = cycle_error.cycle.get(0) - && info.frame.dep_kind == DepKind::fn_sig - && let Some(def_id) = info.frame.def_id - && let Some(node) = tcx.hir_get_if_local(def_id) - && let Some(sig) = node.fn_sig() - { - sig.decl.inputs.len() - } else { - tcx.dcx().abort_if_errors(); - unreachable!() - }; - - let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig( - std::iter::repeat_n(err, arity), - err, - false, - rustc_hir::Safety::Safe, - rustc_abi::ExternAbi::Rust, - )); - - // SAFETY: This is never called when `Self` is not `ty::Binder<'tcx, ty::FnSig<'tcx>>`. - // FIXME: Represent the above fact in the trait system somehow. - unsafe { std::mem::transmute::, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) } - } -} - -impl<'tcx> FromCycleError<'tcx> for Representability { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle_error: CycleError, - _guar: ErrorGuaranteed, - ) -> Self { - let mut item_and_field_ids = Vec::new(); - let mut representable_ids = FxHashSet::default(); - for info in &cycle_error.cycle { - if info.frame.dep_kind == DepKind::check_representability - && let Some(field_id) = info.frame.def_id - && let Some(field_id) = field_id.as_local() - && let Some(DefKind::Field) = info.frame.info.def_kind - { - let parent_id = tcx.parent(field_id.to_def_id()); - let item_id = match tcx.def_kind(parent_id) { - DefKind::Variant => tcx.parent(parent_id), - _ => parent_id, - }; - item_and_field_ids.push((item_id.expect_local(), field_id)); - } - } - for info in &cycle_error.cycle { - if info.frame.dep_kind == DepKind::check_representability_adt_ty - && let Some(def_id) = info.frame.def_id_for_ty_in_cycle - && let Some(def_id) = def_id.as_local() - && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) - { - representable_ids.insert(def_id); - } - } - // We used to continue here, but the cycle error printed next is actually less useful than - // the error produced by `recursive_type_error`. - let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids); - guar.raise_fatal(); - } -} - -impl<'tcx> FromCycleError<'tcx> for ty::EarlyBinder<'_, Ty<'_>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle_error: CycleError, guar: ErrorGuaranteed) -> Self { - ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle_error, guar)) - } -} - -impl<'tcx> FromCycleError<'tcx> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig<'_>>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle_error: CycleError, guar: ErrorGuaranteed) -> Self { - ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle_error, guar)) - } -} - -impl<'tcx> FromCycleError<'tcx> for &[ty::Variance] { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle_error: CycleError, - _guar: ErrorGuaranteed, - ) -> Self { - search_for_cycle_permutation( - &cycle_error.cycle, - |cycle| { - if let Some(info) = cycle.get(0) - && info.frame.dep_kind == DepKind::variances_of - && let Some(def_id) = info.frame.def_id - { - let n = tcx.generics_of(def_id).own_params.len(); - ControlFlow::Break(vec![ty::Bivariant; n].leak()) - } else { - ControlFlow::Continue(()) - } - }, - || { - span_bug!( - cycle_error.usage.as_ref().unwrap().0, - "only `variances_of` returns `&[ty::Variance]`" - ) - }, - ) - } -} - -// Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`. -fn search_for_cycle_permutation( - cycle: &[Q], - try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow, - otherwise: impl FnOnce() -> T, -) -> T { - let mut cycle: VecDeque<_> = cycle.iter().collect(); - for _ in 0..cycle.len() { - match try_cycle(&mut cycle) { - ControlFlow::Continue(_) => { - cycle.rotate_left(1); - } - ControlFlow::Break(t) => return t, - } - } - - otherwise() -} - -impl<'tcx, T> FromCycleError<'tcx> for Result> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle_error: CycleError, - _guar: ErrorGuaranteed, - ) -> Self { - let diag = search_for_cycle_permutation( - &cycle_error.cycle, - |cycle| { - if cycle[0].frame.dep_kind == DepKind::layout_of - && let Some(def_id) = cycle[0].frame.def_id_for_ty_in_cycle - && let Some(def_id) = def_id.as_local() - && let def_kind = tcx.def_kind(def_id) - && matches!(def_kind, DefKind::Closure) - && let Some(coroutine_kind) = tcx.coroutine_kind(def_id) - { - // FIXME: `def_span` for an fn-like coroutine will point to the fn's body - // due to interactions between the desugaring into a closure expr and the - // def_span code. I'm not motivated to fix it, because I tried and it was - // not working, so just hack around it by grabbing the parent fn's span. - let span = if coroutine_kind.is_fn_like() { - tcx.def_span(tcx.local_parent(def_id)) - } else { - tcx.def_span(def_id) - }; - let mut diag = struct_span_code_err!( - tcx.sess.dcx(), - span, - E0733, - "recursion in {} {} requires boxing", - tcx.def_kind_descr_article(def_kind, def_id.to_def_id()), - tcx.def_kind_descr(def_kind, def_id.to_def_id()), - ); - for (i, info) in cycle.iter().enumerate() { - if info.frame.dep_kind != DepKind::layout_of { - continue; - } - let Some(frame_def_id) = info.frame.def_id_for_ty_in_cycle else { - continue; - }; - let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else { - continue; - }; - let frame_span = - info.frame.info.default_span(cycle[(i + 1) % cycle.len()].span); - if frame_span.is_dummy() { - continue; - } - if i == 0 { - diag.span_label(frame_span, "recursive call here"); - } else { - let coroutine_span: Span = if frame_coroutine_kind.is_fn_like() { - tcx.def_span(tcx.parent(frame_def_id)) - } else { - tcx.def_span(frame_def_id) - }; - let mut multispan = MultiSpan::from_span(coroutine_span); - multispan - .push_span_label(frame_span, "...leading to this recursive call"); - diag.span_note( - multispan, - format!("which leads to this {}", tcx.def_descr(frame_def_id)), - ); - } - } - // FIXME: We could report a structured suggestion if we had - // enough info here... Maybe we can use a hacky HIR walker. - if matches!( - coroutine_kind, - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) - ) { - diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future"); - } - - ControlFlow::Break(diag) - } else { - ControlFlow::Continue(()) - } - }, - || report_cycle(tcx.sess, &cycle_error), - ); - - let guar = diag.emit(); - - // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under - // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, - // tcx.arena.alloc is pretty much equal to leaking). - Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle(guar)))) - } -} - -// item_and_field_ids should form a cycle where each field contains the -// type in the next element in the list -fn recursive_type_error( - tcx: TyCtxt<'_>, - mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>, - representable_ids: &FxHashSet, -) -> ErrorGuaranteed { - const ITEM_LIMIT: usize = 5; - - // Rotate the cycle so that the item with the lowest span is first - let start_index = item_and_field_ids - .iter() - .enumerate() - .min_by_key(|&(_, &(id, _))| tcx.def_span(id)) - .unwrap() - .0; - item_and_field_ids.rotate_left(start_index); - - let cycle_len = item_and_field_ids.len(); - let show_cycle_len = cycle_len.min(ITEM_LIMIT); - - let mut err_span = MultiSpan::from_spans( - item_and_field_ids[..show_cycle_len] - .iter() - .map(|(id, _)| tcx.def_span(id.to_def_id())) - .collect(), - ); - let mut suggestion = Vec::with_capacity(show_cycle_len * 2); - for i in 0..show_cycle_len { - let (_, field_id) = item_and_field_ids[i]; - let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len]; - // Find the span(s) that contain the next item in the cycle - let hir::Node::Field(field) = tcx.hir_node_by_def_id(field_id) else { - bug!("expected field") - }; - let mut found = Vec::new(); - find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids); - - // Couldn't find the type. Maybe it's behind a type alias? - // In any case, we'll just suggest boxing the whole field. - if found.is_empty() { - found.push(field.ty.span); - } - - for span in found { - err_span.push_span_label(span, "recursive without indirection"); - // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed - suggestion.push((span.shrink_to_lo(), "Box<".to_string())); - suggestion.push((span.shrink_to_hi(), ">".to_string())); - } - } - let items_list = { - let mut s = String::new(); - for (i, &(item_id, _)) in item_and_field_ids.iter().enumerate() { - let path = tcx.def_path_str(item_id); - write!(&mut s, "`{path}`").unwrap(); - if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT { - write!(&mut s, " and {} more", cycle_len - 5).unwrap(); - break; - } - if cycle_len > 1 && i < cycle_len - 2 { - s.push_str(", "); - } else if cycle_len > 1 && i == cycle_len - 2 { - s.push_str(" and ") - } - } - s - }; - struct_span_code_err!( - tcx.dcx(), - err_span, - E0072, - "recursive type{} {} {} infinite size", - pluralize!(cycle_len), - items_list, - pluralize!("has", cycle_len), - ) - .with_multipart_suggestion( - "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle", - suggestion, - Applicability::HasPlaceholders, - ) - .emit() -} - -fn find_item_ty_spans( - tcx: TyCtxt<'_>, - ty: &hir::Ty<'_>, - needle: LocalDefId, - spans: &mut Vec, - seen_representable: &FxHashSet, -) { - match ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { - if let Res::Def(kind, def_id) = path.res - && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union) - { - let check_params = def_id.as_local().is_none_or(|def_id| { - if def_id == needle { - spans.push(ty.span); - } - seen_representable.contains(&def_id) - }); - if check_params && let Some(args) = path.segments.last().unwrap().args { - let params_in_repr = tcx.params_in_repr(def_id); - // the domain size check is needed because the HIR may not be well-formed at this point - for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size()) - { - if let hir::GenericArg::Type(ty) = arg - && params_in_repr.contains(i as u32) - { - find_item_ty_spans( - tcx, - ty.as_unambig_ty(), - needle, - spans, - seen_representable, - ); - } - } - } - } - } - hir::TyKind::Array(ty, _) => find_item_ty_spans(tcx, ty, needle, spans, seen_representable), - hir::TyKind::Tup(tys) => { - tys.iter().for_each(|ty| find_item_ty_spans(tcx, ty, needle, spans, seen_representable)) - } - _ => {} - } -} diff --git a/compiler/rustc_query_impl/src/handle_cycle_error.rs b/compiler/rustc_query_impl/src/handle_cycle_error.rs new file mode 100644 index 000000000000..5676669bf1c0 --- /dev/null +++ b/compiler/rustc_query_impl/src/handle_cycle_error.rs @@ -0,0 +1,339 @@ +use std::collections::VecDeque; +use std::fmt::Write; +use std::iter; +use std::ops::ControlFlow; + +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::codes::*; +use rustc_errors::{Applicability, Diag, MultiSpan, pluralize, struct_span_code_err}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_middle::bug; +use rustc_middle::queries::{QueryVTables, TaggedQueryKey}; +use rustc_middle::query::Cycle; +use rustc_middle::query::erase::erase_val; +use rustc_middle::ty::layout::LayoutError; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::{ErrorGuaranteed, Span}; + +use crate::job::create_cycle_error; + +pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) { + vtables.fn_sig.handle_cycle_error_fn = |tcx, key, _, err| { + let guar = err.delay_as_bug(); + erase_val(fn_sig(tcx, key, guar)) + }; + + vtables.check_representability.handle_cycle_error_fn = + |tcx, _, cycle, _err| check_representability(tcx, cycle); + + vtables.check_representability_adt_ty.handle_cycle_error_fn = + |tcx, _, cycle, _err| check_representability(tcx, cycle); + + vtables.variances_of.handle_cycle_error_fn = |tcx, key, _, err| { + let _guar = err.delay_as_bug(); + erase_val(variances_of(tcx, key)) + }; + + vtables.layout_of.handle_cycle_error_fn = |tcx, _, cycle, err| { + let _guar = err.delay_as_bug(); + erase_val(Err(layout_of(tcx, cycle))) + } +} + +pub(crate) fn default(err: Diag<'_>) -> ! { + let guar = err.emit(); + guar.raise_fatal() +} + +fn fn_sig<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + guar: ErrorGuaranteed, +) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { + let err = Ty::new_error(tcx, guar); + + let arity = if let Some(node) = tcx.hir_get_if_local(def_id) + && let Some(sig) = node.fn_sig() + { + sig.decl.inputs.len() + } else { + tcx.dcx().abort_if_errors(); + unreachable!() + }; + + ty::EarlyBinder::bind(ty::Binder::dummy(tcx.mk_fn_sig( + std::iter::repeat_n(err, arity), + err, + false, + rustc_hir::Safety::Safe, + rustc_abi::ExternAbi::Rust, + ))) +} + +fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! { + let mut item_and_field_ids = Vec::new(); + let mut representable_ids = FxHashSet::default(); + for frame in &cycle.frames { + if let TaggedQueryKey::check_representability(def_id) = frame.tagged_key + && tcx.def_kind(def_id) == DefKind::Field + { + let field_id: LocalDefId = def_id; + let parent_id = tcx.parent(field_id.to_def_id()); + let item_id = match tcx.def_kind(parent_id) { + DefKind::Variant => tcx.parent(parent_id), + _ => parent_id, + }; + item_and_field_ids.push((item_id.expect_local(), field_id)); + } + } + for frame in &cycle.frames { + if let TaggedQueryKey::check_representability_adt_ty(key) = frame.tagged_key + && let Some(adt) = key.ty_adt_def() + && let Some(def_id) = adt.did().as_local() + && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) + { + representable_ids.insert(def_id); + } + } + // We used to continue here, but the cycle error printed next is actually less useful than + // the error produced by `recursive_type_error`. + let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids); + guar.raise_fatal() +} + +fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [ty::Variance] { + let n = tcx.generics_of(def_id).own_params.len(); + tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n)) +} + +// Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`. +fn search_for_cycle_permutation( + cycle: &[Q], + try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow, + otherwise: impl FnOnce() -> T, +) -> T { + let mut cycle: VecDeque<_> = cycle.iter().collect(); + for _ in 0..cycle.len() { + match try_cycle(&mut cycle) { + ControlFlow::Continue(_) => { + cycle.rotate_left(1); + } + ControlFlow::Break(t) => return t, + } + } + + otherwise() +} + +fn layout_of<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> &'tcx ty::layout::LayoutError<'tcx> { + let diag = search_for_cycle_permutation( + &cycle.frames, + |frames| { + if let TaggedQueryKey::layout_of(key) = frames[0].tagged_key + && let ty::Coroutine(def_id, _) = key.value.kind() + && let Some(def_id) = def_id.as_local() + && let def_kind = tcx.def_kind(def_id) + && matches!(def_kind, DefKind::Closure) + && let Some(coroutine_kind) = tcx.coroutine_kind(def_id) + { + // FIXME: `def_span` for an fn-like coroutine will point to the fn's body + // due to interactions between the desugaring into a closure expr and the + // def_span code. I'm not motivated to fix it, because I tried and it was + // not working, so just hack around it by grabbing the parent fn's span. + let span = if coroutine_kind.is_fn_like() { + tcx.def_span(tcx.local_parent(def_id)) + } else { + tcx.def_span(def_id) + }; + let mut diag = struct_span_code_err!( + tcx.sess.dcx(), + span, + E0733, + "recursion in {} {} requires boxing", + tcx.def_kind_descr_article(def_kind, def_id.to_def_id()), + tcx.def_kind_descr(def_kind, def_id.to_def_id()), + ); + for (i, frame) in frames.iter().enumerate() { + let TaggedQueryKey::layout_of(frame_key) = frame.tagged_key else { + continue; + }; + let &ty::Coroutine(frame_def_id, _) = frame_key.value.kind() else { + continue; + }; + let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else { + continue; + }; + let frame_span = + frame.tagged_key.default_span(tcx, frames[(i + 1) % frames.len()].span); + if frame_span.is_dummy() { + continue; + } + if i == 0 { + diag.span_label(frame_span, "recursive call here"); + } else { + let coroutine_span: Span = if frame_coroutine_kind.is_fn_like() { + tcx.def_span(tcx.parent(frame_def_id)) + } else { + tcx.def_span(frame_def_id) + }; + let mut multispan = MultiSpan::from_span(coroutine_span); + multispan.push_span_label(frame_span, "...leading to this recursive call"); + diag.span_note( + multispan, + format!("which leads to this {}", tcx.def_descr(frame_def_id)), + ); + } + } + // FIXME: We could report a structured suggestion if we had + // enough info here... Maybe we can use a hacky HIR walker. + if matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + ) { + diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future"); + } + + ControlFlow::Break(diag) + } else { + ControlFlow::Continue(()) + } + }, + || create_cycle_error(tcx, &cycle), + ); + + let guar = diag.emit(); + tcx.arena.alloc(LayoutError::Cycle(guar)) +} + +// item_and_field_ids should form a cycle where each field contains the +// type in the next element in the list +fn recursive_type_error( + tcx: TyCtxt<'_>, + mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>, + representable_ids: &FxHashSet, +) -> ErrorGuaranteed { + const ITEM_LIMIT: usize = 5; + + // Rotate the cycle so that the item with the lowest span is first + let start_index = item_and_field_ids + .iter() + .enumerate() + .min_by_key(|&(_, &(id, _))| tcx.def_span(id)) + .unwrap() + .0; + item_and_field_ids.rotate_left(start_index); + + let cycle_len = item_and_field_ids.len(); + let show_cycle_len = cycle_len.min(ITEM_LIMIT); + + let mut err_span = MultiSpan::from_spans( + item_and_field_ids[..show_cycle_len] + .iter() + .map(|(id, _)| tcx.def_span(id.to_def_id())) + .collect(), + ); + let mut suggestion = Vec::with_capacity(show_cycle_len * 2); + for i in 0..show_cycle_len { + let (_, field_id) = item_and_field_ids[i]; + let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len]; + // Find the span(s) that contain the next item in the cycle + let hir::Node::Field(field) = tcx.hir_node_by_def_id(field_id) else { + bug!("expected field") + }; + let mut found = Vec::new(); + find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids); + + // Couldn't find the type. Maybe it's behind a type alias? + // In any case, we'll just suggest boxing the whole field. + if found.is_empty() { + found.push(field.ty.span); + } + + for span in found { + err_span.push_span_label(span, "recursive without indirection"); + // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed + suggestion.push((span.shrink_to_lo(), "Box<".to_string())); + suggestion.push((span.shrink_to_hi(), ">".to_string())); + } + } + let items_list = { + let mut s = String::new(); + for (i, &(item_id, _)) in item_and_field_ids.iter().enumerate() { + let path = tcx.def_path_str(item_id); + write!(&mut s, "`{path}`").unwrap(); + if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT { + write!(&mut s, " and {} more", cycle_len - 5).unwrap(); + break; + } + if cycle_len > 1 && i < cycle_len - 2 { + s.push_str(", "); + } else if cycle_len > 1 && i == cycle_len - 2 { + s.push_str(" and ") + } + } + s + }; + struct_span_code_err!( + tcx.dcx(), + err_span, + E0072, + "recursive type{} {} {} infinite size", + pluralize!(cycle_len), + items_list, + pluralize!("has", cycle_len), + ) + .with_multipart_suggestion( + "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle", + suggestion, + Applicability::HasPlaceholders, + ) + .emit() +} + +fn find_item_ty_spans( + tcx: TyCtxt<'_>, + ty: &hir::Ty<'_>, + needle: LocalDefId, + spans: &mut Vec, + seen_representable: &FxHashSet, +) { + match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { + if let Res::Def(kind, def_id) = path.res + && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union) + { + let check_params = def_id.as_local().is_none_or(|def_id| { + if def_id == needle { + spans.push(ty.span); + } + seen_representable.contains(&def_id) + }); + if check_params && let Some(args) = path.segments.last().unwrap().args { + let params_in_repr = tcx.params_in_repr(def_id); + // the domain size check is needed because the HIR may not be well-formed at this point + for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size()) + { + if let hir::GenericArg::Type(ty) = arg + && params_in_repr.contains(i as u32) + { + find_item_ty_spans( + tcx, + ty.as_unambig_ty(), + needle, + spans, + seen_representable, + ); + } + } + } + } + } + hir::TyKind::Array(ty, _) => find_item_ty_spans(tcx, ty, needle, spans, seen_representable), + hir::TyKind::Tup(tys) => { + tys.iter().for_each(|ty| find_item_ty_spans(tcx, ty, needle, spans, seen_representable)) + } + _ => {} + } +} diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs index 2a7f7bf5efd4..a27a6f4ea322 100644 --- a/compiler/rustc_query_impl/src/job.rs +++ b/compiler/rustc_query_impl/src/job.rs @@ -1,23 +1,20 @@ use std::io::Write; -use std::iter; use std::ops::ControlFlow; use std::sync::Arc; +use std::{iter, mem}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::def::DefKind; -use rustc_middle::query::{ - CycleError, QueryInfo, QueryJob, QueryJobId, QueryLatch, QueryStackDeferred, QueryStackFrame, - QueryWaiter, -}; +use rustc_middle::queries::TaggedQueryKey; +use rustc_middle::query::{Cycle, QueryJob, QueryJobId, QueryLatch, QueryStackFrame, QueryWaiter}; use rustc_middle::ty::TyCtxt; -use rustc_session::Session; use rustc_span::{DUMMY_SP, Span}; -use crate::collect_active_jobs_from_all_queries; +use crate::{CollectActiveJobsKind, collect_active_query_jobs}; /// Map from query job IDs to job information collected by -/// `collect_active_jobs_from_all_queries`. +/// `collect_active_query_jobs`. #[derive(Debug, Default)] pub struct QueryJobMap<'tcx> { map: FxHashMap>, @@ -26,13 +23,13 @@ pub struct QueryJobMap<'tcx> { impl<'tcx> QueryJobMap<'tcx> { /// Adds information about a job ID to the job map. /// - /// Should only be called by `gather_active_jobs`. + /// Should only be called by `collect_active_query_jobs_inner`. pub(crate) fn insert(&mut self, id: QueryJobId, info: QueryJobInfo<'tcx>) { self.map.insert(id, info); } - fn frame_of(&self, id: QueryJobId) -> &QueryStackFrame> { - &self.map[&id].frame + fn tagged_key_of(&self, id: QueryJobId) -> TaggedQueryKey<'tcx> { + self.map[&id].tagged_key } fn span_of(&self, id: QueryJobId) -> Span { @@ -48,9 +45,9 @@ fn latch_of(&self, id: QueryJobId) -> Option<&QueryLatch<'tcx>> { } } -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct QueryJobInfo<'tcx> { - pub(crate) frame: QueryStackFrame>, + pub(crate) tagged_key: TaggedQueryKey<'tcx>, pub(crate) job: QueryJob<'tcx>, } @@ -59,29 +56,28 @@ pub(crate) fn find_cycle_in_stack<'tcx>( job_map: QueryJobMap<'tcx>, current_job: &Option, span: Span, -) -> CycleError> { - // Find the waitee amongst `current_job` parents - let mut cycle = Vec::new(); +) -> Cycle<'tcx> { + // Find the waitee amongst `current_job` parents. + let mut frames = Vec::new(); let mut current_job = Option::clone(current_job); while let Some(job) = current_job { let info = &job_map.map[&job]; - cycle.push(QueryInfo { span: info.job.span, frame: info.frame.clone() }); + frames.push(QueryStackFrame { span: info.job.span, tagged_key: info.tagged_key }); if job == id { - cycle.reverse(); + frames.reverse(); - // This is the end of the cycle - // The span entry we included was for the usage - // of the cycle itself, and not part of the cycle - // Replace it with the span which caused the cycle to form - cycle[0].span = span; - // Find out why the cycle itself was used + // This is the end of the cycle. The span entry we included was for + // the usage of the cycle itself, and not part of the cycle. + // Replace it with the span which caused the cycle to form. + frames[0].span = span; + // Find out why the cycle itself was used. let usage = try { let parent = info.job.parent?; - (info.job.span, job_map.frame_of(parent).clone()) + QueryStackFrame { span: info.job.span, tagged_key: job_map.tagged_key_of(parent) } }; - return CycleError { usage, cycle }; + return Cycle { usage, frames }; } current_job = info.job.parent; @@ -90,80 +86,89 @@ pub(crate) fn find_cycle_in_stack<'tcx>( panic!("did not find a cycle") } +/// Finds the query job closest to the root that is for the same query method as `id` +/// (but not necessarily the same query key), and returns information about it. #[cold] #[inline(never)] pub(crate) fn find_dep_kind_root<'tcx>( + tcx: TyCtxt<'tcx>, id: QueryJobId, job_map: QueryJobMap<'tcx>, -) -> (QueryJobInfo<'tcx>, usize) { +) -> (Span, String, usize) { let mut depth = 1; - let info = &job_map.map[&id]; - let dep_kind = info.frame.dep_kind; - let mut current_id = info.job.parent; - let mut last_layout = (info.clone(), depth); + let mut info = &job_map.map[&id]; + // Two query jobs are for the same query method if they have the same + // `TaggedQueryKey` discriminant. + let expected_query = mem::discriminant::>(&info.tagged_key); + let mut last_info = info; - while let Some(id) = current_id { - let info = &job_map.map[&id]; - if info.frame.dep_kind == dep_kind { + while let Some(id) = info.job.parent { + info = &job_map.map[&id]; + if mem::discriminant(&info.tagged_key) == expected_query { depth += 1; - last_layout = (info.clone(), depth); + last_info = info; } - current_id = info.job.parent; } - last_layout + (last_info.job.span, last_info.tagged_key.description(tcx), depth) } -/// A resumable waiter of a query. The usize is the index into waiters in the query's latch -type Waiter = (QueryJobId, usize); +/// The locaton of a resumable waiter. The usize is the index into waiters in the query's latch. +/// We'll use this to remove the waiter using `QueryLatch::extract_waiter` if we're waking it up. +type ResumableWaiterLocation = (QueryJobId, usize); -/// Visits all the non-resumable and resumable waiters of a query. -/// Only waiters in a query are visited. -/// `visit` is called for every waiter and is passed a query waiting on `query` -/// and a span indicating the reason the query waited on `query`. -/// If `visit` returns `Break`, this function also returns `Break`, -/// and if all `visit` calls returns `Continue` it also returns `Continue`. -/// For visits of non-resumable waiters it returns the return value of `visit`. -/// For visits of resumable waiters it returns information required to resume that waiter. -fn visit_waiters<'tcx>( - job_map: &QueryJobMap<'tcx>, - query: QueryJobId, - mut visit: impl FnMut(Span, QueryJobId) -> ControlFlow>, -) -> ControlFlow> { - // Visit the parent query which is a non-resumable waiter since it's on the same stack - if let Some(parent) = job_map.parent_of(query) { - visit(job_map.span_of(query), parent)?; - } +/// This abstracts over non-resumable waiters which are found in `QueryJob`'s `parent` field +/// and resumable waiters are in `latch` field. +struct AbstractedWaiter { + /// The span corresponding to the reason for why we're waiting on this query. + span: Span, + /// The query which we are waiting from, if none the waiter is from a compiler root. + parent: Option, + resumable: Option, +} - // Visit the explicit waiters which use condvars and are resumable +/// Returns all the non-resumable and resumable waiters of a query. +/// This is used so we can uniformly loop over both non-resumable and resumable waiters. +fn abstracted_waiters_of(job_map: &QueryJobMap<'_>, query: QueryJobId) -> Vec { + let mut result = Vec::new(); + + // Add the parent which is a non-resumable waiter since it's on the same stack + result.push(AbstractedWaiter { + span: job_map.span_of(query), + parent: job_map.parent_of(query), + resumable: None, + }); + + // Add the explicit waiters which use condvars and are resumable if let Some(latch) = job_map.latch_of(query) { - for (i, waiter) in latch.info.lock().waiters.iter().enumerate() { - if let Some(waiter_query) = waiter.query { - // Return a value which indicates that this waiter can be resumed - visit(waiter.span, waiter_query).map_break(|_| Some((query, i)))?; - } + for (i, waiter) in latch.waiters.lock().as_ref().unwrap().iter().enumerate() { + result.push(AbstractedWaiter { + span: waiter.span, + parent: waiter.parent, + resumable: Some((query, i)), + }); } } - ControlFlow::Continue(()) + result } -/// Look for query cycles by doing a depth first search starting at `query`. +/// Looks for a query cycle by doing a depth first search starting at `query`. /// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. /// If a cycle is detected, this initial value is replaced with the span causing -/// the cycle. -fn cycle_check<'tcx>( +/// the cycle. `stack` will contain just the cycle on return if detected. +fn find_cycle<'tcx>( job_map: &QueryJobMap<'tcx>, query: QueryJobId, span: Span, stack: &mut Vec<(Span, QueryJobId)>, visited: &mut FxHashSet, -) -> ControlFlow> { +) -> ControlFlow> { if !visited.insert(query) { - return if let Some(p) = stack.iter().position(|q| q.1 == query) { + return if let Some(pos) = stack.iter().position(|q| q.1 == query) { // We detected a query cycle, fix up the initial span and return Some // Remove previous stack entries - stack.drain(0..p); + stack.drain(0..pos); // Replace the span for the first query with the cycle cause stack[0].0 = span; ControlFlow::Break(None) @@ -176,16 +181,23 @@ fn cycle_check<'tcx>( stack.push((span, query)); // Visit all the waiters - let r = visit_waiters(job_map, query, |span, successor| { - cycle_check(job_map, successor, span, stack, visited) - }); - - // Remove the entry in our stack if we didn't find a cycle - if r.is_continue() { - stack.pop(); + for abstracted_waiter in abstracted_waiters_of(job_map, query) { + let Some(parent) = abstracted_waiter.parent else { + // Skip waiters which are not queries + continue; + }; + if let ControlFlow::Break(maybe_resumable) = + find_cycle(job_map, parent, abstracted_waiter.span, stack, visited) + { + // Return the resumable waiter in `waiter.resumable` if present + return ControlFlow::Break(abstracted_waiter.resumable.or(maybe_resumable)); + } } - r + // Remove the entry in our stack since we didn't find a cycle + stack.pop(); + + ControlFlow::Continue(()) } /// Finds out if there's a path to the compiler root (aka. code which isn't in a query) @@ -195,21 +207,29 @@ fn connected_to_root<'tcx>( job_map: &QueryJobMap<'tcx>, query: QueryJobId, visited: &mut FxHashSet, -) -> ControlFlow> { +) -> bool { // We already visited this or we're deliberately ignoring it if !visited.insert(query) { - return ControlFlow::Continue(()); + return false; } - // This query is connected to the root (it has no query parent), return true - if job_map.parent_of(query).is_none() { - return ControlFlow::Break(None); + // Visit all the waiters + for abstracted_waiter in abstracted_waiters_of(job_map, query) { + match abstracted_waiter.parent { + // This query is connected to the root + None => return true, + Some(parent) => { + if connected_to_root(job_map, parent, visited) { + return true; + } + } + } } - visit_waiters(job_map, query, |_, successor| connected_to_root(job_map, successor, visited)) + false } -/// Looks for query cycles starting from the last query in `jobs`. +/// Looks for a query cycle using the last query in `jobs`. /// If a cycle is found, all queries in the cycle is removed from `jobs` and /// the function return true. /// If a cycle was not found, the starting query is removed from `jobs` and @@ -222,8 +242,8 @@ fn remove_cycle<'tcx>( let mut visited = FxHashSet::default(); let mut stack = Vec::new(); // Look for a cycle starting with the last query in `jobs` - if let ControlFlow::Break(waiter) = - cycle_check(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited) + if let ControlFlow::Break(resumable) = + find_cycle(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited) { // The stack is a vector of pairs of spans and queries; reverse it so that // the earlier entries require later entries @@ -244,7 +264,7 @@ fn remove_cycle<'tcx>( struct EntryPoint { query_in_cycle: QueryJobId, - waiter: Option<(Span, QueryJobId)>, + query_waiting_on_cycle: Option<(Span, QueryJobId)>, } // Find the queries in the cycle which are @@ -252,36 +272,36 @@ struct EntryPoint { let entry_points = stack .iter() .filter_map(|&(_, query_in_cycle)| { - if job_map.parent_of(query_in_cycle).is_none() { - // This query is connected to the root (it has no query parent) - Some(EntryPoint { query_in_cycle, waiter: None }) - } else { - let mut waiter_on_cycle = None; - // Find a direct waiter who leads to the root - let _ = visit_waiters(job_map, query_in_cycle, |span, waiter| { - // Mark all the other queries in the cycle as already visited - let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1)); + let mut entrypoint = false; + let mut query_waiting_on_cycle = None; - if connected_to_root(job_map, waiter, &mut visited).is_break() { - waiter_on_cycle = Some((span, waiter)); - ControlFlow::Break(None) - } else { - ControlFlow::Continue(()) - } - }); + // Find a direct waiter who leads to the root + for abstracted_waiter in abstracted_waiters_of(job_map, query_in_cycle) { + let Some(parent) = abstracted_waiter.parent else { + // The query in the cycle is directly connected to root. + entrypoint = true; + continue; + }; - waiter_on_cycle.map(|waiter_on_cycle| EntryPoint { - query_in_cycle, - waiter: Some(waiter_on_cycle), - }) + // Mark all the other queries in the cycle as already visited, + // so paths to the root through the cycle itself won't count. + let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1)); + + if connected_to_root(job_map, parent, &mut visited) { + query_waiting_on_cycle = Some((abstracted_waiter.span, parent)); + entrypoint = true; + break; + } } + + entrypoint.then_some(EntryPoint { query_in_cycle, query_waiting_on_cycle }) }) .collect::>(); // Pick an entry point, preferring ones with waiters let entry_point = entry_points .iter() - .find(|entry_point| entry_point.waiter.is_some()) + .find(|entry_point| entry_point.query_waiting_on_cycle.is_some()) .unwrap_or(&entry_points[0]); // Shift the stack so that our entry point is first @@ -291,20 +311,25 @@ struct EntryPoint { stack.rotate_left(pos); } - let usage = entry_point.waiter.map(|(span, job)| (span, job_map.frame_of(job).clone())); + let usage = entry_point + .query_waiting_on_cycle + .map(|(span, job)| QueryStackFrame { span, tagged_key: job_map.tagged_key_of(job) }); // Create the cycle error - let error = CycleError { + let error = Cycle { usage, - cycle: stack + frames: stack .iter() - .map(|&(span, job)| QueryInfo { span, frame: job_map.frame_of(job).clone() }) + .map(|&(span, job)| QueryStackFrame { + span, + tagged_key: job_map.tagged_key_of(job), + }) .collect(), }; - // We unwrap `waiter` here since there must always be one + // We unwrap `resumable` here since there must always be one // edge which is resumable / waited using a query latch - let (waitee_query, waiter_idx) = waiter.unwrap(); + let (waitee_query, waiter_idx) = resumable.unwrap(); // Extract the waiter we want to resume let waiter = job_map.latch_of(waitee_query).unwrap().extract_waiter(waiter_idx); @@ -385,8 +410,7 @@ pub fn print_query_stack<'tcx>( let mut count_total = 0; // Make use of a partial query job map if we fail to take locks collecting active queries. - let job_map: QueryJobMap<'_> = collect_active_jobs_from_all_queries(tcx, false) - .unwrap_or_else(|partial_job_map| partial_job_map); + let job_map = collect_active_query_jobs(tcx, CollectActiveJobsKind::PartialAllowed); if let Some(ref mut file) = file { let _ = writeln!(file, "\n\nquery stack during panic:"); @@ -395,12 +419,12 @@ pub fn print_query_stack<'tcx>( let Some(query_info) = job_map.map.get(&query) else { break; }; - let query_extra = query_info.frame.info.extract(); + let description = query_info.tagged_key.description(tcx); if Some(count_printed) < limit_frames || limit_frames.is_none() { // Only print to stderr as many stack frames as `num_frames` when present. dcx.struct_failure_note(format!( - "#{} [{:?}] {}", - count_printed, query_info.frame.dep_kind, query_extra.description + "#{count_printed} [{query_name}] {description}", + query_name = query_info.tagged_key.query_name(), )) .with_span(query_info.job.span) .emit(); @@ -410,8 +434,8 @@ pub fn print_query_stack<'tcx>( if let Some(ref mut file) = file { let _ = writeln!( file, - "#{} [{:?}] {}", - count_total, query_info.frame.dep_kind, query_extra.description + "#{count_total} [{query_name}] {description}", + query_name = query_info.tagged_key.query_name(), ); } @@ -427,47 +451,47 @@ pub fn print_query_stack<'tcx>( #[inline(never)] #[cold] -pub(crate) fn report_cycle<'a>( - sess: &'a Session, - CycleError { usage, cycle: stack }: &CycleError, -) -> Diag<'a> { - assert!(!stack.is_empty()); +pub(crate) fn create_cycle_error<'tcx>( + tcx: TyCtxt<'tcx>, + Cycle { usage, frames }: &Cycle<'tcx>, +) -> Diag<'tcx> { + assert!(!frames.is_empty()); - let span = stack[0].frame.info.default_span(stack[1 % stack.len()].span); + let span = frames[0].tagged_key.default_span(tcx, frames[1 % frames.len()].span); let mut cycle_stack = Vec::new(); use crate::error::StackCount; - let stack_bottom = stack[0].frame.info.description.to_owned(); - let stack_count = if stack.len() == 1 { + let stack_bottom = frames[0].tagged_key.description(tcx); + let stack_count = if frames.len() == 1 { StackCount::Single { stack_bottom: stack_bottom.clone() } } else { StackCount::Multiple { stack_bottom: stack_bottom.clone() } }; - for i in 1..stack.len() { - let frame = &stack[i].frame; - let span = frame.info.default_span(stack[(i + 1) % stack.len()].span); + for i in 1..frames.len() { + let frame = &frames[i]; + let span = frame.tagged_key.default_span(tcx, frames[(i + 1) % frames.len()].span); cycle_stack - .push(crate::error::CycleStack { span, desc: frame.info.description.to_owned() }); + .push(crate::error::CycleStack { span, desc: frame.tagged_key.description(tcx) }); } - let mut cycle_usage = None; - if let Some((span, ref query)) = *usage { - cycle_usage = Some(crate::error::CycleUsage { - span: query.info.default_span(span), - usage: query.info.description.to_string(), - }); - } + let cycle_usage = usage.as_ref().map(|usage| crate::error::CycleUsage { + span: usage.tagged_key.default_span(tcx, usage.span), + usage: usage.tagged_key.description(tcx), + }); - let alias = - if stack.iter().all(|entry| matches!(entry.frame.info.def_kind, Some(DefKind::TyAlias))) { - Some(crate::error::Alias::Ty) - } else if stack.iter().all(|entry| entry.frame.info.def_kind == Some(DefKind::TraitAlias)) { - Some(crate::error::Alias::Trait) - } else { - None - }; + let alias = if frames + .iter() + .all(|frame| frame.tagged_key.def_kind(tcx) == Some(DefKind::TyAlias)) + { + Some(crate::error::Alias::Ty) + } else if frames.iter().all(|frame| frame.tagged_key.def_kind(tcx) == Some(DefKind::TraitAlias)) + { + Some(crate::error::Alias::Trait) + } else { + None + }; let cycle_diag = crate::error::Cycle { span, @@ -479,5 +503,5 @@ pub(crate) fn report_cycle<'a>( note_span: (), }; - sess.dcx().create_err(cycle_diag) + tcx.sess.dcx().create_err(cycle_diag) } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index d92d80dbfb86..de03b48394b1 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -10,27 +10,23 @@ use rustc_data_structures::sync::AtomicU64; use rustc_middle::dep_graph; -use rustc_middle::queries::{self, ExternProviders, Providers}; -use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; -use rustc_middle::query::plumbing::{QuerySystem, QueryVTable}; -use rustc_middle::query::{AsLocalQueryKey, QueryCache, QueryMode}; +use rustc_middle::queries::{ExternProviders, Providers}; +use rustc_middle::query::on_disk_cache::OnDiskCache; +use rustc_middle::query::{QueryCache, QuerySystem, QueryVTable}; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; pub use crate::dep_kind_vtables::make_dep_kind_vtables; -use crate::from_cycle_error::FromCycleError; +pub use crate::execution::{CollectActiveJobsKind, collect_active_query_jobs}; pub use crate::job::{QueryJobMap, break_query_cycles, print_query_stack}; -use crate::profiling_support::QueryKeyStringCache; - -#[macro_use] -mod plumbing; mod dep_kind_vtables; mod error; mod execution; -mod from_cycle_error; +mod handle_cycle_error; mod job; +mod plumbing; mod profiling_support; +mod query_impl; /// Trait that knows how to look up the [`QueryVTable`] for a particular query. /// @@ -52,9 +48,12 @@ pub fn query_system<'tcx>( on_disk_cache: Option, incremental: bool, ) -> QuerySystem<'tcx> { + let mut query_vtables = query_impl::make_query_vtables(incremental); + handle_cycle_error::specialize_query_vtables(&mut query_vtables); QuerySystem { arenas: Default::default(), - query_vtables: make_query_vtables(incremental), + query_vtables, + side_effects: Default::default(), on_disk_cache, local_providers, extern_providers, @@ -62,10 +61,9 @@ pub fn query_system<'tcx>( } } -rustc_middle::rustc_with_all_queries! { define_queries! } - pub fn provide(providers: &mut rustc_middle::util::Providers) { - providers.hooks.alloc_self_profile_query_strings = alloc_self_profile_query_strings; - providers.hooks.query_key_hash_verify_all = query_key_hash_verify_all; - providers.hooks.encode_all_query_results = encode_all_query_results; + providers.hooks.alloc_self_profile_query_strings = + profiling_support::alloc_self_profile_query_strings; + providers.hooks.verify_query_key_hashes = plumbing::verify_query_key_hashes; + providers.hooks.encode_query_values = plumbing::encode_query_values; } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f4649b2403a6..ef4fff293bf6 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -1,53 +1,38 @@ -//! The implementation of the query system itself. This defines the macros that -//! generate the actual methods on tcx which find and execute the provider, -//! manage the caches, and so forth. - use std::num::NonZero; -use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordMap; -use rustc_hir::def_id::DefId; use rustc_hir::limit::Limit; -use rustc_index::Idx; use rustc_middle::bug; #[expect(unused_imports, reason = "used by doc comments")] use rustc_middle::dep_graph::DepKindVTable; -use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, DepNodeKey, SerializedDepNodeIndex}; +use rustc_middle::dep_graph::{DepNode, DepNodeIndex, DepNodeKey, SerializedDepNodeIndex}; use rustc_middle::query::erase::{Erasable, Erased}; -use rustc_middle::query::on_disk_cache::{ - AbsoluteBytePos, CacheDecoder, CacheEncoder, EncodedDepNodeIndex, -}; -use rustc_middle::query::plumbing::QueryVTable; -use rustc_middle::query::{ - QueryCache, QueryJobId, QueryKey, QueryMode, QueryStackDeferred, QueryStackFrame, - QueryStackFrameExtra, erase, -}; -use rustc_middle::ty::codec::TyEncoder; -use rustc_middle::ty::print::with_reduced_queries; +use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder}; +use rustc_middle::query::{QueryCache, QueryJobId, QueryMode, QueryVTable, erase}; +use rustc_middle::ty::TyCtxt; use rustc_middle::ty::tls::{self, ImplicitCtxt}; -use rustc_middle::ty::{self, TyCtxt}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::DUMMY_SP; use rustc_span::def_id::LOCAL_CRATE; use crate::error::{QueryOverflow, QueryOverflowNote}; -use crate::execution::{all_inactive, force_query}; +use crate::execution::all_inactive; use crate::job::find_dep_kind_root; -use crate::{GetQueryVTable, collect_active_jobs_from_all_queries}; +use crate::query_impl::for_each_query_vtable; +use crate::{CollectActiveJobsKind, collect_active_query_jobs}; fn depth_limit_error<'tcx>(tcx: TyCtxt<'tcx>, job: QueryJobId) { - let job_map = - collect_active_jobs_from_all_queries(tcx, true).expect("failed to collect active queries"); - let (info, depth) = find_dep_kind_root(job, job_map); + let job_map = collect_active_query_jobs(tcx, CollectActiveJobsKind::Full); + let (span, desc, depth) = find_dep_kind_root(tcx, job, job_map); let suggested_limit = match tcx.recursion_limit() { Limit(0) => Limit(2), limit => limit * 2, }; - tcx.sess.dcx().emit_fatal(QueryOverflow { - span: info.job.span, - note: QueryOverflowNote { desc: info.frame.info.extract().description, depth }, + tcx.dcx().emit_fatal(QueryOverflow { + span, + note: QueryOverflowNote { desc, depth }, suggested_limit, crate_name: tcx.crate_name(LOCAL_CRATE), }); @@ -90,67 +75,16 @@ pub(crate) fn start_query( }) } -/// The deferred part of a deferred query stack frame. -fn mk_query_stack_frame_extra<'tcx, Cache>( - (tcx, vtable, key): (TyCtxt<'tcx>, &'tcx QueryVTable<'tcx, Cache>, Cache::Key), -) -> QueryStackFrameExtra -where - Cache: QueryCache, - Cache::Key: QueryKey, -{ - let def_id = key.key_as_def_id(); - - // If reduced queries are requested, we may be printing a query stack due - // to a panic. Avoid using `default_span` and `def_kind` in that case. - let reduce_queries = with_reduced_queries(); - - // Avoid calling queries while formatting the description - let description = ty::print::with_no_queries!((vtable.description_fn)(tcx, key)); - let description = if tcx.sess.verbose_internals() { - format!("{description} [{name:?}]", name = vtable.name) - } else { - description - }; - let span = if vtable.dep_kind == DepKind::def_span || reduce_queries { - // The `def_span` query is used to calculate `default_span`, - // so exit to avoid infinite recursion. - None - } else { - Some(key.default_span(tcx)) - }; - - let def_kind = if vtable.dep_kind == DepKind::def_kind || reduce_queries { - // Try to avoid infinite recursion. - None - } else { - def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) - }; - QueryStackFrameExtra::new(description, span, def_kind) +pub(crate) fn encode_query_values<'tcx>(tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'_, 'tcx>) { + for_each_query_vtable!(CACHE_ON_DISK, tcx, |query| { + encode_query_values_inner(tcx, query, encoder) + }); } -pub(crate) fn create_deferred_query_stack_frame<'tcx, C>( - tcx: TyCtxt<'tcx>, - vtable: &'tcx QueryVTable<'tcx, C>, - key: C::Key, -) -> QueryStackFrame> -where - C: QueryCache, - QueryVTable<'tcx, C>: DynSync, -{ - let kind = vtable.dep_kind; - - let def_id: Option = key.key_as_def_id(); - let def_id_for_ty_in_cycle: Option = key.def_id_for_ty_in_cycle(); - - let info = QueryStackDeferred::new((tcx, vtable, key), mk_query_stack_frame_extra); - QueryStackFrame::new(info, kind, def_id, def_id_for_ty_in_cycle) -} - -pub(crate) fn encode_query_results<'a, 'tcx, C, V>( +fn encode_query_values_inner<'a, 'tcx, C, V>( tcx: TyCtxt<'tcx>, query: &'tcx QueryVTable<'tcx, C>, encoder: &mut CacheEncoder<'a, 'tcx>, - query_result_index: &mut EncodedDepNodeIndex, ) where C: QueryCache>, V: Erasable + Encodable>, @@ -160,19 +94,22 @@ pub(crate) fn encode_query_results<'a, 'tcx, C, V>( assert!(all_inactive(&query.state)); query.cache.for_each(&mut |key, value, dep_node| { if (query.will_cache_on_disk_for_key_fn)(tcx, *key) { - let dep_node = SerializedDepNodeIndex::new(dep_node.index()); - - // Record position of the cache entry. - query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position()))); - - // Encode the type check tables with the `SerializedDepNodeIndex` - // as tag. - encoder.encode_tagged(dep_node, &erase::restore_val::(*value)); + encoder.encode_query_value::(dep_node, &erase::restore_val::(*value)); } }); } -pub(crate) fn query_key_hash_verify<'tcx, C: QueryCache>( +pub(crate) fn verify_query_key_hashes<'tcx>(tcx: TyCtxt<'tcx>) { + if tcx.sess.opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions) { + tcx.sess.time("verify_query_key_hashes", || { + for_each_query_vtable!(ALL, tcx, |query| { + verify_query_key_hashes_inner(query, tcx); + }); + }); + } +} + +fn verify_query_key_hashes_inner<'tcx, C: QueryCache>( query: &'tcx QueryVTable<'tcx, C>, tcx: TyCtxt<'tcx>, ) { @@ -198,15 +135,15 @@ pub(crate) fn query_key_hash_verify<'tcx, C: QueryCache>( }); } -/// Implementation of [`DepKindVTable::promote_from_disk_fn`] for queries. -pub(crate) fn promote_from_disk_inner<'tcx, Q: GetQueryVTable<'tcx>>( +/// Inner implementation of [`DepKindVTable::promote_from_disk_fn`] for queries. +pub(crate) fn promote_from_disk_inner<'tcx, C: QueryCache>( tcx: TyCtxt<'tcx>, + query: &'tcx QueryVTable<'tcx, C>, dep_node: DepNode, ) { - let query = Q::query_vtable(tcx); debug_assert!(tcx.dep_graph.is_green(&dep_node)); - let key = ::Key::try_recover_key(tcx, &dep_node).unwrap_or_else(|| { + let key = C::Key::try_recover_key(tcx, &dep_node).unwrap_or_else(|| { panic!( "Failed to recover key for {dep_node:?} with key fingerprint {}", dep_node.key_fingerprint @@ -261,346 +198,9 @@ pub(crate) fn try_load_from_disk<'tcx, V>( // details. let value = tcx .dep_graph - .with_query_deserialization(|| on_disk_cache.try_load_query_result(tcx, prev_index)); + .with_query_deserialization(|| on_disk_cache.try_load_query_value(tcx, prev_index)); prof_timer.finish_with_query_invocation_id(index.into()); value } - -/// Implementation of [`DepKindVTable::force_from_dep_node_fn`] for queries. -pub(crate) fn force_from_dep_node_inner<'tcx, Q: GetQueryVTable<'tcx>>( - tcx: TyCtxt<'tcx>, - dep_node: DepNode, - // Needed by the vtable function signature, but not used when forcing queries. - _prev_index: SerializedDepNodeIndex, -) -> bool { - let query = Q::query_vtable(tcx); - - // We must avoid ever having to call `force_from_dep_node()` for a - // `DepNode::codegen_unit`: - // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we - // would always end up having to evaluate the first caller of the - // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just - // to re-trigger calling the `codegen_unit` query with the right key. At - // that point we would already have re-done all the work we are trying to - // avoid doing in the first place. - // The solution is simple: Just explicitly call the `codegen_unit` query for - // each CGU, right after partitioning. This way `try_mark_green` will always - // hit the cache instead of having to go through `force_from_dep_node`. - // This assertion makes sure, we actually keep applying the solution above. - debug_assert!( - dep_node.kind != DepKind::codegen_unit, - "calling force_from_dep_node() on dep_kinds::codegen_unit" - ); - - if let Some(key) = ::Key::try_recover_key(tcx, &dep_node) { - force_query(query, tcx, key, dep_node); - true - } else { - false - } -} - -macro_rules! define_queries { - ( - // Note: `$K` and `$V` are unused but present so this can be called by - // `rustc_with_all_queries`. - queries { - $( - $(#[$attr:meta])* - fn $name:ident($K:ty) -> $V:ty - { - // Search for (QMODLIST) to find all occurrences of this query modifier list. - anon: $anon:literal, - arena_cache: $arena_cache:literal, - cache_on_disk: $cache_on_disk:literal, - cycle_error_handling: $cycle_error_handling:ident, - depth_limit: $depth_limit:literal, - eval_always: $eval_always:literal, - feedable: $feedable:literal, - no_hash: $no_hash:literal, - returns_error_guaranteed: $returns_error_guaranteed:literal, - separate_provide_extern: $separate_provide_extern:literal, - } - )* - } - // Non-queries are unused here. - non_queries { $($_:tt)* } - ) => { - pub(crate) mod query_impl { $(pub(crate) mod $name { - use super::super::*; - use ::rustc_middle::query::erase::{self, Erased}; - - // It seems to be important that every query has its own monomorphic - // copy of `execute_query_incr` and `execute_query_non_incr`. - // Trying to inline these wrapper functions into their generic - // "inner" helpers tends to break `tests/run-make/short-ice`. - - pub(crate) mod execute_query_incr { - use super::*; - - // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames - // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming - #[inline(never)] - pub(crate) fn __rust_end_short_backtrace<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - key: queries::$name::Key<'tcx>, - mode: QueryMode, - ) -> Option>> { - #[cfg(debug_assertions)] - let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); - execution::execute_query_incr_inner( - &tcx.query_system.query_vtables.$name, - tcx, - span, - key, - mode - ) - } - } - - pub(crate) mod execute_query_non_incr { - use super::*; - - #[inline(never)] - pub(crate) fn __rust_end_short_backtrace<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - key: queries::$name::Key<'tcx>, - __mode: QueryMode, - ) -> Option>> { - Some(execution::execute_query_non_incr_inner( - &tcx.query_system.query_vtables.$name, - tcx, - span, - key, - )) - } - } - - /// Defines an `invoke_provider` function that calls the query's provider, - /// to be used as a function pointer in the query's vtable. - /// - /// To mark a short-backtrace boundary, the function's actual name - /// (after demangling) must be `__rust_begin_short_backtrace`. - mod invoke_provider_fn { - use super::*; - use ::rustc_middle::queries::$name::{Key, Value, provided_to_erased}; - - #[inline(never)] - pub(crate) fn __rust_begin_short_backtrace<'tcx>( - tcx: TyCtxt<'tcx>, - key: Key<'tcx>, - ) -> Erased> { - #[cfg(debug_assertions)] - let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); - - // Call the actual provider function for this query. - - #[cfg($separate_provide_extern)] - let provided_value = if let Some(local_key) = key.as_local_key() { - (tcx.query_system.local_providers.$name)(tcx, local_key) - } else { - (tcx.query_system.extern_providers.$name)(tcx, key) - }; - - #[cfg(not($separate_provide_extern))] - let provided_value = (tcx.query_system.local_providers.$name)(tcx, key); - - rustc_middle::ty::print::with_reduced_queries!({ - tracing::trace!(?provided_value); - }); - - // Erase the returned value, because `QueryVTable` uses erased values. - // For queries with `arena_cache`, this also arena-allocates the value. - provided_to_erased(tcx, provided_value) - } - } - - pub(crate) fn make_query_vtable<'tcx>(incremental: bool) - -> QueryVTable<'tcx, queries::$name::Cache<'tcx>> - { - QueryVTable { - name: stringify!($name), - anon: $anon, - eval_always: $eval_always, - depth_limit: $depth_limit, - feedable: $feedable, - dep_kind: dep_graph::DepKind::$name, - cycle_error_handling: - rustc_middle::query::CycleErrorHandling::$cycle_error_handling, - state: Default::default(), - cache: Default::default(), - - invoke_provider_fn: self::invoke_provider_fn::__rust_begin_short_backtrace, - - #[cfg($cache_on_disk)] - will_cache_on_disk_for_key_fn: - rustc_middle::queries::_cache_on_disk_if_fns::$name, - #[cfg(not($cache_on_disk))] - will_cache_on_disk_for_key_fn: |_, _| false, - - #[cfg($cache_on_disk)] - try_load_from_disk_fn: |tcx, key, prev_index, index| { - // Check the `cache_on_disk_if` condition for this key. - if !rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) { - return None; - } - - let value: queries::$name::ProvidedValue<'tcx> = - $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?; - - // Arena-alloc the value if appropriate, and erase it. - Some(queries::$name::provided_to_erased(tcx, value)) - }, - #[cfg(not($cache_on_disk))] - try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None, - - #[cfg($cache_on_disk)] - is_loadable_from_disk_fn: |tcx, key, index| -> bool { - rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) && - $crate::plumbing::loadable_from_disk(tcx, index) - }, - #[cfg(not($cache_on_disk))] - is_loadable_from_disk_fn: |_tcx, _key, _index| false, - - value_from_cycle_error: |tcx, cycle, guar| { - let result: queries::$name::Value<'tcx> = - FromCycleError::from_cycle_error(tcx, cycle, guar); - erase::erase_val(result) - }, - - #[cfg($no_hash)] - hash_value_fn: None, - #[cfg(not($no_hash))] - hash_value_fn: Some(|hcx, erased_value: &erase::Erased>| { - let value = erase::restore_val(*erased_value); - rustc_middle::dep_graph::hash_result(hcx, &value) - }), - - format_value: |value| format!("{:?}", erase::restore_val::>(*value)), - description_fn: $crate::queries::_description_fns::$name, - execute_query_fn: if incremental { - query_impl::$name::execute_query_incr::__rust_end_short_backtrace - } else { - query_impl::$name::execute_query_non_incr::__rust_end_short_backtrace - }, - } - } - - /// Marker type that implements [`GetQueryVTable`] for this query. - pub(crate) enum VTableGetter {} - - impl<'tcx> GetQueryVTable<'tcx> for VTableGetter { - type Cache = rustc_middle::queries::$name::Cache<'tcx>; - - #[inline(always)] - fn query_vtable(tcx: TyCtxt<'tcx>) -> &'tcx QueryVTable<'tcx, Self::Cache> { - &tcx.query_system.query_vtables.$name - } - } - })*} - - pub fn make_query_vtables<'tcx>(incremental: bool) -> queries::QueryVTables<'tcx> { - queries::QueryVTables { - $( - $name: query_impl::$name::make_query_vtable(incremental), - )* - } - } - - /// Returns a map of currently active query jobs, collected from all queries. - /// - /// If `require_complete` is `true`, this function locks all shards of the - /// query results to produce a complete map, which always returns `Ok`. - /// Otherwise, it may return an incomplete map as an error if any shard - /// lock cannot be acquired. - /// - /// Prefer passing `false` to `require_complete` to avoid potential deadlocks, - /// especially when called from within a deadlock handler, unless a - /// complete map is needed and no deadlock is possible at this call site. - pub fn collect_active_jobs_from_all_queries<'tcx>( - tcx: TyCtxt<'tcx>, - require_complete: bool, - ) -> Result, QueryJobMap<'tcx>> { - let mut job_map_out = QueryJobMap::default(); - let mut complete = true; - - $( - let res = crate::execution::gather_active_jobs( - &tcx.query_system.query_vtables.$name, - tcx, - require_complete, - &mut job_map_out, - ); - if res.is_none() { - complete = false; - } - )* - - if complete { Ok(job_map_out) } else { Err(job_map_out) } - } - - /// All self-profiling events generated by the query engine use - /// virtual `StringId`s for their `event_id`. This method makes all - /// those virtual `StringId`s point to actual strings. - /// - /// If we are recording only summary data, the ids will point to - /// just the query names. If we are recording query keys too, we - /// allocate the corresponding strings here. - pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { - if !tcx.prof.enabled() { - return; - } - - let _prof_timer = tcx.sess.prof.generic_activity("self_profile_alloc_query_strings"); - - let mut string_cache = QueryKeyStringCache::new(); - - $( - $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache( - tcx, - stringify!($name), - &tcx.query_system.query_vtables.$name.cache, - &mut string_cache, - ); - )* - - tcx.sess.prof.store_query_cache_hits(); - } - - fn encode_all_query_results<'tcx>( - tcx: TyCtxt<'tcx>, - encoder: &mut CacheEncoder<'_, 'tcx>, - query_result_index: &mut EncodedDepNodeIndex, - ) { - $( - #[cfg($cache_on_disk)] - { - $crate::plumbing::encode_query_results( - tcx, - &tcx.query_system.query_vtables.$name, - encoder, - query_result_index, - ) - } - )* - } - - pub fn query_key_hash_verify_all<'tcx>(tcx: TyCtxt<'tcx>) { - if tcx.sess.opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions) { - tcx.sess.time("query_key_hash_verify_all", || { - $( - $crate::plumbing::query_key_hash_verify( - &tcx.query_system.query_vtables.$name, - tcx - ); - )* - }) - } - } - } -} diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 0c0e966f1fa4..980e2b130524 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -6,9 +6,11 @@ use rustc_data_structures::profiling::SelfProfiler; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::DefPathData; -use rustc_middle::query::QueryCache; +use rustc_middle::query::{QueryCache, QueryVTable}; use rustc_middle::ty::TyCtxt; +use crate::query_impl::for_each_query_vtable; + pub(crate) struct QueryKeyStringCache { def_id_cache: FxHashMap, } @@ -172,13 +174,35 @@ fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_ } } +/// All self-profiling events generated by the query engine use +/// virtual `StringId`s for their `event_id`. This method makes all +/// those virtual `StringId`s point to actual strings. +/// +/// If we are recording only summary data, the ids will point to +/// just the query names. If we are recording query keys too, we +/// allocate the corresponding strings here. +pub(crate) fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { + if !tcx.prof.enabled() { + return; + } + + let _prof_timer = tcx.sess.prof.generic_activity("self_profile_alloc_query_strings"); + + let mut string_cache = QueryKeyStringCache::new(); + + for_each_query_vtable!(ALL, tcx, |query| { + alloc_self_profile_query_strings_inner(tcx, query, &mut string_cache); + }); + + tcx.sess.prof.store_query_cache_hits(); +} + /// Allocate the self-profiling query strings for a single query cache. This /// method is called from `alloc_self_profile_query_strings` which knows all /// the queries via macro magic. -pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( +fn alloc_self_profile_query_strings_inner<'tcx, C>( tcx: TyCtxt<'tcx>, - query_name: &'static str, - query_cache: &C, + query: &'tcx QueryVTable<'tcx, C>, string_cache: &mut QueryKeyStringCache, ) where C: QueryCache, @@ -193,14 +217,14 @@ pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( if profiler.query_key_recording_enabled() { let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache); - let query_name = profiler.get_or_alloc_cached_string(query_name); + let query_name = profiler.get_or_alloc_cached_string(query.name); // Since building the string representation of query keys might // need to invoke queries itself, we cannot keep the query caches // locked while doing so. Instead we copy out the // `(query_key, dep_node_index)` pairs and release the lock again. let mut query_keys_and_indices = Vec::new(); - query_cache.for_each(&mut |k, _, i| query_keys_and_indices.push((*k, i))); + query.cache.for_each(&mut |k, _, i| query_keys_and_indices.push((*k, i))); // Now actually allocate the strings. If allocating the strings // generates new entries in the query cache, we'll miss them but @@ -221,14 +245,14 @@ pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( } } else { // In this branch we don't allocate query keys - let query_name = profiler.get_or_alloc_cached_string(query_name); + let query_name = profiler.get_or_alloc_cached_string(query.name); let event_id = event_id_builder.from_label(query_name).to_string_id(); // FIXME(eddyb) make this O(1) by using a pre-cached query name `EventId`, // instead of passing the `DepNodeIndex` to `finish_with_query_invocation_id`, // when recording the event in the first place. let mut query_invocation_ids = Vec::new(); - query_cache.for_each(&mut |_, _, i| { + query.cache.for_each(&mut |_, _, i| { query_invocation_ids.push(i.into()); }); diff --git a/compiler/rustc_query_impl/src/query_impl.rs b/compiler/rustc_query_impl/src/query_impl.rs new file mode 100644 index 000000000000..60ddf3e4ad38 --- /dev/null +++ b/compiler/rustc_query_impl/src/query_impl.rs @@ -0,0 +1,265 @@ +use rustc_middle::queries::TaggedQueryKey; +use rustc_middle::query::erase::{self, Erased}; +use rustc_middle::query::{AsLocalQueryKey, QueryMode, QueryVTable}; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; + +use crate::GetQueryVTable; + +macro_rules! define_queries { + ( + // Note: `$K` and `$V` are unused but present so this can be called by + // `rustc_with_all_queries`. + queries { + $( + $(#[$attr:meta])* + fn $name:ident($K:ty) -> $V:ty + { + // Search for (QMODLIST) to find all occurrences of this query modifier list. + arena_cache: $arena_cache:literal, + cache_on_disk: $cache_on_disk:literal, + depth_limit: $depth_limit:literal, + eval_always: $eval_always:literal, + feedable: $feedable:literal, + no_force: $no_force:literal, + no_hash: $no_hash:literal, + returns_error_guaranteed: $returns_error_guaranteed:literal, + separate_provide_extern: $separate_provide_extern:literal, + } + )* + } + // Non-queries are unused here. + non_queries { $($_:tt)* } + ) => { + // This macro expects to be expanded into `crate::query_impl`, which is this file. + $( + pub(crate) mod $name { + use super::*; + + // It seems to be important that every query has its own monomorphic + // copy of `execute_query_incr` and `execute_query_non_incr`. + // Trying to inline these wrapper functions into their generic + // "inner" helpers tends to break `tests/run-make/short-ice`. + + pub(crate) mod execute_query_incr { + use super::*; + use rustc_middle::queries::$name::{Key, Value}; + + // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames + // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming + #[inline(never)] + pub(crate) fn __rust_end_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + key: Key<'tcx>, + mode: QueryMode, + ) -> Option>> { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); + crate::execution::execute_query_incr_inner( + &tcx.query_system.query_vtables.$name, + tcx, + span, + key, + mode + ) + } + } + + pub(crate) mod execute_query_non_incr { + use super::*; + use rustc_middle::queries::$name::{Key, Value}; + + #[inline(never)] + pub(crate) fn __rust_end_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + key: Key<'tcx>, + __mode: QueryMode, + ) -> Option>> { + Some(crate::execution::execute_query_non_incr_inner( + &tcx.query_system.query_vtables.$name, + tcx, + span, + key, + )) + } + } + + /// Defines an `invoke_provider` function that calls the query's provider, + /// to be used as a function pointer in the query's vtable. + /// + /// To mark a short-backtrace boundary, the function's actual name + /// (after demangling) must be `__rust_begin_short_backtrace`. + mod invoke_provider_fn { + use super::*; + use rustc_middle::queries::$name::{Key, Value, provided_to_erased}; + + #[inline(never)] + pub(crate) fn __rust_begin_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + key: Key<'tcx>, + ) -> Erased> { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); + + // Call the actual provider function for this query. + + #[cfg($separate_provide_extern)] + let provided_value = if let Some(local_key) = key.as_local_key() { + (tcx.query_system.local_providers.$name)(tcx, local_key) + } else { + (tcx.query_system.extern_providers.$name)(tcx, key) + }; + + #[cfg(not($separate_provide_extern))] + let provided_value = (tcx.query_system.local_providers.$name)(tcx, key); + + rustc_middle::ty::print::with_reduced_queries!({ + tracing::trace!(?provided_value); + }); + + // Erase the returned value, because `QueryVTable` uses erased values. + // For queries with `arena_cache`, this also arena-allocates the value. + provided_to_erased(tcx, provided_value) + } + } + + pub(crate) fn make_query_vtable<'tcx>(incremental: bool) + -> QueryVTable<'tcx, rustc_middle::queries::$name::Cache<'tcx>> + { + use rustc_middle::queries::$name::Value; + + QueryVTable { + name: stringify!($name), + eval_always: $eval_always, + depth_limit: $depth_limit, + feedable: $feedable, + dep_kind: rustc_middle::dep_graph::DepKind::$name, + state: Default::default(), + cache: Default::default(), + + invoke_provider_fn: self::invoke_provider_fn::__rust_begin_short_backtrace, + + #[cfg($cache_on_disk)] + will_cache_on_disk_for_key_fn: + rustc_middle::queries::_cache_on_disk_if_fns::$name, + #[cfg(not($cache_on_disk))] + will_cache_on_disk_for_key_fn: |_, _| false, + + #[cfg($cache_on_disk)] + try_load_from_disk_fn: |tcx, key, prev_index, index| { + use rustc_middle::queries::$name::{ProvidedValue, provided_to_erased}; + + // Check the `cache_on_disk_if` condition for this key. + if !rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) { + return None; + } + + let loaded_value: ProvidedValue<'tcx> = + $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?; + + // Arena-alloc the value if appropriate, and erase it. + Some(provided_to_erased(tcx, loaded_value)) + }, + #[cfg(not($cache_on_disk))] + try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None, + + // The default just emits `err` and then aborts. + // `handle_cycle_error::specialize_query_vtables` overwrites this default + // for certain queries. + handle_cycle_error_fn: |_tcx, _key, _cycle, err| { + $crate::handle_cycle_error::default(err) + }, + + #[cfg($no_hash)] + hash_value_fn: None, + #[cfg(not($no_hash))] + hash_value_fn: Some(|hcx, erased_value: &erase::Erased>| { + let value = erase::restore_val(*erased_value); + rustc_middle::dep_graph::hash_result(hcx, &value) + }), + + format_value: |erased_value: &erase::Erased>| { + format!("{:?}", erase::restore_val(*erased_value)) + }, + create_tagged_key: TaggedQueryKey::$name, + execute_query_fn: if incremental { + crate::query_impl::$name::execute_query_incr::__rust_end_short_backtrace + } else { + crate::query_impl::$name::execute_query_non_incr::__rust_end_short_backtrace + }, + } + } + + /// Marker type that implements [`GetQueryVTable`] for this query. + pub(crate) enum VTableGetter {} + + impl<'tcx> GetQueryVTable<'tcx> for VTableGetter { + type Cache = rustc_middle::queries::$name::Cache<'tcx>; + + #[inline(always)] + fn query_vtable(tcx: TyCtxt<'tcx>) -> &'tcx QueryVTable<'tcx, Self::Cache> { + &tcx.query_system.query_vtables.$name + } + } + } + )* + + pub(crate) fn make_query_vtables<'tcx>(incremental: bool) + -> rustc_middle::queries::QueryVTables<'tcx> + { + rustc_middle::queries::QueryVTables { + $( + $name: crate::query_impl::$name::make_query_vtable(incremental), + )* + } + } + + /// Given a filter condition (e.g. `ALL` or `CACHE_ON_DISK`), a `tcx`, + /// and a closure expression that accepts `&QueryVTable`, this macro + /// calls that closure with each query vtable that satisfies the filter + /// condition. + /// + /// This needs to be a macro, because the vtables can have different + /// key/value/cache types for different queries. + /// + /// This macro's argument syntax is specifically intended to look like + /// plain Rust code, so that `for_each_query_vtable!(..)` calls will be + /// formatted by rustfmt. + /// + /// To avoid too much nested-macro complication, filter conditions are + /// implemented by hand as needed. + macro_rules! for_each_query_vtable { + // Call with all queries. + (ALL, $tcx:expr, $closure:expr) => {{ + let tcx: rustc_middle::ty::TyCtxt<'_> = $tcx; + $( + let query: &rustc_middle::query::QueryVTable<'_, _> = + &tcx.query_system.query_vtables.$name; + $closure(query); + )* + }}; + + // Only call with queries that can potentially cache to disk. + // + // This allows the use of trait bounds that only need to be satisfied + // by the subset of queries that actually cache to disk. + (CACHE_ON_DISK, $tcx:expr, $closure:expr) => {{ + let tcx: rustc_middle::ty::TyCtxt<'_> = $tcx; + $( + #[cfg($cache_on_disk)] + { + let query: &rustc_middle::query::QueryVTable<'_, _> = + &tcx.query_system.query_vtables.$name; + $closure(query); + } + )* + }} + } + + pub(crate) use for_each_query_vtable; + } +} + +rustc_middle::queries::rustc_with_all_queries! { define_queries! } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a280acc0d51d..29b5cdb2c899 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -357,6 +357,7 @@ fn build_reduced_graph_for_external_crate_res( | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(..) + | Res::OpenMod(..) | Res::Err => bug!("unexpected resolution: {:?}", res), } } @@ -898,7 +899,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) { } // These items live in both the type and value namespaces. - ItemKind::Struct(ident, _, ref vdata) => { + ItemKind::Struct(ident, ref generics, ref vdata) => { self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, @@ -947,6 +948,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'a Item) { .struct_constructors .insert(local_def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields)); } + self.r.struct_generics.insert(local_def_id, generics.clone()); } ItemKind::Union(ident, _, ref vdata) => { @@ -1474,7 +1476,9 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { return; } - AssocItemKind::DelegationMac(..) => bug!(), + AssocItemKind::DelegationMac(..) => { + span_bug!(item.span, "delegation mac should already have been removed") + } }; let vis = self.resolve_visibility(&item.vis); let feed = self.r.feed(item.id); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 45fdea82d47b..8e150b7f3a5d 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -36,7 +36,7 @@ use rustc_span::{DUMMY_SP, Ident, Span, kw}; use crate::imports::{Import, ImportKind}; -use crate::{DeclKind, IdentKey, LateDecl, Resolver, module_to_string}; +use crate::{DeclKind, IdentKey, LateDecl, Resolver, errors, module_to_string}; struct UnusedImport { use_tree: ast::UseTree, @@ -554,7 +554,7 @@ pub(crate) fn check_unused(&mut self, krate: &ast::Crate) { UNUSED_QUALIFICATIONS, unn_qua.node_id, unn_qua.path_span, - BuiltinLintDiag::UnusedQualifications { removal_span: unn_qua.removal_span }, + errors::UnusedQualifications { removal_span: unn_qua.removal_span }, ); } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 81820e049716..de36f01b6d0e 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -358,9 +358,12 @@ fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { }, ), AssocItemKind::Type(box TyAlias { ident, .. }) => (*ident, DefKind::AssocTy), - AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { + AssocItemKind::MacCall(..) => { return self.visit_macro_invoc(i.id); } + AssocItemKind::DelegationMac(..) => { + span_bug!(i.span, "degation mac invoc should have already been handled") + } }; let def = self.create_def(i.id, Some(ident.name), def_kind, i.span); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 1b1198af41c0..97c88064e979 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -32,8 +32,10 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::{SourceMap, Spanned}; -use rustc_span::{BytePos, Ident, RemapPathScopeComponents, Span, Symbol, SyntaxContext, kw, sym}; +use rustc_span::source_map::SourceMap; +use rustc_span::{ + BytePos, Ident, RemapPathScopeComponents, Span, Spanned, Symbol, SyntaxContext, kw, sym, +}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, instrument}; @@ -1738,8 +1740,8 @@ pub(crate) fn unresolved_macro_suggestions( Res::Def(DefKind::Macro(kinds), _) => { format!("{} {}", kinds.article(), kinds.descr()) } - Res::ToolMod => { - // Don't confuse the user with tool modules. + Res::ToolMod | Res::OpenMod(..) => { + // Don't confuse the user with tool modules or open modules. continue; } Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => { @@ -1976,7 +1978,8 @@ fn decl_description(&self, b: Decl<'_>, ident: Ident, scope: Scope<'_>) -> Strin let (built_in, from) = match scope { Scope::StdLibPrelude | Scope::MacroUsePrelude => ("", " from prelude"), Scope::ExternPreludeFlags - if self.tcx.sess.opts.externs.get(ident.as_str()).is_some() => + if self.tcx.sess.opts.externs.get(ident.as_str()).is_some() + || matches!(res, Res::OpenMod(..)) => { ("", " passed with `--extern`") } @@ -3081,12 +3084,8 @@ pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, mod .stripped_cfg_items .iter() .filter_map(|item| { - let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id(); - Some(StrippedCfgItem { - parent_module, - ident: item.ident, - cfg: item.cfg.clone(), - }) + let parent_scope = self.opt_local_def_id(item.parent_scope)?.to_def_id(); + Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg.clone() }) }) .collect::>(); local_items.as_slice() @@ -3094,11 +3093,13 @@ pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, mod self.tcx.stripped_cfg_items(module.krate) }; - for &StrippedCfgItem { parent_module, ident, ref cfg } in symbols { + for &StrippedCfgItem { parent_scope, ident, ref cfg } in symbols { if ident.name != *segment { continue; } + let parent_module = self.get_nearest_non_block_module(parent_scope).def_id(); + fn comes_from_same_module_for_glob( r: &Resolver<'_, '_>, parent_module: DefId, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 63ffdbc37f7d..c9dad4dcd4a7 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,12 +1,11 @@ use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, ElidedLifetimeInPathSubdiag, + Applicability, Diag, DiagCtxtHandle, Diagnostic, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::source_map::Spanned; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{Ident, Span, Spanned, Symbol}; use crate::Res; use crate::late::PatternSource; @@ -561,6 +560,10 @@ pub(crate) struct ExpectedModuleFound { #[diag("cannot determine resolution for the visibility", code = E0578)] pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span); +#[derive(Diagnostic)] +#[diag("trait implementation can only be restricted to ancestor modules")] +pub(crate) struct RestrictionAncestorOnly(#[primary_span] pub(crate) Span); + #[derive(Diagnostic)] #[diag("cannot use a tool module through an import")] pub(crate) struct ToolModuleImported { @@ -884,6 +887,21 @@ pub(crate) struct UnexpectedResChangeTyToConstParamSugg { pub applicability: Applicability, } +#[derive(Subdiagnostic)] +#[suggestion( + "you might have meant to introduce a const parameter `{$item_name}` on the {$item_location}", + code = "{snippet}", + applicability = "machine-applicable", + style = "verbose" +)] +pub(crate) struct UnexpectedMissingConstParameter { + #[primary_span] + pub span: Span, + pub snippet: String, + pub item_name: String, + pub item_location: String, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( "you might have meant to write a const parameter here", @@ -1454,17 +1472,6 @@ pub(crate) struct MacroRuleNeverUsed { pub name: Symbol, } -pub(crate) struct UnstableFeature { - pub msg: DiagMessage, -} - -impl<'a> Diagnostic<'a, ()> for UnstableFeature { - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { - let Self { msg } = self; - Diag::new(dcx, level, msg) - } -} - #[derive(Diagnostic)] #[diag("`extern crate` is not idiomatic in the new edition")] pub(crate) struct ExternCrateNotIdiomatic { @@ -1576,3 +1583,108 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { diag } } + +#[derive(Diagnostic)] +#[diag("lifetime parameter `{$ident}` never used")] +pub(crate) struct UnusedLifetime { + #[suggestion("elide the unused lifetime", code = "", applicability = "machine-applicable")] + pub deletion_span: Option, + + pub ident: Ident, +} + +#[derive(Diagnostic)] +#[diag("ambiguous glob re-exports")] +pub(crate) struct AmbiguousGlobReexports { + #[label("the name `{$name}` in the {$namespace} namespace is first re-exported here")] + pub first_reexport: Span, + #[label("but the name `{$name}` in the {$namespace} namespace is also re-exported here")] + pub duplicate_reexport: Span, + + pub name: String, + pub namespace: String, +} + +#[derive(Diagnostic)] +#[diag("private item shadows public glob re-export")] +pub(crate) struct HiddenGlobReexports { + #[note( + "the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here" + )] + pub glob_reexport: Span, + #[note("but the private item here shadows it")] + pub private_item: Span, + + pub name: String, + pub namespace: String, +} + +#[derive(Diagnostic)] +#[diag("the item `{$ident}` is imported redundantly")] +pub(crate) struct RedundantImport { + #[subdiagnostic] + pub subs: Vec, + pub ident: Ident, +} + +#[derive(Subdiagnostic)] +pub(crate) enum RedundantImportSub { + #[label("the item `{$ident}` is already imported here")] + ImportedHere { + #[primary_span] + span: Span, + ident: Ident, + }, + #[label("the item `{$ident}` is already defined here")] + DefinedHere { + #[primary_span] + span: Span, + ident: Ident, + }, + #[label("the item `{$ident}` is already imported by the extern prelude")] + ImportedPrelude { + #[primary_span] + span: Span, + ident: Ident, + }, + #[label("the item `{$ident}` is already defined by the extern prelude")] + DefinedPrelude { + #[primary_span] + span: Span, + ident: Ident, + }, +} + +#[derive(Diagnostic)] +#[diag("unnecessary qualification")] +pub(crate) struct UnusedQualifications { + #[suggestion( + "remove the unnecessary path segments", + style = "verbose", + code = "", + applicability = "machine-applicable" + )] + pub removal_span: Span, +} + +#[derive(Diagnostic)] +#[diag( + "{$elided -> + [true] `&` without an explicit lifetime name cannot be used here + *[false] `'_` cannot be used here + }" +)] +pub(crate) struct AssociatedConstElidedLifetime { + #[suggestion( + "use the `'static` lifetime", + style = "verbose", + code = "{code}", + applicability = "machine-applicable" + )] + pub span: Span, + + pub code: &'static str, + pub elided: bool, + #[note("cannot automatically infer `'static` because of other lifetimes in scope")] + pub lifetimes_in_scope: MultiSpan, +} diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7cfd5b5f861a..069018139145 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -26,7 +26,7 @@ AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingKey, CmResolver, Decl, DeclKind, Determinacy, Finalize, IdentKey, ImportKind, LateDecl, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, - Segment, Stage, Used, errors, + Segment, Stage, Symbol, Used, errors, }; #[derive(Copy, Clone)] @@ -386,7 +386,6 @@ pub(crate) fn resolve_ident_in_lexical_scope( } /// Resolve an identifier in the specified set of scopes. - #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_ident_in_scope_set<'r>( self: CmResolver<'r, 'ra, 'tcx>, orig_ident: Ident, @@ -639,6 +638,13 @@ fn resolve_ident_in_scope<'r>( Err(ControlFlow::Break(..)) => return decl, } } + Scope::ModuleGlobs(module, _) + if let ModuleKind::Def(_, def_id, _) = module.kind + && !def_id.is_local() => + { + // Fast path: external module decoding only creates non-glob declarations. + Err(Determined) + } Scope::ModuleGlobs(module, derive_fallback_lint_id) => { let (adjusted_parent_scope, adjusted_finalize) = if matches!( scope_set, @@ -976,6 +982,14 @@ pub(crate) fn resolve_ident_in_module<'r>( ignore_import, ) } + ModuleOrUniformRoot::OpenModule(sym) => { + let open_ns_name = format!("{}::{}", sym.as_str(), ident.name); + let ns_ident = IdentKey::with_root_ctxt(Symbol::intern(&open_ns_name)); + match self.extern_prelude_get_flag(ns_ident, ident.span, finalize.is_some()) { + Some(decl) => Ok(decl), + None => Err(Determinacy::Determined), + } + } ModuleOrUniformRoot::ModuleAndExternPrelude(module) => self.resolve_ident_in_scope_set( ident, ScopeSet::ModuleAndExternPrelude(ns, module), @@ -1366,7 +1380,7 @@ fn single_import_can_define_name<'r>( &single_import.parent_scope, None, ignore_decl, - ignore_import, + None, ) { Err(Determined) => continue, Ok(binding) @@ -1962,7 +1976,10 @@ fn record_segment_res<'r, 'ra, 'tcx>( } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); - if let Some(def_id) = binding.res().module_like_def_id() { + if let Res::OpenMod(sym) = binding.res() { + module = Some(ModuleOrUniformRoot::OpenModule(sym)); + record_segment_res(self.reborrow(), finalize, res, id); + } else if let Some(def_id) = binding.res().module_like_def_id() { if self.mods_with_parse_errors.contains(&def_id) { module_had_parse_errors = true; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7696b4b220d6..6507ee347737 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -6,13 +6,12 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_errors::codes::*; -use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; +use rustc_errors::{Applicability, Diagnostic, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_hir::def_id::{DefId, LocalDefIdMap}; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::span_bug; use rustc_middle::ty::Visibility; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS, @@ -26,9 +25,10 @@ use crate::Namespace::{self, *}; use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ - CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate, - CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, - ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate, + self, CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, + CannotBeReexportedPrivate, CannotBeReexportedPrivateNS, CannotDetermineImportResolution, + CannotGlobImportAllCrates, ConsiderAddingMacroExport, ConsiderMarkingAsPub, + ConsiderMarkingAsPubCrate, }; use crate::ref_mut::CmCell; use crate::{ @@ -41,7 +41,7 @@ /// A potential import declaration in the process of being planted into a module. /// Also used for lazily planting names from `--extern` flags to extern prelude. -#[derive(Clone, Copy, Default, PartialEq)] +#[derive(Clone, Copy, Default, PartialEq, Debug)] pub(crate) enum PendingDecl<'ra> { Ready(Option>), #[default] @@ -721,11 +721,11 @@ pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet) -> boo let mut redundant_spans: Vec<_> = redundant_span.present_items().collect(); redundant_spans.sort(); redundant_spans.dedup(); - self.lint_buffer.buffer_lint( + self.lint_buffer.dyn_buffer_lint( REDUNDANT_IMPORTS, id, import.span, - BuiltinLintDiag::RedundantImport(redundant_spans, source), + move |dcx, level| { + let ident = source; + let subs = redundant_spans + .into_iter() + .map(|(span, is_imported)| match (span.is_dummy(), is_imported) { + (false, true) => { + errors::RedundantImportSub::ImportedHere { span, ident } + } + (false, false) => { + errors::RedundantImportSub::DefinedHere { span, ident } + } + (true, true) => { + errors::RedundantImportSub::ImportedPrelude { span, ident } + } + (true, false) => { + errors::RedundantImportSub::DefinedPrelude { span, ident } + } + }) + .collect(); + errors::RedundantImport { subs, ident }.into_diag(dcx, level) + }, ); return true; } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1e2daff6d97c..b3a6fe95e5fa 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -29,24 +29,20 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::{ - AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationAttrs, DelegationFnSig, - DelegationFnSigAttrs, DelegationInfo, Visibility, -}; +use rustc_middle::ty::{AssocTag, DelegationInfo, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; use rustc_session::parse::feature_err; -use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Spanned, Symbol, kw, respan, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ - BindingError, BindingKey, Decl, Finalize, IdentKey, LateDecl, Module, ModuleOrUniformRoot, - ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used, - errors, path_names_to_string, rustdoc, + BindingError, BindingKey, Decl, DelegationFnSig, Finalize, IdentKey, LateDecl, Module, + ModuleOrUniformRoot, ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, + TyCtxt, UseError, Used, errors, path_names_to_string, rustdoc, }; mod diagnostics; @@ -453,6 +449,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> { DefineOpaques, /// Resolving a macro Macro, + /// Paths for module or crate root. Used for restrictions. + Module, } impl PathSource<'_, '_, '_> { @@ -461,7 +459,8 @@ fn namespace(self) -> Namespace { PathSource::Type | PathSource::Trait(_) | PathSource::Struct(_) - | PathSource::DefineOpaques => TypeNS, + | PathSource::DefineOpaques + | PathSource::Module => TypeNS, PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) @@ -486,7 +485,8 @@ fn defer_to_typeck(self) -> bool { | PathSource::DefineOpaques | PathSource::Delegation | PathSource::PreciseCapturingArg(..) - | PathSource::Macro => false, + | PathSource::Macro + | PathSource::Module => false, } } @@ -529,6 +529,7 @@ fn descr_expected(self) -> &'static str { PathSource::ReturnTypeNotation | PathSource::Delegation => "function", PathSource::PreciseCapturingArg(..) => "type or const parameter", PathSource::Macro => "macro", + PathSource::Module => "module", } } @@ -627,6 +628,7 @@ pub(crate) fn is_expected(self, res: Res) -> bool { ), PathSource::PreciseCapturingArg(MacroNS) => false, PathSource::Macro => matches!(res, Res::Def(DefKind::Macro(_), _)), + PathSource::Module => matches!(res, Res::Def(DefKind::Mod, _)), } } @@ -647,6 +649,12 @@ fn error_code(self, has_unexpected_resolution: bool) -> ErrCode { (PathSource::PreciseCapturingArg(..), true) => E0799, (PathSource::PreciseCapturingArg(..), false) => E0800, (PathSource::Macro, _) => E0425, + // FIXME: There is no dedicated error code for this case yet. + // E0577 already covers the same situation for visibilities, + // so we reuse it here for now. It may make sense to generalize + // it for restrictions in the future. + (PathSource::Module, true) => E0577, + (PathSource::Module, false) => E0433, } } } @@ -1874,13 +1882,21 @@ fn resolve_anonymous_lifetime( ); return; } else if emit_lint { + let lt_span = if elided { + lifetime.ident.span.shrink_to_hi() + } else { + lifetime.ident.span + }; + let code = if elided { "'static " } else { "'static" }; + self.r.lint_buffer.buffer_lint( lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, node_id, lifetime.ident.span, - lint::BuiltinLintDiag::AssociatedConstElidedLifetime { + crate::errors::AssociatedConstElidedLifetime { elided, - span: lifetime.ident.span, + code, + span: lt_span, lifetimes_in_scope: lifetimes_in_scope.into(), }, ); @@ -2175,7 +2191,8 @@ fn resolve_elided_lifetimes_in_path( | PathSource::Type | PathSource::PreciseCapturingArg(..) | PathSource::ReturnTypeNotation - | PathSource::Macro => false, + | PathSource::Macro + | PathSource::Module => false, PathSource::Expr(..) | PathSource::Pat | PathSource::Struct(_) @@ -2801,7 +2818,10 @@ fn resolve_item(&mut self, item: &'ast Item) { self.diag_metadata.current_impl_items = None; } - ItemKind::Trait(box Trait { generics, bounds, items, .. }) => { + ItemKind::Trait(box Trait { generics, bounds, items, impl_restriction, .. }) => { + // resolve paths for `impl` restrictions + self.resolve_impl_restriction_path(impl_restriction); + // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, @@ -2990,7 +3010,7 @@ fn resolve_item(&mut self, item: &'ast Item) { item.id, LifetimeBinderKind::Function, span, - |this| this.resolve_delegation(delegation, item.id, false, &item.attrs), + |this| this.resolve_delegation(delegation, item.id, false), ); } @@ -3336,7 +3356,7 @@ fn resolve_trait_items(&mut self, trait_items: &'ast [Box]) { item.id, LifetimeBinderKind::Function, delegation.path.segments.last().unwrap().ident.span, - |this| this.resolve_delegation(delegation, item.id, false, &item.attrs), + |this| this.resolve_delegation(delegation, item.id, false), ); } AssocItemKind::Type(box TyAlias { generics, .. }) => self @@ -3650,7 +3670,7 @@ fn resolve_impl_item( // Here we don't use `trait_id`, as we can process unresolved trait, however // in this case we are still in a trait impl, https://github.com/rust-lang/rust/issues/150152 - this.resolve_delegation(delegation, item.id, is_in_trait_impl, &item.attrs); + this.resolve_delegation(delegation, item.id, is_in_trait_impl); }, ); } @@ -3805,7 +3825,6 @@ fn resolve_delegation( delegation: &'ast Delegation, item_id: NodeId, is_in_trait_impl: bool, - attrs: &[Attribute], ) { self.smart_resolve_path( delegation.id, @@ -3823,7 +3842,6 @@ fn resolve_delegation( self.r.delegation_infos.insert( self.r.local_def_id(item_id), DelegationInfo { - attrs: create_delegation_attrs(attrs), resolution_node: if is_in_trait_impl { item_id } else { delegation.id }, }, ); @@ -4055,7 +4073,7 @@ fn check_consistent_bindings(&mut self, pat: &'ast Pat) { fn resolve_arm(&mut self, arm: &'ast Arm) { self.with_rib(ValueNS, RibKind::Normal, |this| { this.resolve_pattern_top(&arm.pat, PatternSource::Match); - visit_opt!(this, visit_expr, &arm.guard); + visit_opt!(this, visit_expr, arm.guard.as_ref().map(|g| &g.cond)); visit_opt!(this, visit_expr, &arm.body); }); } @@ -4197,7 +4215,7 @@ fn resolve_pattern_inner( let subpat_bindings = bindings.pop().unwrap().1; self.with_rib(ValueNS, RibKind::Normal, |this| { *this.innermost_rib_bindings(ValueNS) = subpat_bindings.clone(); - this.resolve_expr(guard, None); + this.resolve_expr(&guard.cond, None); }); // Propagate the subpattern's bindings upwards. // FIXME(guard_patterns): For `if let` guards, we'll also need to get the @@ -4390,6 +4408,25 @@ fn try_resolve_as_non_binding( } } + fn resolve_impl_restriction_path(&mut self, restriction: &'ast ast::ImplRestriction) { + match &restriction.kind { + ast::RestrictionKind::Unrestricted => (), + ast::RestrictionKind::Restricted { path, id, shorthand: _ } => { + self.smart_resolve_path(*id, &None, path, PathSource::Module); + if let Some(res) = self.r.partial_res_map[&id].full_res() + && let Some(def_id) = res.opt_def_id() + { + if !self.r.is_accessible_from( + Visibility::Restricted(def_id), + self.parent_scope.module, + ) { + self.r.dcx().create_err(errors::RestrictionAncestorOnly(path.span)).emit(); + } + } + } + } + } + // High-level and context dependent path resolution routine. // Resolves the path and records the resolution into definition map. // If resolution fails tries several techniques to find likely @@ -4426,7 +4463,7 @@ fn smart_resolve_path_fragment( let Finalize { node_id, path_span, .. } = finalize; let report_errors = |this: &mut Self, res: Option| { if this.should_report_errs() { - let (err, candidates) = this.smart_resolve_report_errors( + let (mut err, candidates) = this.smart_resolve_report_errors( path, None, path_span, @@ -4437,7 +4474,8 @@ fn smart_resolve_path_fragment( let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); - let suggestion = if let Some((start, end)) = this.diag_metadata.in_range + let (suggestion, const_err) = if let Some((start, end)) = + this.diag_metadata.in_range && path[0].ident.span.lo() == end.span.lo() && !matches!(start.kind, ExprKind::Lit(_)) { @@ -4449,12 +4487,15 @@ fn smart_resolve_path_fragment( span = span.with_lo(span.lo() + BytePos(1)); sugg = ""; } - Some(( - span, - "you might have meant to write `.` instead of `..`", - sugg.to_string(), - Applicability::MaybeIncorrect, - )) + ( + Some(( + span, + "you might have meant to write `.` instead of `..`", + sugg.to_string(), + Applicability::MaybeIncorrect, + )), + None, + ) } else if res.is_none() && let PathSource::Type | PathSource::Expr(_) @@ -4462,9 +4503,14 @@ fn smart_resolve_path_fragment( { this.suggest_adding_generic_parameter(path, source) } else { - None + (None, None) }; + if let Some(const_err) = const_err { + err.cancel(); + err = const_err; + } + let ue = UseError { err, candidates, @@ -5434,52 +5480,13 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> { } impl ItemInfoCollector<'_, '_, '_> { - fn collect_fn_info( - &mut self, - header: FnHeader, - decl: &FnDecl, - id: NodeId, - attrs: &[Attribute], - ) { - self.r.delegation_fn_sigs.insert( - self.r.local_def_id(id), - DelegationFnSig { - header, - param_count: decl.inputs.len(), - has_self: decl.has_self(), - c_variadic: decl.c_variadic(), - attrs: create_delegation_attrs(attrs), - }, - ); + fn collect_fn_info(&mut self, decl: &FnDecl, id: NodeId) { + self.r + .delegation_fn_sigs + .insert(self.r.local_def_id(id), DelegationFnSig { has_self: decl.has_self() }); } } -fn create_delegation_attrs(attrs: &[Attribute]) -> DelegationAttrs { - static NAMES_TO_FLAGS: &[(Symbol, DelegationFnSigAttrs)] = &[ - (sym::target_feature, DelegationFnSigAttrs::TARGET_FEATURE), - (sym::must_use, DelegationFnSigAttrs::MUST_USE), - ]; - - let mut to_inherit_attrs = AttrVec::new(); - let mut flags = DelegationFnSigAttrs::empty(); - - 'attrs_loop: for attr in attrs { - for &(name, flag) in NAMES_TO_FLAGS { - if attr.has_name(name) { - flags.set(flag, true); - - if flag.bits() >= DELEGATION_INHERIT_ATTRS_START.bits() { - to_inherit_attrs.push(attr.clone()); - } - - continue 'attrs_loop; - } - } - } - - DelegationAttrs { flags, to_inherit: to_inherit_attrs } -} - fn required_generic_args_suggestion(generics: &ast::Generics) -> Option { let required = generics .params @@ -5519,7 +5526,7 @@ fn visit_item(&mut self, item: &'ast Item) { | ItemKind::Trait(box Trait { generics, .. }) | ItemKind::TraitAlias(box TraitAlias { generics, .. }) => { if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind { - self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs); + self.collect_fn_info(&sig.decl, item.id); } let def_id = self.r.local_def_id(item.id); @@ -5531,12 +5538,10 @@ fn visit_item(&mut self, item: &'ast Item) { self.r.item_generics_num_lifetimes.insert(def_id, count); } - ItemKind::ForeignMod(ForeignMod { extern_span, safety: _, abi, items }) => { + ItemKind::ForeignMod(ForeignMod { items, .. }) => { for foreign_item in items { if let ForeignItemKind::Fn(box Fn { sig, .. }) = &foreign_item.kind { - let new_header = - FnHeader { ext: Extern::from_abi(*abi, *extern_span), ..sig.header }; - self.collect_fn_info(new_header, &sig.decl, foreign_item.id, &item.attrs); + self.collect_fn_info(&sig.decl, foreign_item.id); } } } @@ -5562,7 +5567,7 @@ fn visit_item(&mut self, item: &'ast Item) { fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) { if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { - self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs); + self.collect_fn_info(&sig.decl, item.id); } if let AssocItemKind::Type(box ast::TyAlias { generics, .. }) = &item.kind { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 95a6b25d54e6..cf048231bd60 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -6,11 +6,12 @@ use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty}; use rustc_ast::{ - self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind, - Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind, + self as ast, AngleBracketedArg, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericArg, + GenericArgs, GenericParam, GenericParamKind, Item, ItemKind, MethodCall, NodeId, Path, + PathSegment, Ty, TyKind, }; use rustc_ast_pretty::pprust::{path_to_string, where_bound_predicate_to_string}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize, @@ -37,8 +38,8 @@ }; use crate::ty::fast_reject::SimplifiedType; use crate::{ - Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, Resolver, - ScopeSet, Segment, errors, path_names_to_string, + Finalize, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, + Resolver, ScopeSet, Segment, errors, path_names_to_string, }; type Res = def::Res; @@ -1271,7 +1272,7 @@ fn suggest_typo( Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_error.span) && base_error.could_be_expr => { - err.span_suggestion_short( + err.span_suggestion_verbose( pat_sp.between(ty_sp), "use `=` if you meant to assign", " = ", @@ -3277,11 +3278,203 @@ fn suggest_using_enum_variant( } } - pub(crate) fn suggest_adding_generic_parameter( - &self, + /// Detects missing const parameters in `impl` blocks and suggests adding them. + /// + /// When a const parameter is used in the self type of an `impl` but not declared + /// in the `impl`'s own generic parameter list, this function emits a targeted + /// diagnostic with a suggestion to add it at the correct position. + /// + /// Example: + /// + /// ```rust,ignore (suggested field is not completely correct, it should be a single suggestion) + /// struct C; + /// + /// impl Foo for C {} + /// // ^ the struct `C` in `C` is used as the self type + /// // ^ ^ ^ but A, X and P are not declared on the impl + /// + /// Suggested fix: + /// + /// impl Foo for C {} + /// + /// Current behavior (suggestions are emitted one-by-one): + /// + /// impl Foo for C {} + /// impl Foo for C {} + /// impl Foo for C {} + /// + /// Ideally the suggestion should aggregate them into a single line: + /// + /// impl Foo for C {} + /// ``` + /// + pub(crate) fn detect_and_suggest_const_parameter_error( + &mut self, path: &[Segment], - source: PathSource<'_, '_, '_>, - ) -> Option<(Span, &'static str, String, Applicability)> { + source: PathSource<'_, 'ast, 'ra>, + ) -> Option> { + let Some(item) = self.diag_metadata.current_item else { return None }; + let ItemKind::Impl(impl_) = &item.kind else { return None }; + let self_ty = &impl_.self_ty; + + // Represents parameter to the struct whether `A`, `X` or `P` + let [current_parameter] = path else { + return None; + }; + + let target_ident = current_parameter.ident; + + // Find the parent segment i.e `C` in `C` + let visitor = ParentPathVisitor::new(self_ty, target_ident); + + let Some(parent_segment) = visitor.parent else { + return None; + }; + + let Some(args) = parent_segment.args.as_ref() else { + return None; + }; + + let GenericArgs::AngleBracketed(angle) = args.as_ref() else { + return None; + }; + + // Build map: NodeId of each usage in C -> its position + // e.g NodeId(A) -> 0, NodeId(X) -> 1, NodeId(C) -> 2 + let usage_to_pos: FxHashMap = angle + .args + .iter() + .enumerate() + .filter_map(|(pos, arg)| { + if let AngleBracketedArg::Arg(GenericArg::Type(ty)) = arg + && let TyKind::Path(_, path) = &ty.kind + && let [segment] = path.segments.as_slice() + { + Some((segment.id, pos)) + } else { + None + } + }) + .collect(); + + // Get the position of the missing param in C + // e.g for missing `B` in `C` this gives idx=1 + let Some(idx) = current_parameter.id.and_then(|id| usage_to_pos.get(&id).copied()) else { + return None; + }; + + // Now resolve the parent struct `C` to get its definition + let ns = source.namespace(); + let segment = Segment::from(parent_segment); + let segments = [segment]; + let finalize = Finalize::new(parent_segment.id, parent_segment.ident.span); + + if let Ok(Some(resolve)) = self.resolve_qpath_anywhere( + &None, + &segments, + ns, + source.defer_to_typeck(), + finalize, + source, + ) && let Some(resolve) = resolve.full_res() + && let Res::Def(_, def_id) = resolve + && def_id.is_local() + && let Some(local_def_id) = def_id.as_local() + && let Some(struct_generics) = self.r.struct_generics.get(&local_def_id) + && let Some(target_param) = &struct_generics.params.get(idx) + && let GenericParamKind::Const { ty, .. } = &target_param.kind + && let TyKind::Path(_, path) = &ty.kind + { + let full_type = path + .segments + .iter() + .map(|seg| seg.ident.to_string()) + .collect::>() + .join("::"); + + // Find the first impl param whose position in C + // is strictly greater than our missing param's index + // e.g missing B(idx=1), impl has A(pos=0) and C(pos=2) + // C has pos=2 > 1 so insert before C + let next_impl_param = impl_.generics.params.iter().find(|impl_param| { + angle + .args + .iter() + .find_map(|arg| { + if let AngleBracketedArg::Arg(GenericArg::Type(ty)) = arg + && let TyKind::Path(_, path) = &ty.kind + && let [segment] = path.segments.as_slice() + && segment.ident == impl_param.ident + { + usage_to_pos.get(&segment.id).copied() + } else { + None + } + }) + .map_or(false, |pos| pos > idx) + }); + + let (insert_span, snippet) = match next_impl_param { + Some(next_param) => { + // Insert in the middle before next_param + // e.g impl -> impl + ( + next_param.span().shrink_to_lo(), + format!("const {}: {}, ", target_ident, full_type), + ) + } + None => match impl_.generics.params.last() { + Some(last) => { + // Append after last existing param + // e.g impl -> impl + ( + last.span().shrink_to_hi(), + format!(", const {}: {}", target_ident, full_type), + ) + } + None => { + // No generics at all on impl + // e.g impl Foo for C -> impl Foo for C + ( + impl_.generics.span.shrink_to_hi(), + format!("", target_ident, full_type), + ) + } + }, + }; + + let mut err = self.r.dcx().struct_span_err( + target_ident.span, + format!("cannot find const `{}` in this scope", target_ident), + ); + + err.code(E0425); + + err.span_label(target_ident.span, "not found in this scope"); + + err.span_label( + target_param.span(), + format!("corresponding const parameter on the type defined here",), + ); + + err.subdiagnostic(errors::UnexpectedMissingConstParameter { + span: insert_span, + snippet, + item_name: format!("{}", target_ident), + item_location: String::from("impl"), + }); + + return Some(err); + } + + None + } + + pub(crate) fn suggest_adding_generic_parameter( + &mut self, + path: &[Segment], + source: PathSource<'_, 'ast, 'ra>, + ) -> (Option<(Span, &'static str, String, Applicability)>, Option>) { let (ident, span) = match path { [segment] if !segment.has_generic_args @@ -3290,13 +3483,13 @@ pub(crate) fn suggest_adding_generic_parameter( { (segment.ident.to_string(), segment.ident.span) } - _ => return None, + _ => return (None, None), }; let mut iter = ident.chars().map(|c| c.is_uppercase()); let single_uppercase_char = matches!(iter.next(), Some(true)) && matches!(iter.next(), None); if !self.diag_metadata.currently_processing_generic_args && !single_uppercase_char { - return None; + return (None, None); } match (self.diag_metadata.current_item, single_uppercase_char, self.diag_metadata.currently_processing_generic_args) { (Some(Item { kind: ItemKind::Fn(fn_), .. }), _, _) if fn_.ident.name == sym::main => { @@ -3326,18 +3519,21 @@ pub(crate) fn suggest_adding_generic_parameter( // | ^- help: you might be missing a type parameter: `, A` // | | // | not found in this scope - return None; + return (None, None); } let (msg, sugg) = match source { PathSource::Type | PathSource::PreciseCapturingArg(TypeNS) => { + if let Some(err) = self.detect_and_suggest_const_parameter_error(path, source) { + return (None, Some(err)); + } ("you might be missing a type parameter", ident) } PathSource::Expr(_) | PathSource::PreciseCapturingArg(ValueNS) => ( "you might be missing a const parameter", format!("const {ident}: /* Type */"), ), - _ => return None, + _ => return (None, None), }; let (span, sugg) = if let [.., param] = &generics.params[..] { let span = if let [.., bound] = ¶m.bounds[..] { @@ -3355,18 +3551,18 @@ pub(crate) fn suggest_adding_generic_parameter( }; // Do not suggest if this is coming from macro expansion. if span.can_be_used_for_suggestions() { - return Some(( + return (Some(( span.shrink_to_hi(), msg, sugg, Applicability::MaybeIncorrect, - )); + )), None); } } } _ => {} } - None + (None, None) } /// Given the target `label`, search the `rib_index`th label rib for similarly named labels, @@ -3457,7 +3653,8 @@ pub(crate) fn maybe_report_lifetime_uses( param.ident.span, lint::BuiltinLintDiag::SingleUseLifetime { param_span: param.ident.span, - use_span: Some((use_span, elidable)), + use_span, + elidable, deletion_span, ident: param.ident, }, @@ -3473,12 +3670,7 @@ pub(crate) fn maybe_report_lifetime_uses( lint::builtin::UNUSED_LIFETIMES, param.id, param.ident.span, - lint::BuiltinLintDiag::SingleUseLifetime { - param_span: param.ident.span, - use_span: None, - deletion_span, - ident: param.ident, - }, + errors::UnusedLifetime { deletion_span, ident: param.ident }, ); } } @@ -4349,3 +4541,44 @@ pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident .with_span_label(shadower, format!("label `{name}` already in scope")) .emit(); } + +struct ParentPathVisitor<'a> { + target: Ident, + parent: Option<&'a PathSegment>, + stack: Vec<&'a Ty>, +} + +impl<'a> ParentPathVisitor<'a> { + fn new(self_ty: &'a Ty, target: Ident) -> Self { + let mut v = ParentPathVisitor { target, parent: None, stack: Vec::new() }; + + v.visit_ty(self_ty); + v + } +} + +impl<'a> Visitor<'a> for ParentPathVisitor<'a> { + fn visit_ty(&mut self, ty: &'a Ty) { + if self.parent.is_some() { + return; + } + + // push current type + self.stack.push(ty); + + if let TyKind::Path(_, path) = &ty.kind + // is this just `N`? + && let [segment] = path.segments.as_slice() + && segment.ident == self.target + // parent is previous element in stack + && let [.., parent_ty, _ty] = self.stack.as_slice() + && let TyKind::Path(_, parent_path) = &parent_ty.kind + { + self.parent = parent_path.segments.first(); + } + + walk_ty(self, ty); + + self.stack.pop(); + } +} diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ead69473b00d..72d5cdcf1f3b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -40,7 +40,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::{ self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, - NodeId, Path, attr, + Generics, NodeId, Path, attr, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, default}; use rustc_data_structures::intern::Interned; @@ -61,12 +61,13 @@ use rustc_hir::{PrimTy, TraitCandidate, find_attr}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::CStore; +use rustc_middle::bug; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, DelegationFnSig, DelegationInfo, Feed, MainDefinition, RegisteredTools, - ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, + self, DelegationInfo, Feed, MainDefinition, RegisteredTools, ResolverAstLowering, + ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_session::config::CrateType; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; @@ -445,6 +446,11 @@ enum ModuleOrUniformRoot<'ra> { /// Used only for resolving single-segment imports. The reason it exists is that import paths /// are always split into two parts, the first of which should be some kind of module. CurrentScope, + + /// Virtual module for the resolution of base names of namespaced crates, + /// where the base name doesn't correspond to a module in the extern prelude. + /// E.g. `my_api::utils` is in the prelude, but `my_api` is not. + OpenModule(Symbol), } #[derive(Debug)] @@ -541,6 +547,13 @@ fn name(&self) -> Option { ModuleKind::Def(.., name) => name, } } + + fn opt_def_id(&self) -> Option { + match self { + ModuleKind::Def(_, def_id, _) => Some(*def_id), + _ => None, + } + } } /// Combination of a symbol and its macros 2.0 normalized hygiene context. @@ -778,10 +791,7 @@ fn def_id(self) -> DefId { } fn opt_def_id(self) -> Option { - match self.kind { - ModuleKind::Def(_, def_id, _) => Some(def_id), - _ => None, - } + self.kind.opt_def_id() } // `self` resolves to the first module ancestor that `is_normal`. @@ -1105,13 +1115,20 @@ fn determined(&self) -> bool { } } +#[derive(Debug)] struct ExternPreludeEntry<'ra> { /// Name declaration from an `extern crate` item. /// The boolean flag is true is `item_decl` is non-redundant, happens either when /// `flag_decl` is `None`, or when `extern crate` introducing `item_decl` used renaming. item_decl: Option<(Decl<'ra>, Span, /* introduced by item */ bool)>, /// Name declaration from an `--extern` flag, lazily populated on first use. - flag_decl: Option, /* finalized */ bool)>>, + flag_decl: Option< + CacheCell<( + PendingDecl<'ra>, + /* finalized */ bool, + /* open flag (namespaced crate) */ bool, + )>, + >, } impl ExternPreludeEntry<'_> { @@ -1122,7 +1139,14 @@ fn introduced_by_item(&self) -> bool { fn flag() -> Self { ExternPreludeEntry { item_decl: None, - flag_decl: Some(CacheCell::new((PendingDecl::Pending, false))), + flag_decl: Some(CacheCell::new((PendingDecl::Pending, false, false))), + } + } + + fn open_flag() -> Self { + ExternPreludeEntry { + item_decl: None, + flag_decl: Some(CacheCell::new((PendingDecl::Pending, false, true))), } } @@ -1157,6 +1181,11 @@ pub struct ResolverOutputs<'tcx> { pub ast_lowering: ResolverAstLowering<'tcx>, } +#[derive(Debug)] +struct DelegationFnSig { + pub has_self: bool, +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -1317,6 +1346,10 @@ pub struct Resolver<'ra, 'tcx> { /// Also includes of list of each fields visibility struct_constructors: LocalDefIdMap<(Res, Visibility, Vec>)> = Default::default(), + /// for all the struct + /// it's not used during normal resolution, only for better error reporting. + struct_generics: LocalDefIdMap = Default::default(), + lint_buffer: LintBuffer, next_node_id: NodeId = CRATE_NODE_ID, @@ -1421,14 +1454,19 @@ fn new_module( &'ra self, parent: Option>, kind: ModuleKind, + vis: Visibility, expn_id: ExpnId, span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { let self_decl = match kind { - ModuleKind::Def(def_kind, def_id, _) => { - Some(self.new_pub_def_decl(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)) - } + ModuleKind::Def(def_kind, def_id, _) => Some(self.new_def_decl( + Res::Def(def_kind, def_id), + vis, + span, + LocalExpnId::ROOT, + None, + )), ModuleKind::Block => None, }; Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( @@ -1610,6 +1648,7 @@ pub fn new( let graph_root = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), + Visibility::Public, ExpnId::root(), crate_span, attr::contains_name(attrs, sym::no_implicit_prelude), @@ -1619,6 +1658,7 @@ pub fn new( let empty_module = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), + Visibility::Public, ExpnId::root(), DUMMY_SP, true, @@ -1634,35 +1674,7 @@ pub fn new( let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); - let mut extern_prelude: FxIndexMap<_, _> = tcx - .sess - .opts - .externs - .iter() - .filter_map(|(name, entry)| { - // Make sure `self`, `super`, `_` etc do not get into extern prelude. - // FIXME: reject `--extern self` and similar in option parsing instead. - if entry.add_prelude - && let name = Symbol::intern(name) - && name.can_be_raw() - { - let ident = IdentKey::with_root_ctxt(name); - Some((ident, ExternPreludeEntry::flag())) - } else { - None - } - }) - .collect(); - - if !attr::contains_name(attrs, sym::no_core) { - let ident = IdentKey::with_root_ctxt(sym::core); - extern_prelude.insert(ident, ExternPreludeEntry::flag()); - if !attr::contains_name(attrs, sym::no_std) { - let ident = IdentKey::with_root_ctxt(sym::std); - extern_prelude.insert(ident, ExternPreludeEntry::flag()); - } - } - + let extern_prelude = build_extern_prelude(tcx, attrs); let registered_tools = tcx.registered_tools(()); let edition = tcx.sess.edition(); @@ -1748,7 +1760,9 @@ fn new_local_module( span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { - let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude); + let vis = + kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id)); + let module = self.arenas.new_module(parent, kind, vis, expn_id, span, no_implicit_prelude); self.local_modules.push(module); if let Some(def_id) = module.opt_def_id() { self.local_module_map.insert(def_id.expect_local(), module); @@ -1764,7 +1778,9 @@ fn new_extern_module( span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { - let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude); + let vis = + kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id)); + let module = self.arenas.new_module(parent, kind, vis, expn_id, span, no_implicit_prelude); self.extern_module_map.borrow_mut().insert(module.def_id(), module); module } @@ -1817,9 +1833,9 @@ pub fn into_outputs(self) -> ResolverOutputs<'tcx> { .stripped_cfg_items .into_iter() .filter_map(|item| { - let parent_module = - self.node_id_to_def_id.get(&item.parent_module)?.key().to_def_id(); - Some(StrippedCfgItem { parent_module, ident: item.ident, cfg: item.cfg }) + let parent_scope = + self.node_id_to_def_id.get(&item.parent_scope)?.key().to_def_id(); + Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg }) }) .collect(); @@ -1856,7 +1872,6 @@ pub fn into_outputs(self) -> ResolverOutputs<'tcx> { trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), - delegation_fn_sigs: self.delegation_fn_sigs, delegation_infos: self.delegation_infos, }; ResolverOutputs { global_ctxt, ast_lowering } @@ -2318,10 +2333,10 @@ fn extern_prelude_get_flag( ) -> Option> { let entry = self.extern_prelude.get(&ident); entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| { - let (pending_decl, finalized) = flag_decl.get(); + let (pending_decl, finalized, is_open) = flag_decl.get(); let decl = match pending_decl { PendingDecl::Ready(decl) => { - if finalize && !finalized { + if finalize && !finalized && !is_open { self.cstore_mut().process_path_extern( self.tcx, ident.name, @@ -2332,18 +2347,28 @@ fn extern_prelude_get_flag( } PendingDecl::Pending => { debug_assert!(!finalized); - let crate_id = if finalize { - self.cstore_mut().process_path_extern(self.tcx, ident.name, orig_ident_span) + if is_open { + let res = Res::OpenMod(ident.name); + Some(self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT)) } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) - }; - crate_id.map(|crate_id| { - let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT) - }) + let crate_id = if finalize { + self.cstore_mut().process_path_extern( + self.tcx, + ident.name, + orig_ident_span, + ) + } else { + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) + }; + crate_id.map(|crate_id| { + let def_id = crate_id.as_def_id(); + let res = Res::Def(DefKind::Mod, def_id); + self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT) + }) + } } }; - flag_decl.set((PendingDecl::Ready(decl), finalize || finalized)); + flag_decl.set((PendingDecl::Ready(decl), finalize || finalized, is_open)); decl.or_else(|| finalize.then_some(self.dummy_decl)) }) } @@ -2385,7 +2410,9 @@ fn resolve_rustdoc_path( PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => { None } - PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), + path_result @ (PathResult::Module(..) | PathResult::Indeterminate) => { + bug!("got invalid path_result: {path_result:?}") + } } } @@ -2503,6 +2530,60 @@ fn resolve_main(&mut self) { } } +fn build_extern_prelude<'tcx, 'ra>( + tcx: TyCtxt<'tcx>, + attrs: &[ast::Attribute], +) -> FxIndexMap> { + let mut extern_prelude: FxIndexMap> = tcx + .sess + .opts + .externs + .iter() + .filter_map(|(name, entry)| { + // Make sure `self`, `super`, `_` etc do not get into extern prelude. + // FIXME: reject `--extern self` and similar in option parsing instead. + if entry.add_prelude + && let sym = Symbol::intern(name) + && sym.can_be_raw() + { + Some((IdentKey::with_root_ctxt(sym), ExternPreludeEntry::flag())) + } else { + None + } + }) + .collect(); + + // Add open base entries for namespaced crates whose base segment + // is missing from the prelude (e.g. `foo::bar` without `foo`). + // These are necessary in order to resolve the open modules, whereas + // the namespaced names are necessary in `extern_prelude` for actually + // resolving the namespaced crates. + let missing_open_bases: Vec = extern_prelude + .keys() + .filter_map(|ident| { + let (base, _) = ident.name.as_str().split_once("::")?; + let base_sym = Symbol::intern(base); + base_sym.can_be_raw().then(|| IdentKey::with_root_ctxt(base_sym)) + }) + .filter(|base_ident| !extern_prelude.contains_key(base_ident)) + .collect(); + + extern_prelude.extend( + missing_open_bases.into_iter().map(|ident| (ident, ExternPreludeEntry::open_flag())), + ); + + // Inject `core` / `std` unless suppressed by attributes. + if !attr::contains_name(attrs, sym::no_core) { + extern_prelude.insert(IdentKey::with_root_ctxt(sym::core), ExternPreludeEntry::flag()); + + if !attr::contains_name(attrs, sym::no_std) { + extern_prelude.insert(IdentKey::with_root_ctxt(sym::std), ExternPreludeEntry::flag()); + } + } + + extern_prelude +} + fn names_to_string(names: impl Iterator) -> String { let mut result = String::new(); for (i, name) in names.enumerate().filter(|(_, name)| *name != kw::PathRoot) { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 551d89ee6022..6ae9d3aaeb23 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -512,7 +512,7 @@ fn append_stripped_cfg_item( cfg_span: Span, ) { self.stripped_cfg_items.push(StrippedCfgItem { - parent_module: parent_node, + parent_scope: parent_node, ident, cfg: (cfg, cfg_span), }); @@ -707,7 +707,7 @@ fn smart_resolve_macro_path( } const DIAG_ATTRS: &[Symbol] = - &[sym::on_unimplemented, sym::do_not_recommend, sym::on_const]; + &[sym::on_unimplemented, sym::do_not_recommend, sym::on_const, sym::on_move]; if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) && let [namespace, attribute, ..] = &*path.segments @@ -1064,8 +1064,7 @@ fn check_stability_and_deprecation( ) { let span = path.span; if let Some(stability) = &ext.stability - && let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } = - stability.level + && let StabilityLevel::Unstable { reason, issue, implied_by, .. } = stability.level { let feature = stability.feature; @@ -1073,25 +1072,13 @@ fn check_stability_and_deprecation( |feature| self.tcx.features().enabled(feature) || span.allows_unstable(feature); let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature)); if !is_allowed(feature) && !allowed_by_implication { - let lint_buffer = &mut self.lint_buffer; - let soft_handler = |lint, span, msg: String| { - lint_buffer.buffer_lint( - lint, - node_id, - span, - // FIXME make this translatable - errors::UnstableFeature { msg: msg.into() }, - ) - }; stability::report_unstable( self.tcx.sess, feature, reason.to_opt_reason(), issue, None, - is_soft, span, - soft_handler, stability::UnstableKind::Regular, ); } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 90b489258360..5691ed146927 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -239,7 +239,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc .flat_map(|super_poly_trait_ref| { tcx.associated_items(super_poly_trait_ref.def_id()) .in_definition_order() - .filter(|item| item.is_type() || item.is_const()) + .filter(|item| item.is_type() || item.is_type_const()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .map(move |assoc_item| { super_poly_trait_ref.map_bound(|super_trait_ref| { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0677ca0fddba..42d5a50df699 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1405,7 +1405,6 @@ fn default() -> Options { }; Options { - assert_incr_state: None, crate_types: Vec::new(), optimize: OptLevel::No, debuginfo: DebugInfo::None, @@ -2287,20 +2286,6 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf if max_g > max_c { DebugInfo::Full } else { cg.debuginfo } } -fn parse_assert_incr_state( - early_dcx: &EarlyDiagCtxt, - opt_assertion: &Option, -) -> Option { - match opt_assertion { - Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded), - Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded), - Some(s) => { - early_dcx.early_fatal(format!("unexpected incremental state assertion value: {s}")) - } - None => None, - } -} - pub fn parse_externs( early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, @@ -2506,8 +2491,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let incremental = cg.incremental.as_ref().map(PathBuf::from); - let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state); - if cg.profile_generate.enabled() && cg.profile_use.is_some() { early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive"); } @@ -2759,7 +2742,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals; Options { - assert_incr_state, crate_types, optimize: opt_level, debuginfo, diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index ebbbe36878da..a7b54e68a071 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -229,6 +229,10 @@ macro_rules! ins_sym { if s == SanitizerSet::KERNELADDRESS { s = SanitizerSet::ADDRESS; } + // KHWASAN is still HWASAN under the hood, so it uses the same attribute. + if s == SanitizerSet::KERNELHWADDRESS { + s = SanitizerSet::HWADDRESS; + } ins_str!(sym::sanitize, &s.to_string()); } @@ -239,7 +243,7 @@ macro_rules! ins_sym { ins_none!(sym::sanitizer_cfi_normalize_integers); } - ins_sym!(sym::target_abi, sess.target.abi.desc_symbol()); + ins_sym!(sym::target_abi, sess.target.cfg_abi.desc_symbol()); ins_sym!(sym::target_arch, sess.target.arch.desc_symbol()); ins_str!(sym::target_endian, sess.target.endian.as_str()); ins_sym!(sym::target_env, sess.target.env.desc_symbol()); @@ -447,7 +451,7 @@ macro_rules! ins { }; for target in Target::builtins().chain(iter::once(current_target.clone())) { - values_target_abi.insert(target.options.abi.desc_symbol()); + values_target_abi.insert(target.options.cfg_abi.desc_symbol()); values_target_arch.insert(target.arch.desc_symbol()); values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); values_target_env.insert(target.options.env.desc_symbol()); diff --git a/compiler/rustc_session/src/config/externs.rs b/compiler/rustc_session/src/config/externs.rs index d668d8b4203d..ff76eaaeaf4f 100644 --- a/compiler/rustc_session/src/config/externs.rs +++ b/compiler/rustc_session/src/config/externs.rs @@ -43,6 +43,13 @@ pub(crate) fn split_extern_opt<'a>( } }; + // Reject paths with more than two segments. + if unstable_opts.namespaced_crates && crate_name.split("::").count() > 2 { + return Err(early_dcx.early_struct_fatal(format!( + "crate name `{crate_name}` passed to `--extern` can have at most two segments." + ))); + } + if !valid_crate_name(&crate_name, unstable_opts) { let mut error = early_dcx.early_struct_fatal(format!( "crate name `{crate_name}` passed to `--extern` is not a valid ASCII identifier" diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 2f969aefda18..c186557ccaa4 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -97,8 +97,15 @@ pub struct DllImport { pub calling_convention: DllCallingConvention, /// Span of import's "extern" declaration; used for diagnostics. pub span: Span, - /// Is this for a function (rather than a static variable). - pub is_fn: bool, + pub symbol_type: DllImportSymbolType, + pub size: rustc_abi::Size, +} + +#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic, PartialEq)] +pub enum DllImportSymbolType { + Function, + Static, + ThreadLocal, } impl DllImport { diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index cb3f7363957e..d1899de067b4 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -517,17 +517,6 @@ pub(crate) struct FailedToCreateProfiler { pub(crate) err: String, } -#[derive(Diagnostic)] -#[diag("`-Csoft-float` is ignored on this target; it only has an effect on *eabihf targets")] -#[note("this may become a hard error in a future version of Rust")] -pub(crate) struct SoftFloatIgnored; - -#[derive(Diagnostic)] -#[diag("`-Csoft-float` is unsound and deprecated; use a corresponding *eabi target instead")] -#[note("it will be removed or ignored in a future version of Rust")] -#[note("see issue #129893 for more information")] -pub(crate) struct SoftFloatDeprecated; - #[derive(Diagnostic)] #[diag("unexpected `--cfg {$cfg}` flag")] #[note("config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}`")] diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 98731a235d41..1741dde90f5c 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,5 +1,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![feature(const_option_ops)] +#![feature(const_trait_impl)] #![feature(default_field_values)] #![feature(iter_intersperse)] #![feature(macro_derive)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 74b3aa11d0d8..8771dbd05c49 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -106,6 +106,7 @@ pub(super) fn sanitizer(l: &TargetModifier, r: Option<&TargetModifier>) -> bool | SanitizerSet::SHADOWCALLSTACK | SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS | SanitizerSet::SAFESTACK | SanitizerSet::DATAFLOW; @@ -418,10 +419,9 @@ pub struct Options { /// If `Some`, enable incremental compilation, using the given /// directory to store intermediate results. incremental: Option [UNTRACKED], - assert_incr_state: Option [UNTRACKED], - /// Set by the `Config::hash_untracked_state` callback for custom - /// drivers to invalidate the incremental cache - #[rustc_lint_opt_deny_field_access("should only be used via `Config::hash_untracked_state`")] + /// Set based on the result of the `Config::track_state` callback + /// for custom drivers to invalidate the incremental cache. + #[rustc_lint_opt_deny_field_access("should only be used via `Config::track_state`")] untracked_state_hash: Hash64 [TRACKED_NO_CRATE_HASH], unstable_opts: UnstableOptions [SUBSTRUCT UnstableOptionsTargetModifiers UnstableOptions], @@ -611,7 +611,7 @@ macro_rules! options { $parse:ident, [$dep_tracking_marker:ident $( $tmod:ident )?], $desc:expr - $(, is_deprecated_and_do_nothing: $dnn:literal )?) + $(, removed: $removed:ident )?) ),* ,) => ( #[derive(Clone)] @@ -667,7 +667,7 @@ pub fn gather_target_modifiers( pub const $stat: OptionDescrs<$struct_name> = &[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt, - type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )?, + type_desc: desc::$parse, desc: $desc, removed: None $( .or(Some(RemovedOption::$removed)) )?, tmod: tmod_enum_opt!($struct_name, $tmod_enum_name, $opt, $($tmod),*) } ),* ]; mod $optmod { @@ -705,6 +705,12 @@ macro_rules! redirect_field { type OptionSetter = fn(&mut O, v: Option<&str>) -> bool; type OptionDescrs = &'static [OptionDesc]; +/// Indicates whether a removed option should warn or error. +enum RemovedOption { + Warn, + Err, +} + pub struct OptionDesc { name: &'static str, setter: OptionSetter, @@ -712,7 +718,7 @@ pub struct OptionDesc { type_desc: &'static str, // description for option from options table desc: &'static str, - is_deprecated_and_do_nothing: bool, + removed: Option, tmod: Option, } @@ -743,18 +749,18 @@ fn build_options( let option_to_lookup = key.replace('-', "_"); match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) { - Some(OptionDesc { - name: _, - setter, - type_desc, - desc, - is_deprecated_and_do_nothing, - tmod, - }) => { - if *is_deprecated_and_do_nothing { + Some(OptionDesc { name: _, setter, type_desc, desc, removed, tmod }) => { + if let Some(removed) = removed { // deprecation works for prefixed options only assert!(!prefix.is_empty()); - early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}")); + match removed { + RemovedOption::Warn => { + early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}")) + } + RemovedOption::Err => { + early_dcx.early_fatal(format!("`-{prefix} {key}`: {desc}")) + } + } } if !setter(&mut op, value) { match value { @@ -783,6 +789,7 @@ fn build_options( #[allow(non_upper_case_globals)] mod desc { + pub(crate) const parse_ignore: &str = ""; // should not be user-visible pub(crate) const parse_no_value: &str = "no value"; pub(crate) const parse_bool: &str = "one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false`"; @@ -810,7 +817,7 @@ mod desc { pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)"; pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy; pub(crate) const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or 'realtime'"; + pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `kernel-hwaddress`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or 'realtime'"; pub(crate) const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub(crate) const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -881,6 +888,7 @@ mod desc { pub(crate) const parse_mir_include_spans: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)"; pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29"; + pub(crate) const parse_assert_incr_state: &str = "one of: `loaded`, `not-loaded`"; } pub mod parse { @@ -889,6 +897,12 @@ pub mod parse { pub(crate) use super::*; pub(crate) const MAX_THREADS_CAP: usize = 256; + /// Ignore the value. Used for removed options where we don't actually want to store + /// anything in the session. + pub(crate) fn parse_ignore(_slot: &mut (), _v: Option<&str>) -> bool { + true + } + /// This is for boolean options that don't take a value, and are true simply /// by existing on the command-line. /// @@ -1252,6 +1266,7 @@ pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool "dataflow" => SanitizerSet::DATAFLOW, "kcfi" => SanitizerSet::KCFI, "kernel-address" => SanitizerSet::KERNELADDRESS, + "kernel-hwaddress" => SanitizerSet::KERNELHWADDRESS, "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, "memtag" => SanitizerSet::MEMTAG, @@ -2046,6 +2061,18 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { true } + + pub(crate) fn parse_assert_incr_state( + slot: &mut Option, + v: Option<&str>, + ) -> bool { + *slot = match v { + Some("loaded") => Some(IncrementalStateAssertion::Loaded), + Some("not-loaded") => Some(IncrementalStateAssertion::NotLoaded), + _ => return false, + }; + true + } } options! { @@ -2059,7 +2086,7 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { #[rustc_lint_opt_deny_field_access("documented to do nothing")] ar: String = (String::new(), parse_string, [UNTRACKED], "this option is deprecated and does nothing", - is_deprecated_and_do_nothing: true), + removed: Warn), #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")] code_model: Option = (None, parse_code_model, [TRACKED], "choose the code model to use (`rustc --print code-models` for details)"), @@ -2098,7 +2125,7 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { inline_threshold: Option = (None, parse_opt_number, [UNTRACKED], "this option is deprecated and does nothing \ (consider using `-Cllvm-args=--inline-threshold=...`)", - is_deprecated_and_do_nothing: true), + removed: Warn), #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage reports \ @@ -2139,7 +2166,7 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { #[rustc_lint_opt_deny_field_access("documented to do nothing")] no_stack_check: bool = (false, parse_no_value, [UNTRACKED], "this option is deprecated and does nothing", - is_deprecated_and_do_nothing: true), + removed: Warn), no_vectorize_loops: bool = (false, parse_no_value, [TRACKED], "disable loop vectorization optimization passes"), no_vectorize_slp: bool = (false, parse_no_value, [TRACKED], @@ -2173,8 +2200,11 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { "set rpath values in libs/exes (default: no)"), save_temps: bool = (false, parse_bool, [UNTRACKED], "save all temporary output files during compilation (default: no)"), - soft_float: bool = (false, parse_bool, [TRACKED], - "deprecated option: use soft float ABI (*eabihf targets only) (default: no)"), + #[rustc_lint_opt_deny_field_access("documented to do nothing")] + soft_float: () = ((), parse_ignore, [UNTRACKED], + "this option has been removed \ + (use a corresponding *eabi target instead)", + removed: Err), #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")] split_debuginfo: Option = (None, parse_split_debuginfo, [TRACKED], "how to handle split-debuginfo, a platform-specific option"), @@ -2212,7 +2242,7 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { annotate_moves: AnnotateMoves = (AnnotateMoves::Disabled, parse_annotate_moves, [TRACKED], "emit debug info for compiler-generated move and copy operations \ to make them visible in profilers. Can be a boolean or a size limit in bytes (default: disabled)"), - assert_incr_state: Option = (None, parse_opt_string, [UNTRACKED], + assert_incr_state: Option = (None, parse_assert_incr_state, [UNTRACKED], "assert that the incremental cache is in given state: \ either `loaded` or `not-loaded`."), assume_incomplete_release: bool = (false, parse_bool, [TRACKED], @@ -2240,7 +2270,7 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { (default: no)"), box_noalias: bool = (true, parse_bool, [TRACKED], "emit noalias metadata for box (default: yes)"), - branch_protection: Option = (None, parse_branch_protection, [TRACKED], + branch_protection: Option = (None, parse_branch_protection, [TRACKED TARGET_MODIFIER], "set options for branch target identification and pointer authentication on AArch64"), build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED], "whether the stable interface is being built"), @@ -2456,6 +2486,8 @@ pub(crate) fn parse_align(slot: &mut Option, v: Option<&str>) -> bool { "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"), min_function_alignment: Option = (None, parse_align, [TRACKED], "align all functions to at least this many bytes. Must be a power of 2"), + min_recursion_limit: Option = (None, parse_opt_number, [TRACKED], + "set a minimum recursion limit (final limit = max(this, recursion_limit_from_crate))"), mir_emit_retag: bool = (false, parse_bool, [TRACKED], "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ (default: no)"), diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 9c12c480cacd..65a15dba4287 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -6,13 +6,13 @@ use rustc_ast::attr::AttrIdGenerator; use rustc_ast::node_id::NodeId; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; -use rustc_data_structures::sync::{AppendOnlyVec, Lock}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::sync::{AppendOnlyVec, DynSend, DynSync, Lock}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{EmitterWithNote, stderr_destination}; use rustc_errors::{ BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle, - DiagMessage, EmissionGuarantee, MultiSpan, StashKey, + DiagMessage, EmissionGuarantee, Level, MultiSpan, StashKey, }; use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue}; use rustc_span::edition::Edition; @@ -79,7 +79,7 @@ pub fn insert(&self, symbol: Symbol, span: Span) { } } -// todo: this function now accepts `Session` instead of `ParseSess` and should be relocated +// FIXME: this function now accepts `Session` instead of `ParseSess` and should be relocated /// Construct a diagnostic for a language feature error due to the given `span`. /// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbol`. #[track_caller] @@ -264,10 +264,6 @@ pub struct ParseSess { pub ambiguous_block_expr_parse: Lock>, pub gated_spans: GatedSpans, pub symbol_gallery: SymbolGallery, - /// Environment variables accessed during the build and their values when they exist. - pub env_depinfo: Lock)>>, - /// File paths accessed during the build. - pub file_depinfo: Lock>, /// Whether cfg(version) should treat the current release as incomplete pub assume_incomplete_release: bool, /// Spans passed to `proc_macro::quote_span`. Each span has a numerical @@ -303,8 +299,6 @@ pub fn with_dcx(dcx: DiagCtxt, source_map: Arc) -> Self { ambiguous_block_expr_parse: Lock::new(Default::default()), gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), - env_depinfo: Default::default(), - file_depinfo: Default::default(), assume_incomplete_release: false, proc_macro_quoted_spans: Default::default(), attr_id_generator: AttrIdGenerator::new(), @@ -337,6 +331,23 @@ pub fn buffer_lint( self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic.into()) } + pub fn dyn_buffer_lint< + F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSync + DynSend + 'static, + >( + &self, + lint: &'static Lint, + span: impl Into, + node_id: NodeId, + callback: F, + ) { + self.opt_span_buffer_lint( + lint, + Some(span.into()), + node_id, + DecorateDiagCompat::Dynamic(Box::new(callback)), + ) + } + pub(crate) fn opt_span_buffer_lint( &self, lint: &'static Lint, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 0548380331be..53eae0d87328 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -143,6 +143,12 @@ pub struct Session { /// None signifies that this is not tracked. pub using_internal_features: &'static AtomicBool, + /// Environment variables accessed during the build and their values when they exist. + pub env_depinfo: Lock)>>, + + /// File paths accessed during the build. + pub file_depinfo: Lock>, + target_filesearch: FileSearch, host_filesearch: FileSearch, @@ -527,9 +533,12 @@ pub fn needs_plt(&self) -> bool { pub fn emit_lifetime_markers(&self) -> bool { self.opts.optimize != config::OptLevel::No // AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs. + // // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. - // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future. - || self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) + // + // HWAddressSanitizer and KernelHWAddressSanitizer will use lifetimes to detect use after + // scope bugs in the future. + || self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS) } pub fn diagnostic_width(&self) -> usize { @@ -1095,6 +1104,8 @@ pub fn build_session( unstable_target_features: Default::default(), cfg_version, using_internal_features, + env_depinfo: Default::default(), + file_depinfo: Default::default(), target_filesearch, host_filesearch, invocation_temp, @@ -1352,16 +1363,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } } - - if sess.opts.cg.soft_float { - if sess.target.arch == Arch::Arm { - sess.dcx().emit_warn(errors::SoftFloatDeprecated); - } else { - // All `use_softfp` does is the equivalent of `-mfloat-abi` in GCC/clang, which only exists on ARM targets. - // We document this flag to only affect `*eabihf` targets, so let's show a warning for all other targets. - sess.dcx().emit_warn(errors::SoftFloatIgnored); - } - } } /// Holds data on the current incremental compilation session, if there is one. diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index a1d43d986384..d7d2ecb5bbe7 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -90,6 +90,20 @@ #[cfg(test)] mod tests; +#[derive(Clone, Encodable, Decodable, Debug, Copy, PartialEq, Hash, HashStable_Generic)] +pub struct Spanned { + pub node: T, + pub span: Span, +} + +pub fn respan(sp: Span, t: T) -> Spanned { + Spanned { node: t, span: sp } +} + +pub fn dummy_spanned(t: T) -> Spanned { + respan(DUMMY_SP, t) +} + /// Per-session global variables: this struct is stored in thread-local storage /// in such a way that it is accessible without any kind of handle to all /// threads within the compilation session, but is not accessible outside the diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 35694be9e492..ec335e7b4339 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -15,7 +15,6 @@ use rustc_data_structures::sync::{IntoDynSyncSend, MappedReadGuard, ReadGuard, RwLock}; use rustc_data_structures::unhash::UnhashMap; -use rustc_macros::{Decodable, Encodable}; use tracing::{debug, instrument, trace}; use crate::*; @@ -74,20 +73,6 @@ fn deref(&self) -> &Self::Target { impl !DerefMut for MonotonicVec {} } -#[derive(Clone, Encodable, Decodable, Debug, Copy, PartialEq, Hash, HashStable_Generic)] -pub struct Spanned { - pub node: T, - pub span: Span, -} - -pub fn respan(sp: Span, t: T) -> Spanned { - Spanned { node: t, span: sp } -} - -pub fn dummy_spanned(t: T) -> Spanned { - respan(DUMMY_SP, t) -} - // _____________________________________________________________________________ // SourceFile, MultiByteChar, FileName, FileLines // diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 257ac3f51c2c..7b359dcd6b25 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -746,6 +746,7 @@ custom_mir, custom_test_frameworks, d32, + dbg_macro, dead_code, dealloc, debug, @@ -797,6 +798,7 @@ diagnostic, diagnostic_namespace, diagnostic_on_const, + diagnostic_on_move, dialect, direct, discriminant_kind, @@ -914,10 +916,7 @@ f64_nan, f128, f128_nan, - fabsf16, - fabsf32, - fabsf64, - fabsf128, + fabs, fadd_algebraic, fadd_fast, fake_variadic, @@ -1027,6 +1026,7 @@ global_registration, globs, gt, + guard, guard_patterns, half_open_range_patterns, half_open_range_patterns_in_slices, @@ -1073,6 +1073,7 @@ include_bytes, include_str, inclusive_range_syntax, + incomplete_features, index, index_mut, infer_outlives_requirements, @@ -1114,6 +1115,7 @@ iterator_collect_fn, kcfi, kernel_address, + kernel_hwaddress, keylocker_x86, keyword, kind, @@ -1190,6 +1192,7 @@ macro_derive, macro_escape, macro_export, + macro_guard_matcher, macro_lifetime_matcher, macro_literal_matcher, macro_metavar_expr, @@ -1208,20 +1211,21 @@ masked, match_beginning_vert, match_default_bindings, + maximum_number_nsz_f16, + maximum_number_nsz_f32, + maximum_number_nsz_f64, + maximum_number_nsz_f128, maximumf16, maximumf32, maximumf64, maximumf128, - maxnumf16, - maxnumf32, - maxnumf64, - maxnumf128, may_dangle, may_unwind, maybe_dangling, maybe_uninit, maybe_uninit_uninit, maybe_uninit_zeroed, + mem, mem_align_const, mem_discriminant, mem_drop, @@ -1246,14 +1250,14 @@ min_generic_const_args, min_specialization, min_type_alias_impl_trait, + minimum_number_nsz_f16, + minimum_number_nsz_f32, + minimum_number_nsz_f64, + minimum_number_nsz_f128, minimumf16, minimumf32, minimumf64, minimumf128, - minnumf16, - minnumf32, - minnumf64, - minnumf128, mips, mips32r6, mips64, @@ -1406,6 +1410,7 @@ omit_gdb_pretty_printer_section, on, on_const, + on_move, on_unimplemented, opaque, opaque_generic_const_args, @@ -1849,8 +1854,6 @@ simd_flog10, simd_floor, simd_fma, - simd_fmax, - simd_fmin, simd_fsin, simd_fsqrt, simd_funnel_shl, @@ -1864,6 +1867,8 @@ simd_lt, simd_masked_load, simd_masked_store, + simd_maximum_number_nsz, + simd_minimum_number_nsz, simd_mul, simd_ne, simd_neg, @@ -1914,7 +1919,6 @@ slice_len_fn, slice_patterns, slicing_syntax, - soft, sparc, sparc64, sparc_target_feature, @@ -2005,6 +2009,7 @@ test_2018_feature, test_accepted_feature, test_case, + test_incomplete_feature, test_removed_feature, test_runner, test_unstable_lint, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index ea16231880e2..54ecf277cd3d 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -155,9 +155,7 @@ fn get_symbol_hash<'tcx>( args.hash_stable(hcx, &mut hasher); if let Some(instantiating_crate) = instantiating_crate { - tcx.def_path_hash(instantiating_crate.as_def_id()) - .stable_crate_id() - .hash_stable(hcx, &mut hasher); + tcx.stable_crate_id(instantiating_crate).hash_stable(hcx, &mut hasher); } // We want to avoid accidental collision between different types of instances. diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 95cbb9e07ebb..eff8cbef9954 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -841,7 +841,7 @@ fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.push("C"); if !self.is_exportable { - let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); + let stable_crate_id = self.tcx.stable_crate_id(cnum); self.push_disambiguator(stable_crate_id.as_u64()); } let name = self.tcx.crate_name(cnum); diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 27dd0b764f3b..643eeaa00ce7 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -5,7 +5,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::Symbol; -use crate::spec::{Abi, Arch, RelocModel, Target}; +use crate::spec::{Arch, CfgAbi, RelocModel, Target}; pub struct ModifierInfo { pub modifier: char, @@ -1001,7 +1001,7 @@ pub fn parse( _ => Err(&["C", "system", "efiapi"]), }, InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => match name { - "C" | "system" => Ok(if target.abi == Abi::Spe { + "C" | "system" => Ok(if target.cfg_abi == CfgAbi::Spe { InlineAsmClobberAbi::PowerPCSPE } else { InlineAsmClobberAbi::PowerPC diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index fd0e118fcc87..a09b93c64e0e 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -4,7 +4,7 @@ use rustc_span::Symbol; use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use crate::spec::{Abi, RelocModel, Target}; +use crate::spec::{CfgAbi, RelocModel, Target}; def_reg_class! { PowerPC PowerPCInlineAsmRegClass { @@ -105,9 +105,9 @@ fn reserved_v20to31( _is_clobber: bool, ) -> Result<(), &'static str> { if target.is_like_aix { - match &target.options.abi { - Abi::VecDefault => Err("v20-v31 (vs52-vs63) are reserved on vec-default ABI"), - Abi::VecExtAbi => Ok(()), + match &target.options.cfg_abi { + CfgAbi::VecDefault => Err("v20-v31 (vs52-vs63) are reserved on vec-default ABI"), + CfgAbi::VecExtAbi => Ok(()), abi => unreachable!("unrecognized AIX ABI: {abi}"), } } else { @@ -122,7 +122,11 @@ fn spe_acc_target_check( target: &Target, _is_clobber: bool, ) -> Result<(), &'static str> { - if target.abi == Abi::Spe { Ok(()) } else { Err("spe_acc is only available on spe targets") } + if target.cfg_abi == CfgAbi::Spe { + Ok(()) + } else { + Err("spe_acc is only available on spe targets") + } } def_regs! { diff --git a/compiler/rustc_target/src/callconv/hexagon.rs b/compiler/rustc_target/src/callconv/hexagon.rs index e08e6daa7405..1e0f1f769c3b 100644 --- a/compiler/rustc_target/src/callconv/hexagon.rs +++ b/compiler/rustc_target/src/callconv/hexagon.rs @@ -1,36 +1,76 @@ -use rustc_abi::TyAbiInterface; +use rustc_abi::{HasDataLayout, TyAbiInterface}; -use crate::callconv::{ArgAbi, FnAbi}; +use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform}; -fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { - if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 { - ret.make_indirect(); - } else { +fn classify_ret<'a, Ty, C>(_cx: &C, ret: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout, +{ + if !ret.layout.is_sized() { + return; + } + + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); + return; + } + + // Per the Hexagon ABI: + // - Aggregates up to 32 bits are returned in R0 + // - Aggregates 33-64 bits are returned in R1:R0 + // - Aggregates > 64 bits are returned indirectly via hidden first argument + let size = ret.layout.size; + let bits = size.bits(); + if bits <= 32 { + ret.cast_to(Uniform::new(Reg::i32(), size)); + } else if bits <= 64 { + ret.cast_to(Uniform::new(Reg::i64(), size)); + } else { + ret.make_indirect(); } } fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout, { + if !arg.layout.is_sized() { + return; + } if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { arg.make_indirect(); return; } - if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 { - arg.make_indirect(); - } else { + + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); + return; + } + + // Per the Hexagon ABI: + // - Aggregates up to 32 bits are passed in a single register + // - Aggregates 33-64 bits are passed in a register pair + // - Aggregates > 64 bits are passed on the stack + let size = arg.layout.size; + let bits = size.bits(); + if bits <= 32 { + arg.cast_to(Uniform::new(Reg::i32(), size)); + } else if bits <= 64 { + arg.cast_to(Uniform::new(Reg::i64(), size)); + } else { + arg.pass_by_stack_offset(None); } } pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout, { if !fn_abi.ret.is_ignore() { - classify_ret(&mut fn_abi.ret); + classify_ret(cx, &mut fn_abi.ret); } for arg in fn_abi.args.iter_mut() { diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index d74d15446eaf..6d3826abf27a 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -4,7 +4,7 @@ }; use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; -use crate::spec::HasTargetSpec; +use crate::spec::{HasTargetSpec, LlvmAbi}; #[derive(Copy, Clone)] enum RegPassKind { @@ -88,7 +88,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>( BackendRepr::SimdVector { .. } => { return Err(CannotUseFpConv); } - BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"), + BackendRepr::SimdScalableVector { .. } => panic!("scalable vectors are unsupported"), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") @@ -415,9 +415,9 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) C: HasDataLayout + HasTargetSpec, { let xlen = cx.data_layout().pointer_size().bits(); - let flen = match &cx.target_spec().llvm_abiname[..] { - "ilp32f" | "lp64f" => 32, - "ilp32d" | "lp64d" => 64, + let flen = match &cx.target_spec().llvm_abiname { + LlvmAbi::Ilp32f | LlvmAbi::Lp64f => 32, + LlvmAbi::Ilp32d | LlvmAbi::Lp64d => 64, _ => 0, }; diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 4083e28c09cb..7dc270795281 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -392,7 +392,7 @@ pub fn new( ), BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()), BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), - BackendRepr::ScalableVector { .. } => PassMode::Direct(ArgAttributes::new()), + BackendRepr::SimdScalableVector { .. } => PassMode::Direct(ArgAttributes::new()), }; ArgAbi { layout, mode } } @@ -878,7 +878,7 @@ fn layout_is_noundef<'a, Ty, C>(layout: TyAndLayout<'a, Ty>, cx: &C) -> bool matches!(layout.variants, Variants::Single { .. }) && fields_are_noundef(layout, cx) } }, - BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => false, + BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => false, } } diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index 683b615eec83..d807617491d1 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -5,7 +5,7 @@ use rustc_abi::{Endian, HasDataLayout, TyAbiInterface}; use crate::callconv::{Align, ArgAbi, FnAbi, Reg, RegKind, Uniform}; -use crate::spec::{HasTargetSpec, Os}; +use crate::spec::{HasTargetSpec, LlvmAbi, Os}; #[derive(Debug, Clone, Copy, PartialEq)] enum ABI { @@ -106,9 +106,9 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - let abi = if cx.target_spec().options.llvm_abiname == "elfv2" { + let abi = if cx.target_spec().options.llvm_abiname == LlvmAbi::ElfV2 { ELFv2 - } else if cx.target_spec().options.llvm_abiname == "elfv1" { + } else if cx.target_spec().options.llvm_abiname == LlvmAbi::ElfV1 { ELFv1 } else if cx.target_spec().os == Os::Aix { AIX diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index f166b8330516..bc81ec95c86e 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -10,7 +10,7 @@ }; use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; -use crate::spec::HasTargetSpec; +use crate::spec::{HasTargetSpec, LlvmAbi}; #[derive(Copy, Clone)] enum RegPassKind { @@ -91,7 +91,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>( } } }, - BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => { return Err(CannotUseFpConv); } BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { @@ -419,9 +419,9 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - let flen = match &cx.target_spec().llvm_abiname[..] { - "ilp32f" | "lp64f" => 32, - "ilp32d" | "lp64d" => 64, + let flen = match &cx.target_spec().llvm_abiname { + LlvmAbi::Ilp32f | LlvmAbi::Lp64f => 32, + LlvmAbi::Ilp32d | LlvmAbi::Lp64d => 64, _ => 0, }; let xlen = cx.data_layout().pointer_size().bits(); diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index f55d03d89e8f..55f264d89bb4 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -65,7 +65,7 @@ fn classify<'a, Ty, C>( Primitive::Int(_, _) | Primitive::Pointer(_) => { /* pass in integer registers */ } }, BackendRepr::SimdVector { .. } => {} - BackendRepr::ScalableVector { .. } => {} + BackendRepr::SimdScalableVector { .. } => {} BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 5e8cab0ee987..9aaa411db6c0 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -103,7 +103,7 @@ fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool } false } - BackendRepr::ScalableVector { .. } => { + BackendRepr::SimdScalableVector { .. } => { panic!("scalable vectors are unsupported") } } diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 8fab4e444228..dc73907c0c18 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -59,7 +59,7 @@ fn classify<'a, Ty, C>( BackendRepr::SimdVector { .. } => Class::Sse, - BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"), + BackendRepr::SimdScalableVector { .. } => panic!("scalable vectors are unsupported"), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 4026c4f471a7..624563c68e5b 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -25,7 +25,7 @@ pub(crate) fn compute_abi_info<'a, Ty, C: HasTargetSpec>(cx: &C, fn_abi: &mut Fn // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } - BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"), + BackendRepr::SimdScalableVector { .. } => panic!("scalable vectors are unsupported"), BackendRepr::Scalar(scalar) => { if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) { if cx.target_spec().rustc_abi == Some(RustcAbi::Softfloat) { diff --git a/compiler/rustc_target/src/spec/base/aix.rs b/compiler/rustc_target/src/spec/base/aix.rs index 76e8fb763e58..41cf3e001fdf 100644 --- a/compiler/rustc_target/src/spec/base/aix.rs +++ b/compiler/rustc_target/src/spec/base/aix.rs @@ -1,13 +1,13 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, BinaryFormat, Cc, CodeModel, LinkOutputKind, LinkerFlavor, Os, TargetOptions, crt_objects, - cvs, + BinaryFormat, Cc, CfgAbi, CodeModel, LinkOutputKind, LinkerFlavor, Os, TargetOptions, + crt_objects, cvs, }; pub(crate) fn opts() -> TargetOptions { TargetOptions { - abi: Abi::VecExtAbi, + cfg_abi: CfgAbi::VecExtAbi, code_model: Some(CodeModel::Large), cpu: "pwr7".into(), os: Os::Aix, diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 542c5e278499..d1d91cbd3788 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use crate::spec::{ - Abi, BinaryFormat, Cc, DebuginfoKind, Env, FloatAbi, FramePointer, LinkerFlavor, Lld, Os, + BinaryFormat, Cc, CfgAbi, DebuginfoKind, Env, FloatAbi, FramePointer, LinkerFlavor, Lld, Os, RustcAbi, SplitDebuginfo, StackProbeType, StaticCow, Target, TargetOptions, cvs, }; @@ -108,11 +108,11 @@ fn target_env(self) -> Env { // // But let's continue setting them for backwards compatibility. // FIXME(madsmtm): Warn about using these in the future. - fn target_abi(self) -> Abi { + fn target_abi(self) -> CfgAbi { match self { - Self::Normal => Abi::Unspecified, - Self::MacCatalyst => Abi::MacAbi, - Self::Simulator => Abi::Sim, + Self::Normal => CfgAbi::Unspecified, + Self::MacCatalyst => CfgAbi::MacAbi, + Self::Simulator => CfgAbi::Sim, } } } @@ -127,10 +127,15 @@ pub(crate) fn base( let link_env_remove = link_env_remove(&os); let unversioned_llvm_target = unversioned_llvm_target(&os, arch, env); let mut opts = TargetOptions { - llvm_floatabi: Some(FloatAbi::Hard), + llvm_floatabi: if arch.target_arch() == crate::spec::Arch::Arm { + Some(FloatAbi::Hard) + } else { + // `llvm_floatabi` makes no sense on x86 and aarch64. + None + }, os, env: env.target_env(), - abi: env.target_abi(), + cfg_abi: env.target_abi(), cpu: arch.target_cpu(env).into(), link_env_remove, vendor: "apple".into(), diff --git a/compiler/rustc_target/src/spec/base/apple/tests.rs b/compiler/rustc_target/src/spec/base/apple/tests.rs index fd3fd6da9116..f178698afb49 100644 --- a/compiler/rustc_target/src/spec/base/apple/tests.rs +++ b/compiler/rustc_target/src/spec/base/apple/tests.rs @@ -4,7 +4,7 @@ aarch64_apple_watchos_sim, i686_apple_darwin, x86_64_apple_darwin, x86_64_apple_ios, x86_64_apple_tvos, x86_64_apple_watchos_sim, }; -use crate::spec::{Abi, Env}; +use crate::spec::{CfgAbi, Env}; #[test] fn simulator_targets_set_env() { @@ -21,7 +21,7 @@ fn simulator_targets_set_env() { for target in &all_sim_targets { assert_eq!(target.env, Env::Sim); // Ensure backwards compat - assert_eq!(target.abi, Abi::Sim); + assert_eq!(target.cfg_abi, CfgAbi::Sim); } } diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index d2fe42b90306..cee3f9122699 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -106,6 +106,7 @@ pub(crate) fn opts() -> TargetOptions { // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + mcount: "_mcount".into(), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 3bd8ebd0ed3d..c1b4eecae3f5 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -2,7 +2,7 @@ use crate::spec::crt_objects::pre_mingw_self_contained; use crate::spec::{ - Abi, BinaryFormat, Cc, DebuginfoKind, Env, LinkSelfContainedDefault, LinkerFlavor, Lld, Os, + BinaryFormat, Cc, CfgAbi, DebuginfoKind, Env, LinkSelfContainedDefault, LinkerFlavor, Lld, Os, SplitDebuginfo, TargetOptions, add_link_args, cvs, }; @@ -26,7 +26,7 @@ pub(crate) fn opts() -> TargetOptions { os: Os::Windows, env: Env::Gnu, vendor: "pc".into(), - abi: Abi::Llvm, + cfg_abi: CfgAbi::Llvm, linker: Some("clang".into()), dynamic_linking: true, dll_tls_export: false, @@ -53,6 +53,7 @@ pub(crate) fn opts() -> TargetOptions { // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + mcount: "_mcount".into(), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/base/windows_uwp_gnu.rs b/compiler/rustc_target/src/spec/base/windows_uwp_gnu.rs index 0f009fffae8d..d1adc891ad21 100644 --- a/compiler/rustc_target/src/spec/base/windows_uwp_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_uwp_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Cc, LinkArgs, LinkerFlavor, Lld, TargetOptions, add_link_args, base}; +use crate::spec::{Cc, CfgAbi, LinkArgs, LinkerFlavor, Lld, TargetOptions, add_link_args, base}; pub(crate) fn opts() -> TargetOptions { let base = base::windows_gnu::opts(); @@ -23,7 +23,7 @@ pub(crate) fn opts() -> TargetOptions { let late_link_args_static = LinkArgs::new(); TargetOptions { - abi: Abi::Uwp, + cfg_abi: CfgAbi::Uwp, vendor: "uwp".into(), limit_rdylib_exports: false, late_link_args, diff --git a/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs b/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs index 15832989f085..b9b2f4248e6c 100644 --- a/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs +++ b/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs @@ -1,8 +1,8 @@ -use crate::spec::{Abi, LinkerFlavor, Lld, TargetOptions, base}; +use crate::spec::{CfgAbi, LinkerFlavor, Lld, TargetOptions, base}; pub(crate) fn opts() -> TargetOptions { let mut opts = - TargetOptions { abi: Abi::Uwp, vendor: "uwp".into(), ..base::windows_msvc::opts() }; + TargetOptions { cfg_abi: CfgAbi::Uwp, vendor: "uwp".into(), ..base::windows_msvc::opts() }; opts.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/APPCONTAINER", "mincore.lib"]); diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 20fbb687b308..5507af086675 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -5,14 +5,14 @@ use super::crt_objects::CrtObjects; use super::{ - Abi, Arch, BinaryFormat, CodeModel, DebuginfoKind, Env, FloatAbi, FramePointer, LinkArgsCli, + Arch, BinaryFormat, CfgAbi, CodeModel, DebuginfoKind, Env, FloatAbi, FramePointer, LinkArgsCli, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFlavorCli, LldFlavor, MergeFunctions, Os, PanicStrategy, RelocModel, RelroLevel, RustcAbi, SanitizerSet, SmallDataThresholdSupport, SplitDebuginfo, StackProbeType, StaticCow, SymbolVisibility, Target, TargetKind, TargetOptions, TargetWarnings, TlsModel, }; use crate::json::{Json, ToJson}; -use crate::spec::AbiMap; +use crate::spec::{AbiMap, LlvmAbi}; impl Target { /// Loads a target descriptor from a JSON object. @@ -42,11 +42,7 @@ pub fn from_json(json: &str) -> Result<(Target, TargetWarnings), String> { } let alignment_error = |field_name: &str, error: AlignFromBytesError| -> String { - let msg = match error { - AlignFromBytesError::NotPowerOfTwo(_) => "not a power of 2 number of bytes", - AlignFromBytesError::TooLarge(_) => "too large", - }; - format!("`{}` bits is not a valid value for {field_name}: {msg}", error.align() * 8) + format!("invalid value for {field_name}: {error}") }; macro_rules! forward { @@ -73,7 +69,9 @@ macro_rules! forward_opt { forward_opt!(c_enum_min_bits); // if None, matches c_int_width forward!(os); forward!(env); - forward!(abi); + if let Some(abi) = json.abi { + base.cfg_abi = abi; + } forward!(vendor); forward_opt!(linker); forward!(linker_flavor_json); @@ -301,7 +299,7 @@ macro_rules! target_option_val { target_option_val!(c_int_width, "target-c-int-width"); target_option_val!(os); target_option_val!(env); - target_option_val!(abi); + target_option_val!(cfg_abi, "abi"); target_option_val!(vendor); target_option_val!(linker); target_option_val!(linker_flavor_json, "linker-flavor"); @@ -509,7 +507,7 @@ struct TargetSpecJson { c_enum_min_bits: Option, os: Option, env: Option, - abi: Option, + abi: Option, vendor: Option>, linker: Option>, #[serde(rename = "linker-flavor")] @@ -613,7 +611,7 @@ struct TargetSpecJson { #[serde(rename = "target-mcount")] mcount: Option>, llvm_mcount_intrinsic: Option>, - llvm_abiname: Option>, + llvm_abiname: Option, llvm_floatabi: Option, rustc_abi: Option, relax_elf_relocations: Option, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a4460a372517..14746da57c47 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1005,7 +1005,7 @@ pub enum FloatAbi { pub enum RustcAbi { /// On x86-32 only: make use of SSE and SSE2 for ABI purposes. X86Sse2 = "x86-sse2", - /// On x86-32/64 and S390x: do not use any FPU or SIMD registers for the ABI. + /// On x86-32/64, aarch64, and S390x: do not use any FPU or SIMD registers for the ABI. Softfloat = "softfloat", "x86-softfloat", } @@ -1175,9 +1175,10 @@ impl SanitizerSet: u16 { const SHADOWCALLSTACK = 1 << 7; const KCFI = 1 << 8; const KERNELADDRESS = 1 << 9; - const SAFESTACK = 1 << 10; - const DATAFLOW = 1 << 11; - const REALTIME = 1 << 12; + const KERNELHWADDRESS = 1 << 10; + const SAFESTACK = 1 << 11; + const DATAFLOW = 1 << 12; + const REALTIME = 1 << 13; } } rustc_data_structures::external_bitflags_debug! { SanitizerSet } @@ -1191,24 +1192,32 @@ impl SanitizerSet { (SanitizerSet::ADDRESS, SanitizerSet::HWADDRESS), (SanitizerSet::ADDRESS, SanitizerSet::MEMTAG), (SanitizerSet::ADDRESS, SanitizerSet::KERNELADDRESS), + (SanitizerSet::ADDRESS, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::ADDRESS, SanitizerSet::SAFESTACK), (SanitizerSet::LEAK, SanitizerSet::MEMORY), (SanitizerSet::LEAK, SanitizerSet::THREAD), (SanitizerSet::LEAK, SanitizerSet::KERNELADDRESS), + (SanitizerSet::LEAK, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::LEAK, SanitizerSet::SAFESTACK), (SanitizerSet::MEMORY, SanitizerSet::THREAD), (SanitizerSet::MEMORY, SanitizerSet::HWADDRESS), (SanitizerSet::MEMORY, SanitizerSet::KERNELADDRESS), + (SanitizerSet::MEMORY, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::MEMORY, SanitizerSet::SAFESTACK), (SanitizerSet::THREAD, SanitizerSet::HWADDRESS), (SanitizerSet::THREAD, SanitizerSet::KERNELADDRESS), + (SanitizerSet::THREAD, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::THREAD, SanitizerSet::SAFESTACK), (SanitizerSet::HWADDRESS, SanitizerSet::MEMTAG), (SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS), + (SanitizerSet::HWADDRESS, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::HWADDRESS, SanitizerSet::SAFESTACK), (SanitizerSet::CFI, SanitizerSet::KCFI), (SanitizerSet::MEMTAG, SanitizerSet::KERNELADDRESS), + (SanitizerSet::MEMTAG, SanitizerSet::KERNELHWADDRESS), + (SanitizerSet::KERNELADDRESS, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::KERNELADDRESS, SanitizerSet::SAFESTACK), + (SanitizerSet::KERNELHWADDRESS, SanitizerSet::SAFESTACK), ]; /// Return sanitizer's name @@ -1221,6 +1230,7 @@ pub fn as_str(self) -> Option<&'static str> { SanitizerSet::DATAFLOW => "dataflow", SanitizerSet::KCFI => "kcfi", SanitizerSet::KERNELADDRESS => "kernel-address", + SanitizerSet::KERNELHWADDRESS => "kernel-hwaddress", SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", SanitizerSet::MEMTAG => "memtag", @@ -1266,6 +1276,7 @@ fn from_str(s: &str) -> Result { "dataflow" => SanitizerSet::DATAFLOW, "kcfi" => SanitizerSet::KCFI, "kernel-address" => SanitizerSet::KERNELADDRESS, + "kernel-hwaddress" => SanitizerSet::KERNELHWADDRESS, "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, "memtag" => SanitizerSet::MEMTAG, @@ -1815,6 +1826,8 @@ fn $module() { ("x86_64-pc-cygwin", x86_64_pc_cygwin), ("x86_64-unknown-linux-gnuasan", x86_64_unknown_linux_gnuasan), + ("x86_64-unknown-linux-gnumsan", x86_64_unknown_linux_gnumsan), + ("x86_64-unknown-linux-gnutsan", x86_64_unknown_linux_gnutsan), } /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]> @@ -1956,6 +1969,19 @@ pub fn supports_c_variadic_definitions(&self) -> bool { | X86_64 | Xtensa => true, } } + + /// Whether `#[rustc_scalable_vector]` is supported for a target architecture + pub fn supports_scalable_vectors(&self) -> bool { + use Arch::*; + + match self { + AArch64 | RiscV32 | RiscV64 => true, + AmdGpu | Arm | Arm64EC | Avr | Bpf | CSky | Hexagon | LoongArch32 | LoongArch64 + | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC + | PowerPC64 | S390x | Sparc | Sparc64 | SpirV | Wasm32 | Wasm64 | X86 | X86_64 + | Xtensa | Other(_) => false, + } + } } crate::target_spec_enum! { @@ -2052,7 +2078,10 @@ pub fn desc_symbol(&self) -> Symbol { } crate::target_spec_enum! { - pub enum Abi { + /// An enum representing possible values for `cfg(target_abi)`. + /// This field is not forwarded to LLVM so it does not by itself affect codegen. + /// See the `cfg_abi` field of [`TargetOptions`] for more details. + pub enum CfgAbi { Abi64 = "abi64", AbiV2 = "abiv2", AbiV2Hf = "abiv2hf", @@ -2077,12 +2106,40 @@ pub enum Abi { other_variant = Other; } -impl Abi { +impl CfgAbi { pub fn desc_symbol(&self) -> Symbol { Symbol::intern(self.desc()) } } +crate::target_spec_enum! { + /// An enum representing possible values for the `llvm_abiname` field of [`TargetOptions`]. + /// This field is used by LLVM on some targets to control which ABI to use. + pub enum LlvmAbi { + // RISC-V and LoongArch + Ilp32 = "ilp32", + Ilp32f = "ilp32f", + Ilp32d = "ilp32d", + Ilp32e = "ilp32e", + Ilp32s = "ilp32s", + Lp64 = "lp64", + Lp64f = "lp64f", + Lp64d = "lp64d", + Lp64e = "lp64e", + Lp64s = "lp64s", + // MIPS + O32 = "o32", + N32 = "n32", + N64 = "n64", + // PowerPC + ElfV1 = "elfv1", + ElfV2 = "elfv2", + + Unspecified = "", + } + other_variant = Other; +} + /// Everything `rustc` knows about how to compile for a specific target. /// /// Every field here must be specified, and has no default value. @@ -2208,13 +2265,18 @@ pub struct TargetOptions { pub os: Os, /// Environment name to use for conditional compilation (`target_env`). Defaults to [`Env::Unspecified`]. pub env: Env, - /// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"` - /// or `"eabihf"`. Defaults to [`Abi::Unspecified`]. - /// This field is *not* forwarded directly to LLVM and therefore does not control which ABI (in - /// the sense of function calling convention) is actually used; its primary purpose is - /// `cfg(target_abi)`. The actual calling convention is controlled by `llvm_abiname`, - /// `llvm_floatabi`, and `rustc_abi`. - pub abi: Abi, + /// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, + /// `"eabi"` or `"eabihf"`. Defaults to [`CfgAbi::Unspecified`]. + /// The only purpose of this field is to control `cfg(target_abi)`. This does not control the + /// calling convention used by this target! The actual calling convention is controlled by + /// `llvm_abiname`, `llvm_floatabi`, and `rustc_abi`. + /// + /// In a target spec, this field generally *informs* the user about what the ABI is, but you + /// have to also set up other parts of the target spec to ensure that this information is + /// correct. In the rest of the compiler, do not check this field if what you actually need to + /// know about is the calling convention. Most targets have an open-ended set of values for this + /// field. + pub cfg_abi: CfgAbi, /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". #[rustc_lint_opt_deny_field_access( "use `Target::is_like_*` instead of this field; see https://github.com/rust-lang/rust/issues/100343 for rationale" @@ -2524,7 +2586,7 @@ pub struct TargetOptions { /// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers /// and the `-target-abi` flag in llc. In the LLVM API this is `MCOptions.ABIName`. - pub llvm_abiname: StaticCow, + pub llvm_abiname: LlvmAbi, /// Control the float ABI to use, for architectures that support it. The only architecture we /// currently use this for is ARM. Corresponds to the `-float-abi` flag in llc. In the LLVM API @@ -2537,7 +2599,6 @@ pub struct TargetOptions { /// Picks a specific ABI for this target. This is *not* just for "Rust" ABI functions, /// it can also affect "C" ABI functions; the point is that this flag is interpreted by /// rustc and not forwarded to LLVM. - /// So far, this is only used on x86. pub rustc_abi: Option, /// Whether or not RelaxElfRelocation flag will be passed to the linker @@ -2726,7 +2787,7 @@ fn default() -> TargetOptions { c_int_width: 32, os: Os::None, env: Env::Unspecified, - abi: Abi::Unspecified, + cfg_abi: CfgAbi::Unspecified, vendor: "unknown".into(), linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()), linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No), @@ -2822,7 +2883,7 @@ fn default() -> TargetOptions { merge_functions: MergeFunctions::Aliases, mcount: "mcount".into(), llvm_mcount_intrinsic: None, - llvm_abiname: "".into(), + llvm_abiname: LlvmAbi::Unspecified, llvm_floatabi: None, rustc_abi: None, relax_elf_relocations: false, @@ -3170,69 +3231,331 @@ macro_rules! check_matches { ); } - // Check that RISC-V targets always specify which ABI they use, - // and that ARM targets specify their float ABI. + // Ensure built-in targets don't use the `Other` variants. + if kind == TargetKind::Builtin { + check!( + !matches!(self.arch, Arch::Other(_)), + "`Arch::Other` is only meant for JSON targets" + ); + check!(!matches!(self.os, Os::Other(_)), "`Os::Other` is only meant for JSON targets"); + check!( + !matches!(self.env, Env::Other(_)), + "`Env::Other` is only meant for JSON targets" + ); + check!( + !matches!(self.cfg_abi, CfgAbi::Other(_)), + "`CfgAbi::Other` is only meant for JSON targets" + ); + check!( + !matches!(self.llvm_abiname, LlvmAbi::Other(_)), + "`LlvmAbi::Other` is only meant for JSON targets" + ); + } + + // Check ABI flag consistency, for the architectures where we have proper ABI treatment. + // To ensure targets are trated consistently, please consult with the team before allowing + // new cases. match self.arch { - Arch::RiscV32 => { + Arch::X86 => { + check!( + self.llvm_abiname == LlvmAbi::Unspecified, + "`llvm_abiname` is unused on x86-32" + ); + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on x86-32"); check_matches!( - &*self.llvm_abiname, - "ilp32" | "ilp32f" | "ilp32d" | "ilp32e", - "invalid RISC-V ABI name: {}", + (&self.rustc_abi, &self.cfg_abi), + // FIXME: we do not currently set a target_abi for softfloat targets here, + // but we probably should, so we already allow it. + ( + Some(RustcAbi::Softfloat), + CfgAbi::SoftFloat | CfgAbi::Unspecified | CfgAbi::Other(_) + ) | ( + Some(RustcAbi::X86Sse2) | None, + CfgAbi::Uwp + | CfgAbi::Llvm + | CfgAbi::Sim + | CfgAbi::Unspecified + | CfgAbi::Other(_) + ), + "invalid x86-32 Rust-specific ABI and `cfg(target_abi)` combination:\n\ + Rust-specific ABI: {:?}\n\ + cfg(target_abi): {}", + self.rustc_abi, + self.cfg_abi, + ); + } + Arch::X86_64 => { + check!( + self.llvm_abiname == LlvmAbi::Unspecified, + "`llvm_abiname` is unused on x86-64" + ); + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on x86-64"); + // FIXME: we do not currently set a target_abi for softfloat targets here, but we + // probably should, so we already allow it. + // FIXME: Ensure that target_abi = "x32" correlates with actually using that ABI. + // Do any of the others need a similar check? + check_matches!( + (&self.rustc_abi, &self.cfg_abi), + ( + Some(RustcAbi::Softfloat), + CfgAbi::SoftFloat | CfgAbi::Unspecified | CfgAbi::Other(_) + ) | ( + None, + CfgAbi::X32 + | CfgAbi::Llvm + | CfgAbi::Fortanix + | CfgAbi::Uwp + | CfgAbi::MacAbi + | CfgAbi::Sim + | CfgAbi::Unspecified + | CfgAbi::Other(_) + ), + "invalid x86-64 Rust-specific ABI and `cfg(target_abi)` combination:\n\ + Rust-specific ABI: {:?}\n\ + cfg(target_abi): {}", + self.rustc_abi, + self.cfg_abi, + ); + } + Arch::RiscV32 => { + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on RISC-V"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on RISC-V"); + check_matches!( + (&self.llvm_abiname, &self.cfg_abi), + (LlvmAbi::Ilp32, CfgAbi::Unspecified | CfgAbi::Other(_)) + | (LlvmAbi::Ilp32f, CfgAbi::Unspecified | CfgAbi::Other(_)) + | (LlvmAbi::Ilp32d, CfgAbi::Unspecified | CfgAbi::Other(_)) + | (LlvmAbi::Ilp32e, CfgAbi::Ilp32e), + "invalid RISC-V ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", self.llvm_abiname, + self.cfg_abi, ); } Arch::RiscV64 => { // Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI. + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on RISC-V"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on RISC-V"); check_matches!( - &*self.llvm_abiname, - "lp64" | "lp64f" | "lp64d" | "lp64e", - "invalid RISC-V ABI name: {}", + (&self.llvm_abiname, &self.cfg_abi), + (LlvmAbi::Lp64, CfgAbi::Unspecified | CfgAbi::Other(_)) + | (LlvmAbi::Lp64f, CfgAbi::Unspecified | CfgAbi::Other(_)) + | (LlvmAbi::Lp64d, CfgAbi::Unspecified | CfgAbi::Other(_)) + | (LlvmAbi::Lp64e, CfgAbi::Unspecified | CfgAbi::Other(_)), + "invalid RISC-V ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", self.llvm_abiname, + self.cfg_abi, ); } Arch::Arm => { check!( - self.llvm_floatabi.is_some(), - "ARM targets must set `llvm-floatabi` to `hard` or `soft`", + self.llvm_abiname == LlvmAbi::Unspecified, + "`llvm_abiname` is unused on ARM" + ); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on ARM"); + check_matches!( + (&self.llvm_floatabi, &self.cfg_abi), + ( + Some(FloatAbi::Hard), + CfgAbi::EabiHf | CfgAbi::Uwp | CfgAbi::Unspecified | CfgAbi::Other(_) + ) | (Some(FloatAbi::Soft), CfgAbi::Eabi), + "Invalid combination of float ABI and `cfg(target_abi)` for ARM target\n\ + float ABI: {:?}\n\ + cfg(target_abi): {}", + self.llvm_floatabi, + self.cfg_abi, ) } - // PowerPC64 targets that are not AIX must set their ABI to either ELFv1 or ELFv2 + Arch::AArch64 => { + check!( + self.llvm_abiname == LlvmAbi::Unspecified, + "`llvm_abiname` is unused on aarch64" + ); + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on aarch64"); + // FIXME: Ensure that target_abi = "ilp32" correlates with actually using that ABI. + // Do any of the others need a similar check? + check_matches!( + (&self.rustc_abi, &self.cfg_abi), + (Some(RustcAbi::Softfloat), CfgAbi::SoftFloat) + | ( + None, + CfgAbi::Ilp32 + | CfgAbi::Llvm + | CfgAbi::MacAbi + | CfgAbi::Sim + | CfgAbi::Uwp + | CfgAbi::Unspecified + | CfgAbi::Other(_) + ), + "invalid aarch64 Rust-specific ABI and `cfg(target_abi)` combination:\n\ + Rust-specific ABI: {:?}\n\ + cfg(target_abi): {}", + self.rustc_abi, + self.cfg_abi, + ); + } + Arch::PowerPC => { + check!( + self.llvm_abiname == LlvmAbi::Unspecified, + "`llvm_abiname` is unused on PowerPC" + ); + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on PowerPC"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on PowerPC"); + // FIXME: Check that `target_abi` matches the actually configured ABI (with or + // without SPE). + check_matches!( + self.cfg_abi, + CfgAbi::Spe | CfgAbi::Unspecified | CfgAbi::Other(_), + "invalid `target_abi` for PowerPC" + ); + } Arch::PowerPC64 => { + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on PowerPC64"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on PowerPC64"); + // PowerPC64 targets that are not AIX must set their ABI to either ELFv1 or ELFv2 if self.os == Os::Aix { - check!( - self.llvm_abiname.is_empty(), - "AIX targets always use the AIX ABI and `llvm_abiname` should be left empty", + // FIXME: Check that `target_abi` matches the actually configured ABI + // (vec-default vs vec-ext). + check_matches!( + (&self.llvm_abiname, &self.cfg_abi), + (LlvmAbi::Unspecified, CfgAbi::VecDefault | CfgAbi::VecExtAbi), + "invalid PowerPC64 AIX ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", + self.llvm_abiname, + self.cfg_abi, ); } else if self.endian == Endian::Big { check_matches!( - &*self.llvm_abiname, - "elfv1" | "elfv2", - "invalid PowerPC64 ABI name: {}", + (&self.llvm_abiname, &self.cfg_abi), + (LlvmAbi::ElfV1, CfgAbi::ElfV1) | (LlvmAbi::ElfV2, CfgAbi::ElfV2), + "invalid PowerPC64 big-endian ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", self.llvm_abiname, + self.cfg_abi, ); } else { - check!( - self.llvm_abiname == "elfv2", - "little-endian PowerPC64 targets only support the `elfv2` ABI", + check_matches!( + (&self.llvm_abiname, &self.cfg_abi), + (LlvmAbi::ElfV2, CfgAbi::ElfV2), + "invalid PowerPC64 little-endian ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", + self.llvm_abiname, + self.cfg_abi, ); } } - _ => {} - } - - // Check consistency of Rust ABI declaration. - if let Some(rust_abi) = self.rustc_abi { - match rust_abi { - RustcAbi::X86Sse2 => check_matches!( - self.arch, - Arch::X86, - "`x86-sse2` ABI is only valid for x86-32 targets" - ), - RustcAbi::Softfloat => check_matches!( - self.arch, - Arch::X86 | Arch::X86_64 | Arch::S390x | Arch::AArch64, - "`softfloat` ABI is only valid for x86, s390x, and aarch64 targets" - ), + Arch::S390x => { + check!( + self.llvm_abiname == LlvmAbi::Unspecified, + "`llvm_abiname` is unused on s390x" + ); + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on s390x"); + check_matches!( + (&self.rustc_abi, &self.cfg_abi), + (Some(RustcAbi::Softfloat), CfgAbi::SoftFloat) + | (None, CfgAbi::Unspecified | CfgAbi::Other(_)), + "invalid s390x Rust-specific ABI and `cfg(target_abi)` combination:\n\ + Rust-specific ABI: {:?}\n\ + cfg(target_abi): {}", + self.rustc_abi, + self.cfg_abi, + ); + } + Arch::LoongArch32 => { + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on LoongArch"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on LoongArch"); + check_matches!( + (&self.llvm_abiname, &self.cfg_abi), + (LlvmAbi::Ilp32s, CfgAbi::SoftFloat) + | (LlvmAbi::Ilp32f, CfgAbi::Unspecified | CfgAbi::Other(_)) + | (LlvmAbi::Ilp32d, CfgAbi::Unspecified | CfgAbi::Other(_)), + "invalid LoongArch ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", + self.llvm_abiname, + self.cfg_abi, + ); + } + Arch::LoongArch64 => { + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on LoongArch"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on LoongArch"); + check_matches!( + (&self.llvm_abiname, &self.cfg_abi), + (LlvmAbi::Lp64s, CfgAbi::SoftFloat) + | (LlvmAbi::Lp64f, CfgAbi::Unspecified | CfgAbi::Other(_)) + | (LlvmAbi::Lp64d, CfgAbi::Unspecified | CfgAbi::Other(_)), + "invalid LoongArch ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", + self.llvm_abiname, + self.cfg_abi, + ); + } + Arch::Mips | Arch::Mips32r6 => { + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on MIPS"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on MIPS"); + check_matches!( + (&self.llvm_abiname, &self.cfg_abi), + (LlvmAbi::O32, CfgAbi::Unspecified | CfgAbi::Other(_)), + "invalid MIPS ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", + self.llvm_abiname, + self.cfg_abi, + ); + } + Arch::Mips64 | Arch::Mips64r6 => { + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on MIPS"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on MIPS"); + check_matches!( + (&self.llvm_abiname, &self.cfg_abi), + // No in-tree targets use "n32" but at least for now we let out-of-tree targets + // experiment with that. + (LlvmAbi::N64, CfgAbi::Abi64) + | (LlvmAbi::N32, CfgAbi::Unspecified | CfgAbi::Other(_)), + "invalid MIPS ABI name and `cfg(target_abi)` combination:\n\ + ABI name: {}\n\ + cfg(target_abi): {}", + self.llvm_abiname, + self.cfg_abi, + ); + } + Arch::CSky => { + check!( + self.llvm_abiname == LlvmAbi::Unspecified, + "`llvm_abiname` is unused on CSky" + ); + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on CSky"); + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on CSky"); + // FIXME: Check that `target_abi` matches the actually configured ABI (v2 vs v2hf). + check_matches!( + self.cfg_abi, + CfgAbi::AbiV2 | CfgAbi::AbiV2Hf, + "invalid `target_abi` for CSky" + ); + } + ref arch => { + check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on {arch}"); + // Ensure consistency among built-in targets, but give JSON targets the opportunity + // to experiment with these. + if kind == TargetKind::Builtin { + check!( + self.llvm_abiname == LlvmAbi::Unspecified, + "`llvm_abiname` is unused on {arch}" + ); + check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on {arch}"); + check_matches!( + self.cfg_abi, + CfgAbi::Unspecified | CfgAbi::Other(_), + "`target_abi` is unused on {arch}" + ); + } } } @@ -3292,7 +3615,8 @@ fn test_target(mut self) { let recycled_target = Target::from_json(&serde_json::to_string(&self.to_json()).unwrap()).map(|(j, _)| j); self.update_to_cli(); - self.check_consistency(TargetKind::Builtin).unwrap(); + self.check_consistency(TargetKind::Builtin) + .unwrap_or_else(|err| panic!("Target consistency check failed:\n{err}")); assert_eq!(recycled_target, Ok(self)); } @@ -3443,7 +3767,7 @@ pub fn object_architecture( // it using a custom target specification. N32 // is an ILP32 ABI like the Aarch64_Ilp32 // and X86_64_X32 cases above and below this one. - if self.options.llvm_abiname.as_ref() == "n32" { + if self.options.llvm_abiname == LlvmAbi::N32 { Architecture::Mips64_N32 } else { Architecture::Mips64 diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs index 4abd5553eb97..8a432ca2c2d2 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs @@ -1,7 +1,7 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, CfgAbi, FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: Arch::AArch64, options: TargetOptions { - abi: Abi::Ilp32, + cfg_abi: CfgAbi::Ilp32, features: "+v8a,+outline-atomics".into(), // the AAPCS64 expects use of non-leaf frame pointers per // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs index e204c6466e29..77a57f99a6b5 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs @@ -8,13 +8,13 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { let opts = TargetOptions { - abi: Abi::SoftFloat, + cfg_abi: CfgAbi::SoftFloat, rustc_abi: Some(RustcAbi::Softfloat), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), @@ -22,7 +22,9 @@ pub(crate) fn target() -> Target { relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, stack_probes: StackProbeType::Inline, panic_strategy: PanicStrategy::Abort, endian: Endian::Big, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs index 22f2717b56b4..e8e7b847cc84 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Abi, Arch, FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, CfgAbi, FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: Arch::AArch64, options: TargetOptions { - abi: Abi::Ilp32, + cfg_abi: CfgAbi::Ilp32, features: "+v8a,+outline-atomics".into(), // the AAPCS64 expects use of non-leaf frame pointers per // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs index 1c166030d5e5..13d3b77588a0 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs @@ -21,7 +21,9 @@ pub(crate) fn target() -> Target { &["--fix-cortex-a53-843419"], ), features: "+v8a,+strict-align,+neon".into(), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs index ed2e2fb6ab70..05876891ebd7 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs @@ -7,13 +7,13 @@ // For example, `-C target-cpu=cortex-a53`. use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { let opts = TargetOptions { - abi: Abi::SoftFloat, + cfg_abi: CfgAbi::SoftFloat, rustc_abi: Some(RustcAbi::Softfloat), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), @@ -21,7 +21,9 @@ pub(crate) fn target() -> Target { relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, stack_probes: StackProbeType::Inline, panic_strategy: PanicStrategy::Abort, default_uwtable: true, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs index 19b7ebe03674..1e06d3abb723 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs @@ -21,7 +21,9 @@ pub(crate) fn target() -> Target { &["--fix-cortex-a53-843419"], ), features: "+v8a,+strict-align,+neon".into(), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none.rs index 8f8bbb4a41ca..680d89653db8 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none.rs @@ -8,7 +8,9 @@ pub(crate) fn target() -> Target { // based off the aarch64-unknown-none target at time of addition linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs index 6f11f97e3d1d..ee9a6b802360 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs @@ -1,18 +1,20 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { let opts = TargetOptions { - abi: Abi::SoftFloat, + cfg_abi: CfgAbi::SoftFloat, rustc_abi: Some(RustcAbi::Softfloat), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, stack_probes: StackProbeType::Inline, panic_strategy: PanicStrategy::Abort, default_uwtable: true, diff --git a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs index 7dc6509fc823..5b0951ba9de7 100644 --- a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs @@ -1,4 +1,6 @@ -use crate::spec::{Abi, Arch, FloatAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CfgAbi, FloatAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -13,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), // https://developer.android.com/ndk/guides/abis.html#armeabi features: "+strict-align,+v5te".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs index cc63ffa2e2a5..5275113de23a 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+strict-align,+v6".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs index 1cae42c14559..7dd36d6e82c4 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+strict-align,+v6,+vfp2".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs index 25ef767c4b10..5dce42042876 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), // Most of these settings are copied from the arm_unknown_linux_gnueabi // target. diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs index 99995e27af0d..5b1d1e2a5a48 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Most of these settings are copied from the arm_unknown_linux_gnueabihf // target. diff --git a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs index 73374bcdf0b1..df9ecd6fb94a 100644 --- a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+strict-align,+v8,+crc".into(), endian: Endian::Big, diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs index 7a62464aea4b..a4608522e68f 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs @@ -3,8 +3,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CfgAbi, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), endian: Endian::Big, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs index 33147c5f1b09..4452b3ba3314 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs @@ -3,8 +3,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CfgAbi, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), endian: Endian::Big, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs index c917531932f6..176bdecca831 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs @@ -9,7 +9,7 @@ //! The default link script is very likely wrong, so you should use //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], features: "+soft-float,+strict-align".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs index 8c386011f89a..9d95a2bde2ca 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+soft-float,+strict-align".into(), // Atomic operations provided by compiler-builtins diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs index b8ae881f3dae..17065c8e86ca 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs @@ -1,6 +1,6 @@ //! Targets the ARMv5TE architecture, with `a32` code by default. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], features: "+soft-float,+strict-align".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs index d1fded203671..17ad14cb7763 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+soft-float,+strict-align".into(), // Atomic operations provided by compiler-builtins diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs index 2daf2ab4d8fe..b5a31a9821e2 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+soft-float,+strict-align".into(), // Atomic operations provided by compiler-builtins diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs index b05df3a77a43..ac07c87bda76 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+soft-float,+strict-align".into(), // Atomic operations provided by compiler-builtins diff --git a/compiler/rustc_target/src/spec/targets/armv6_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv6_none_eabi.rs index 48a196b231b0..c2c6ec4774e9 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_none_eabi.rs @@ -1,6 +1,6 @@ //! Targets the ARMv6K architecture, with `a32` code by default. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",], features: "+soft-float,+strict-align,+v6k".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs index 8bc6b06ecee3..d4886ee16e91 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs @@ -1,6 +1,6 @@ //! Targets the ARMv6K architecture, with `a32` code by default, and hard-float ABI -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",], features: "+strict-align,+v6k,+vfp2,-d32".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs index 6d6dfeed96b0..bd71c839e0b5 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+v6,+vfp2".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs index cb931e6c0e33..5e5468d467d3 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+v6,+vfp2".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs index ed2ab47c0e24..d2bdf747b8f1 100644 --- a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs +++ b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Abi, Arch, Cc, Env, FloatAbi, LinkerFlavor, Lld, Os, RelocModel, Target, TargetMetadata, + Arch, Cc, CfgAbi, Env, FloatAbi, LinkerFlavor, Lld, Os, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; @@ -29,7 +29,7 @@ pub(crate) fn target() -> Target { env: Env::Newlib, vendor: "nintendo".into(), cpu: "mpcore".into(), - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), families: cvs!["unix"], linker: Some("arm-none-eabi-gcc".into()), diff --git a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs index 3ccb99c9ab0f..99adc85947ab 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, SanitizerSet, Target, TargetMetadata, + Arch, Cc, CfgAbi, FloatAbi, LinkerFlavor, Lld, SanitizerSet, Target, TargetMetadata, TargetOptions, base, }; @@ -26,7 +26,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+v7,+thumb-mode,+thumb2,+vfp3d16,-neon".into(), supported_sanitizers: SanitizerSet::ADDRESS, diff --git a/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs index 382658a87b54..90daac16bcc7 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Abi, Arch, Cc, Env, FloatAbi, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, + Arch, Cc, CfgAbi, Env, FloatAbi, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { os: Os::Rtems, families: cvs!["unix"], - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No), linker: None, diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs index 20e5c0acca96..56d129d7b523 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs @@ -1,7 +1,7 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, Env, FloatAbi, LinkerFlavor, Lld, Os, RelocModel, Target, TargetMetadata, + Arch, Cc, CfgAbi, Env, FloatAbi, LinkerFlavor, Lld, Os, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; @@ -34,7 +34,7 @@ pub(crate) fn target() -> Target { c_int_width: 32, env: Env::Newlib, vendor: "sony".into(), - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No), no_default_libraries: false, diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs index c358b530f742..cd6d8b76f1a9 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+v7,+vfp3d16,+thumb2,-neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs index 8fad2ce19632..88f9b9e848d8 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for glibc Linux on ARMv7 without thumb-mode, NEON or // hardfloat. @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+v7,+thumb2,+soft-float,-neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs index 639a9d225729..a1f90b307c3c 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for glibc Linux on ARMv7 without NEON or // thumb-mode. See the thumbv7neon variant for enabling both. @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Info about features at https://wiki.debian.org/ArmHardFloatPort features: "+v7,+vfp3d16,+thumb2,-neon".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs index 9bf0b4fd7e4c..66e1eb1115e5 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for musl Linux on ARMv7 without thumb-mode, NEON or // hardfloat. @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+v7,+thumb2,+soft-float,-neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs index fb7bd1226a37..6ce45de909a8 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for musl Linux on ARMv7 without thumb-mode or NEON. @@ -18,7 +18,7 @@ pub(crate) fn target() -> Target { // Most of these settings are copied from the armv7_unknown_linux_gnueabihf // target. options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+v7,+vfp3d16,+thumb2,-neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs index 318170fe0f8d..1709bef36f88 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for OpenHarmony on ARMv7 Linux with thumb-mode, but no NEON or // hardfloat. @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+v7,+thumb2,+soft-float,-neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs index 37a70da09c51..979a02bcb1c7 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for uclibc Linux on ARMv7 without NEON, // thumb-mode or hardfloat. @@ -18,7 +18,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+v7,+thumb2,+soft-float,-neon".into(), cpu: "generic".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs index 8fb38d315bf6..63845a1a555c 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for uclibc Linux on ARMv7 without NEON or // thumb-mode. See the thumbv7neon variant for enabling both. @@ -23,7 +23,7 @@ pub(crate) fn target() -> Target { cpu: "generic".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs index 8869210ce002..4000e395c5bc 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+v7,+vfp3d16,+thumb2,-neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs index fb3954abb286..e561af2bbf30 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Abi, Arch, FloatAbi, LinkSelfContainedDefault, Os, PanicStrategy, RelroLevel, Target, + Arch, CfgAbi, FloatAbi, LinkSelfContainedDefault, Os, PanicStrategy, RelroLevel, Target, TargetMetadata, TargetOptions, }; @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+v7,+thumb2,+soft-float,-neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs index 27e81c5834f2..63f82a0d7e68 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Info about features at https://wiki.debian.org/ArmHardFloatPort features: "+v7,+vfp3d16,+thumb2,-neon".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs index bd18d6d8ae90..8723dc0f1d29 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs @@ -1,4 +1,6 @@ -use crate::spec::{Abi, Arch, FloatAbi, RelocModel, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CfgAbi, FloatAbi, RelocModel, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { let base = base::solid::opts(); @@ -14,7 +16,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), linker: Some("arm-kmc-eabi-gcc".into()), features: "+v7,+soft-float,+thumb2,-neon".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs index cb652e6a1e1b..b59ce32b48e0 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs @@ -1,4 +1,6 @@ -use crate::spec::{Abi, Arch, FloatAbi, RelocModel, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CfgAbi, FloatAbi, RelocModel, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { let base = base::solid::opts(); @@ -14,7 +16,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), linker: Some("arm-kmc-eabi-gcc".into()), features: "+v7,+vfp3d16,+thumb2,-neon".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs index e8c5c16d8eb5..01d55ce979e8 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-A8 (and similar) processors (ARMv7-A) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+soft-float,-neon,+strict-align".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs index 32a79e346adc..cbeb409110ff 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-A8 (and similar) processors (ARMv7-A) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+vfp3d16,-neon,+strict-align".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs index 5ab74e0533ba..9af6bacbf8e8 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs @@ -5,13 +5,13 @@ // configuration without hardware floating point support. use crate::spec::{ - Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, + Arch, Cc, CfgAbi, FloatAbi, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { let opts = TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs index 4ac07e24a48b..5008f38d52e4 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs @@ -5,13 +5,13 @@ // configuration with hardware floating point support. use crate::spec::{ - Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, + Arch, Cc, CfgAbi, FloatAbi, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { let opts = TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index b83d7b090689..cf4ea3ce9502 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Abi, Arch, Cc, Env, FloatAbi, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, + Arch, Cc, CfgAbi, Env, FloatAbi, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, }; @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { env: Env::V5, os: Os::VexOs, cpu: "cortex-a9".into(), - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, is_like_vexos: true, llvm_floatabi: Some(FloatAbi::Hard), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs index 114b079f360b..382f862e99ff 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(64), has_thumb_interworking: true, diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs index 1c6114f9fc83..b8d0ea226710 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+vfp3d16".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs index 16006e4c52cf..a488637f885d 100644 --- a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-R52 processor (ARMv8-R) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Armv8-R requires a minimum set of floating-point features equivalent to: // fp-armv8, SP-only, with 16 DP (32 SP) registers diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs index 176b853493ef..72193fc7bc24 100644 --- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs +++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs @@ -1,4 +1,6 @@ -use crate::spec::{Abi, Arch, Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, Cc, CfgAbi, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base, +}; // This target is for glibc Linux on Csky @@ -16,7 +18,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32".into(), arch: Arch::CSky, options: TargetOptions { - abi: Abi::AbiV2, + cfg_abi: CfgAbi::AbiV2, features: "+2e3,+3e7,+7e10,+cache,+dsp1e2,+dspe60,+e1,+e2,+edsp,+elrw,+hard-tp,+high-registers,+hwdiv,+mp,+mp1e2,+nvic,+trust".into(), late_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-l:libatomic.a"]), max_atomic_width: Some(32), diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs index 5af54493063d..cf4493249542 100644 --- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs +++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs @@ -1,4 +1,6 @@ -use crate::spec::{Abi, Arch, Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, Cc, CfgAbi, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base, +}; // This target is for glibc Linux on Csky @@ -16,7 +18,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32".into(), arch: Arch::CSky, options: TargetOptions { - abi: Abi::AbiV2Hf, + cfg_abi: CfgAbi::AbiV2Hf, cpu: "ck860fv".into(), features: "+hard-float,+hard-float-abi,+2e3,+3e7,+7e10,+cache,+dsp1e2,+dspe60,+e1,+e2,+edsp,+elrw,+hard-tp,+high-registers,+hwdiv,+mp,+mp1e2,+nvic,+trust".into(), late_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-l:libatomic.a", "-mhard-float"]), diff --git a/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none.rs index d9a4708a9c2d..7e074b73919f 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -19,8 +20,9 @@ pub(crate) fn target() -> Target { features: "+f,+d".into(), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - llvm_abiname: "ilp32d".into(), + llvm_abiname: LlvmAbi::Ilp32d, max_atomic_width: Some(32), + mcount: "_mcount".into(), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none_softfloat.rs index 896cf0f59d58..4e6807012e89 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch32_unknown_none_softfloat.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -18,11 +18,12 @@ pub(crate) fn target() -> Target { options: TargetOptions { cpu: "generic".into(), features: "-f,-d".into(), - abi: Abi::SoftFloat, + cfg_abi: CfgAbi::SoftFloat, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - llvm_abiname: "ilp32s".into(), + llvm_abiname: LlvmAbi::Ilp32s, max_atomic_width: Some(32), + mcount: "_mcount".into(), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index 255756b5b4f1..8dad88bfc46f 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -1,4 +1,6 @@ -use crate::spec::{Arch, CodeModel, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -15,9 +17,10 @@ pub(crate) fn target() -> Target { options: TargetOptions { code_model: Some(CodeModel::Medium), cpu: "generic".into(), - features: "+f,+d,+lsx".into(), - llvm_abiname: "lp64d".into(), + features: "+f,+d,+lsx,+relax".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), + mcount: "_mcount".into(), supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs index 74b0efd63e77..91a028988548 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs @@ -1,4 +1,6 @@ -use crate::spec::{Arch, CodeModel, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -15,9 +17,10 @@ pub(crate) fn target() -> Target { options: TargetOptions { code_model: Some(CodeModel::Medium), cpu: "generic".into(), - features: "+f,+d,+lsx".into(), - llvm_abiname: "lp64d".into(), + features: "+f,+d,+lsx,+relax".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), + mcount: "_mcount".into(), crt_static_default: false, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs index 222cf5c92c56..679235673488 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs @@ -1,4 +1,6 @@ -use crate::spec::{Arch, CodeModel, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -15,9 +17,10 @@ pub(crate) fn target() -> Target { options: TargetOptions { code_model: Some(CodeModel::Medium), cpu: "generic".into(), - features: "+f,+d,+lsx".into(), - llvm_abiname: "lp64d".into(), + features: "+f,+d,+lsx,+relax".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), + mcount: "_mcount".into(), supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index d8b509582017..2d3b217e7789 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Arch, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CodeModel, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -20,8 +20,9 @@ pub(crate) fn target() -> Target { features: "+f,+d,-lsx".into(), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), + mcount: "_mcount".into(), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs index efeb864de1a7..f5e2fb4eb832 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Abi, Arch, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CfgAbi, CodeModel, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -18,11 +18,12 @@ pub(crate) fn target() -> Target { options: TargetOptions { cpu: "generic".into(), features: "-f,-d".into(), - abi: Abi::SoftFloat, + cfg_abi: CfgAbi::SoftFloat, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - llvm_abiname: "lp64s".into(), + llvm_abiname: LlvmAbi::Lp64s, max_atomic_width: Some(64), + mcount: "_mcount".into(), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs index f90e689912e1..8b02e1235e60 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs @@ -2,7 +2,7 @@ use rustc_abi::Endian; -use crate::spec::{Abi, Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -24,10 +24,10 @@ pub(crate) fn target() -> Target { arch: Arch::Mips64, options: TargetOptions { vendor: "openwrt".into(), - abi: Abi::Abi64, + cfg_abi: CfgAbi::Abi64, endian: Endian::Big, mcount: "_mcount".into(), - llvm_abiname: "n64".into(), + llvm_abiname: LlvmAbi::N64, ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs index ecb66b43712c..14942885c6b9 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Abi, Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,14 +15,14 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: Arch::Mips64, options: TargetOptions { - abi: Abi::Abi64, + cfg_abi: CfgAbi::Abi64, endian: Endian::Big, // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".into(), features: "+mips64r2,+xgot".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), - llvm_abiname: "n64".into(), + llvm_abiname: LlvmAbi::N64, ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index ccb13fee37a1..c5336fd58fc9 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Abi, Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -20,10 +20,10 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: Arch::Mips64, options: TargetOptions { - abi: Abi::Abi64, + cfg_abi: CfgAbi::Abi64, endian: Endian::Big, mcount: "_mcount".into(), - llvm_abiname: "n64".into(), + llvm_abiname: LlvmAbi::N64, ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs index 2457bd838c57..665cf1d4362d 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,13 +13,13 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: Arch::Mips64, options: TargetOptions { - abi: Abi::Abi64, + cfg_abi: CfgAbi::Abi64, // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".into(), features: "+mips64r2,+xgot".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), - llvm_abiname: "n64".into(), + llvm_abiname: LlvmAbi::N64, ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index 41353729df8f..bd237eaedc66 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -18,9 +18,9 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: Arch::Mips64, options: TargetOptions { - abi: Abi::Abi64, + cfg_abi: CfgAbi::Abi64, mcount: "_mcount".into(), - llvm_abiname: "n64".into(), + llvm_abiname: LlvmAbi::N64, ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs b/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs index 54039925e795..32440cdd92e9 100644 --- a/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -24,6 +25,7 @@ pub(crate) fn target() -> Target { endian: Endian::Big, cpu: "mips32r2".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), features: "+mips32r2,+soft-float,+noabicalls".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs index ea6e237895ae..8bfa8ecf6022 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -18,6 +18,7 @@ pub(crate) fn target() -> Target { endian: Endian::Big, cpu: "mips32r2".into(), features: "+mips32r2,+fpxx,+nooddspreg".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs index ab68c2495b5a..316e59dea88b 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -18,6 +18,11 @@ pub(crate) fn target() -> Target { pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), arch: Arch::Mips, - options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, + options: TargetOptions { + endian: Endian::Big, + llvm_abiname: LlvmAbi::O32, + mcount: "_mcount".into(), + ..base + }, } } diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs index c699f7e20b06..b03dec5b5b6e 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -18,6 +18,7 @@ pub(crate) fn target() -> Target { endian: Endian::Big, cpu: "mips32r2".into(), features: "+mips32r2,+soft-float".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs b/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs index 06c4d14be432..ce50cedef99f 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -24,6 +25,7 @@ pub(crate) fn target() -> Target { endian: Endian::Little, cpu: "mips32r2".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), features: "+mips32r2,+soft-float,+noabicalls".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs index 370e585f65ad..2fde3e9b24b7 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, Os, RelocModel, Target, TargetMetadata, TargetOptions, cvs, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, Os, RelocModel, Target, TargetMetadata, TargetOptions, + cvs, }; // The PSP has custom linker requirements. @@ -36,6 +37,7 @@ pub(crate) fn target() -> Target { // PSP does not support trap-on-condition instructions. llvm_args: cvs!["-mno-check-zero-division"], + llvm_abiname: LlvmAbi::O32, pre_link_args, link_script: Some(LINKER_SCRIPT.into()), ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs index 06631fdefb4a..cb88c7161f54 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; @@ -41,7 +41,7 @@ pub(crate) fn target() -> Target { // PSX does not support trap-on-condition instructions. llvm_args: cvs!["-mno-check-zero-division"], - llvm_abiname: "o32".into(), + llvm_abiname: LlvmAbi::O32, panic_strategy: PanicStrategy::Abort, ..Default::default() }, diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs index 79a22e518b0c..0541e0e9b2c5 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,6 +16,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cpu: "mips32r2".into(), features: "+mips32r2,+fpxx,+nooddspreg".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs index 8c64b17a37b5..5d0136a6699a 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -16,6 +16,6 @@ pub(crate) fn target() -> Target { pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), arch: Arch::Mips, - options: TargetOptions { mcount: "_mcount".into(), ..base }, + options: TargetOptions { llvm_abiname: LlvmAbi::O32, mcount: "_mcount".into(), ..base }, } } diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs index 295b1788877c..0add21bfc9c6 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,6 +16,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cpu: "mips32r2".into(), features: "+mips32r2,+soft-float".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs index 69b232d71ea1..5395c15ad581 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::netbsd::opts(); @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { arch: Arch::Mips, options: TargetOptions { features: "+soft-float".into(), + llvm_abiname: LlvmAbi::O32, mcount: "__mcount".into(), endian: Endian::Little, ..base diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs index 7012651afc34..0e184c834801 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs @@ -3,7 +3,8 @@ //! Can be used for MIPS M4K core (e.g. on PIC32MX devices) use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -23,6 +24,7 @@ pub(crate) fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), cpu: "mips32r2".into(), features: "+mips32r2,+soft-float,+noabicalls".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), linker: Some("rust-lld".into()), panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs index b45511446d8d..80916500a431 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -18,6 +18,7 @@ pub(crate) fn target() -> Target { endian: Endian::Big, cpu: "mips32r6".into(), features: "+mips32r6".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs index 36845029de3b..87db5a282872 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,6 +16,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cpu: "mips32r6".into(), features: "+mips32r6".into(), + llvm_abiname: LlvmAbi::O32, max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs index fb97a2e65eab..8e66407470a2 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Abi, Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,14 +15,14 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: Arch::Mips64r6, options: TargetOptions { - abi: Abi::Abi64, + cfg_abi: CfgAbi::Abi64, endian: Endian::Big, // NOTE(mips64r6) matches C toolchain cpu: "mips64r6".into(), features: "+mips64r6".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), - llvm_abiname: "n64".into(), + llvm_abiname: LlvmAbi::N64, ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs index 556962458fa5..5523f4470bd5 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -13,13 +13,13 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: Arch::Mips64r6, options: TargetOptions { - abi: Abi::Abi64, + cfg_abi: CfgAbi::Abi64, // NOTE(mips64r6) matches C toolchain cpu: "mips64r6".into(), features: "+mips64r6".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), - llvm_abiname: "n64".into(), + llvm_abiname: LlvmAbi::N64, ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs index f5d5698713c2..537b21c54b7c 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, + TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -10,8 +11,8 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.abi = Abi::ElfV2; - base.llvm_abiname = "elfv2".into(); + base.cfg_abi = CfgAbi::ElfV2; + base.llvm_abiname = LlvmAbi::ElfV2; Target { llvm_target: "powerpc64-unknown-freebsd".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs index e2dada235271..df7f115e99b0 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, + TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -10,8 +11,8 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.abi = Abi::ElfV1; - base.llvm_abiname = "elfv1".into(); + base.cfg_abi = CfgAbi::ElfV1; + base.llvm_abiname = LlvmAbi::ElfV1; Target { llvm_target: "powerpc64-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index 130bcacfc8cc..474d20d2f054 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, + TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -10,8 +11,8 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.abi = Abi::ElfV2; - base.llvm_abiname = "elfv2".into(); + base.cfg_abi = CfgAbi::ElfV2; + base.llvm_abiname = LlvmAbi::ElfV2; Target { llvm_target: "powerpc64-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs index 082358e82be1..052dbf55724b 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, + TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -10,8 +11,8 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.abi = Abi::ElfV2; - base.llvm_abiname = "elfv2".into(); + base.cfg_abi = CfgAbi::ElfV2; + base.llvm_abiname = LlvmAbi::ElfV2; Target { llvm_target: "powerpc64-unknown-openbsd".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs index f576d2372bfa..4a684fe97bb9 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, + TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -10,8 +11,8 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.abi = Abi::ElfV1; - base.llvm_abiname = "elfv1".into(); + base.cfg_abi = CfgAbi::ElfV1; + base.llvm_abiname = LlvmAbi::ElfV1; Target { llvm_target: "powerpc64-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index b2713af3bd56..35c477d2bdaf 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, + TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -8,8 +9,8 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.abi = Abi::ElfV2; - base.llvm_abiname = "elfv2".into(); + base.cfg_abi = CfgAbi::ElfV2; + base.llvm_abiname = LlvmAbi::ElfV2; Target { llvm_target: "powerpc64le-unknown-freebsd".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs index 550ad563e6f2..ae2c8714224b 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, + TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -8,8 +9,8 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.abi = Abi::ElfV2; - base.llvm_abiname = "elfv2".into(); + base.cfg_abi = CfgAbi::ElfV2; + base.llvm_abiname = LlvmAbi::ElfV2; Target { llvm_target: "powerpc64le-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs index 38e3d09c2c35..0060a41d79d0 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, + TargetOptions, base, }; pub(crate) fn target() -> Target { @@ -10,8 +11,8 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; - base.abi = Abi::ElfV2; - base.llvm_abiname = "elfv2".into(); + base.cfg_abi = CfgAbi::ElfV2; + base.llvm_abiname = LlvmAbi::ElfV2; Target { llvm_target: "powerpc64le-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs index 49620305e0e8..88655c9b22a6 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, + base, }; pub(crate) fn target() -> Target { @@ -22,7 +23,7 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: Arch::PowerPC, options: TargetOptions { - abi: Abi::Spe, + cfg_abi: CfgAbi::Spe, endian: Endian::Big, features: "+secure-plt,+msync".into(), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs index 210a80fe422e..c61ceab6bd39 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, + base, }; pub(crate) fn target() -> Target { @@ -22,7 +23,7 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: Arch::PowerPC, options: TargetOptions { - abi: Abi::Spe, + cfg_abi: CfgAbi::Spe, endian: Endian::Big, features: "+msync".into(), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs index 041580f2bdaf..8f7aaa025bcc 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs @@ -1,7 +1,8 @@ use rustc_abi::Endian; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, TargetOptions, + base, }; pub(crate) fn target() -> Target { @@ -22,7 +23,7 @@ pub(crate) fn target() -> Target { data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: Arch::PowerPC, options: TargetOptions { - abi: Abi::Spe, + cfg_abi: CfgAbi::Spe, endian: Endian::Big, // feature msync would disable instruction 'fsync' which is not supported by fsl_p1p2 features: "+secure-plt,+msync".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs index 3ec8891c95ee..2e0a13f7bf39 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, StackProbeType, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -14,7 +14,7 @@ pub(crate) fn target() -> Target { arch: Arch::RiscV32, options: TargetOptions { cpu: "generic-rv32".into(), - llvm_abiname: "ilp32d".into(), + llvm_abiname: LlvmAbi::Ilp32d, max_atomic_width: Some(32), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), stack_probes: StackProbeType::Inline, diff --git a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs index 65dbd391db74..90dcf177c19a 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -19,12 +19,12 @@ pub(crate) fn target() -> Target { arch: Arch::RiscV32, options: TargetOptions { - abi: Abi::Ilp32e, + cfg_abi: CfgAbi::Ilp32e, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), // The ilp32e ABI specifies the `data_layout` - llvm_abiname: "ilp32e".into(), + llvm_abiname: LlvmAbi::Ilp32e, max_atomic_width: Some(32), atomic_cas: false, features: "+e,+forced-atomics".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs index 0826326a2b4b..cba18095725b 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -19,12 +19,12 @@ pub(crate) fn target() -> Target { arch: Arch::RiscV32, options: TargetOptions { - abi: Abi::Ilp32e, + cfg_abi: CfgAbi::Ilp32e, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), // The ilp32e ABI specifies the `data_layout` - llvm_abiname: "ilp32e".into(), + llvm_abiname: LlvmAbi::Ilp32e, max_atomic_width: Some(32), atomic_cas: false, features: "+e,+m,+forced-atomics".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs index e37a44e1edc4..9de6ef9fab96 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -19,12 +19,12 @@ pub(crate) fn target() -> Target { arch: Arch::RiscV32, options: TargetOptions { - abi: Abi::Ilp32e, + cfg_abi: CfgAbi::Ilp32e, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), // The ilp32e ABI specifies the `data_layout` - llvm_abiname: "ilp32e".into(), + llvm_abiname: LlvmAbi::Ilp32e, max_atomic_width: Some(32), atomic_cas: false, features: "+e,+m,+c,+forced-atomics".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs index 29b0f35a205f..c11edf7c618c 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Arch, CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -18,7 +20,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv32".into(), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), - llvm_abiname: "ilp32d".into(), + llvm_abiname: LlvmAbi::Ilp32d, max_atomic_width: Some(32), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_gnu::opts() diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs index 28116052151e..e5618ea6b20d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Arch, CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -18,7 +20,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv32".into(), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), - llvm_abiname: "ilp32d".into(), + llvm_abiname: LlvmAbi::Ilp32d, max_atomic_width: Some(32), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_musl::opts() diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs index bd6375fef163..2e4d83b564bd 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -22,7 +23,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), atomic_cas: false, features: "+forced-atomics".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs index af25334a2e53..82cc02aacd1a 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, }; @@ -32,7 +32,7 @@ pub(crate) fn target() -> Target { atomic_cas: true, features: "+m".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs index 5aef58b153d1..f47102cb585f 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -22,7 +23,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), atomic_cas: false, features: "+m,+forced-atomics".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs index c455f654b400..a96367473c3c 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -21,7 +22,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs index 11a5626c5641..889152752043 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Env, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, + Arch, Env, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -29,7 +29,7 @@ pub(crate) fn target() -> Target { atomic_cas: true, features: "+m,+a,+c".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs index deca348b9e1b..c27e7aab1a93 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -21,7 +22,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs index 7205fb61de74..3a5a9424311d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Unwind, relocation_model: RelocModel::Static, ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs index 363e465e2ef4..6d8bf3095d98 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, }; @@ -23,7 +23,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Unwind, relocation_model: RelocModel::Static, ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs index b3a3ab9b7543..614d81f1e2b7 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Env, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, + Arch, Env, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -26,7 +26,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), atomic_cas: true, - llvm_abiname: "ilp32f".into(), + llvm_abiname: LlvmAbi::Ilp32f, features: "+m,+a,+c,+f".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs index 21f683516f7c..bf519fbe223a 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -20,7 +21,7 @@ pub(crate) fn target() -> Target { linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), max_atomic_width: Some(32), - llvm_abiname: "ilp32f".into(), + llvm_abiname: LlvmAbi::Ilp32f, features: "+m,+a,+c,+f".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs index 0bba2e47dc85..045845acda06 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_nuttx_elf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; @@ -23,7 +23,7 @@ pub(crate) fn target() -> Target { linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), max_atomic_width: Some(32), - llvm_abiname: "ilp32f".into(), + llvm_abiname: LlvmAbi::Ilp32f, features: "+m,+a,+c,+f".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs index f903bbdb04bf..cfec1b539eb2 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Env, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, + Arch, Env, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -32,7 +32,7 @@ pub(crate) fn target() -> Target { atomic_cas: true, features: "+m,+c".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs index 0b8e44744206..1010039a6cb0 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs @@ -1,5 +1,6 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, }; pub(crate) fn target() -> Target { @@ -22,7 +23,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), atomic_cas: false, features: "+m,+c,+forced-atomics".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs index d1d73842703e..6143080f485c 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, Target, TargetMetadata, + Arch, Cc, LinkerFlavor, Lld, LlvmAbi, Os, PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions, cvs, }; @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+c".into(), - llvm_abiname: "ilp32".into(), + llvm_abiname: LlvmAbi::Ilp32, panic_strategy: PanicStrategy::Unwind, relocation_model: RelocModel::Static, ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs index 404f4143c5be..9842b9f82432 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs @@ -1,7 +1,8 @@ use std::borrow::Cow; use crate::spec::{ - Arch, CodeModel, SanitizerSet, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base, + Arch, CodeModel, LlvmAbi, SanitizerSet, SplitDebuginfo, Target, TargetMetadata, TargetOptions, + base, }; pub(crate) fn target() -> Target { @@ -20,7 +21,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), features: "+m,+a,+f,+d,+c,+b,+v,+zicsr,+zifencei".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, supported_sanitizers: SanitizerSet::ADDRESS, max_atomic_width: Some(64), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), diff --git a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs index c6fffc251529..f3389b8eca98 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, StackProbeType, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -14,7 +14,7 @@ pub(crate) fn target() -> Target { arch: Arch::RiscV64, options: TargetOptions { cpu: "generic-rv64".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), stack_probes: StackProbeType::Inline, diff --git a/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs index bbcf31f89bad..f9a7d307c74a 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Arch, CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -18,7 +20,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), features: "+rva23u64".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_gnu::opts() diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs index dbcfbc38ece6..d59d02641344 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, CodeModel, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CodeModel, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), ..base::freebsd::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs index 212704832e55..3944c4cd59c7 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs @@ -1,11 +1,13 @@ -use crate::spec::{Arch, CodeModel, SanitizerSet, StackProbeType, Target, TargetMetadata, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SanitizerSet, StackProbeType, Target, TargetMetadata, base, +}; pub(crate) fn target() -> Target { let mut base = base::fuchsia::opts(); base.code_model = Some(CodeModel::Medium); base.cpu = "generic-rv64".into(); base.features = "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(); - base.llvm_abiname = "lp64d".into(); + base.llvm_abiname = LlvmAbi::Lp64d; base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::SHADOWCALLSTACK; diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs index 68f69044bb25..516610db1d80 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Arch, CodeModel, RelocModel, Target, TargetMetadata, TargetOptions, TlsModel, base, + Arch, CodeModel, LlvmAbi, RelocModel, Target, TargetMetadata, TargetOptions, TlsModel, base, }; pub(crate) fn target() -> Target { @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), tls_model: TlsModel::LocalExec, max_atomic_width: Some(64), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, ..base::hermit::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs index 333a63a25158..76c9ad65700c 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Arch, CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -18,7 +20,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_gnu::opts() diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs index 6eba0994deb4..8ed4e09adbbf 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Arch, CodeModel, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CodeModel, LlvmAbi, SplitDebuginfo, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -18,7 +20,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..base::linux_musl::opts() diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_managarm_mlibc.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_managarm_mlibc.rs index a9ecf27e9134..f837daf4ea9d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_managarm_mlibc.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_managarm_mlibc.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, CodeModel, Target, TargetOptions, base}; +use crate::spec::{Arch, CodeModel, LlvmAbi, Target, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), features: "+m,+a,+f,+d,+c".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), ..base::managarm_mlibc::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs index bc929a07f9c0..564d9b2a6802 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, CodeModel, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CodeModel, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), mcount: "__mcount".into(), ..base::netbsd::opts() diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs index b06727efc9ee..f79cd50cf4c3 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Arch, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target, - TargetMetadata, TargetOptions, + Arch, Cc, CodeModel, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, SanitizerSet, + Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, cpu: "generic-rv64".into(), max_atomic_width: Some(64), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs index 7850cc8105d9..9fde109c57f6 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_nuttx_elf.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Arch, Cc, CodeModel, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, SanitizerSet, Target, - TargetMetadata, TargetOptions, cvs, + Arch, Cc, CodeModel, LinkerFlavor, Lld, LlvmAbi, Os, PanicStrategy, RelocModel, SanitizerSet, + Target, TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { os: Os::NuttX, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, cpu: "generic-rv64".into(), max_atomic_width: Some(64), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs index fb7b077c963d..b93700704bf5 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, CodeModel, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CodeModel, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), features: "+m,+a,+f,+d,+c,+zicsr,+zifencei".into(), - llvm_abiname: "lp64d".into(), + llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), ..base::openbsd::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_redox.rs index b6e88646d4e2..42132216576b 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_redox.rs @@ -1,11 +1,11 @@ -use crate::spec::{Arch, CodeModel, Target, TargetMetadata, base}; +use crate::spec::{Arch, CodeModel, LlvmAbi, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { let mut base = base::redox::opts(); base.code_model = Some(CodeModel::Medium); base.cpu = "generic-rv64".into(); base.features = "+m,+a,+f,+d,+c".into(); - base.llvm_abiname = "lp64d".into(); + base.llvm_abiname = LlvmAbi::Lp64d; base.plt_by_default = false; base.max_atomic_width = Some(64); diff --git a/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs index 6aae40a3f90d..fb36efbc9069 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Arch, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + Arch, Cc, CodeModel, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, + TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -23,7 +23,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), atomic_cas: false, features: "+m,+forced-atomics".into(), - llvm_abiname: "lp64".into(), + llvm_abiname: LlvmAbi::Lp64, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs index 60ee41b47dfd..65c3f1a8d79f 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Arch, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target, - TargetMetadata, TargetOptions, + Arch, Cc, CodeModel, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, SanitizerSet, + Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv64".into(), max_atomic_width: Some(64), features: "+m,+a,+c".into(), - llvm_abiname: "lp64".into(), + llvm_abiname: LlvmAbi::Lp64, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs index b1a1817bbe1f..469c0d15abd8 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Arch, Cc, CodeModel, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, SanitizerSet, Target, - TargetMetadata, TargetOptions, cvs, + Arch, Cc, CodeModel, LinkerFlavor, Lld, LlvmAbi, Os, PanicStrategy, RelocModel, SanitizerSet, + Target, TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv64".into(), max_atomic_width: Some(64), features: "+m,+a,+c".into(), - llvm_abiname: "lp64".into(), + llvm_abiname: LlvmAbi::Lp64, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs index 7d42c1fd9244..8c411091ff50 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs @@ -1,13 +1,13 @@ use rustc_abi::{Align, Endian}; use crate::spec::{ - Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, + Arch, Cc, CfgAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, RustcAbi, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, }; pub(crate) fn target() -> Target { let opts = TargetOptions { - abi: Abi::SoftFloat, + cfg_abi: CfgAbi::SoftFloat, cpu: "z10".into(), endian: Endian::Big, features: "+soft-float,-vector".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs index dfb8ccb06bc2..83bbfff1063f 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs @@ -9,7 +9,7 @@ //! The default link script is very likely wrong, so you should use //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], features: "+soft-float,+strict-align".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs index 3b41208b69f4..7d2f910a22e4 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs @@ -1,6 +1,6 @@ //! Targets the ARMv5TE architecture, with `t32` code by default. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], features: "+soft-float,+strict-align".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv6_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6_none_eabi.rs index 077f02818085..45a122164a14 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6_none_eabi.rs @@ -1,6 +1,6 @@ //! Targets the ARMv6K architecture, with `t32` code by default. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",], features: "+soft-float,+strict-align,+v6k".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs index cc81cb92be6b..19b59197b81a 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs @@ -1,6 +1,6 @@ // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them // with +strict-align. diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs index 8b58d2e16eec..2536152cbb78 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs @@ -1,6 +1,6 @@ // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture) -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -18,7 +18,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them // with +strict-align. diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs index ce11e3f0875c..011307a50c34 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-A8 (and similar) processors (ARMv7-A) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+soft-float,-neon,+strict-align".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs index 12210e9c2b01..4baa73c3cdb8 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-A8 (and similar) processors (ARMv7-A) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+vfp3d16,-neon,+strict-align".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs index 17d25a67acbd..8eaebe7befd9 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs @@ -4,7 +4,7 @@ // and will use software floating point operations. This matches the NuttX EABI // configuration without hardware floating point support. -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), // Cortex-A7/A8/A9 with software floating point features: "+soft-float,-neon".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs index a4e17004e7bf..ea070f093090 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs @@ -7,7 +7,7 @@ // This target uses the "hard" floating convention (ABI) where floating point values // are passed to/from subroutines via FPU registers (S0, S1, D0, D1, etc.). -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Cortex-A7/A8/A9 support VFPv3-D32/VFPv4-D32 with optional double-precision // and NEON SIMD instructions diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs index 6e6975c01f81..a9d766080ffb 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs @@ -9,7 +9,7 @@ // To opt-in to hardware accelerated floating point operations, you can use, for example, // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), ..base::arm_none::opts() diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs index 6a7fe14a26df..6af82f89b277 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs @@ -8,7 +8,7 @@ // // To opt into double precision hardware support, use the `-C target-feature=+fp64` flag. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // vfp4 is the lowest common denominator between the Cortex-M4F (vfp4) and the // Cortex-M7 (vfp5). diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs index 10173273b5d8..3166a01ae888 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs @@ -9,7 +9,7 @@ // To opt-in to hardware accelerated floating point operations, you can use, for example, // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`. -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -27,7 +27,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), ..base::arm_none::opts() diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs index 1f24155a7dab..3e5e7dad4f66 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs @@ -8,7 +8,7 @@ // // To opt into double precision hardware support, use the `-C target-feature=+fp64` flag. -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -26,7 +26,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // vfp4 is the lowest common denominator between the Cortex-M4F (vfp4) and the // Cortex-M7 (vfp5). diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs index 8851f7b63437..d38d2aca0f57 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs @@ -1,6 +1,6 @@ // Targets the Cortex-M3 processor (ARMv7-M) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), ..base::arm_none::opts() diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs index 9f0261c69b3f..7e42c91cb714 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs @@ -1,6 +1,6 @@ // Targets the Cortex-M3 processor (ARMv7-M) -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -18,7 +18,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), ..base::arm_none::opts() diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs index 3ffa30129298..56c581b3a6cf 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs @@ -1,5 +1,5 @@ use crate::spec::{ - Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base, + Arch, Cc, CfgAbi, FloatAbi, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base, }; // This target if is for the Android v7a ABI in thumb mode with @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), features: "+v7,+thumb-mode,+thumb2,+vfp3,+neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs index 36b99516d377..5829d37cf826 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for glibc Linux on ARMv7 with thumb mode enabled // (for consistency with Android and Debian-based distributions) @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Info about features at https://wiki.debian.org/ArmHardFloatPort features: "+v7,+thumb-mode,+thumb2,+vfp3,+neon".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs index 41c4bc91f701..dc4f8987d5d2 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; // This target is for musl Linux on ARMv7 with thumb mode enabled // (for consistency with Android and Debian-based distributions) @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target { // Most of these settings are copied from the thumbv7neon_unknown_linux_gnueabihf // target. options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+v7,+thumb-mode,+thumb2,+vfp3,+neon".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs index bf71d31a06ec..da66a5343200 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(64), has_thumb_interworking: true, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs index 88b5e6764403..d591db8faf6a 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), features: "+vfp3d16".into(), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs index 7426eb9bd5e2..b9193a246cde 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs @@ -1,6 +1,6 @@ // Targets the Cortex-M23 processor (Baseline ARMv8-M) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), // ARMv8-M baseline doesn't support unaligned loads/stores so we disable them // with +strict-align. diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs index a74719ba2f0c..1e786a4ee60f 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs @@ -1,6 +1,6 @@ // Targets the Cortex-M23 processor (Baseline ARMv8-M) -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -18,7 +18,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), // ARMv8-M baseline doesn't support unaligned loads/stores so we disable them // with +strict-align. diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs index 540d4bdee07c..a3a8da45b413 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs @@ -1,7 +1,7 @@ // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile), // without the Floating Point extension. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), ..base::arm_none::opts() diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs index 2287cce395aa..d8058ba0074c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs @@ -1,7 +1,7 @@ // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile), // with the Floating Point extension. -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // If the Floating Point extension is implemented in the Cortex-M33 // processor, the Cortex-M33 Technical Reference Manual states that diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs index ec107292d529..e1320666053c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs @@ -1,7 +1,7 @@ // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile), // without the Floating Point extension. -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::Eabi, + cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), ..base::arm_none::opts() diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs index 9ff924b6386b..e3ba784bfb89 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs @@ -1,7 +1,7 @@ // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile), // with the Floating Point extension. -use crate::spec::{Abi, Arch, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Os, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { families: cvs!["unix"], os: Os::NuttX, - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // If the Floating Point extension is implemented in the Cortex-M33 // processor, the Cortex-M33 Technical Reference Manual states that diff --git a/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs index 87434cd7353c..459dff9c1aa9 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs @@ -1,6 +1,6 @@ // Targets the Little-endian Cortex-R52 processor (ARMv8-R) -use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { arch: Arch::Arm, options: TargetOptions { - abi: Abi::EabiHf, + cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Armv8-R requires a minimum set of floating-point features equivalent to: // fp-armv8, SP-only, with 16 DP (32 SP) registers diff --git a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs index cd074a468fd6..1204719c923f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use crate::spec::{ - Abi, Arch, Cc, Env, LinkerFlavor, Lld, Os, Target, TargetMetadata, TargetOptions, cvs, + Arch, Cc, CfgAbi, Env, LinkerFlavor, Lld, Os, Target, TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -60,7 +60,7 @@ pub(crate) fn target() -> Target { os: Os::Unknown, env: Env::Sgx, vendor: "fortanix".into(), - abi: Abi::Fortanix, + cfg_abi: CfgAbi::Fortanix, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnumsan.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnumsan.rs new file mode 100644 index 000000000000..377aae8bf073 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnumsan.rs @@ -0,0 +1,16 @@ +use crate::spec::{SanitizerSet, Target, TargetMetadata}; + +pub(crate) fn target() -> Target { + let mut base = super::x86_64_unknown_linux_gnu::target(); + base.metadata = TargetMetadata { + description: Some( + "64-bit Linux (kernel 3.2+, glibc 2.17+) with MSAN enabled by default".into(), + ), + tier: Some(2), + host_tools: Some(false), + std: Some(true), + }; + base.supported_sanitizers = SanitizerSet::MEMORY; + base.default_sanitizers = SanitizerSet::MEMORY; + base +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnutsan.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnutsan.rs new file mode 100644 index 000000000000..bbe377ca74a6 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnutsan.rs @@ -0,0 +1,16 @@ +use crate::spec::{SanitizerSet, Target, TargetMetadata}; + +pub(crate) fn target() -> Target { + let mut base = super::x86_64_unknown_linux_gnu::target(); + base.metadata = TargetMetadata { + description: Some( + "64-bit Linux (kernel 3.2+, glibc 2.17+) with TSAN enabled by default".into(), + ), + tier: Some(2), + host_tools: Some(false), + std: Some(true), + }; + base.supported_sanitizers = SanitizerSet::THREAD; + base.default_sanitizers = SanitizerSet::THREAD; + base +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs index 7e06a718e480..793d235aa77d 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs @@ -1,9 +1,11 @@ -use crate::spec::{Abi, Arch, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base}; +use crate::spec::{ + Arch, Cc, CfgAbi, LinkerFlavor, Lld, StackProbeType, Target, TargetMetadata, base, +}; pub(crate) fn target() -> Target { let mut base = base::linux_gnu::opts(); base.cpu = "x86-64".into(); - base.abi = Abi::X32; + base.cfg_abi = CfgAbi::X32; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mx32"]); base.stack_probes = StackProbeType::Inline; diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 80674ab4cf8a..161bb31c664e 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -5,7 +5,7 @@ use rustc_macros::HashStable_Generic; use rustc_span::{Symbol, sym}; -use crate::spec::{Arch, FloatAbi, RustcAbi, Target}; +use crate::spec::{Arch, FloatAbi, LlvmAbi, RustcAbi, Target}; /// Features that control behaviour of rustc, rather than the codegen. /// These exist globally and are not in the target-specific lists below. @@ -392,7 +392,11 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> { "avx512vpopcntdq", ], ), - ("avx10.2", Unstable(sym::avx10_target_feature), &["avx10.1"]), + ( + "avx10.2", + Unstable(sym::avx10_target_feature), + &["avx10.1", "avxvnni", "avxvnniint8", "avxvnniint16"], + ), ("avx512bf16", Stable, &["avx512bw"]), ("avx512bitalg", Stable, &["avx512bw"]), ("avx512bw", Stable, &["avx512f"]), @@ -756,8 +760,10 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> { // tidy-alphabetical-end ]; -const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = - &[("alu32", Unstable(sym::bpf_target_feature), &[])]; +const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + ("alu32", Unstable(sym::bpf_target_feature), &[]), + ("allows-misaligned-mem-access", Unstable(sym::bpf_target_feature), &[]), +]; static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start @@ -1174,20 +1180,20 @@ pub fn abi_required_features(&self) -> FeatureConstraints { Arch::RiscV32 | Arch::RiscV64 => { // RISC-V handles ABI in a very sane way, being fully explicit via `llvm_abiname` // about what the intended ABI is. - match &*self.llvm_abiname { - "ilp32d" | "lp64d" => { + match &self.llvm_abiname { + LlvmAbi::Ilp32d | LlvmAbi::Lp64d => { // Requires d (which implies f), incompatible with e and zfinx. FeatureConstraints { required: &["d"], incompatible: &["e", "zfinx"] } } - "ilp32f" | "lp64f" => { + LlvmAbi::Ilp32f | LlvmAbi::Lp64f => { // Requires f, incompatible with e and zfinx. FeatureConstraints { required: &["f"], incompatible: &["e", "zfinx"] } } - "ilp32" | "lp64" => { + LlvmAbi::Ilp32 | LlvmAbi::Lp64 => { // Requires nothing, incompatible with e. FeatureConstraints { required: &[], incompatible: &["e"] } } - "ilp32e" => { + LlvmAbi::Ilp32e => { // ilp32e is documented to be incompatible with features that need aligned // load/stores > 32 bits, like `d`. (One could also just generate more // complicated code to align the stack when needed, but the RISCV @@ -1198,7 +1204,7 @@ pub fn abi_required_features(&self) -> FeatureConstraints { // a program while the rest doesn't know they even exist. FeatureConstraints { required: &[], incompatible: &["d"] } } - "lp64e" => { + LlvmAbi::Lp64e => { // As above, `e` is not required. NOTHING } @@ -1208,16 +1214,16 @@ pub fn abi_required_features(&self) -> FeatureConstraints { Arch::LoongArch32 | Arch::LoongArch64 => { // LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname` // about what the intended ABI is. - match &*self.llvm_abiname { - "ilp32d" | "lp64d" => { + match &self.llvm_abiname { + LlvmAbi::Ilp32d | LlvmAbi::Lp64d => { // Requires d (which implies f), incompatible with nothing. FeatureConstraints { required: &["d"], incompatible: &[] } } - "ilp32f" | "lp64f" => { + LlvmAbi::Ilp32f | LlvmAbi::Lp64f => { // Requires f, incompatible with nothing. FeatureConstraints { required: &["f"], incompatible: &[] } } - "ilp32s" | "lp64s" => { + LlvmAbi::Ilp32s | LlvmAbi::Lp64s => { // The soft-float ABI does not require any features and is also not // incompatible with any features. Rust targets explicitly specify the // LLVM ABI names, which allows for enabling hard-float support even on diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 22342a956710..d9ea2e005789 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -392,7 +392,7 @@ fn note_error_origin( { err.span_suggestion_verbose( span, - "consider dereferencing to access the inner value using the Deref trait", + "consider dereferencing to access the inner value using the `Deref` trait", format!("{prefix}{peeled_snippet}"), Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 80e97d36c23f..46bc9bdee04b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -158,6 +158,7 @@ fn try_get_prefix(&self) -> Option<&str> { struct ClosureEraser<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, + depth: usize, } impl<'a, 'tcx> ClosureEraser<'a, 'tcx> { @@ -172,7 +173,8 @@ fn cx(&self) -> TyCtxt<'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind() { + self.depth += 1; + let ty = match ty.kind() { ty::Closure(_, args) => { // For a closure type, we turn it into a function pointer so that it gets rendered // as `fn(args) -> Ret`. @@ -233,9 +235,15 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { // its type parameters. ty.super_fold_with(self) } - // We don't have an unknown type parameter anywhere, replace with `_`. + // We are in the top-level type, not one of its type parameters. Name it with its + // parameters replaced. + _ if self.depth == 1 => ty.super_fold_with(self), + // We don't have an unknown type parameter anywhere, and we are in a type parameter. + // Replace with `_`. _ => self.new_infer(), - } + }; + self.depth -= 1; + ty } fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { @@ -287,7 +295,7 @@ fn ty_to_string<'tcx>( let ty = infcx.resolve_vars_if_possible(ty); // We use `fn` ptr syntax for closures, but this only works when the closure does not capture // anything. We also remove all type parameters that are fully known to the type system. - let ty = ty.fold_with(&mut ClosureEraser { infcx }); + let ty = ty.fold_with(&mut ClosureEraser { infcx, depth: 0 }); match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in @@ -467,6 +475,25 @@ pub fn emit_inference_failure_err( term: Term<'tcx>, error_code: TypeAnnotationNeeded, should_label_span: bool, + ) -> Diag<'a> { + self.emit_inference_failure_err_with_type_hint( + body_def_id, + failure_span, + term, + error_code, + should_label_span, + None, + ) + } + + pub fn emit_inference_failure_err_with_type_hint( + &self, + body_def_id: LocalDefId, + failure_span: Span, + term: Term<'tcx>, + error_code: TypeAnnotationNeeded, + should_label_span: bool, + ty: Option>, ) -> Diag<'a> { let term = self.resolve_vars_if_possible(term); let arg_data = self @@ -479,19 +506,18 @@ pub fn emit_inference_failure_err( return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; - let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term); - if let Some(body) = self.tcx.hir_maybe_body_owned_by( - self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(), - ) { + let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term, ty); + if let Some(body) = + self.tcx.hir_maybe_body_owned_by(self.tcx.typeck_root_def_id_local(body_def_id)) + { let expr = body.value; local_visitor.visit_expr(expr); } let Some(InferSource { span, kind }) = local_visitor.infer_source else { let silence = if let DefKind::AssocFn = self.tcx.def_kind(body_def_id) - && let parent = self.tcx.parent(body_def_id.into()) - && self.tcx.is_automatically_derived(parent) - && let Some(parent) = parent.as_local() + && let parent = self.tcx.local_parent(body_def_id) + && self.tcx.is_automatically_derived(parent.to_def_id()) && let hir::Node::Item(item) = self.tcx.hir_node_by_def_id(parent) && let hir::ItemKind::Impl(imp) = item.kind && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = imp.self_ty.kind @@ -555,6 +581,7 @@ pub fn emit_inference_failure_err( def_id: _, generic_args, have_turbofish, + hir_id, } => { let generics = self.tcx.generics_of(generics_def_id); let is_type = term.as_type().is_some(); @@ -577,7 +604,32 @@ pub fn emit_inference_failure_err( let args = if self.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(generics_def_id) { - "Vec<_>".to_string() + if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(hir_id) + && let hir::ExprKind::Call(expr, _args) = expr.kind + && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind + && let Res::Def(DefKind::AssocFn, def_id) = path.res + && let Some(try_trait) = self.tcx.lang_items().try_trait() + && try_trait == self.tcx.parent(def_id) + && let DefKind::Fn | DefKind::AssocFn = + self.tcx.def_kind(body_def_id.to_def_id()) + && let ret = self + .tcx + .fn_sig(body_def_id.to_def_id()) + .instantiate_identity() + .skip_binder() + .output() + && let ty::Adt(adt, _args) = ret.kind() + && let Some(sym::Option | sym::Result) = + self.tcx.get_diagnostic_name(adt.did()) + { + if let Some(sym::Option) = self.tcx.get_diagnostic_name(adt.did()) { + "Option<_>".to_string() + } else { + "Result<_, _>".to_string() + } + } else { + "Vec<_>".to_string() + } } else { let mut p = fmt_printer(self, Namespace::TypeNS); p.comma_sep(generic_args.iter().copied().map(|arg| { @@ -710,6 +762,7 @@ enum InferSourceKind<'tcx> { def_id: DefId, generic_args: &'tcx [GenericArg<'tcx>], have_turbofish: bool, + hir_id: HirId, }, FullyQualifiedMethodCall { receiver: &'tcx Expr<'tcx>, @@ -752,10 +805,20 @@ fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String, Op | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { ("closure", closure_as_fn_str(infcx, ty), long_ty_path) - } else if !ty.is_ty_or_numeric_infer() { - ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path) - } else { + } else if ty.is_ty_or_numeric_infer() + || ty.is_primitive() + || matches!( + ty.kind(), + ty::Adt(_, args) + if args.types().count() == 0 && args.consts().count() == 0 + ) + { + // `ty` is either `_`, a primitive type like `u32` or a type with no type or + // const parameters. We will not mention the type in the main inference error + // message. ("other", String::new(), long_ty_path) + } else { + ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path) } } // FIXME: We should be able to add some additional info here. @@ -788,6 +851,7 @@ struct FindInferSourceVisitor<'a, 'tcx> { typeck_results: &'a TypeckResults<'tcx>, target: Term<'tcx>, + ty: Option>, attempt: usize, infer_source_cost: usize, @@ -799,12 +863,14 @@ fn new( tecx: &'a TypeErrCtxt<'a, 'tcx>, typeck_results: &'a TypeckResults<'tcx>, target: Term<'tcx>, + ty: Option>, ) -> Self { FindInferSourceVisitor { tecx, typeck_results, target, + ty, attempt: 0, infer_source_cost: usize::MAX, @@ -1030,12 +1096,15 @@ fn expr_inferred_arg_iter( let args = self.node_args_opt(expr.hir_id)?; let span = tcx.hir_span(segment.hir_id); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); + let have_turbofish = segment.args.is_some_and(|args| { + args.args.iter().any(|arg| arg.is_ty_or_const()) + }); InsertableGenericArgs { insert_span, args, generics_def_id: def_id, def_id, - have_turbofish: false, + have_turbofish, } }; return Box::new(insertable.into_iter()); @@ -1183,21 +1252,51 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) { intravisit::walk_local(self, local); - if let Some(ty) = self.opt_node_type(local.hir_id) { + if let Some(mut ty) = self.opt_node_type(local.hir_id) { if self.generic_arg_contains_target(ty.into()) { - match local.source { - LocalSource::Normal if local.ty.is_none() => { - self.update_infer_source(InferSource { - span: local.pat.span, - kind: InferSourceKind::LetBinding { - insert_span: local.pat.span.shrink_to_hi(), - pattern_name: local.pat.simple_ident(), - ty, - def_id: None, - }, - }) + fn get_did( + typeck_results: &TypeckResults<'_>, + expr: &hir::Expr<'_>, + ) -> Option { + match expr.kind { + hir::ExprKind::Match(expr, _, hir::MatchSource::TryDesugar(_)) + if let hir::ExprKind::Call(_, [expr]) = expr.kind => + { + get_did(typeck_results, expr) + } + hir::ExprKind::Call(base, _args) + if let hir::ExprKind::Path(path) = base.kind + && let hir::QPath::Resolved(_, path) = path + && let Res::Def(_, did) = path.res => + { + Some(did) + } + hir::ExprKind::MethodCall(..) + if let Some(did) = + typeck_results.type_dependent_def_id(expr.hir_id) => + { + Some(did) + } + _ => None, } - _ => {} + } + if let Some(t) = self.ty + && ty.has_infer() + { + ty = t; + } + if let LocalSource::Normal = local.source + && local.ty.is_none() + { + self.update_infer_source(InferSource { + span: local.pat.span, + kind: InferSourceKind::LetBinding { + insert_span: local.pat.span.shrink_to_hi(), + pattern_name: local.pat.simple_ident(), + ty, + def_id: local.init.and_then(|expr| get_did(self.typeck_results, expr)), + }, + }); } } } @@ -1257,21 +1356,32 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { have_turbofish, } = args; let generics = tcx.generics_of(generics_def_id); - if let Some(mut argument_index) = generics + if let Some(argument_index) = generics .own_args(args) .iter() .position(|&arg| self.generic_arg_contains_target(arg)) { - if generics.has_own_self() { - argument_index += 1; - } let args = self.tecx.resolve_vars_if_possible(args); let generic_args = &generics.own_args_no_defaults(tcx, args)[generics.own_counts().lifetimes..]; let span = match expr.kind { - ExprKind::MethodCall(path, ..) => path.ident.span, + ExprKind::MethodCall(segment, ..) + if have_turbofish + && let Some(hir_args) = segment.args + && let Some(idx) = + argument_index.checked_sub(generics.own_counts().lifetimes) + && let Some(arg) = + hir_args.args.get(hir_args.num_lifetime_params() + idx) => + { + arg.span() + } + ExprKind::MethodCall(segment, ..) => segment.ident.span, _ => expr.span, }; + let mut argument_index = argument_index; + if generics.has_own_self() { + argument_index += 1; + } self.update_infer_source(InferSource { span, @@ -1282,6 +1392,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { def_id, generic_args, have_turbofish, + hir_id: expr.hir_id, }, }); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index adb2d2c185ca..7f53fdbc2c9f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -263,8 +263,13 @@ fn foo(&self, x: T) -> T { x } cause.code(), ); } + // Don't suggest constraining a projection to something + // containing itself, e.g. `Item = &::Item`. (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) - if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => + if !tcx.is_impl_trait_in_trait(proj_ty.def_id) + && !tcx + .erase_and_anonymize_regions(values.expected) + .contains(tcx.erase_and_anonymize_regions(values.found)) => { let msg = || { format!( @@ -272,18 +277,21 @@ fn foo(&self, x: T) -> T { x } values.found, values.expected, ) }; - if !(self.suggest_constraining_opaque_associated_type( - diag, - msg, - proj_ty, - values.expected, - ) || self.suggest_constraint( - diag, - &msg, - body_owner_def_id, - proj_ty, - values.expected, - )) { + let suggested_projection_constraint = proj_ty.kind(tcx) + == ty::AliasTyKind::Projection + && (self.suggest_constraining_opaque_associated_type( + diag, + msg, + proj_ty, + values.expected, + ) || self.suggest_constraint( + diag, + &msg, + body_owner_def_id, + proj_ty, + values.expected, + )); + if !suggested_projection_constraint { diag.help(msg()); diag.note( "for more information, visit \ diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 2afc1b040353..7f5ed9ecb6d1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -11,6 +11,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, }; +use rustc_middle::ty::print::PrintPolyTraitPredicateExt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; use rustc_session::parse::feature_err_unstable_feature_bound; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; @@ -245,12 +246,37 @@ pub(super) fn maybe_report_ambiguity( .find(|s| s.has_non_region_infer()); let mut err = if let Some(term) = term { - self.emit_inference_failure_err( + let candidates: Vec<_> = self + .tcx + .all_impls(trait_pred.def_id()) + .filter_map(|def_id| { + let imp = self.tcx.impl_trait_header(def_id); + if imp.polarity != ty::ImplPolarity::Positive + || !self.tcx.is_user_visible_dep(def_id.krate) + { + return None; + } + let imp = imp.trait_ref.skip_binder(); + if imp + .with_replaced_self_ty(self.tcx, trait_pred.skip_binder().self_ty()) + == trait_pred.skip_binder().trait_ref + { + Some(imp.self_ty()) + } else { + None + } + }) + .collect(); + self.emit_inference_failure_err_with_type_hint( obligation.cause.body_id, span, term, TypeAnnotationNeeded::E0283, true, + match &candidates[..] { + [candidate] => Some(*candidate), + _ => None, + }, ) } else { struct_span_code_err!( @@ -306,8 +332,18 @@ pub(super) fn maybe_report_ambiguity( err.cancel(); return e; } - let pred = self.tcx.short_string(predicate, &mut err.long_ty_path()); - err.note(format!("cannot satisfy `{pred}`")); + if let Some(clause) = predicate.as_trait_clause() + && let ty::Infer(_) = clause.self_ty().skip_binder().kind() + { + let tr = self.tcx.short_string( + clause.print_modifiers_and_trait_path(), + &mut err.long_ty_path(), + ); + err.note(format!("the type must implement `{tr}`")); + } else { + let pred = self.tcx.short_string(predicate, &mut err.long_ty_path()); + err.note(format!("cannot satisfy `{pred}`")); + } let impl_candidates = self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap()); if impl_candidates.len() < 40 { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 364152475e94..d0358b03af19 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -285,14 +285,16 @@ pub fn report_selection_error( let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); let trait_def_id = main_trait_predicate.def_id(); - if self.tcx.is_diagnostic_item(sym::From, trait_def_id) - || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) + let leaf_trait_def_id = leaf_trait_predicate.def_id(); + if (self.tcx.is_diagnostic_item(sym::From, trait_def_id) + || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)) + && (self.tcx.is_diagnostic_item(sym::From, leaf_trait_def_id) + || self.tcx.is_diagnostic_item(sym::TryFrom, leaf_trait_def_id)) { let trait_ref = leaf_trait_predicate.skip_binder().trait_ref; - // Defensive: next-solver may produce fewer args than expected. - if trait_ref.args.len() > 1 { - let found_ty = trait_ref.args.type_at(1); + if let Some(found_ty) = trait_ref.args.get(1).and_then(|arg| arg.as_type()) + { let ty = main_trait_predicate.skip_binder().self_ty(); if let Some(cast_ty) = self.find_explicit_cast_type( @@ -756,11 +758,6 @@ pub fn report_selection_error( } } - SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => return self.report_opaque_type_auto_trait_leakage( - &obligation, - def_id, - ), - SelectionError::TraitDynIncompatible(did) => { let violations = self.tcx.dyn_compatibility_violations(did); report_dyn_incompatibility(self.tcx, span, None, did, violations) @@ -2256,6 +2253,16 @@ pub(super) fn report_similar_impl_candidates( if candidates.is_empty() { return false; } + let mut specific_candidates = candidates.clone(); + specific_candidates.retain(|(tr, _)| { + tr.with_replaced_self_ty(self.tcx, trait_pred.skip_binder().self_ty()) + == trait_pred.skip_binder().trait_ref + }); + if !specific_candidates.is_empty() { + // We have found a subset of impls that fully satisfy the expected trait, only + // mention those types. + candidates = specific_candidates; + } if let &[(cand, def_id)] = &candidates[..] { if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id) && !self.tcx.features().enabled(sym::try_trait_v2) @@ -2294,6 +2301,11 @@ pub(super) fn report_similar_impl_candidates( // FIXME: this could use a better heuristic, like just checking // that args[1..] is the same. let all_traits_equal = traits.len() == 1; + let mut types: Vec<_> = + candidates.iter().map(|(c, _)| c.self_ty().to_string()).collect(); + types.sort(); + types.dedup(); + let all_types_equal = types.len() == 1; let end = if candidates.len() <= 9 || self.tcx.sess.opts.verbose { candidates.len() @@ -2307,6 +2319,11 @@ pub(super) fn report_similar_impl_candidates( for (c, def_id) in &candidates { let msg = if all_traits_equal { format!("`{}`", self.tcx.short_string(c.self_ty(), err.long_ty_path())) + } else if all_types_equal { + format!( + "`{}`", + self.tcx.short_string(c.print_only_trait_path(), err.long_ty_path()) + ) } else { format!( "`{}` implements `{}`", @@ -2316,13 +2333,19 @@ pub(super) fn report_similar_impl_candidates( }; span.push_span_label(self.tcx.def_span(*def_id), msg); } - err.span_help( - span, + let msg = if all_types_equal { + format!( + "`{}` implements trait `{}`", + self.tcx.short_string(candidates[0].0.self_ty(), err.long_ty_path()), + self.tcx.short_string(trait_ref.print_trait_sugared(), err.long_ty_path()), + ) + } else { format!( "the following {other}types implement trait `{}`", - trait_ref.print_trait_sugared(), - ), - ); + self.tcx.short_string(trait_ref.print_trait_sugared(), err.long_ty_path()), + ) + }; + err.span_help(span, msg); } else { let candidate_names: Vec = candidates .iter() @@ -2332,6 +2355,12 @@ pub(super) fn report_similar_impl_candidates( "\n {}", self.tcx.short_string(c.self_ty(), err.long_ty_path()) ) + } else if all_types_equal { + format!( + "\n {}", + self.tcx + .short_string(c.print_only_trait_path(), err.long_ty_path()) + ) } else { format!( "\n `{}` implements `{}`", @@ -2342,9 +2371,21 @@ pub(super) fn report_similar_impl_candidates( } }) .collect(); + let msg = if all_types_equal { + format!( + "`{}` implements trait `{}`", + self.tcx.short_string(candidates[0].0.self_ty(), err.long_ty_path()), + self.tcx.short_string(trait_ref.print_trait_sugared(), err.long_ty_path()), + ) + } else { + format!( + "the following {other}types implement trait `{}`", + self.tcx.short_string(trait_ref.print_trait_sugared(), err.long_ty_path()), + ) + }; + err.help(format!( - "the following {other}types implement trait `{}`:{}{}", - trait_ref.print_trait_sugared(), + "{msg}:{}{}", candidate_names[..end].join(""), if candidates.len() > 9 && !self.tcx.sess.opts.verbose { format!("\nand {} others", candidates.len() - 8) @@ -2837,6 +2878,10 @@ fn select_transmute_obligation_for_reporting( trait_predicate: ty::PolyTraitPredicate<'tcx>, root_obligation: &PredicateObligation<'tcx>, ) -> (PredicateObligation<'tcx>, ty::PolyTraitPredicate<'tcx>) { + if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() { + return (obligation.clone(), trait_predicate); + } + let ocx = ObligationCtxt::new(self); let normalized_predicate = self.tcx.erase_and_anonymize_regions( self.tcx.instantiate_bound_regions_with_erased(trait_predicate), @@ -3178,6 +3223,7 @@ fn try_to_add_help_message( self.suggest_tuple_wrapping(err, root_obligation, obligation); } + self.suggest_shadowed_inherent_method(err, obligation, trait_predicate); } fn add_help_message_for_fn_trait( @@ -3330,34 +3376,6 @@ fn report_cyclic_signature_error( ) } - fn report_opaque_type_auto_trait_leakage( - &self, - obligation: &PredicateObligation<'tcx>, - def_id: DefId, - ) -> ErrorGuaranteed { - let name = match self.tcx.local_opaque_ty_origin(def_id.expect_local()) { - hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } => { - "opaque type".to_string() - } - hir::OpaqueTyOrigin::TyAlias { .. } => { - format!("`{}`", self.tcx.def_path_debug_str(def_id)) - } - }; - let mut err = self.dcx().struct_span_err( - obligation.cause.span, - format!("cannot check whether the hidden type of {name} satisfies auto traits"), - ); - - err.note( - "fetching the hidden types of an opaque inside of the defining scope is not supported. \ - You can try moving the opaque type and the item that actually registers a hidden type into a new submodule", - ); - err.span_note(self.tcx.def_span(def_id), "opaque type is declared here"); - - self.note_obligation_cause(&mut err, &obligation); - self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err) - } - fn report_signature_mismatch_error( &self, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index d08e0fa3521b..4ae6584fc2d1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -124,8 +124,11 @@ pub(crate) fn on_unimplemented_components( } } - if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) { - crate_local = true; + if let Some(adt) = self_ty.ty_adt_def() { + if adt.did().is_local() { + crate_local = true; + } + self_types.push(format!("{{{}}}", adt.descr())) } // Allow targeting all integers using `{integral}`, even if the exact type was resolved diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index a0876d8fe759..a543f549bdae 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -99,6 +99,15 @@ fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String "overflow assigning `{a}` to `{b}`", ) } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { + let term = with_short_path(self.tcx, term); + struct_span_code_err!( + self.dcx(), + span, + E0275, + "overflow evaluating whether `{term}` is well-formed", + ) + } _ => { let pred_str = with_short_path(self.tcx, predicate); struct_span_code_err!( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 14aff65d4b51..2d9574ea8c54 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -545,8 +545,12 @@ pub(super) fn suggest_dereferences( .all(|obligation| self.predicate_may_hold(obligation)) }) && steps > 0 { + if span.in_external_macro(self.tcx.sess.source_map()) { + return false; + } let derefs = "*".repeat(steps); let msg = "consider dereferencing here"; + let call_node = self.tcx.hir_node(*call_hir_id); let is_receiver = matches!( call_node, @@ -593,7 +597,6 @@ pub(super) fn suggest_dereferences( }) { // Suggest dereferencing the LHS, RHS, or both terms of a binop if possible - let trait_pred = predicate.unwrap_or(trait_pred); let lhs_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty()); let lhs_autoderef = (self.autoderef_steps)(lhs_ty); @@ -644,6 +647,9 @@ pub(super) fn suggest_dereferences( }) { let make_sugg = |mut expr: &Expr<'_>, mut steps| { + if expr.span.in_external_macro(self.tcx.sess.source_map()) { + return None; + } let mut prefix_span = expr.span.shrink_to_lo(); let mut msg = "consider dereferencing here"; if let hir::ExprKind::AddrOf(_, _, inner) = expr.kind { @@ -661,10 +667,10 @@ pub(super) fn suggest_dereferences( } // Empty suggestions with empty spans ICE with debug assertions if steps == 0 { - return ( + return Some(( msg.trim_end_matches(" and dereferencing instead"), vec![(prefix_span, String::new())], - ); + )); } let derefs = "*".repeat(steps); let needs_parens = steps > 0 && expr_needs_parens(expr); @@ -686,7 +692,7 @@ pub(super) fn suggest_dereferences( if !prefix_span.is_empty() { suggestion.push((prefix_span, String::new())); } - (msg, suggestion) + Some((msg, suggestion)) }; if let Some(lsteps) = lsteps @@ -694,8 +700,13 @@ pub(super) fn suggest_dereferences( && lsteps > 0 && rsteps > 0 { - let mut suggestion = make_sugg(lhs, lsteps).1; - suggestion.append(&mut make_sugg(rhs, rsteps).1); + let Some((_, mut suggestion)) = make_sugg(lhs, lsteps) else { + return false; + }; + let Some((_, mut rhs_suggestion)) = make_sugg(rhs, rsteps) else { + return false; + }; + suggestion.append(&mut rhs_suggestion); err.multipart_suggestion( "consider dereferencing both sides of the expression", suggestion, @@ -705,13 +716,17 @@ pub(super) fn suggest_dereferences( } else if let Some(lsteps) = lsteps && lsteps > 0 { - let (msg, suggestion) = make_sugg(lhs, lsteps); + let Some((msg, suggestion)) = make_sugg(lhs, lsteps) else { + return false; + }; err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable); return true; } else if let Some(rsteps) = rsteps && rsteps > 0 { - let (msg, suggestion) = make_sugg(rhs, rsteps); + let Some((msg, suggestion)) = make_sugg(rhs, rsteps) else { + return false; + }; err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable); return true; } @@ -1966,10 +1981,9 @@ pub(super) fn suggest_impl_trait( let mut span = obligation.cause.span; if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id) - && let parent = self.tcx.parent(obligation.cause.body_id.into()) + && let parent = self.tcx.local_parent(obligation.cause.body_id) && let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent) && self.tcx.asyncness(parent).is_async() - && let Some(parent) = parent.as_local() && let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. }) | Node::TraitItem(hir::TraitItem { @@ -2916,12 +2930,21 @@ pub(super) fn note_obligation_cause_code( | ObligationCauseCode::CheckAssociatedTypeBounds { .. } | ObligationCauseCode::LetElse | ObligationCauseCode::UnOp { .. } - | ObligationCauseCode::BinOp { .. } | ObligationCauseCode::AscribeUserTypeProvePredicate(..) | ObligationCauseCode::AlwaysApplicableImpl | ObligationCauseCode::ConstParam(_) | ObligationCauseCode::ReferenceOutlivesReferent(..) | ObligationCauseCode::ObjectTypeBound(..) => {} + ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } => { + if let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id) + && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id) + && tcx.sess.source_map().lookup_char_pos(lhs.span.lo()).line + != tcx.sess.source_map().lookup_char_pos(rhs.span.hi()).line + { + err.span_label(lhs.span, ""); + err.span_label(rhs.span, ""); + } + } ObligationCauseCode::RustCall => { if let Some(pred) = predicate.as_trait_clause() && tcx.is_lang_item(pred.def_id(), LangItem::Sized) @@ -4037,12 +4060,13 @@ pub fn can_suggest_derive( _ => return false, }; let is_derivable_trait = match diagnostic_name { - sym::Default => !adt.is_enum(), + sym::Copy | sym::Clone => true, + _ if adt.is_union() => false, sym::PartialEq | sym::PartialOrd => { let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1); trait_pred.skip_binder().self_ty() == rhs_ty } - sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true, + sym::Eq | sym::Ord | sym::Hash | sym::Debug | sym::Default => true, _ => false, }; is_derivable_trait && @@ -4815,6 +4839,9 @@ pub(super) fn suggest_convert_to_slice( candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { + if span.in_external_macro(self.tcx.sess.source_map()) { + return; + } // We can only suggest the slice coercion for function and binary operation arguments, // since the suggestion would make no sense in turbofish or call let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) = @@ -4916,6 +4943,79 @@ pub(super) fn suggest_tuple_wrapping( } } + pub(super) fn suggest_shadowed_inherent_method( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, + ) { + let ObligationCauseCode::FunctionArg { call_hir_id, .. } = obligation.cause.code() else { + return; + }; + let Node::Expr(call) = self.tcx.hir_node(*call_hir_id) else { return }; + let hir::ExprKind::MethodCall(segment, rcvr, args, ..) = call.kind else { return }; + let Some(typeck) = &self.typeck_results else { return }; + let Some(rcvr_ty) = typeck.expr_ty_adjusted_opt(rcvr) else { return }; + let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); + let autoderef = (self.autoderef_steps)(rcvr_ty); + for (ty, def_id) in autoderef.iter().filter_map(|(ty, obligations)| { + if let ty::Adt(def, _) = ty.kind() + && *ty != rcvr_ty.peel_refs() + && obligations.iter().all(|obligation| self.predicate_may_hold(obligation)) + { + Some((ty, def.did())) + } else { + None + } + }) { + for impl_def_id in self.tcx.inherent_impls(def_id) { + if *impl_def_id == trait_predicate.def_id() { + continue; + } + for m in self + .tcx + .provided_trait_methods(*impl_def_id) + .filter(|m| m.name() == segment.ident.name) + { + let fn_sig = self.tcx.fn_sig(m.def_id); + if fn_sig.skip_binder().inputs().skip_binder().len() != args.len() + 1 { + continue; + } + let rcvr_ty = fn_sig.skip_binder().input(0).skip_binder(); + let (mutability, _ty) = match rcvr_ty.kind() { + ty::Ref(_, ty, hir::Mutability::Mut) => ("&mut ", ty), + ty::Ref(_, ty, _) => ("&", ty), + _ => ("", &rcvr_ty), + }; + let path = self.tcx.def_path_str(def_id); + err.note(format!( + "there's an inherent method on `{ty}` of the same name, which can be \ + auto-dereferenced from `{rcvr_ty}`" + )); + err.multipart_suggestion( + format!( + "to access the inherent method on `{ty}`, use the fully-qualified path", + ), + vec![ + ( + call.span.until(rcvr.span), + format!("{path}::{}({}", m.name(), mutability), + ), + match &args { + [] => ( + rcvr.span.shrink_to_hi().with_hi(call.span.hi()), + ")".to_string(), + ), + [first, ..] => (rcvr.span.between(first.span), ", ".to_string()), + }, + ], + Applicability::MaybeIncorrect, + ); + } + } + } + } + pub(super) fn explain_hrtb_projection( &self, diag: &mut Diag<'_>, diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 6f63c1d663f1..34b9c9988f35 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1707,7 +1707,8 @@ pub enum TypeErrorAdditionalDiags { #[suggestion( "if you meant to write a byte literal, prefix with `b`", code = "b'{code}'", - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "verbose" )] MeantByteLiteral { #[primary_span] @@ -1717,7 +1718,8 @@ pub enum TypeErrorAdditionalDiags { #[suggestion( "if you meant to write a `char` literal, use single quotes", code = "'{code}'", - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "verbose" )] MeantCharLiteral { #[primary_span] @@ -1737,7 +1739,8 @@ pub enum TypeErrorAdditionalDiags { #[suggestion( "consider specifying the actual array length", code = "{length}", - applicability = "maybe-incorrect" + applicability = "maybe-incorrect", + style = "verbose" )] ConsiderSpecifyingLength { #[primary_span] diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 66c949a38cea..469e24c9c248 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -472,12 +472,17 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) | ty::Error(_) => thin_vec![], - // Coroutines and closures could implement `[const] Drop`, + // Closures are [const] Destruct when all of their upvars (captures) are [const] Destruct. + ty::Closure(_, args) => { + let closure_args = args.as_closure(); + thin_vec![ty::TraitRef::new(tcx, destruct_def_id, [closure_args.tupled_upvars_ty()])] + } + + // Coroutines could implement `[const] Drop`, // but they don't really need to right now. - ty::Closure(_, _) - | ty::CoroutineClosure(_, _) - | ty::Coroutine(_, _) - | ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution), + ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(_, _) => { + return Err(EvaluationFailure::NoSolution); + } // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop` // if their inner type implements it. @@ -519,10 +524,21 @@ fn evaluate_host_effect_for_fn_goal<'tcx>( // We may support function pointers at some point in the future ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution), - // Closures could implement `[const] Fn`, + // Coroutines could implement `[const] Fn`, // but they don't really need to right now. - ty::Closure(..) | ty::CoroutineClosure(_, _) => { - return Err(EvaluationFailure::NoSolution); + ty::CoroutineClosure(_, _) => return Err(EvaluationFailure::NoSolution), + + ty::Closure(def, args) => { + // For now we limit ourselves to closures without binders. The next solver can handle them. + let sig = + args.as_closure().sig().no_bound_vars().ok_or(EvaluationFailure::NoSolution)?; + ( + def, + tcx.mk_args_from_iter( + [ty::GenericArg::from(*sig.inputs().get(0).unwrap()), sig.output().into()] + .into_iter(), + ), + ) } // Everything else needs explicit impls or cannot have an impl diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 71a8e081146e..a575630a0503 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -349,7 +349,7 @@ fn process_obligation( &mut self, pending_obligation: &mut PendingPredicateObligation<'tcx>, ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { - pending_obligation.stalled_on.truncate(0); + pending_obligation.stalled_on.clear(); let obligation = &mut pending_obligation.obligation; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 1fde7e5d43b7..bdad1b259b73 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -300,19 +300,14 @@ fn do_normalize_predicates<'tcx>( Ok(predicates) => Ok(predicates), Err(fixup_err) => { // If we encounter a fixup error, it means that some type - // variable wound up unconstrained. I actually don't know - // if this can happen, and I certainly don't expect it to - // happen often, but if it did happen it probably - // represents a legitimate failure due to some kind of - // unconstrained variable. - // - // @lcnr: Let's still ICE here for now. I want a test case - // for that. - span_bug!( + // variable wound up unconstrained. That can happen for + // ill-formed impls, so we delay a bug here instead of + // immediately ICEing and let type checking report the + // actual user-facing errors. + Err(tcx.dcx().span_delayed_bug( span, - "inference variables in normalized parameter environment: {}", - fixup_err - ); + format!("inference variables in normalized parameter environment: {fixup_err}"), + )) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 9e7637df2649..e948994b8689 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -115,11 +115,6 @@ pub(super) fn confirm_candidate( ImplSource::Builtin(BuiltinImplSource::Misc, data) } - PointerLikeCandidate => { - let data = self.confirm_pointer_like_candidate(obligation); - ImplSource::Builtin(BuiltinImplSource::Misc, data) - } - TraitAliasCandidate => { let data = self.confirm_trait_alias_candidate(obligation); ImplSource::Builtin(BuiltinImplSource::Misc, data) @@ -638,25 +633,6 @@ fn confirm_fn_pointer_candidate( Ok(nested) } - fn confirm_pointer_like_candidate( - &mut self, - obligation: &PolyTraitObligation<'tcx>, - ) -> PredicateObligations<'tcx> { - debug!(?obligation, "confirm_pointer_like_candidate"); - let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); - let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); - let ty::Pat(base, _) = *self_ty.kind() else { bug!() }; - let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - placeholder_predicate.def_id(), - vec![base], - ) - } - fn confirm_trait_alias_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a7f47a8615c2..0008ce4b4984 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2038,7 +2038,6 @@ fn winnow_candidates( | TraitUpcastingUnsizeCandidate(_) | BuiltinObjectCandidate | BuiltinUnsizeCandidate - | PointerLikeCandidate | BikeshedGuaranteedNoDropCandidate => false, // Non-global param candidates have already been handled, global // where-bounds get ignored. @@ -2404,15 +2403,11 @@ fn constituent_types_for_auto_trait( // We can resolve the opaque type to its hidden type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - match self.tcx().type_of_opaque(def_id) { - Ok(ty) => ty::Binder::dummy(AutoImplConstituents { - types: vec![ty.instantiate(self.tcx(), args)], - assumptions: vec![], - }), - Err(_) => { - return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); - } - } + let ty = self.tcx().type_of_opaque(def_id); + ty::Binder::dummy(AutoImplConstituents { + types: vec![ty.instantiate(self.tcx(), args)], + assumptions: vec![], + }) } } }) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index e66aa6bc4a9e..fa9d617604e5 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -578,10 +578,15 @@ fn decorate<'tcx, G: EmissionGuarantee>( let lint = match kind { FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, }; - tcx.node_span_lint(lint, tcx.local_def_id_to_hir_id(impl_def_id), impl_span, |err| { - err.primary_message(msg()); - decorate(tcx, &overlap, impl_span, err); - }); + tcx.emit_node_span_lint( + lint, + tcx.local_def_id_to_hir_id(impl_def_id), + impl_span, + rustc_errors::DiagDecorator(|err| { + err.primary_message(msg()); + decorate(tcx, &overlap, impl_span, err); + }), + ); Ok(()) } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 4a0a99ea2764..b8f5336115e1 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -942,14 +942,53 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { // FIXME(#27579) RFC also considers adding trait // obligations that don't refer to Self and // checking those - if let Some(principal) = data.principal_def_id() { + if let Some(principal) = data.principal() { + let principal_def_id = principal.skip_binder().def_id; self.out.push(traits::Obligation::with_depth( tcx, self.cause(ObligationCauseCode::WellFormed(None)), self.recursion_depth, self.param_env, - ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)), + ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal_def_id)), )); + + // For the most part we don't add wf predicates corresponding to + // the trait ref's generic arguments which allows code like this + // to compile: + // ```rust + // trait Trait {} + // fn foo(_: &dyn Trait<[u32]>) {} + // ``` + // + // However, we sometimes incidentally check that const arguments + // have the correct type as a side effect of the anon const + // desugaring. To make this "consistent" for users we explicitly + // check `ConstArgHasType` clauses so that const args that don't + // go through an anon const still have their types checked. + // + // See also: https://rustc-dev-guide.rust-lang.org/const-generics.html + let args = principal.skip_binder().with_self_ty(self.tcx(), t).args; + let obligations = + self.nominal_obligations(principal_def_id, args).into_iter().filter(|o| { + let kind = o.predicate.kind().skip_binder(); + match kind { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType( + ct, + _, + )) if matches!(ct.kind(), ty::ConstKind::Param(..)) => { + // ConstArgHasType clauses are not higher kinded. Assert as + // such so we can fix this up if that ever changes. + assert!(o.predicate.kind().bound_vars().is_empty()); + // In stable rust, variables from the trait object binder + // cannot be referenced by a ConstArgHasType clause. However, + // under `generic_const_parameter_types`, it can. Ignore those + // predicates for now, to not have HKT-ConstArgHasTypes. + !kind.has_escaping_bound_vars() + } + _ => false, + } + }); + self.out.extend(obligations); } if !t.has_escaping_bound_vars() { diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 44762caf6e83..5008794bcb19 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -485,7 +485,7 @@ fn fn_arg_sanity_check<'tcx>( match arg.layout.backend_repr { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } - | BackendRepr::ScalableVector { .. } => {} + | BackendRepr::SimdScalableVector { .. } => {} BackendRepr::ScalarPair(..) => { panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty) } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 1d444079f896..49e0bdde3787 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -58,7 +58,8 @@ fn recurse_build<'tcx>( } &ExprKind::Literal { lit, neg } => { let sp = node.span; - match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) { + match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: Some(node.ty), neg }) + { Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty), None => ty::Const::new_misc_error(tcx), } diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 166e44d3c486..03ac1674dbd5 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -250,7 +250,7 @@ fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { // And the size has to be element * count plus alignment padding, of course assert!(size == (element_size * count).align_to(align)); } - BackendRepr::Memory { .. } | BackendRepr::ScalableVector { .. } => {} // Nothing to check. + BackendRepr::Memory { .. } | BackendRepr::SimdScalableVector { .. } => {} // Nothing to check. } } diff --git a/compiler/rustc_ty_utils/src/nested_bodies.rs b/compiler/rustc_ty_utils/src/nested_bodies.rs index 11dfbad7dbb7..874c8161453b 100644 --- a/compiler/rustc_ty_utils/src/nested_bodies.rs +++ b/compiler/rustc_ty_utils/src/nested_bodies.rs @@ -1,27 +1,26 @@ use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; fn nested_bodies_within<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx ty::List { let body = tcx.hir_body_owned_by(item); - let mut collector = - NestedBodiesVisitor { tcx, root_def_id: item.to_def_id(), nested_bodies: vec![] }; + let mut collector = NestedBodiesVisitor { tcx, root_def_id: item, nested_bodies: vec![] }; collector.visit_body(body); tcx.mk_local_def_ids(&collector.nested_bodies) } struct NestedBodiesVisitor<'tcx> { tcx: TyCtxt<'tcx>, - root_def_id: DefId, + root_def_id: LocalDefId, nested_bodies: Vec, } impl<'tcx> Visitor<'tcx> for NestedBodiesVisitor<'tcx> { fn visit_nested_body(&mut self, id: hir::BodyId) { let body_def_id = self.tcx.hir_body_owner_def_id(id); - if self.tcx.typeck_root_def_id(body_def_id.to_def_id()) == self.root_def_id { + if self.tcx.typeck_root_def_id_local(body_def_id) == self.root_def_id { // We visit nested bodies before adding the current body. This // means that nested bodies are always stored before their parent. let body = self.tcx.hir_body(id); diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 1814e7604a2d..c83e0bb77fcf 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -2,7 +2,7 @@ use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; pub(crate) fn provide(providers: &mut Providers) { @@ -14,12 +14,12 @@ pub(crate) fn provide(providers: &mut Providers) { }; } -fn check_representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability { +fn check_representability(tcx: TyCtxt<'_>, def_id: LocalDefId) { match tcx.def_kind(def_id) { DefKind::Struct | DefKind::Union | DefKind::Enum => { for variant in tcx.adt_def(def_id).variants() { for field in variant.fields.iter() { - let _ = tcx.check_representability(field.did.expect_local()); + tcx.ensure_ok().check_representability(field.did.expect_local()); } } } @@ -28,7 +28,6 @@ fn check_representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representabili } def_kind => bug!("unexpected {def_kind:?}"), } - Representability } fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { @@ -36,7 +35,7 @@ fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { // This one must be a query rather than a vanilla `check_representability_adt_ty` call. See // the comment on `check_representability_adt_ty` below for why. ty::Adt(..) => { - let _ = tcx.check_representability_adt_ty(ty); + tcx.ensure_ok().check_representability_adt_ty(ty); } // FIXME(#11924) allow zero-length arrays? ty::Array(ty, _) => { @@ -59,7 +58,7 @@ fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { // -> check_representability_adt_ty(Bar) // -> check_representability(Foo) // -// For the diagnostic output (in `Value::from_cycle_error`), we want to detect +// For the diagnostic output (in `check_representability`), we want to detect // that the `Foo` in the *second* field of the struct is culpable. This // requires traversing the HIR of the struct and calling `params_in_repr(Bar)`. // But we can't call params_in_repr for a given type unless it is known to be @@ -67,10 +66,10 @@ fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { // Looking at the query cycle above, we know that `Bar` is representable // because `check_representability_adt_ty(Bar<..>)` is in the cycle and // `check_representability(Bar)` is *not* in the cycle. -fn check_representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { +fn check_representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { let ty::Adt(adt, args) = ty.kind() else { bug!("expected adt") }; if let Some(def_id) = adt.did().as_local() { - let _ = tcx.check_representability(def_id); + tcx.ensure_ok().check_representability(def_id); } // At this point, we know that the item of the ADT type is representable; // but the type parameters may cause a cycle with an upstream type @@ -82,7 +81,6 @@ fn check_representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Repre } } } - Representability } fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DenseBitSet { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 78f3a1922887..7a84a87a789a 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -117,7 +117,7 @@ fn adt_sizedness_constraint<'tcx>( (def_id, sizedness): (DefId, SizedTraitKind), ) -> Option>> { if let Some(def_id) = def_id.as_local() { - let _ = tcx.check_representability(def_id); + tcx.ensure_ok().check_representability(def_id); } let def = tcx.adt_def(def_id); diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 10c53c881a36..b00f9eebb826 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" -derive-where = "1.2.7" +derive-where = "1.6.1" ena = "0.14.4" indexmap = "2.0.0" rustc-hash = "2.0.0" diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index fc8b39f7c01f..0b0f0fd2f424 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -26,11 +26,7 @@ /// for more details. /// /// `Decodable` and `Encodable` are implemented for `Binder` using the `impl_binder_encode_decode!` macro. -// FIXME(derive-where#136): Need to use separate `derive_where` for -// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd` -// impls from incorrectly relying on `T: Copy` and `T: Ord`. -#[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, T)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner, T)] #[derive(GenericTypeVisitable)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct Binder { @@ -365,12 +361,7 @@ fn visit_region(&mut self, r: I::Region) -> Self::Result { /// `instantiate`. /// /// See for more details. -// FIXME(derive-where#136): Need to use separate `derive_where` for -// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd` -// impls from incorrectly relying on `T: Copy` and `T: Ord`. -#[derive_where(Ord; I: Interner, T: Ord)] -#[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(Clone, PartialOrd, PartialEq, Hash, Debug; I: Interner, T)] +#[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Hash, Debug; I: Interner, T)] #[derive(GenericTypeVisitable)] #[cfg_attr( feature = "nightly", @@ -964,12 +955,7 @@ pub enum BoundVarIndexKind { /// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are /// 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 -// FIXME(derive-where#136): Need to use separate `derive_where` for -// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd` -// impls from incorrectly relying on `T: Copy` and `T: Ord`. -#[derive_where(Ord; I: Interner, T: Ord)] -#[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(Clone, PartialOrd, PartialEq, Eq, Hash; I: Interner, T)] +#[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash; I: Interner, T)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e77e7af071b9..25f7c36e9985 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -308,6 +308,7 @@ fn impl_super_outlives( fn impl_is_const(self, def_id: Self::ImplId) -> bool; fn fn_is_const(self, def_id: Self::FunctionId) -> bool; + fn closure_is_const(self, def_id: Self::ClosureId) -> bool; fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool; fn const_conditions( self, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 62965f947387..a0b444024ca7 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -123,7 +123,7 @@ /// is the outer fn. /// /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index - #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] + #[stable_hash_no_context] #[encodable] #[orderable] #[debug_format = "DebruijnIndex({})"] @@ -333,7 +333,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// declared, but a type name in a non-zero universe is a placeholder /// type -- an idealized representative of "types in general" that we /// use for checking generic functions. - #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] + #[stable_hash_no_context] #[encodable] #[orderable] #[debug_format = "U{}"] @@ -388,7 +388,7 @@ fn default() -> Self { } rustc_index::newtype_index! { - #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] + #[stable_hash_generic] #[encodable] #[orderable] #[debug_format = "{}"] diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index e08c274f9f14..4c1b0700da58 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -4,7 +4,7 @@ #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext}; use rustc_type_ir_macros::GenericTypeVisitable; use self::RegionKind::*; @@ -16,7 +16,7 @@ #[orderable] #[debug_format = "'?{}"] #[gate_rustc_only] - #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] + #[stable_hash_no_context] pub struct RegionVid {} } @@ -34,26 +34,26 @@ pub struct RegionVid {} /// In general, the region lattice looks like /// /// ```text -/// static ----------+-----...------+ (greatest) +/// empty(Un) -------- (smallest) +/// | \ +/// ... \ +/// | \ +/// empty(U1) -- \ +/// | \ placeholder(Un) +/// | \ | +/// empty(root) placeholder(U1) | +/// | | | +/// | | | /// | | | /// param regions | | /// | | | -/// | | | -/// | | | -/// empty(root) placeholder(U1) | -/// | / | -/// | / placeholder(Un) -/// empty(U1) -- / -/// | / -/// ... / -/// | / -/// empty(Un) -------- (smallest) +/// static ----------+-----...------+ (greatest) /// ``` /// -/// Early-bound/free regions are the named lifetimes in scope from the -/// function declaration. They have relationships to one another -/// determined based on the declared relationships from the -/// function. +/// Lifetimes in scope from a function declaration are represented via +/// [`RegionKind::ReEarlyParam`]/[`RegionKind::ReLateParam`]. They +/// have relationships to one another and `'static` based on the +/// declared relationships from the function. /// /// Note that inference variables and bound regions are not included /// in this diagram. In the case of inference variables, they should @@ -62,29 +62,36 @@ pub struct RegionVid {} /// include -- the diagram indicates the relationship between free /// regions. /// +/// You can read more about the distinction between early and late bound +/// parameters in the rustc dev guide: [Early vs Late bound parameters]. +/// +/// A note on subtyping: If we assume that references take their region +/// covariantly, and use that to define the subtyping relationship of regions, +/// it may be somewhat surprising that `'empty` is Top and `'static` is Bottom, +/// and that "`'a` is a subtype of `'b`" is defined as "`'a` is bigger than +/// `'b`" - good to keep in mind. +/// /// ## Inference variables /// /// During region inference, we sometimes create inference variables, -/// represented as `ReVar`. These will be inferred by the code in -/// `infer::lexical_region_resolve` to some free region from the -/// lattice above (the minimal region that meets the +/// represented as [`RegionKind::ReVar`]. These will be inferred by +/// the code in `infer::lexical_region_resolve` to some free region +/// from the lattice above (the minimal region that meets the /// constraints). /// /// During NLL checking, where regions are defined differently, we -/// also use `ReVar` -- in that case, the index is used to index into -/// the NLL region checker's data structures. The variable may in fact -/// represent either a free region or an inference variable, in that -/// case. +/// also use [`RegionKind::ReVar`] -- in that case, the index is used +/// to index into the NLL region checker's data structures. The +/// variable may in fact represent either a free region or an +/// inference variable, in that case. /// /// ## Bound Regions /// /// These are regions that are stored behind a binder and must be instantiated -/// with some concrete region before being used. There are two kind of -/// bound regions: early-bound, which are bound in an item's `Generics`, -/// and are instantiated by an `GenericArgs`, and late-bound, which are part of -/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are instantiated by -/// the likes of `liberate_late_bound_regions`. The distinction exists -/// because higher-ranked lifetimes aren't supported in all places. See [1][2]. +/// with some concrete region before being used. A type can be wrapped in a +/// `Binder`, which introduces new type/const/lifetime variables (e.g., `for<'a> +/// fn(&'a ())`). These parameters are referred to via [`RegionKind::ReBound`]. +/// You can instantiate them by the likes of `liberate_late_bound_regions`. /// /// Unlike `Param`s, bound regions are not supposed to exist "in the wild" /// outside their binder, e.g., in types passed to type inference, and @@ -123,8 +130,7 @@ pub struct RegionVid {} /// happen, you can use `leak_check`. This is more clearly explained /// by the [rustc dev guide]. /// -/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ -/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ +/// [Early vs Late bound parameters]: https://rustc-dev-guide.rust-lang.org/early-late-parameters.html /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(GenericTypeVisitable)] @@ -160,7 +166,7 @@ pub enum RegionKind { /// more info about early and late bound lifetime parameters. ReLateParam(I::LateParamRegion), - /// Static data that has an "infinite" lifetime. Top in the region lattice. + /// Static data that has an "infinite" lifetime. Bottom in the region lattice. ReStatic, /// A region variable. Should not exist outside of type inference. diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 7c58cd7303eb..e0c6c777c09a 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -247,6 +247,8 @@ impl CandidateHeadUsages { pub fn merge_usages(&mut self, other: CandidateHeadUsages) { if let Some(other_usages) = other.usages { if let Some(ref mut self_usages) = self.usages { + // Each head is merged independently, so the final usage counts are the same + // regardless of hash iteration order. #[allow(rustc::potential_query_instability)] for (head_index, head) in other_usages.into_iter() { let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = head; @@ -501,6 +503,8 @@ fn insert(&mut self, input: X::Input, paths_to_nested: PathsToNested) { /// to all nested goals of that nested goal are also inductive. Otherwise the paths are /// the same as for the child. fn extend_from_child(&mut self, step_kind: PathKind, nested_goals: &NestedGoals) { + // Each nested goal is updated independently, and `insert` only unions paths for that + // goal, so traversal order cannot affect the result. #[allow(rustc::potential_query_instability)] for (input, paths_to_nested) in nested_goals.iter() { let paths_to_nested = paths_to_nested.extend_with(step_kind); @@ -508,6 +512,8 @@ fn extend_from_child(&mut self, step_kind: PathKind, nested_goals: &NestedGoals< } } + // This helper intentionally exposes unstable hash iteration so each caller must opt in + // locally and justify why its traversal is order-insensitive. #[cfg_attr(feature = "nightly", rustc_lint_query_instability)] #[allow(rustc::potential_query_instability)] fn iter(&self) -> impl Iterator + '_ { @@ -710,6 +716,8 @@ pub fn finish_single_candidate(&mut self) -> CandidateHeadUsages { pub fn ignore_candidate_head_usages(&mut self, usages: CandidateHeadUsages) { if let Some(usages) = usages.usages { let (entry_index, entry) = self.stack.last_mut_with_index().unwrap(); + // Ignoring usages only mutates the state for the current `head_index`, so the + // resulting per-head state is unchanged by iteration order. #[allow(rustc::potential_query_instability)] for (head_index, usages) in usages.into_iter() { if head_index == entry_index { @@ -901,6 +909,8 @@ fn handle_overflow(&mut self, cx: X, input: X::Input) -> X::Result { /// don't depend on its value. fn clear_dependent_provisional_results_for_rerun(&mut self) { let rerun_index = self.stack.next_index(); + // Each cached entry is filtered independently based on whether it depends on + // `rerun_index`, so bucket traversal order does not matter. #[allow(rustc::potential_query_instability)] self.provisional_cache.retain(|_, entries| { entries.retain(|entry| { @@ -958,6 +968,8 @@ fn rebase_provisional_cache_entries( rebase_reason: RebaseReason, ) { let popped_head_index = self.stack.next_index(); + // Rebasing decisions depend only on each provisional entry and the current stack state, + // so traversing the cache in hash order cannot change the final cache contents. #[allow(rustc::potential_query_instability)] self.provisional_cache.retain(|&input, entries| { entries.retain_mut(|entry| { @@ -1139,6 +1151,8 @@ fn candidate_is_applicable( // The global cache entry is also invalid if there's a provisional cache entry // would apply for any of its nested goals. + // Any matching provisional entry rejects the candidate, + // so iteration order only affects when we return `false`, not the final answer. #[allow(rustc::potential_query_instability)] for (input, path_from_global_entry) in nested_goals.iter() { let Some(entries) = self.provisional_cache.get(&input) else { diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 541257b6cda6..b32e5e991cc7 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["rustc-dep-of-std"] } +compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["compiler-builtins"] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 7e09a88156a0..52f099e77255 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -5,7 +5,8 @@ #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; -use core::ptr::{self, Alignment, NonNull}; +use core::mem::Alignment; +use core::ptr::{self, NonNull}; use core::{cmp, hint}; unsafe extern "Rust" { diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index b50810b8d923..2a34537f58e3 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -430,3 +430,12 @@ fn source(&self) -> Option<&(dyn Error + 'static)> { self.deref().source() } } + +#[cfg(not(no_global_oom_handling))] +#[unstable(feature = "thin_box", issue = "92791")] +impl From for ThinBox { + #[inline(always)] + fn from(value: T) -> Self { + Self::new(value) + } +} diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 4ddfcde57280..d46b1972b5b0 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -1364,6 +1364,37 @@ pub fn as_slice(&self) -> &[T] { self.data.as_slice() } + /// Returns a mutable slice of all values in the underlying vector. + /// + /// # Safety + /// + /// The caller must ensure that the slice remains a max-heap, i.e. for all indices + /// `0 < i < slice.len()`, `slice[(i - 1) / 2] >= slice[i]`, before the borrow ends + /// and the binary heap is used. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(binary_heap_as_mut_slice)] + /// + /// use std::collections::BinaryHeap; + /// + /// let mut heap = BinaryHeap::::from([1, 2, 3, 4, 5, 6, 7]); + /// + /// unsafe { + /// for value in heap.as_mut_slice() { + /// *value = (*value).saturating_mul(2); + /// } + /// } + /// ``` + #[must_use] + #[unstable(feature = "binary_heap_as_mut_slice", issue = "154009")] + pub unsafe fn as_mut_slice(&mut self) -> &mut [T] { + self.data.as_mut_slice() + } + /// Consumes the `BinaryHeap` and returns the underlying vector /// in arbitrary order. /// diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 66ea22e75247..cc8d793e98e4 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -1,38 +1,8 @@ use core::alloc::Allocator; -use core::iter::FusedIterator; -use super::merge_iter::MergeIterInner; use super::node::{self, Root}; impl Root { - /// Appends all key-value pairs from the union of two ascending iterators, - /// incrementing a `length` variable along the way. The latter makes it - /// easier for the caller to avoid a leak when a drop handler panicks. - /// - /// If both iterators produce the same key, this method drops the pair from - /// the left iterator and appends the pair from the right iterator. - /// - /// If you want the tree to end up in a strictly ascending order, like for - /// a `BTreeMap`, both iterators should produce keys in strictly ascending - /// order, each greater than all keys in the tree, including any keys - /// already in the tree upon entry. - pub(super) fn append_from_sorted_iters( - &mut self, - left: I, - right: I, - length: &mut usize, - alloc: A, - ) where - K: Ord, - I: Iterator + FusedIterator, - { - // We prepare to merge `left` and `right` into a sorted sequence in linear time. - let iter = MergeIter(MergeIterInner::new(left, right)); - - // Meanwhile, we build a tree from the sorted sequence in linear time. - self.bulk_push(iter, length, alloc) - } - /// Pushes all key-value pairs to the end of the tree, incrementing a /// `length` variable along the way. The latter makes it easier for the /// caller to avoid a leak when the iterator panicks. @@ -94,24 +64,3 @@ pub(super) fn bulk_push( self.fix_right_border_of_plentiful(); } } - -// An iterator for merging two sorted sequences into one -struct MergeIter>(MergeIterInner); - -impl Iterator for MergeIter -where - I: Iterator + FusedIterator, -{ - type Item = (K, V); - - /// If two keys are equal, returns the key from the left and the value from the right. - fn next(&mut self) -> Option<(K, V)> { - let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0)); - match (a_next, b_next) { - (Some((a_k, _)), Some((_, b_v))) => Some((a_k, b_v)), - (Some(a), None) => Some(a), - (None, Some(b)) => Some(b), - (None, None) => None, - } - } -} diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index fdeb9e332c7e..e3a6e90566f5 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1219,26 +1219,8 @@ pub fn append(&mut self, other: &mut Self) K: Ord, A: Clone, { - // Do we have to append anything at all? - if other.is_empty() { - return; - } - - // We can just swap `self` and `other` if `self` is empty. - if self.is_empty() { - mem::swap(self, other); - return; - } - - let self_iter = mem::replace(self, Self::new_in((*self.alloc).clone())).into_iter(); - let other_iter = mem::replace(other, Self::new_in((*self.alloc).clone())).into_iter(); - let root = self.root.get_or_insert_with(|| Root::new((*self.alloc).clone())); - root.append_from_sorted_iters( - self_iter, - other_iter, - &mut self.length, - (*self.alloc).clone(), - ) + let other = mem::replace(other, Self::new_in((*self.alloc).clone())); + self.merge(other, |_key, _self_val, other_val| other_val); } /// Moves all elements from `other` into `self`, leaving `other` empty. @@ -2120,7 +2102,9 @@ fn default() -> Self { } } -/// An iterator produced by calling `extract_if` on BTreeMap. +/// This `struct` is created by the [`extract_if`] method on [`BTreeMap`]. +/// +/// [`extract_if`]: BTreeMap::extract_if #[stable(feature = "btree_extract_if", since = "1.91.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `retain` or `extract_if().for_each(drop)` to remove and discard elements"] diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 73546caa05ea..64348745aa07 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -2224,7 +2224,7 @@ fn test_append_drop_leak() { catch_unwind(move || left.append(&mut right)).unwrap_err(); assert_eq!(a.dropped(), 1); - assert_eq!(b.dropped(), 1); // should be 2 were it not for Rust issue #47949 + assert_eq!(b.dropped(), 2); assert_eq!(c.dropped(), 2); } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index af6f5c7d7017..db8007834432 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1547,7 +1547,9 @@ fn into_iter(self) -> Iter<'a, T> { } } -/// An iterator produced by calling `extract_if` on BTreeSet. +/// This `struct` is created by the [`extract_if`] method on [`BTreeSet`]. +/// +/// [`extract_if`]: BTreeSet::extract_if #[stable(feature = "btree_extract_if", since = "1.91.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `retain` or `extract_if().for_each(drop)` to remove and discard elements"] diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 674828b8e7de..1816349e45f4 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1942,7 +1942,9 @@ pub fn back_mut(&mut self) -> Option<&mut T> { } } -/// An iterator produced by calling `extract_if` on LinkedList. +/// This `struct` is created by the [`extract_if`] method on [`LinkedList`]. +/// +/// [`extract_if`]: LinkedList::extract_if #[stable(feature = "extract_if", since = "1.87.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `extract_if().for_each(drop)` to remove and discard elements"] diff --git a/library/alloc/src/collections/vec_deque/splice.rs b/library/alloc/src/collections/vec_deque/splice.rs index d7b9a96291c3..b82f9fba7ceb 100644 --- a/library/alloc/src/collections/vec_deque/splice.rs +++ b/library/alloc/src/collections/vec_deque/splice.rs @@ -138,8 +138,48 @@ unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { /// self.deque must be valid. unsafe fn move_tail(&mut self, additional: usize) { let deque = unsafe { self.deque.as_mut() }; - let tail_start = deque.len + self.drain_len; - deque.buf.reserve(tail_start + self.tail_len, additional); + + // `Drain::new` modifies the deque's len (so does `Drain::fill` here) + // directly with the start bound of the range passed into + // `VecDeque::splice`. This causes a few different issue: + // - Most notably, there will be a hole at the end of the + // buffer when our buffer resizes in the case that our + // data wraps around. + // - We cannot use `VecDeque::reserve` directly because + // how it reserves more space and updates the `VecDeque`'s + // `head` field accordingly depends on the `VecDeque`'s + // actual `len`. + // - We cannot just directly modify `VecDeque`'s `len` and + // and call `VecDeque::reserve` afterward because if + // `VecDeque::reserve` panics on capacity overflow, + // well now our `VecDeque`'s head does not get updated + // and we still have a potential hole at the end of the + // buffer. + // Therefore, we manually reserve additional space (if necessary) + // based on calculating the actual `len` of the `VecDeque` and adjust + // `VecDeque`'s len right *after* the panicking region of `VecDeque::reserve` + // (that is `RawVec` `reserve()` call) + + let drain_start = deque.len; + let tail_start = drain_start + self.drain_len; + + // Actual VecDeque's len = drain_start + tail_len + drain_len + let actual_len = drain_start + self.tail_len + self.drain_len; + let new_cap = actual_len.checked_add(additional).expect("capacity overflow"); + let old_cap = deque.capacity(); + + if new_cap > old_cap { + deque.buf.reserve(actual_len, additional); + // If new_cap doesn't panic, we can safely set the `VecDeque` len to its + // actual len; this needs to be done in order to set deque.head correctly + // on `VecDeque::handle_capacity_increase` + deque.len = actual_len; + // SAFETY: this cannot panic since our internal buffer's new_cap should + // be bigger than the passed in old_cap + unsafe { + deque.handle_capacity_increase(old_cap); + } + } let new_tail_start = tail_start + additional; unsafe { @@ -149,6 +189,9 @@ unsafe fn move_tail(&mut self, additional: usize) { self.tail_len, ); } + + // revert the `VecDeque` len to what it was before + deque.len = drain_start; self.drain_len += additional; } } diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index fba967c04895..b2f4277458f1 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -321,6 +321,10 @@ fn spec_new_impl(self) -> Result { /// assertion is made that `v` contains no 0 bytes, and it requires an /// actual byte vector, not anything that can be converted to one with Into. /// + /// # Safety + /// + /// The caller must ensure `v` contains no nul bytes in its contents. + /// /// # Examples /// /// ``` diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 73e93657b02f..bcd9e092a310 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -63,7 +63,7 @@ #![doc( html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", - test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) + test(no_crate_inject, attr(allow(unused_variables, duplicate_features), deny(warnings))) )] #![doc(auto_cfg(hide(no_global_oom_handling, no_rc, no_sync, target_has_atomic = "ptr")))] #![doc(rust_logo)] @@ -148,6 +148,7 @@ #![feature(slice_range)] #![feature(std_internals)] #![feature(temporary_niche_types)] +#![feature(titlecase)] #![feature(transmutability)] #![feature(trivial_clone)] #![feature(trusted_fused)] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 09150259ce43..cabf6accf3b5 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -5,8 +5,8 @@ // run the tests. See the comment there for an explanation why this is the case. use core::marker::{Destruct, PhantomData}; -use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; -use core::ptr::{self, Alignment, NonNull, Unique}; +use core::mem::{Alignment, ManuallyDrop, MaybeUninit, SizedTypeProperties}; +use core::ptr::{self, NonNull, Unique}; use core::{cmp, hint}; #[cfg(not(no_global_oom_handling))] @@ -570,7 +570,7 @@ unsafe fn finish_grow( impl RawVecInner { #[inline] const fn new_in(alloc: A, align: Alignment) -> Self { - let ptr = Unique::from_non_null(NonNull::without_provenance(align.as_nonzero())); + let ptr = Unique::from_non_null(NonNull::without_provenance(align.as_nonzero_usize())); // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr, cap: ZERO_CAP, alloc } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index cec41524325e..cfca2d9ec970 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -252,7 +252,7 @@ #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, ManuallyDrop}; +use core::mem::{self, Alignment, ManuallyDrop}; use core::num::NonZeroUsize; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; #[cfg(not(no_global_oom_handling))] @@ -261,7 +261,7 @@ #[cfg(not(no_global_oom_handling))] use core::pin::Pin; use core::pin::PinCoerceUnsized; -use core::ptr::{self, Alignment, NonNull, drop_in_place}; +use core::ptr::{self, NonNull, drop_in_place}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; use core::{borrow, fmt, hint}; @@ -1430,29 +1430,32 @@ impl Rc { /// Constructs an `Rc` from a raw pointer. /// /// The raw pointer must have been previously returned by a call to - /// [`Rc::into_raw`][into_raw] with the following requirements: + /// [`Rc::into_raw`][into_raw] or [`Rc::into_raw_with_allocator`][into_raw_with_allocator]. /// + /// # Safety + /// + /// * Creating a `Rc` from a pointer other than one returned from + /// [`Rc::into_raw`][into_raw] or [`Rc::into_raw_with_allocator`][into_raw_with_allocator] + /// is undefined behavior. /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and /// alignment as `T`. This is trivially true if `Rc` was constructed /// through `Rc` and then converted to `Rc` through an [unsized /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by the global allocator - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. + /// * Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// * The raw pointer must point to a block of memory allocated by the global allocator + /// * The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. /// /// This function is unsafe because improper use may lead to memory unsafety, /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw + /// [into_raw_with_allocator]: Rc::into_raw_with_allocator /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// @@ -1662,29 +1665,32 @@ pub fn as_ptr(this: &Self) -> *const T { /// Constructs an `Rc` from a raw pointer in the provided allocator. /// /// The raw pointer must have been previously returned by a call to [`Rc::into_raw`][into_raw] with the following requirements: + /// A>::into_raw`][into_raw] or [`Rc::into_raw_with_allocator`][into_raw_with_allocator]. /// + /// # Safety + /// + /// * Creating a `Rc` from a pointer other than one returned from + /// [`Rc::into_raw`][into_raw] or [`Rc::into_raw_with_allocator`][into_raw_with_allocator] + /// is undefined behavior. /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Rc` was constructed - /// through `Rc` and then converted to `Rc` through an [unsized + /// alignment as `T`. This is trivially true if `Rc` was constructed + /// through `Rc` and then converted to `Rc` through an [unsized /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by `alloc` - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. + /// * Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// * The raw pointer must point to a block of memory allocated by `alloc` + /// * The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. /// /// This function is unsafe because improper use may lead to memory unsafety, - /// even if the returned `Rc` is never accessed. + /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw + /// [into_raw_with_allocator]: Rc::into_raw_with_allocator /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// @@ -2424,9 +2430,6 @@ unsafe impl PinCoerceUnsized for Rc {} #[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] unsafe impl PinCoerceUnsized for UniqueRc {} -#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinCoerceUnsized for Weak {} - #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Rc {} @@ -3980,6 +3983,15 @@ fn as_mut(&mut self) -> &mut T { #[unstable(feature = "unique_rc_arc", issue = "112566")] impl Unpin for UniqueRc {} +#[cfg(not(no_global_oom_handling))] +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl From for UniqueRc { + #[inline(always)] + fn from(value: T) -> Self { + Self::new(value) + } +} + #[unstable(feature = "unique_rc_arc", issue = "112566")] impl PartialEq for UniqueRc { /// Equality for two `UniqueRc`s. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index dc82357dd146..b3e49af868b8 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -19,14 +19,14 @@ #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, ManuallyDrop}; +use core::mem::{self, Alignment, ManuallyDrop}; use core::num::NonZeroUsize; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; #[cfg(not(no_global_oom_handling))] use core::ops::{Residual, Try}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::{Pin, PinCoerceUnsized}; -use core::ptr::{self, Alignment, NonNull}; +use core::ptr::{self, NonNull}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; @@ -1581,29 +1581,32 @@ impl Arc { /// Constructs an `Arc` from a raw pointer. /// /// The raw pointer must have been previously returned by a call to - /// [`Arc::into_raw`][into_raw] with the following requirements: + /// [`Arc::into_raw`][into_raw] or [`Arc::into_raw_with_allocator`][into_raw_with_allocator]. /// + /// # Safety + /// + /// * Creating a `Arc` from a pointer other than one returned from + /// [`Arc::into_raw`][into_raw] or [`Arc::into_raw_with_allocator`][into_raw_with_allocator] + /// is undefined behavior. /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and /// alignment as `T`. This is trivially true if `Arc` was constructed /// through `Arc` and then converted to `Arc` through an [unsized /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by the global allocator. - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. + /// * Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// * The raw pointer must point to a block of memory allocated by the global allocator. + /// * The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. /// /// This function is unsafe because improper use may lead to memory unsafety, /// even if the returned `Arc` is never accessed. /// /// [into_raw]: Arc::into_raw + /// [into_raw_with_allocator]: Arc::into_raw_with_allocator /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// @@ -1819,29 +1822,32 @@ pub fn as_ptr(this: &Self) -> *const T { /// Constructs an `Arc` from a raw pointer. /// /// The raw pointer must have been previously returned by a call to [`Arc::into_raw`][into_raw] with the following requirements: + /// A>::into_raw`][into_raw] or [`Arc::into_raw_with_allocator`][into_raw_with_allocator]. /// + /// # Safety + /// + /// * Creating a `Arc` from a pointer other than one returned from + /// [`Arc::into_raw`][into_raw] or [`Arc::into_raw_with_allocator`][into_raw_with_allocator] + /// is undefined behavior. /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Arc` was constructed - /// through `Arc` and then converted to `Arc` through an [unsized + /// alignment as `T`. This is trivially true if `Arc` was constructed + /// through `Arc` and then converted to `Arc` through an [unsized /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by `alloc` - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. + /// * Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// * The raw pointer must point to a block of memory allocated by `alloc` + /// * The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. /// /// This function is unsafe because improper use may lead to memory unsafety, /// even if the returned `Arc` is never accessed. /// /// [into_raw]: Arc::into_raw + /// [into_raw_with_allocator]: Arc::into_raw_with_allocator /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// @@ -2426,9 +2432,6 @@ fn deref(&self) -> &T { #[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] unsafe impl PinCoerceUnsized for Arc {} -#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinCoerceUnsized for Weak {} - #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Arc {} @@ -4424,6 +4427,15 @@ fn as_mut(&mut self) -> &mut T { } } +#[cfg(not(no_global_oom_handling))] +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl From for UniqueArc { + #[inline(always)] + fn from(value: T) -> Self { + Self::new(value) + } +} + #[unstable(feature = "unique_rc_arc", issue = "112566")] impl Unpin for UniqueArc {} diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index aa1901314e37..bc668f78bf74 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -87,6 +87,7 @@ /// ``` #[cfg(target_has_atomic = "ptr")] #[stable(feature = "wake_trait", since = "1.51.0")] +#[rustc_diagnostic_item = "Wake"] pub trait Wake { /// Wake this task. #[stable(feature = "wake_trait", since = "1.51.0")] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 7796f3b8b2fb..942b2b9d2dad 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -898,9 +898,17 @@ pub const fn const_make_global(mut self) -> &'static [T] where T: Freeze, { - unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) }; - let me = ManuallyDrop::new(self); - unsafe { slice::from_raw_parts(me.as_ptr(), me.len) } + // `const_make_global` requires the pointer to point to the beginning of a heap allocation, + // which is not the case when `self.capacity()` is 0, or if `T::IS_ZST`, + // which is why we instead return a new slice in this case. + if self.capacity() == 0 || T::IS_ZST { + let me = ManuallyDrop::new(self); + unsafe { slice::from_raw_parts(NonNull::::dangling().as_ptr(), me.len) } + } else { + unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) }; + let me = ManuallyDrop::new(self); + unsafe { slice::from_raw_parts(me.as_ptr(), me.len) } + } } } @@ -1853,7 +1861,7 @@ pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of // size `len` containing properly-initialized `T`s. Data must not be accessed through any // other pointer for the returned lifetime. Further, `len * size_of::` <= - // `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses. + // `isize::MAX` and allocation does not "wrap" through overflowing memory addresses. // // * Vec API guarantees that self.buf: // * contains only properly-initialized items within 0..len diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs index 3eb8ca44a9d1..99ebcb4ada29 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -1,4 +1,4 @@ -use core::{ptr, slice}; +use core::ptr; use super::{Drain, Vec}; use crate::alloc::{Allocator, Global}; @@ -107,15 +107,13 @@ unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { let vec = unsafe { self.vec.as_mut() }; let range_start = vec.len; let range_end = self.tail_start; - let range_slice = unsafe { - slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) - }; + // The elements in this range are not initialized so we avoid creating a slice. - for place in range_slice { + for idx in range_start..range_end { let Some(new_item) = replace_with.next() else { return false; }; - unsafe { ptr::write(place, new_item) }; + unsafe { vec.as_mut_ptr().add(idx).write(new_item) }; vec.len += 1; } true diff --git a/library/alloc/src/wtf8/mod.rs b/library/alloc/src/wtf8/mod.rs index e4834a24bf43..394c41bf3672 100644 --- a/library/alloc/src/wtf8/mod.rs +++ b/library/alloc/src/wtf8/mod.rs @@ -342,14 +342,18 @@ pub fn push(&mut self, code_point: CodePoint) { /// Shortens a string to the specified length. /// + /// If `new_len` is greater than the string's current length, this has no + /// effect. + /// /// # Panics /// - /// Panics if `new_len` > current length, - /// or if `new_len` is not a code point boundary. + /// Panics if `new_len` does not lie on a code point boundary. #[inline] pub fn truncate(&mut self, new_len: usize) { - assert!(self.is_code_point_boundary(new_len)); - self.bytes.truncate(new_len) + if new_len <= self.len() { + assert!(self.is_code_point_boundary(new_len)); + self.bytes.truncate(new_len) + } } /// Consumes the WTF-8 string and tries to convert it to a vec of bytes. diff --git a/library/alloc/src/wtf8/tests.rs b/library/alloc/src/wtf8/tests.rs index a72ad0837d11..79e0bbdef50f 100644 --- a/library/alloc/src/wtf8/tests.rs +++ b/library/alloc/src/wtf8/tests.rs @@ -308,10 +308,10 @@ fn wtf8buf_truncate_fail_code_point_boundary() { } #[test] -#[should_panic] -fn wtf8buf_truncate_fail_longer() { +fn wtf8buf_truncate_invalid_len() { let mut string = Wtf8Buf::from_str("aé"); string.truncate(4); + assert_eq!(string, Wtf8Buf::from_str("aé")); } #[test] diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs index 721d685527fe..4a25778d88c8 100644 --- a/library/alloctests/benches/lib.rs +++ b/library/alloctests/benches/lib.rs @@ -1,4 +1,4 @@ -// Disabling in Miri as these would take too long. +// This is marked as `test = true` and hence picked up by `./x miri`, but that would be too slow. #![cfg(not(miri))] #![feature(iter_next_chunk)] #![feature(repr_simd)] diff --git a/library/alloctests/benches/vec_deque_append.rs b/library/alloctests/benches/vec_deque_append.rs index 7c805da97376..180981abc06f 100644 --- a/library/alloctests/benches/vec_deque_append.rs +++ b/library/alloctests/benches/vec_deque_append.rs @@ -6,11 +6,6 @@ const BENCH_N: usize = 1000; fn main() { - if cfg!(miri) { - // Don't benchmark Miri... - // (Due to bootstrap quirks, this gets picked up by `x.py miri library/alloc --no-doc`.) - return; - } let a: VecDeque = (0..VECDEQUE_LEN).collect(); let b: VecDeque = (0..VECDEQUE_LEN).collect(); diff --git a/library/alloctests/tests/str.rs b/library/alloctests/tests/str.rs index 52cc8afeee90..c0bcdb8500af 100644 --- a/library/alloctests/tests/str.rs +++ b/library/alloctests/tests/str.rs @@ -612,14 +612,14 @@ fn test_slice_fail() { data: "abcdef"; good: data[4..4] == ""; bad: data[4..3]; - message: "begin > end (4 > 3)"; + message: "byte range starts at 4 but ends at 3"; } in mod rangeinclusive_neg_width { data: "abcdef"; good: data[4..=3] == ""; bad: data[4..=2]; - message: "begin > end (4 > 3)"; + message: "byte range starts at 4 but ends at 3"; } } @@ -659,49 +659,49 @@ mod boundary { data: super::DATA; bad: data[super::BAD_START..super::GOOD_END]; message: - "start byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + "start byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5 of string)"; } in mod range_2 { data: super::DATA; bad: data[super::GOOD_START..super::BAD_END]; message: - "end byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + "end byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7 of string)"; } in mod rangefrom { data: super::DATA; bad: data[super::BAD_START..]; message: - "start byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + "start byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5 of string)"; } in mod rangeto { data: super::DATA; bad: data[..super::BAD_END]; message: - "end byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + "end byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7 of string)"; } in mod rangeinclusive_1 { data: super::DATA; bad: data[super::BAD_START..=super::GOOD_END_INCL]; message: - "start byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + "start byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5 of string)"; } in mod rangeinclusive_2 { data: super::DATA; bad: data[super::GOOD_START..=super::BAD_END_INCL]; message: - "end byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + "end byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7 of string)"; } in mod rangetoinclusive { data: super::DATA; bad: data[..=super::BAD_END_INCL]; message: - "end byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + "end byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7 of string)"; } } } @@ -716,18 +716,10 @@ mod boundary { // check the panic includes the prefix of the sliced string #[test] - #[should_panic( - expected = "end byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet" - )] + #[should_panic(expected = "end byte index 1024 is out of bounds for string of length 416")] fn test_slice_fail_truncated_1() { let _ = &LOREM_PARAGRAPH[..1024]; } - // check the truncation in the panic message - #[test] - #[should_panic(expected = "luctus, im`[...]")] - fn test_slice_fail_truncated_2() { - let _ = &LOREM_PARAGRAPH[..1024]; - } } #[test] diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 5ab305f7a504..db7da0db47d7 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2764,3 +2764,25 @@ fn const_heap() { assert_eq!([1, 2, 4, 8, 16, 32], X); } + +// regression test for issue #153158. `const_make_global` previously assumed `Vec`'s buf +// always has a heap allocation, which lead to compilation errors. +#[test] +fn const_make_global_empty_or_zst_regression() { + const EMPTY_SLICE: &'static [i32] = { + let empty_vec: Vec = Vec::new(); + empty_vec.const_make_global() + }; + + assert_eq!(EMPTY_SLICE, &[]); + + const ZST_SLICE: &'static [()] = { + let mut zst_vec: Vec<()> = Vec::new(); + zst_vec.push(()); + zst_vec.push(()); + zst_vec.push(()); + zst_vec.const_make_global() + }; + + assert_eq!(ZST_SLICE, &[(), (), ()]); +} diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 92853fe00fd6..91843dfd0058 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -2347,3 +2347,16 @@ fn test_splice_wrapping() { assert_eq!(Vec::from(vec), [7, 8, 9]); } + +#[test] +fn test_splice_wrapping_and_resize() { + let mut vec = VecDeque::new(); + + for i in [1; 6] { + vec.push_front(i); + } + + vec.splice(1..1, [2, 3, 4]); + + assert_eq!(Vec::from(vec), [1, 2, 3, 4, 1, 1, 1, 1, 1]) +} diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 3fed58f2a207..261b1619f1c5 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -13,7 +13,7 @@ env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full - BENCHMARK_RUSTC: nightly-2025-12-01 # Pin the toolchain for reproducable results + BENCHMARK_RUSTC: nightly-2026-02-10 # Pin the toolchain for reproducable results jobs: # Determine which tests should be run based on changed files. @@ -70,14 +70,12 @@ jobs: os: ubuntu-24.04 - target: powerpc64le-unknown-linux-gnu os: ubuntu-24.04 - # - target: powerpc64le-unknown-linux-gnu - # os: ubuntu-24.04-ppc64le - # # FIXME(rust#151807): remove once PPC builds work again. - # channel: nightly-2026-01-23 + - target: powerpc64le-unknown-linux-gnu + os: ubuntu-24.04-ppc64le - target: riscv64gc-unknown-linux-gnu os: ubuntu-24.04 - # - target: s390x-unknown-linux-gnu - # os: ubuntu-24.04-s390x + - target: s390x-unknown-linux-gnu + os: ubuntu-24.04-s390x - target: thumbv6m-none-eabi os: ubuntu-24.04 - target: thumbv7em-none-eabi @@ -289,7 +287,7 @@ jobs: path: ${{ env.BASELINE_NAME }}.tar.xz - name: Run wall time benchmarks - run: ./ci/bench-runtime.sh + run: ./ci/bench-walltime.sh - name: Print test logs if available if: always() @@ -303,7 +301,9 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install Rust (rustup) - run: rustup update nightly --no-self-update && rustup default nightly + # FIXME(ci): not working in the 2026-02-11 nightly + # https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/build-script-build.20contains.20outdated.20or.20invalid.20JSON/with/573426109 + run: rustup update nightly-2026-02-10 --no-self-update && rustup default nightly-2026-02-10 shell: bash - run: rustup component add miri - run: cargo miri setup diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore index abe346659d4c..1137a19cf093 100644 --- a/library/compiler-builtins/.gitignore +++ b/library/compiler-builtins/.gitignore @@ -1,7 +1,11 @@ # Rust files -Cargo.lock target +# We have a couple of potential Cargo.lock files, but we only the root +# workspace should have dependencies other than (optional) `cc`. +Cargo.lock +!/Cargo.lock + # Sources for external files compiler-rt *.tar.gz diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock new file mode 100644 index 000000000000..7a3e9a38430b --- /dev/null +++ b/library/compiler-builtins/Cargo.lock @@ -0,0 +1,1655 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "assert_cmd" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514" +dependencies = [ + "anstyle", + "bstr", + "libc", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "builtins-test" +version = "0.1.0" +dependencies = [ + "compiler_builtins", + "criterion", + "gungraun", + "paste", + "rand_xoshiro", + "rustc_apfloat", + "test", + "utest-cortex-m-qemu", + "utest-macros", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "compiler_builtins" +version = "0.1.160" +dependencies = [ + "cc", +] + +[[package]] +name = "console" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "windows-sys 0.61.2", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" +dependencies = [ + "alloca", + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "num-traits", + "oorandom", + "page_size", + "plotters", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "escape8259" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getopts" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "rand_core", + "wasip2", + "wasip3", + "wasm-bindgen", +] + +[[package]] +name = "gmp-mpfr-sys" +version = "1.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60f8970a75c006bb2f8ae79c6768a116dd215fa8346a87aed99bf9d82ca43394" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "gungraun" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c1bbe46f51c63bc08a1fac0ee0c530a77c961613a86ecf828ab1b0ffc6687a" +dependencies = [ + "bincode", + "derive_more", + "gungraun-macros", + "gungraun-runner", +] + +[[package]] +name = "gungraun-macros" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdccd089c36fb2ee66ef0eb7b1baa3ce7e7878a8eae682d9c8c368869ff6eca1" +dependencies = [ + "derive_more", + "proc-macro-error2", + "proc-macro2", + "quote", + "rustc_version", + "serde", + "serde_json", + "syn", +] + +[[package]] +name = "gungraun-runner" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6da6487203fa53ae6b1c8fead642fe79a3199464b0dd1337635594d675a9ac05" +dependencies = [ + "serde", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "indicatif" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +dependencies = [ + "console", + "portable-atomic", + "unit-prefix", + "web-time", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libm" +version = "0.2.16" +dependencies = [ + "no-panic", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libm-macros" +version = "0.1.0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "libm-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "criterion", + "getrandom", + "gmp-mpfr-sys", + "gungraun", + "indicatif", + "libm 0.2.16", + "libm-macros", + "libtest-mimic", + "musl-math-sys", + "paste", + "rand", + "rand_chacha", + "rayon", + "rug", +] + +[[package]] +name = "libtest-mimic" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5297962ef19edda4ce33aaa484386e0a5b3d7f2f4e037cbeee00503ef6b29d33" +dependencies = [ + "anstream", + "anstyle", + "clap", + "escape8259", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "musl-math-sys" +version = "0.1.0" +dependencies = [ + "cc", + "libm 0.2.16", +] + +[[package]] +name = "no-panic" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f967505aabc8af5752d098c34146544a43684817cdba8f9725b292530cabbf53" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc" +dependencies = [ + "flate2", + "memchr", + "ruzstd", + "wasmparser 0.243.0", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "panic-handler" +version = "0.1.0" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" +dependencies = [ + "anstyle", + "difflib", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" + +[[package]] +name = "predicates-tree" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "chacha20", + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e6af7f3e25ded52c41df4e0b1af2d047e45896c2f3281792ed68a1c243daedb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + +[[package]] +name = "rand_xoshiro" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f0b2cc7bfeef8f0320ca45f88b00157a03c67137022d59393614352d6bf4312" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "rug" +version = "1.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de190ec858987c79cad4da30e19e546139b3339331282832af004d0ea7829639" +dependencies = [ + "az", + "gmp-mpfr-sys", + "libc", + "libm 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_apfloat" +version = "0.2.3+llvm-462a31f5a5ab" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad" +dependencies = [ + "bitflags", + "smallvec", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ruzstd" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "010e18bd3bfd1d45a7e666b236c78720df0d9a7698ebaa9c1c559961eb60a38b" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "symbol-check" +version = "0.1.0" +dependencies = [ + "assert_cmd", + "cc", + "getopts", + "object", + "regex", + "serde_json", + "tempfile", +] + +[[package]] +name = "syn" +version = "2.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "test" +version = "0.1.0" +source = "git+https://github.com/japaric/utest#e32073e2b078e3bee46001c13ae4c1acf368d762" + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + +[[package]] +name = "utest-cortex-m-qemu" +version = "0.1.0" +source = "git+https://github.com/japaric/utest#e32073e2b078e3bee46001c13ae4c1acf368d762" +dependencies = [ + "sc", +] + +[[package]] +name = "utest-macros" +version = "0.1.0" +source = "git+https://github.com/japaric/utest#e32073e2b078e3bee46001c13ae4c1acf368d762" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "util" +version = "0.1.0" +dependencies = [ + "cfg-if", + "libm 0.2.16", + "libm-macros", + "libm-test", + "musl-math-sys", + "rug", +] + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasmparser" +version = "0.243.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser 0.244.0", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.244.0", +] + +[[package]] +name = "zerocopy" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 26f67e02fc52..26a056f43496 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -34,12 +34,14 @@ exclude = [ [workspace.dependencies] anyhow = "1.0.101" assert_cmd = "2.1.2" -cc = "1.2.55" +cc = "1.2.56" +cfg-if = "1.0.4" compiler_builtins = { path = "builtins-shim", default-features = false } -criterion = { version = "0.6.0", default-features = false, features = ["cargo_bench_support"] } -getrandom = "0.3.4" +criterion = { version = "0.8.2", default-features = false, features = ["cargo_bench_support"] } +getopts = "0.2.24" +getrandom = "0.4.1" gmp-mpfr-sys = { version = "1.6.8", default-features = false } -gungraun = "0.17.0" +gungraun = "0.17.2" heck = "0.5.0" indicatif = { version = "0.18.3", default-features = false } libm = { path = "libm", default-features = false } @@ -47,22 +49,22 @@ libm-macros = { path = "crates/libm-macros" } libm-test = { path = "libm-test", default-features = false } libtest-mimic = "0.8.1" musl-math-sys = { path = "crates/musl-math-sys" } -no-panic = "0.1.35" -object = { version = "0.37.3", features = ["wasm"] } +no-panic = "0.1.36" +object = { version = "0.38.1", features = ["wasm"] } panic-handler = { path = "crates/panic-handler" } paste = "1.0.15" proc-macro2 = "1.0.106" quote = "1.0.44" -rand = "0.9.2" -rand_chacha = "0.9.0" -rand_xoshiro = "0.7" +rand = "0.10.0" +rand_chacha = "0.10.0" +rand_xoshiro = "0.8" rayon = "1.11.0" regex = "1.12.3" rug = { version = "1.28.1", default-features = false, features = ["float", "integer", "std"] } rustc_apfloat = "0.2.3" serde_json = "1.0.149" -syn = "2.0.114" -tempfile = "3.24.0" +syn = "2.0.115" +tempfile = "3.25.0" [profile.release] panic = "abort" diff --git a/library/compiler-builtins/builtins-shim/Cargo.toml b/library/compiler-builtins/builtins-shim/Cargo.toml index 37d3407e9f66..32b0308a7b3c 100644 --- a/library/compiler-builtins/builtins-shim/Cargo.toml +++ b/library/compiler-builtins/builtins-shim/Cargo.toml @@ -39,7 +39,7 @@ test = false cc = { version = "1.2", optional = true } [features] -default = ["compiler-builtins"] +default = [] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics @@ -50,7 +50,8 @@ c = ["dep:cc"] # the generic versions on all platforms. no-asm = [] -# Flag this library as the unstable compiler-builtins lib +# Flag this library as the unstable compiler-builtins lib. This must be enabled +# when using as `std`'s dependency.' compiler-builtins = [] # Generate memory-related intrinsics like memcpy @@ -60,9 +61,6 @@ mem = [] # compiler-rt implementations. Also used for testing mangled-names = [] -# Only used in the compiler's build system -rustc-dep-of-std = ["compiler-builtins"] - # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` unstable-public-internals = [] diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index b9d19ea77256..a3df2c98376c 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -3,10 +3,8 @@ // compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail // to link due to the missing intrinsic (symbol). -#![allow(unused_features)] -#![allow(internal_features)] +#![allow(internal_features, unused_features)] #![deny(dead_code)] -#![feature(allocator_api)] #![feature(f128)] #![feature(f16)] #![feature(lang_items)] diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 9395ab1a985e..b2313bb9d140 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -16,11 +16,11 @@ rand_xoshiro.workspace = true # To compare float builtins against rustc_apfloat.workspace = true -# Really a dev dependency, but dev dependencies can't be optional +# Really dev dependencies, but those can't be optional +criterion = { workspace = true, optional = true } gungraun = { workspace = true, optional = true } [dev-dependencies] -criterion.workspace = true paste.workspace = true [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] @@ -46,8 +46,10 @@ no-sys-f16 = ["no-sys-f16-f64-convert"] # Enable icount benchmarks (requires gungraun-runner and valgrind locally) icount = ["dep:gungraun"] -# Enable report generation without bringing in more dependencies by default -benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] +# Config for wall time benchmarks. Plotters and html_reports bring in extra +# deps so are off by default for CI. +benchmarking-reports = ["walltime", "criterion/plotters", "criterion/html_reports"] +walltime = ["dep:criterion"] # NOTE: benchmarks must be run with `--no-default-features` or with # `-p builtins-test`, otherwise the default `compiler-builtins` feature @@ -57,38 +59,47 @@ benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] [[bench]] name = "float_add" harness = false +required-features = ["walltime"] [[bench]] name = "float_sub" harness = false +required-features = ["walltime"] [[bench]] name = "float_mul" harness = false +required-features = ["walltime"] [[bench]] name = "float_div" harness = false +required-features = ["walltime"] [[bench]] name = "float_cmp" harness = false +required-features = ["walltime"] [[bench]] name = "float_conv" harness = false +required-features = ["walltime"] [[bench]] name = "float_extend" harness = false +required-features = ["walltime"] [[bench]] name = "float_trunc" harness = false +required-features = ["walltime"] [[bench]] name = "float_pow" harness = false +required-features = ["walltime"] [[bench]] name = "mem_icount" diff --git a/library/compiler-builtins/builtins-test/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs index f1673133be27..b9ad649f88dd 100644 --- a/library/compiler-builtins/builtins-test/src/lib.rs +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -22,7 +22,7 @@ use compiler_builtins::float::Float; use compiler_builtins::int::{Int, MinInt}; use rand_xoshiro::Xoshiro128StarStar; -use rand_xoshiro::rand_core::{RngCore, SeedableRng}; +use rand_xoshiro::rand_core::{Rng, SeedableRng}; /// Sets the number of fuzz iterations run for most tests. In practice, the vast majority of bugs /// are caught by the edge case testers. Most of the remaining bugs triggered by more complex diff --git a/library/compiler-builtins/builtins-test/tests/addsub.rs b/library/compiler-builtins/builtins-test/tests/addsub.rs index f3334bd0e2d3..410967967d2a 100644 --- a/library/compiler-builtins/builtins-test/tests/addsub.rs +++ b/library/compiler-builtins/builtins-test/tests/addsub.rs @@ -1,4 +1,4 @@ -#![allow(unused_macros)] +#![allow(unused_macros, unused_features)] #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] diff --git a/library/compiler-builtins/builtins-test/tests/conv.rs b/library/compiler-builtins/builtins-test/tests/conv.rs index 9b04295d2efe..0fd15ad3ee66 100644 --- a/library/compiler-builtins/builtins-test/tests/conv.rs +++ b/library/compiler-builtins/builtins-test/tests/conv.rs @@ -1,8 +1,9 @@ #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] // makes configuration easier -#![allow(unused_macros)] +#![allow(unused_features)] #![allow(unused_imports)] +#![allow(unused_macros)] use builtins_test::*; use compiler_builtins::float::Float; diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs index caee4166c995..4ff86385a963 100644 --- a/library/compiler-builtins/builtins-test/tests/div_rem.rs +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -1,5 +1,5 @@ #![feature(f128)] -#![allow(unused_macros)] +#![allow(unused_macros, unused_features)] use builtins_test::*; use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; diff --git a/library/compiler-builtins/builtins-test/tests/float_pow.rs b/library/compiler-builtins/builtins-test/tests/float_pow.rs index a17dff27c105..3cea83a255c8 100644 --- a/library/compiler-builtins/builtins-test/tests/float_pow.rs +++ b/library/compiler-builtins/builtins-test/tests/float_pow.rs @@ -1,4 +1,4 @@ -#![allow(unused_macros)] +#![allow(unused_macros, unused_features)] #![cfg_attr(f128_enabled, feature(f128))] #[cfg_attr(x86_no_sse, allow(unused))] diff --git a/library/compiler-builtins/builtins-test/tests/lse.rs b/library/compiler-builtins/builtins-test/tests/lse.rs index 56891be8a8ac..d408fe193bcf 100644 --- a/library/compiler-builtins/builtins-test/tests/lse.rs +++ b/library/compiler-builtins/builtins-test/tests/lse.rs @@ -1,30 +1,71 @@ +#![allow(unused_features)] #![feature(decl_macro)] // so we can use pub(super) #![feature(macro_metavar_expr_concat)] -#![cfg(all(target_arch = "aarch64", target_os = "linux"))] +#![cfg(all(target_arch = "aarch64", feature = "mangled-names"))] + +use std::sync::Mutex; + +use compiler_builtins::aarch64_outline_atomics::{get_have_lse_atomics, set_have_lse_atomics}; +use compiler_builtins::int::{Int, MinInt}; +use compiler_builtins::{foreach_bytes, foreach_ordering}; + +#[track_caller] +fn with_maybe_lse_atomics(use_lse: bool, f: impl FnOnce()) { + // Ensure tests run in parallel don't interleave global settings + static LOCK: Mutex<()> = Mutex::new(()); + let _g = LOCK.lock().unwrap(); + let old = get_have_lse_atomics(); + // safety: as the caller of the unsafe fn `set_have_lse_atomics`, we + // have to ensure the CPU supports LSE. This is why we make this assertion. + if use_lse || old { + assert!(std::arch::is_aarch64_feature_detected!("lse")); + } + unsafe { set_have_lse_atomics(use_lse) }; + f(); + unsafe { set_have_lse_atomics(old) }; +} + +pub fn run_fuzz_tests_with_lse_variants(n: u32, f: F) +where + ::Unsigned: Int, +{ + // We use `fuzz_2` because our subject function `f` requires two inputs + let test_fn = || { + builtins_test::fuzz_2(n, f); + }; + // Always run without LSE + with_maybe_lse_atomics(false, test_fn); + + // Conditionally run with LSE + if std::arch::is_aarch64_feature_detected!("lse") { + with_maybe_lse_atomics(true, test_fn); + } +} /// Translate a byte size to a Rust type. macro int_ty { - (1) => { i8 }, - (2) => { i16 }, - (4) => { i32 }, - (8) => { i64 }, - (16) => { i128 } + (1) => { u8 }, + (2) => { u16 }, + (4) => { u32 }, + (8) => { u64 }, + (16) => { u128 } } mod cas { pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { #[test] fn $name() { - builtins_test::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { + crate::run_fuzz_tests_with_lse_variants(10000, |expected: super::int_ty!($bytes), new| { let mut target = expected.wrapping_add(10); + let ret: super::int_ty!($bytes) = unsafe { + compiler_builtins::aarch64_outline_atomics::$name::$name( + expected, + new, + &mut target, + ) + }; assert_eq!( - unsafe { - compiler_builtins::aarch64_outline_atomics::$name::$name( - expected, - new, - &mut target, - ) - }, + ret, expected.wrapping_add(10), "return value should always be the previous value", ); @@ -35,15 +76,17 @@ fn $name() { ); target = expected; + let ret: super::int_ty!($bytes) = unsafe { + compiler_builtins::aarch64_outline_atomics::$name::$name( + expected, + new, + &mut target, + ) + }; assert_eq!( - unsafe { - compiler_builtins::aarch64_outline_atomics::$name::$name( - expected, - new, - &mut target, - ) - }, - expected + ret, + expected, + "the new return value should always be the previous value (i.e. the first parameter passed to the function)", ); assert_eq!(target, new, "should have updated target"); }); @@ -59,16 +102,21 @@ mod swap { pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { #[test] fn $name() { - builtins_test::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { - let orig_right = right; - assert_eq!( - unsafe { - compiler_builtins::aarch64_outline_atomics::$name::$name(left, &mut right) - }, - orig_right - ); - assert_eq!(left, right); - }); + crate::run_fuzz_tests_with_lse_variants( + 10000, + |left: super::int_ty!($bytes), mut right| { + let orig_right = right; + assert_eq!( + unsafe { + compiler_builtins::aarch64_outline_atomics::$name::$name( + left, &mut right, + ) + }, + orig_right + ); + assert_eq!(left, right); + }, + ); } } } @@ -80,7 +128,7 @@ mod $mod { ($_ordering:ident, $bytes:tt, $name:ident) => { #[test] fn $name() { - builtins_test::fuzz_2(10000, |old, val| { + crate::run_fuzz_tests_with_lse_variants(10000, |old, val| { let mut target = old; let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*; let expected = op(old, val); @@ -98,7 +146,6 @@ fn $name() { test_op!(clr, |left, right| left & !right); test_op!(xor, std::ops::BitXor::bitxor); test_op!(or, std::ops::BitOr::bitor); -use compiler_builtins::{foreach_bytes, foreach_ordering}; compiler_builtins::foreach_cas!(cas::test); compiler_builtins::foreach_cas16!(test_cas16); compiler_builtins::foreach_swp!(swap::test); diff --git a/library/compiler-builtins/builtins-test/tests/mul.rs b/library/compiler-builtins/builtins-test/tests/mul.rs index bbf1157db42f..30516ebaf786 100644 --- a/library/compiler-builtins/builtins-test/tests/mul.rs +++ b/library/compiler-builtins/builtins-test/tests/mul.rs @@ -1,6 +1,6 @@ #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] -#![allow(unused_macros)] +#![allow(unused_macros, unused_features)] use builtins_test::*; diff --git a/library/compiler-builtins/ci/bench-runtime.sh b/library/compiler-builtins/ci/bench-walltime.sh similarity index 77% rename from library/compiler-builtins/ci/bench-runtime.sh rename to library/compiler-builtins/ci/bench-walltime.sh index d272cf33463e..0393d02dfc45 100755 --- a/library/compiler-builtins/ci/bench-runtime.sh +++ b/library/compiler-builtins/ci/bench-walltime.sh @@ -6,4 +6,4 @@ export LIBM_SEED=benchesbenchesbenchesbencheswoo! cargo bench --package libm-test \ --no-default-features \ - --features short-benchmarks,build-musl,libm/force-soft-floats + --features walltime,short-benchmarks,build-musl,libm/force-soft-floats diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index ef9ce455178e..392f83c219e7 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -11,7 +11,7 @@ import pprint import re import subprocess as sp import sys -from dataclasses import dataclass +from dataclasses import dataclass, field from functools import cache from glob import glob from inspect import cleandoc @@ -19,8 +19,7 @@ from os import getenv from pathlib import Path from typing import TypedDict, Self -USAGE = cleandoc( - """ +USAGE = cleandoc(""" usage: ./ci/ci-util.py [flags] @@ -44,8 +43,7 @@ USAGE = cleandoc( Exit with success if the pull request contains a line starting with `ci: allow-regressions`, indicating that regressions in benchmarks should be accepted. Otherwise, exit 1. - """ -) + """) REPO_ROOT = Path(__file__).parent.parent GIT = ["git", "-C", REPO_ROOT] @@ -73,17 +71,21 @@ def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) -@dataclass(init=False) +@dataclass(kw_only=True) class PrCfg: """Directives that we allow in the commit body to control test behavior. These are of the form `ci: foo`, at the start of a line. """ + # The PR body + body: str # Skip regression checks (must be at the start of a line). allow_regressions: bool = False # Don't run extensive tests skip_extensive: bool = False + # Add these extensive tests to the list + extra_extensive: list[str] = field(default_factory=list, init=False) # Allow running a large number of extensive tests. If not set, this script # will error out if a threshold is exceeded in order to avoid accidentally @@ -101,11 +103,17 @@ class PrCfg: DIR_SKIP_EXTENSIVE: str = "skip-extensive" DIR_ALLOW_MANY_EXTENSIVE: str = "allow-many-extensive" DIR_TEST_LIBM: str = "test-libm" + DIR_EXTRA_EXTENSIVE: str = "extra-extensive" - def __init__(self, body: str): - directives = re.finditer(r"^\s*ci:\s*(?P\S*)", body, re.MULTILINE) + def __post_init__(self): + directives = re.finditer( + r"^\s*ci:\s*(?P[^\s=]*)(?:\s*=\s*(?P.*))?", + self.body, + re.MULTILINE, + ) for dir in directives: name = dir.group("dir_name") + args = dir.group("args") if name == self.DIR_ALLOW_REGRESSIONS: self.allow_regressions = True elif name == self.DIR_SKIP_EXTENSIVE: @@ -114,11 +122,18 @@ class PrCfg: self.allow_many_extensive = True elif name == self.DIR_TEST_LIBM: self.always_test_libm = True + elif name == self.DIR_EXTRA_EXTENSIVE: + self.extra_extensive = [x.strip() for x in args.split(",")] + args = None else: eprint(f"Found unexpected directive `{name}`") exit(1) - pprint.pp(self) + if args is not None: + eprint("Found arguments where not expected") + exit(1) + + eprint(pprint.pformat(self)) @dataclass @@ -158,7 +173,7 @@ class PrInfo: ) pr_json = json.loads(pr_info) eprint("PR info:", json.dumps(pr_json, indent=4)) - return cls(**json.loads(pr_info), cfg=PrCfg(pr_json["body"])) + return cls(**pr_json, cfg=PrCfg(body=pr_json["body"])) class FunctionDef(TypedDict): @@ -276,29 +291,35 @@ class Context: skip_tests = False error_on_many_tests = False + extra_tests = {} pr = PrInfo.from_env() if pr is not None: skip_tests = pr.cfg.skip_extensive error_on_many_tests = not pr.cfg.allow_many_extensive + for fn_name in pr.cfg.extra_extensive: + extra_tests.setdefault(base_name(fn_name)[1], []).append(fn_name) if skip_tests: eprint("Skipping all extensive tests") changed = self.changed_routines() + eprint(f"Changed: {changed}") + matrix = [] total_to_test = 0 # Figure out which extensive tests need to run for ty in TYPES: ty_changed = changed.get(ty, []) - ty_to_test = [] if skip_tests else ty_changed + ty_to_test = [] if skip_tests else ty_changed.copy() + ty_to_test.extend(extra_tests.get(ty, [])) total_to_test += len(ty_to_test) item = { "ty": ty, - "changed": ",".join(ty_changed), - "to_test": ",".join(ty_to_test), + "changed": ",".join(sorted(set(ty_changed))), + "to_test": ",".join(sorted(set(ty_to_test))), } matrix.append(item) @@ -319,6 +340,33 @@ class Context: exit(1) +def base_name(name: str) -> tuple[str, str]: + """Return the basename and type from a full function name. Keep in sync with Rust's + `fn base_name`. + """ + known_mappings = [ + ("erff", ("erf", "f32")), + ("erf", ("erf", "f64")), + ("modff", ("modf", "f32")), + ("modf", ("modf", "f64")), + ("lgammaf_r", ("lgamma_r", "f32")), + ("lgamma_r", ("lgamma_r", "f64")), + ] + + found = next((base for (full, base) in known_mappings if full == name), None) + if found is not None: + return found + + if name.endswith("f"): + return (name.rstrip("f"), "f32") + elif name.endswith("f16"): + return (name.rstrip("f16"), "f16") + elif name.endswith("f128"): + return (name.rstrip("f128"), "f128") + + return (name, "f64") + + def locate_baseline(flags: list[str]) -> None: """Find the most recent baseline from CI, download it if specified. diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh index 7b0ea44c690f..aae474d88463 100755 --- a/library/compiler-builtins/ci/miri.sh +++ b/library/compiler-builtins/ci/miri.sh @@ -14,5 +14,9 @@ targets=( ) for target in "${targets[@]}"; do # Only run the `mem` tests to avoid this taking too long. - cargo miri test --manifest-path builtins-test/Cargo.toml --features no-asm --target "$target" -- mem + cargo miri test \ + --manifest-path builtins-test/Cargo.toml \ + --features no-asm \ + --target "$target" \ + -- mem done diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 12b3f37889c9..b9a21d555c9e 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -48,21 +48,24 @@ fi # build with the arguments we provide it, then validates the built artifacts. SYMCHECK_TEST_TARGET="$target" cargo test -p symbol-check --release symcheck=(cargo run -p symbol-check --release) -symcheck+=(-- build-and-check) +symcheck+=(-- --build-and-check --target "$target") -"${symcheck[@]}" "$target" -- -p compiler_builtins -"${symcheck[@]}" "$target" -- -p compiler_builtins --release -"${symcheck[@]}" "$target" -- -p compiler_builtins --features c -"${symcheck[@]}" "$target" -- -p compiler_builtins --features c --release -"${symcheck[@]}" "$target" -- -p compiler_builtins --features no-asm -"${symcheck[@]}" "$target" -- -p compiler_builtins --features no-asm --release +# Executable section checks are meaningless on no-std targets +[[ "$target" == *"-none"* ]] && symcheck+=(--no-os) + +"${symcheck[@]}" -- -p compiler_builtins +"${symcheck[@]}" -- -p compiler_builtins --release +"${symcheck[@]}" -- -p compiler_builtins --features c +"${symcheck[@]}" -- -p compiler_builtins --features c --release +"${symcheck[@]}" -- -p compiler_builtins --features no-asm +"${symcheck[@]}" -- -p compiler_builtins --features no-asm --release run_intrinsics_test() { build_args=(--verbose --manifest-path builtins-test-intrinsics/Cargo.toml) build_args+=("$@") # symcheck also checks the results of builtins-test-intrinsics - "${symcheck[@]}" "$target" -- "${build_args[@]}" + "${symcheck[@]}" -- "${build_args[@]}" # FIXME: we get access violations on Windows, our entrypoint may need to # be tweaked. diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index a8b8920421b3..d9acb8341d48 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -34,7 +34,7 @@ core = { path = "../../core", optional = true } cc = { version = "1.2", optional = true } [features] -default = ["compiler-builtins"] +default = [] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics @@ -45,8 +45,9 @@ c = ["dep:cc"] # the generic versions on all platforms. no-asm = [] -# Flag this library as the unstable compiler-builtins lib -compiler-builtins = [] +# Flag this library as the unstable compiler-builtins lib. This must be enabled +# when using as `std`'s dependency.' +compiler-builtins = ["dep:core"] # Generate memory-related intrinsics like memcpy mem = [] @@ -55,9 +56,6 @@ mem = [] # compiler-rt implementations. Also used for testing mangled-names = [] -# Only used in the compiler's build system -rustc-dep-of-std = ["compiler-builtins", "dep:core"] - # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` unstable-public-internals = [] diff --git a/library/compiler-builtins/compiler-builtins/README.md b/library/compiler-builtins/compiler-builtins/README.md index a12bd2ee7349..63cbf33d2aea 100644 --- a/library/compiler-builtins/compiler-builtins/README.md +++ b/library/compiler-builtins/compiler-builtins/README.md @@ -22,7 +22,7 @@ See `build.rs` for details. ## Contributing -See [CONTRIBUTING.md](CONTRIBUTING.md). +See [CONTRIBUTING.md](../CONTRIBUTING.md). ## Progress diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/compiler-builtins/src/aarch64.rs index 1b230a214eef..2c12cb7f3095 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64.rs @@ -1,7 +1,3 @@ -#![allow(unused_imports)] - -use core::intrinsics; - intrinsics! { #[unsafe(naked)] #[cfg(any(all(windows, target_env = "gnu"), target_os = "uefi"))] diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs index df0cf7650222..100b67150772 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs @@ -34,14 +34,27 @@ pub extern "C" fn __rust_enable_lse() { } } +/// Function to enable/disable LSE. To be used only for testing purposes. +#[cfg(feature = "mangled-names")] +pub unsafe fn set_have_lse_atomics(has_lse: bool) { + let lse_flag = if has_lse { 1 } else { 0 }; + HAVE_LSE_ATOMICS.store(lse_flag, Ordering::Relaxed); +} + +/// Function to obtain whether LSE is enabled or not. To be used only for testing purposes. +#[cfg(feature = "mangled-names")] +pub fn get_have_lse_atomics() -> bool { + HAVE_LSE_ATOMICS.load(Ordering::Relaxed) != 0 +} + /// Translate a byte size to a Rust type. #[rustfmt::skip] macro_rules! int_ty { - (1) => { i8 }; - (2) => { i16 }; - (4) => { i32 }; - (8) => { i64 }; - (16) => { i128 }; + (1) => { u8 }; + (2) => { u16 }; + (4) => { u32 }; + (8) => { u64 }; + (16) => { u128 }; } /// Given a byte size and a register number, return a register of the appropriate size. @@ -135,18 +148,73 @@ macro_rules! stxp { }; } +// The AArch64 assembly syntax for relocation specifiers +// when accessing symbols changes depending on the target executable format. +// In ELF (used in Linux), we have a prefix notation surrounded by colons (:specifier:sym), +// while in Mach-O object files (used in MacOS), a postfix notation is used (sym@specifier). + +/// AArch64 ELF position-independent addressing: +/// +/// adrp xN, symbol +/// add xN, xN, :lo12:symbol +/// +/// The :lo12: modifier selects the low 12 bits of the symbol address +/// and emits an ELF relocation such as R_AARCH64_ADD_ABS_LO12_NC. +/// +/// Defined by the AArch64 ELF psABI. +/// See: . +#[cfg(not(target_vendor = "apple"))] +macro_rules! sym { + ($sym:literal) => { + $sym + }; +} + +#[cfg(not(target_vendor = "apple"))] +macro_rules! sym_off { + ($sym:literal) => { + concat!(":lo12:", $sym) + }; +} + +/// Mach-O ARM64 relocation types: +/// ARM64_RELOC_PAGE21 +/// ARM64_RELOC_PAGEOFF12 +/// +/// These relocations implement the @PAGE / @PAGEOFF split used by +/// adrp + add sequences on Apple platforms. +/// +/// adrp xN, symbol@PAGE -> ARM64_RELOC_PAGE21 +/// add xN, xN, symbol@PAGEOFF -> ARM64_RELOC_PAGEOFF12 +/// +/// Relocation types defined by Apple in XNU: . +/// See: . +#[cfg(target_vendor = "apple")] +macro_rules! sym { + ($sym:literal) => { + concat!($sym, "@PAGE") + }; +} + +#[cfg(target_vendor = "apple")] +macro_rules! sym_off { + ($sym:literal) => { + concat!($sym, "@PAGEOFF") + }; +} + // If supported, perform the requested LSE op and return, or fallthrough. macro_rules! try_lse_op { ($op: literal, $ordering:ident, $bytes:tt, $($reg:literal,)* [ $mem:ident ] ) => { concat!( - ".arch_extension lse; ", - "adrp x16, {have_lse}; ", - "ldrb w16, [x16, :lo12:{have_lse}]; ", - "cbz w16, 8f; ", + ".arch_extension lse\n", + concat!("adrp x16, ", sym!("{have_lse}"), "\n"), + concat!("ldrb w16, [x16, ", sym_off!("{have_lse}"), "]\n"), + "cbz w16, 8f\n", // LSE_OP s(reg),* [$mem] - concat!(lse!($op, $ordering, $bytes), $( " ", reg!($bytes, $reg), ", " ,)* "[", stringify!($mem), "]; ",), - "ret; ", - "8:" + concat!(lse!($op, $ordering, $bytes), $( " ", reg!($bytes, $reg), ", " ,)* "[", stringify!($mem), "]\n",), + "ret + 8:" ) }; } @@ -203,15 +271,15 @@ macro_rules! compare_and_swap { }; } -// i128 uses a completely different impl, so it has its own macro. -macro_rules! compare_and_swap_i128 { +// u128 uses a completely different impl, so it has its own macro. +macro_rules! compare_and_swap_u128 { ($ordering:ident, $name:ident) => { intrinsics! { #[maybe_use_optimized_c_shim] #[unsafe(naked)] pub unsafe extern "C" fn $name ( - expected: i128, desired: i128, ptr: *mut i128 - ) -> i128 { + expected: u128, desired: u128, ptr: *mut u128 + ) -> u128 { core::arch::naked_asm! { // CASP x0, x1, x2, x3, [x4]; if LSE supported. try_lse_op!("cas", $ordering, 16, 0, 1, 2, 3, [x4]), @@ -391,7 +459,7 @@ macro_rules! foreach_ldset { } foreach_cas!(compare_and_swap); -foreach_cas16!(compare_and_swap_i128); +foreach_cas16!(compare_and_swap_u128); foreach_swp!(swap); foreach_ldadd!(add); foreach_ldclr!(and); diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 80395a4738eb..07960222f20f 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -7,7 +7,6 @@ #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(linkage)] -#![feature(naked_functions)] #![feature(repr_simd)] #![feature(macro_metavar_expr_concat)] #![feature(rustc_attrs)] @@ -57,7 +56,12 @@ #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] pub mod aarch64; -#[cfg(all(target_arch = "aarch64", target_feature = "outline-atomics"))] +// Note that we enable the module on "mangled-names" because that is the default feature +// in the builtins-test tests. So this is a way of enabling the module during testing. +#[cfg(all( + target_arch = "aarch64", + any(target_feature = "outline-atomics", feature = "mangled-names") +))] pub mod aarch64_outline_atomics; #[cfg(target_arch = "avr")] diff --git a/library/compiler-builtins/compiler-builtins/src/math/mod.rs b/library/compiler-builtins/compiler-builtins/src/math/mod.rs index 62d729674105..61dfad213cbe 100644 --- a/library/compiler-builtins/compiler-builtins/src/math/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/math/mod.rs @@ -28,8 +28,10 @@ pub mod full_availability { fn fdimf16(x: f16, y: f16) -> f16; fn floorf16(x: f16) -> f16; fn fmaxf16(x: f16, y: f16) -> f16; + fn fmaximum_numf16(x: f16, y: f16) -> f16; fn fmaximumf16(x: f16, y: f16) -> f16; fn fminf16(x: f16, y: f16) -> f16; + fn fminimum_numf16(x: f16, y: f16) -> f16; fn fminimumf16(x: f16, y: f16) -> f16; fn fmodf16(x: f16, y: f16) -> f16; fn rintf16(x: f16) -> f16; @@ -81,8 +83,12 @@ pub mod full_availability { // however, so we still provide a fallback. libm_intrinsics! { fn fmaximum(x: f64, y: f64) -> f64; + fn fmaximum_num(x: f64, y: f64) -> f64; + fn fmaximum_numf(x: f32, y: f32) -> f32; fn fmaximumf(x: f32, y: f32) -> f32; fn fminimum(x: f64, y: f64) -> f64; + fn fminimum_num(x: f64, y: f64) -> f64; + fn fminimum_numf(x: f32, y: f32) -> f32; fn fminimumf(x: f32, y: f32) -> f32; fn roundeven(x: f64) -> f64; fn roundevenf(x: f32) -> f32; @@ -97,8 +103,10 @@ pub mod full_availability { fn floorf128(x: f128) -> f128; fn fmaf128(x: f128, y: f128, z: f128) -> f128; fn fmaxf128(x: f128, y: f128) -> f128; + fn fmaximum_numf128(x: f128, y: f128) -> f128; fn fmaximumf128(x: f128, y: f128) -> f128; fn fminf128(x: f128, y: f128) -> f128; + fn fminimum_numf128(x: f128, y: f128) -> f128; fn fminimumf128(x: f128, y: f128) -> f128; fn fmodf128(x: f128, y: f128) -> f128; fn rintf128(x: f128) -> f128; diff --git a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs index da16dee25ce5..9681f5d6dac6 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs @@ -16,7 +16,8 @@ // crate doing wrapping pointer arithmetic with a method that must not wrap won't be the problem if // something does go wrong at runtime. use core::ffi::c_int; -use core::intrinsics::likely; + +use crate::support::cold_path; const WORD_SIZE: usize = core::mem::size_of::(); const WORD_MASK: usize = WORD_SIZE - 1; @@ -209,9 +210,10 @@ unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) let n_words = n & !WORD_MASK; let src_misalignment = src as usize & WORD_MASK; - if likely(src_misalignment == 0) { + if src_misalignment == 0 { copy_forward_aligned_words(dest, src, n_words); } else { + cold_path(); copy_forward_misaligned_words(dest, src, n_words); } dest = dest.wrapping_add(n_words); @@ -327,9 +329,10 @@ unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize let n_words = n & !WORD_MASK; let src_misalignment = src as usize & WORD_MASK; - if likely(src_misalignment == 0) { + if src_misalignment == 0 { copy_backward_aligned_words(dest, src, n_words); } else { + cold_path(); copy_backward_misaligned_words(dest, src, n_words); } dest = dest.wrapping_sub(n_words); @@ -368,7 +371,7 @@ pub unsafe fn set_bytes_words(s: *mut u8, c: u8, n: usize) { } } - if likely(n >= WORD_COPY_THRESHOLD) { + if n >= WORD_COPY_THRESHOLD { // Align s // Because of n >= 2 * WORD_SIZE, dst_misalignment < n let misalignment = (s as usize).wrapping_neg() & WORD_MASK; @@ -380,6 +383,8 @@ pub unsafe fn set_bytes_words(s: *mut u8, c: u8, n: usize) { set_bytes_words(s, c, n_words); s = s.wrapping_add(n_words); n -= n_words; + } else { + cold_path(); } set_bytes_bytes(s, c, n); } diff --git a/library/compiler-builtins/compiler-builtins/src/x86.rs b/library/compiler-builtins/compiler-builtins/src/x86.rs index 1a3c41860945..45f4ba207e6e 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86.rs @@ -1,7 +1,3 @@ -#![allow(unused_imports)] - -use core::intrinsics; - // NOTE These functions are implemented using assembly because they use a custom // calling convention which can't be implemented using a normal Rust function diff --git a/library/compiler-builtins/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs index 99a527ee9ac5..a3a5c8f7e10f 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86_64.rs @@ -1,7 +1,3 @@ -#![allow(unused_imports)] - -use core::intrinsics; - // NOTE These functions are implemented using assembly because they use a custom // calling convention which can't be implemented using a normal Rust function diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 1cefe4e8c7ed..ee1feed7c35e 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -279,6 +279,17 @@ struct NestedOp { fn_list: &["fmaf128"], public: true, }, + NestedOp { + // `(f16) -> i32` + float_ty: FloatTy::F16, + rust_sig: Signature { + args: &[Ty::F16], + returns: &[Ty::I32], + }, + c_sig: None, + fn_list: &["ilogbf16"], + public: true, + }, NestedOp { // `(f32) -> i32` float_ty: FloatTy::F32, @@ -301,6 +312,17 @@ struct NestedOp { fn_list: &["ilogb"], public: true, }, + NestedOp { + // `(f128) -> i32` + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::I32], + }, + c_sig: None, + fn_list: &["ilogbf128"], + public: true, + }, NestedOp { // `(i32, f32) -> f32` float_ty: FloatTy::F32, @@ -395,6 +417,20 @@ struct NestedOp { fn_list: &["modf"], public: true, }, + NestedOp { + // `(f16, &mut c_int) -> f16` as `(f16) -> (f16, i32)` + float_ty: FloatTy::F16, + rust_sig: Signature { + args: &[Ty::F16], + returns: &[Ty::F16, Ty::I32], + }, + c_sig: Some(Signature { + args: &[Ty::F16, Ty::MutCInt], + returns: &[Ty::F16], + }), + fn_list: &["frexpf16"], + public: true, + }, NestedOp { // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` float_ty: FloatTy::F32, @@ -423,6 +459,20 @@ struct NestedOp { fn_list: &["frexp", "lgamma_r"], public: true, }, + NestedOp { + // `(f128, &mut c_int) -> f128` as `(f128) -> (f128, i32)` + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::F128, Ty::I32], + }, + c_sig: Some(Signature { + args: &[Ty::F128, Ty::MutCInt], + returns: &[Ty::F128], + }), + fn_list: &["frexpf128"], + public: true, + }, NestedOp { // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` float_ty: FloatTy::F32, diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs index b4276262229f..1876db8f5869 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -1,3 +1,4 @@ +#![allow(unused_features)] #![feature(f16)] #![feature(f128)] // `STATUS_DLL_NOT_FOUND` on i686 MinGW, not worth looking into. diff --git a/library/compiler-builtins/crates/symbol-check/Cargo.toml b/library/compiler-builtins/crates/symbol-check/Cargo.toml index 5bc13d337c27..6d13f9488800 100644 --- a/library/compiler-builtins/crates/symbol-check/Cargo.toml +++ b/library/compiler-builtins/crates/symbol-check/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" publish = false [dependencies] +getopts.workspace = true object.workspace = true regex.workspace = true serde_json.workspace = true diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 733d9f4e8bef..135019e5f729 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -5,75 +5,100 @@ //! actual target is cross compiled. use std::collections::{BTreeMap, BTreeSet, HashSet}; -use std::fs; use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Command, Stdio, exit}; use std::sync::LazyLock; +use std::{env, fs}; use object::read::archive::ArchiveFile; use object::{ - File as ObjFile, Object, ObjectSection, ObjectSymbol, Result as ObjResult, Symbol, SymbolKind, - SymbolScope, + Architecture, BinaryFormat, Endianness, File as ObjFile, Object, ObjectSection, ObjectSymbol, + Result as ObjResult, SectionFlags, Symbol, SymbolKind, SymbolScope, U32, elf, }; use regex::Regex; use serde_json::Value; const CHECK_LIBRARIES: &[&str] = &["compiler_builtins", "builtins_test_intrinsics"]; const CHECK_EXTENSIONS: &[Option<&str>] = &[Some("rlib"), Some("a"), Some("exe"), None]; +const GNU_STACK: &str = ".note.GNU-stack"; const USAGE: &str = "Usage: - symbol-check build-and-check [TARGET] -- CARGO_BUILD_ARGS ... - -Cargo will get invoked with `CARGO_ARGS` and the specified target. All output -`compiler_builtins*.rlib` files will be checked. - -If TARGET is not specified, the host target is used. - - check PATHS ... - -Run the same checks on the given set of paths, without invoking Cargo. Paths -may be either archives or object files. + symbol-check --build-and-check [--target TARGET] [--no-os] -- CARGO_BUILD_ARGS ... + symbol-check --check PATHS ...\ "; fn main() { - // Create a `&str` vec so we can match on it. - let args = std::env::args().collect::>(); - let args_ref = args.iter().map(String::as_str).collect::>(); + let mut opts = getopts::Options::new(); - match &args_ref[1..] { - ["build-and-check", target, "--", args @ ..] if !args.is_empty() => { - run_build_and_check(target, args); - } - ["build-and-check", "--", args @ ..] if !args.is_empty() => { - run_build_and_check(env!("HOST"), args); - } - ["check", paths @ ..] if !paths.is_empty() => { - check_paths(paths); - } - _ => { - println!("{USAGE}"); - std::process::exit(1); - } + // Ideally these would be subcommands but that isn't supported. + opts.optflag("h", "help", "Print this help message"); + opts.optflag( + "", + "build-and-check", + "Cargo will get invoked with `CARGO_BUILD_ARGS` and the specified target. All output \ + `compiler_builtins*.rlib` files will be checked.", + ); + opts.optopt( + "", + "target", + "Set the target for build-and-check. Falls back to the host target otherwise.", + "TARGET", + ); + opts.optflag( + "", + "check", + "Run checks on the given set of paths, without invoking Cargo. Paths \ + may be either archives or object files.", + ); + opts.optflag( + "", + "no-os", + "The binaries will not be checked for executable stacks. Used for embedded targets which \ + don't set `.note.GNU-stack` since there is no protection.", + ); + opts.optflag("", "no-visibility", "Don't check visibility."); + + let print_usage_and_exit = |code: i32| -> ! { + eprintln!("{}", opts.usage(USAGE)); + exit(code); + }; + + let m = opts.parse(std::env::args().skip(1)).unwrap_or_else(|e| { + eprintln!("{e}"); + print_usage_and_exit(1); + }); + + if m.opt_present("help") { + print_usage_and_exit(0); } -} -fn run_build_and_check(target: &str, args: &[&str]) { - // Make sure `--target` isn't passed to avoid confusion (since it should be - // proivded only once, positionally). - for arg in args { + let no_os_target = m.opt_present("no-os"); + let check_visibility = !m.opt_present("no-visibility"); + let free_args = m.free.iter().map(String::as_str).collect::>(); + for arg in &free_args { assert!( !arg.contains("--target"), - "target must be passed positionally. {USAGE}" + "target must be passed to symbol-check" ); } - let paths = exec_cargo_with_args(target, args); - check_paths(&paths); + if m.opt_present("build-and-check") { + let target = m.opt_str("target").unwrap_or(env!("HOST").to_string()); + let paths = exec_cargo_with_args(&target, &free_args); + check_paths(&paths, no_os_target, check_visibility); + } else if m.opt_present("check") { + if free_args.is_empty() { + print_usage_and_exit(1); + } + check_paths(&free_args, no_os_target, check_visibility); + } else { + print_usage_and_exit(1); + } } -fn check_paths>(paths: &[P]) { +fn check_paths>(paths: &[P], no_os_target: bool, check_visibility: bool) { for path in paths { let path = path.as_ref(); println!("Checking {}", path.display()); @@ -81,6 +106,10 @@ fn check_paths>(paths: &[P]) { verify_no_duplicates(&archive); verify_core_symbols(&archive); + verify_no_exec_stack(&archive, no_os_target); + if check_visibility { + verify_hidden_visibility(&archive); + } } } @@ -244,7 +273,9 @@ fn verify_no_duplicates(archive: &BinFile) { found_any = true; }); - assert!(found_any, "no symbols found"); + if archive.has_symbol_tables() { + assert!(found_any, "no symbols found"); + } if !dups.is_empty() { let count = dups.iter().map(|x| &x.name).collect::>().len(); @@ -285,7 +316,9 @@ fn verify_core_symbols(archive: &BinFile) { } }); - assert!(has_symbols, "no symbols found"); + if archive.has_symbol_tables() { + assert!(has_symbols, "no symbols found"); + } // Discard any symbols that are defined somewhere in the archive undefined.retain(|sym| !defined.contains(&sym.name)); @@ -301,6 +334,209 @@ fn verify_core_symbols(archive: &BinFile) { println!(" success: no undefined references to core found"); } +/// Check for symbols with default visibility. +fn verify_hidden_visibility(archive: &BinFile) { + let mut visible = Vec::new(); + let mut found_any = false; + + archive.for_each_symbol(|symbol, obj, member| { + // Only check defined globals. + if !symbol.is_global() || symbol.is_undefined() { + return; + } + + let sym = SymInfo::new(&symbol, obj, member); + if sym.scope == SymbolScope::Dynamic { + visible.push(sym); + } + + found_any = true + }); + + if archive.has_symbol_tables() { + assert!(found_any, "no symbols found"); + } + + if !visible.is_empty() { + visible.sort_unstable_by(|a, b| a.name.cmp(&b.name)); + let num = visible.len(); + panic!("found {num:#?} visible symbols: {visible:#?}"); + } + + println!(" success: no visible symbols found"); +} + +/// Reasons a binary is considered to have an executable stack. +enum ExeStack { + MissingGnuStackSec, + ExeGnuStackSec, + ExePtGnuStack, +} + +/// Ensure that the object/archive will not require an executable stack. +fn verify_no_exec_stack(archive: &BinFile, no_os_target: bool) { + if no_os_target { + // We don't really have a good way of knowing whether or not an elf file is for a + // no-os environment so we rely on a CLI arg (note.GNU-stack doesn't get emitted if + // there is no OS to protect the stack). + println!(" skipping check for writeable+executable stack on no-os target"); + return; + } + + let mut problem_objfiles = Vec::new(); + + archive.for_each_object(|obj, obj_path| match check_obj_exe_stack(&obj) { + Ok(()) => (), + Err(exe) => problem_objfiles.push((obj_path.to_owned(), exe)), + }); + + if problem_objfiles.is_empty() { + println!(" success: no writeable+executable stack indicators found"); + return; + } + + eprintln!("the following object files require an executable stack:"); + + for (obj, exe) in problem_objfiles { + let reason = match exe { + ExeStack::MissingGnuStackSec => "no .note.GNU-stack section", + ExeStack::ExeGnuStackSec => ".note.GNU-stack section marked SHF_EXECINSTR", + ExeStack::ExePtGnuStack => "PT_GNU_STACK program header marked PF_X", + }; + eprintln!(" {obj} ({reason})"); + } + + exit(1); +} + +/// `Err` if the section/flag combination indicates that the object file should be linked with an +/// executable stack. +fn check_obj_exe_stack(obj: &ObjFile) -> Result<(), ExeStack> { + match obj.format() { + BinaryFormat::Elf => check_elf_exe_stack(obj), + // Technically has the `MH_ALLOW_STACK_EXECUTION` flag but I can't get the compiler to + // emit it (`-allow_stack_execute` doesn't seem to work in recent versions). + BinaryFormat::MachO => Ok(()), + // Can't find much information about Windows stack executability. + BinaryFormat::Coff | BinaryFormat::Pe => Ok(()), + // Also not sure about wasm. + BinaryFormat::Wasm => Ok(()), + BinaryFormat::Xcoff | _ => { + unimplemented!("binary format {:?} is not supported", obj.format()) + } + } +} + +/// Check for an executable stack in elf binaries. +/// +/// If the `PT_GNU_STACK` header on a binary is present and marked executable, the binary will +/// have an executable stack (RWE rather than the desired RW). If any object file has the right +/// `.note.GNU-stack` logic, the final binary will get `PT_GNU_STACK`. +/// +/// Individual object file logic is as follows, paraphrased from [1]: +/// +/// - A `.note.GNU-stack` section with the exe flag means this needs an executable stack +/// - A `.note.GNU-stack` section without the exe flag means there is no executable stack needed +/// - Without the section, behavior is target-specific. Historically it usually means an executable +/// stack is required. +/// +/// Per [2], it is now deprecated behavior for a missing `.note.GNU-stack` section to imply an +/// executable stack. However, we shouldn't assume that tooling has caught up to this. +/// +/// [1]: https://www.man7.org/linux/man-pages/man1/ld.1.html +/// [2]: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0d38576a34ec64a1b4500c9277a8e9d0f07e6774> +fn check_elf_exe_stack(obj: &ObjFile) -> Result<(), ExeStack> { + let end = obj.endianness(); + + // Check for PT_GNU_STACK marked executable + let mut is_obj_exe = false; + let mut found_gnu_stack = false; + let mut check_ph = |p_type: U32, p_flags: U32| { + let ty = p_type.get(end); + let flags = p_flags.get(end); + + // Presence of PT_INTERP indicates that this is an executable rather than a standalone + // object file. + if ty == elf::PT_INTERP { + is_obj_exe = true; + } + + if ty == elf::PT_GNU_STACK { + assert!(!found_gnu_stack, "multiple PT_GNU_STACK sections"); + found_gnu_stack = true; + if flags & elf::PF_X != 0 { + return Err(ExeStack::ExePtGnuStack); + } + } + + Ok(()) + }; + + match obj { + ObjFile::Elf32(f) => { + for ph in f.elf_program_headers() { + check_ph(ph.p_type, ph.p_flags)?; + } + } + ObjFile::Elf64(f) => { + for ph in f.elf_program_headers() { + check_ph(ph.p_type, ph.p_flags)?; + } + } + _ => panic!("should only be called with elf objects"), + } + + if is_obj_exe { + return Ok(()); + } + + // The remaining are checks for individual object files, which wind up controlling PT_GNU_STACK + // in the final binary. + let mut gnu_stack_exe = None; + let mut has_exe_sections = false; + for sec in obj.sections() { + let SectionFlags::Elf { sh_flags } = sec.flags() else { + unreachable!("only elf files are being checked"); + }; + + let is_sec_exe = sh_flags & u64::from(elf::SHF_EXECINSTR) != 0; + + // If the magic section is present, its exe bit tells us whether or not the object + // file requires an executable stack. + if sec.name().unwrap_or_default() == GNU_STACK { + assert!(gnu_stack_exe.is_none(), "multiple {GNU_STACK} sections"); + if is_sec_exe { + gnu_stack_exe = Some(Err(ExeStack::ExeGnuStackSec)); + } else { + gnu_stack_exe = Some(Ok(())); + } + } + + // Otherwise, just keep track of whether or not we have exeuctable sections + has_exe_sections |= is_sec_exe; + } + + // GNU_STACK sets the executability if specified. + if let Some(exe) = gnu_stack_exe { + return exe; + } + + // Ignore object files that have no executable sections, like rmeta. + if !has_exe_sections { + return Ok(()); + } + + // If there is no `.note.GNU-stack` and no executable sections, behavior differs by platform. + match obj.architecture() { + // PPC64 doesn't set `.note.GNU-stack` since GNU nested functions don't need a trampoline, + // . From experimentation, it seems + // like this only applies to big endian. + Architecture::PowerPc64 if obj.endianness() == Endianness::Big => Ok(()), + + _ => Err(ExeStack::MissingGnuStackSec), + } +} + /// Thin wrapper for owning data used by `object`. struct BinFile { path: PathBuf, @@ -361,4 +597,23 @@ fn for_each_symbol(&self, mut f: impl FnMut(Symbol, &ObjFile, &str)) { obj.symbols().for_each(|sym| f(sym, &obj, obj_path)); }); } + + /// PE executable files don't have the same kind of symbol tables. This isn't a perfectly + /// accurate check, but at least tells us whether we can skip erroring if we don't find any + /// symbols. + fn has_symbol_tables(&self) -> bool { + let mut empty = true; + let mut ret = false; + + self.for_each_object(|obj, _obj_path| { + if !matches!(obj.format(), BinaryFormat::Pe) { + // Any non-PE objects should have symbol tables. + ret = true; + } + empty = false; + }); + + // If empty, assume there should be tables. + empty || ret + } } diff --git a/library/compiler-builtins/crates/symbol-check/tests/all.rs b/library/compiler-builtins/crates/symbol-check/tests/all.rs index 400469a49e2a..cfc8641aca82 100644 --- a/library/compiler-builtins/crates/symbol-check/tests/all.rs +++ b/library/compiler-builtins/crates/symbol-check/tests/all.rs @@ -2,10 +2,10 @@ use std::ffi::OsString; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use std::sync::LazyLock; use assert_cmd::assert::Assert; use assert_cmd::cargo::cargo_bin_cmd; +use object::BinaryFormat; use tempfile::tempdir; trait AssertExt { @@ -13,6 +13,7 @@ trait AssertExt { } impl AssertExt for Assert { + #[track_caller] fn stderr_contains(self, s: &str) -> Self { let out = String::from_utf8_lossy(&self.get_output().stderr); assert!(out.contains(s), "looking for: `{s}`\nout:\n```\n{out}\n```"); @@ -22,18 +23,19 @@ fn stderr_contains(self, s: &str) -> Self { #[test] fn test_duplicates() { + let t = TestTarget::from_env(); let dir = tempdir().unwrap(); let dup_out = dir.path().join("dup.o"); let lib_out = dir.path().join("libfoo.rlib"); // For the "bad" file, we need duplicate symbols from different object files in the archive. Do // this reliably by building an archive and a separate object file then merging them. - rustc_build(&input_dir().join("duplicates.rs"), &lib_out, |cmd| cmd); - rustc_build(&input_dir().join("duplicates.rs"), &dup_out, |cmd| { + t.rustc_build(&input_dir().join("duplicates.rs"), &lib_out, |cmd| cmd); + t.rustc_build(&input_dir().join("duplicates.rs"), &dup_out, |cmd| { cmd.arg("--emit=obj") }); - let mut ar = cc_build().get_archiver(); + let mut ar = t.cc_build().get_archiver(); if ar.get_program().to_string_lossy().contains("lib.exe") { let mut out_arg = OsString::from("-out:"); @@ -48,10 +50,10 @@ fn test_duplicates() { .stderr(Stdio::null()) .arg(&lib_out); } - let status = ar.arg(&dup_out).status().unwrap(); - assert!(status.success()); - let assert = cargo_bin_cmd!().arg("check").arg(&lib_out).assert(); + run(ar.arg(&dup_out)); + + let assert = t.symcheck_exe().arg(&lib_out).assert(); assert .failure() .stderr_contains("duplicate symbols") @@ -62,10 +64,11 @@ fn test_duplicates() { #[test] fn test_core_symbols() { + let t = TestTarget::from_env(); let dir = tempdir().unwrap(); let lib_out = dir.path().join("libfoo.rlib"); - rustc_build(&input_dir().join("core_symbols.rs"), &lib_out, |cmd| cmd); - let assert = cargo_bin_cmd!().arg("check").arg(&lib_out).assert(); + t.rustc_build(&input_dir().join("core_symbols.rs"), &lib_out, |cmd| cmd); + let assert = t.symcheck_exe().arg(&lib_out).assert(); assert .failure() .stderr_contains("found 1 undefined symbols from core") @@ -73,40 +76,160 @@ fn test_core_symbols() { } #[test] -fn test_good() { +fn test_visible_symbols() { + let t = TestTarget::from_env(); + if t.is_windows() { + eprintln!("windows does not have visibility, skipping"); + return; + } let dir = tempdir().unwrap(); let lib_out = dir.path().join("libfoo.rlib"); - rustc_build(&input_dir().join("good.rs"), &lib_out, |cmd| cmd); - let assert = cargo_bin_cmd!().arg("check").arg(&lib_out).assert(); + t.rustc_build(&input_dir().join("good_lib.rs"), &lib_out, |cmd| cmd); + let assert = t.symcheck_exe().arg(&lib_out).assert(); + assert.failure().stderr_contains("found 1 visible symbols"); // good is visible. +} + +mod exe_stack { + use super::*; + + /// Check with an object that has no `.note.GNU-stack` section, indicating platform-default stack + /// writeability (usually enabled). + #[test] + fn test_missing_gnu_stack_section() { + let t = TestTarget::from_env(); + if t.is_msvc() { + // Can't easily build asm via cc with cl.exe / masm.exe + eprintln!("assembly on windows, skipping"); + return; + } + + let dir = tempdir().unwrap(); + let src = input_dir().join("missing_gnu_stack_section.S"); + + let objs = t.cc_build().file(src).out_dir(&dir).compile_intermediates(); + let [obj] = objs.as_slice() else { panic!() }; + + let assert = t.symcheck_exe().arg(obj).arg("--no-visibility").assert(); + + if t.is_ppc64be() || t.no_os() || t.binary_obj_format() != BinaryFormat::Elf { + // Ppc64be doesn't emit `.note.GNU-stack`, not relevant without an OS, and non-elf + // targets don't use `.note.GNU-stack`. + assert.success(); + return; + } + + assert + .failure() + .stderr_contains("the following object files require an executable stack") + .stderr_contains("missing_gnu_stack_section.o (no .note.GNU-stack section)"); + } + + /// Check with an object that has a `.note.GNU-stack` section with the executable flag set. + #[test] + fn test_exe_gnu_stack_section() { + let t = TestTarget::from_env(); + let mut build = t.cc_build(); + if !build.get_compiler().is_like_gnu() || t.is_windows() { + eprintln!("unsupported compiler for nested functions, skipping"); + return; + } + + let dir = tempdir().unwrap(); + let objs = build + .file(input_dir().join("has_exe_gnu_stack_section.c")) + .out_dir(&dir) + .compile_intermediates(); + let [obj] = objs.as_slice() else { panic!() }; + + let assert = t.symcheck_exe().arg(obj).arg("--no-visibility").assert(); + + if t.is_ppc64be() || t.no_os() { + // Ppc64be doesn't emit `.note.GNU-stack`, not relevant without an OS. + assert.success(); + return; + } + + assert + .failure() + .stderr_contains("the following object files require an executable stack") + .stderr_contains( + "has_exe_gnu_stack_section.o (.note.GNU-stack section marked SHF_EXECINSTR)", + ); + } + + /// Check a final binary with `PT_GNU_STACK`. + #[test] + fn test_execstack_bin() { + let t = TestTarget::from_env(); + if t.binary_obj_format() != BinaryFormat::Elf || !t.supports_executables() { + // Mac's Clang rejects `-z execstack`. `-allow_stack_execute` should work per the ld + // manpage, at least on x86, but it doesn't seem to., not relevant without an OS. + eprintln!("non-elf or no-executable target, skipping"); + return; + } + + let dir = tempdir().unwrap(); + let out = dir.path().join("execstack.out"); + + let mut cmd = t.cc_build().get_compiler().to_command(); + t.set_bin_out_path(&mut cmd, &out); + + run(cmd + .arg("-z") + .arg("execstack") + .arg(input_dir().join("good_bin.c"))); + + let assert = t.symcheck_exe().arg(&out).assert(); + assert + .failure() + .stderr_contains("the following object files require an executable stack") + .stderr_contains("execstack.out (PT_GNU_STACK program header marked PF_X)"); + } +} + +#[test] +fn test_good_lib() { + let t = TestTarget::from_env(); + let dir = tempdir().unwrap(); + let lib_out = dir.path().join("libfoo.rlib"); + t.rustc_build(&input_dir().join("good_lib.rs"), &lib_out, |cmd| cmd); + let assert = t + .symcheck_exe() + .arg(&lib_out) + .arg("--no-visibility") + .assert(); assert.success(); } -/// Build i -> o with optional additional configuration. -fn rustc_build(i: &Path, o: &Path, mut f: impl FnMut(&mut Command) -> &mut Command) { - let mut cmd = Command::new("rustc"); - cmd.arg(i) - .arg("--target") - .arg(target()) - .arg("--crate-type=lib") - .arg("-o") - .arg(o); - f(&mut cmd); - let status = cmd.status().unwrap(); - assert!(status.success()); +#[test] +fn test_good_bin() { + let t = TestTarget::from_env(); + // Nothing to test if we can't build a binary. + if !t.supports_executables() { + eprintln!("no-exe target, skipping"); + return; + } + + let dir = tempdir().unwrap(); + let out = dir.path().join("good_bin.out"); + + let mut cmd = t.cc_build().get_compiler().to_command(); + t.set_bin_out_path(&mut cmd, &out); + run(cmd.arg(input_dir().join("good_bin.c"))); + + let assert = t.symcheck_exe().arg(&out).arg("--no-visibility").assert(); + assert.success(); } -/// Configure `cc` with the host and target. -fn cc_build() -> cc::Build { - let mut b = cc::Build::new(); - b.host(env!("HOST")).target(&target()); - b +/// Since symcheck is a hostprog, the target we want to build and test symcheck for may not be the +/// same as the host target. +struct TestTarget { + triple: String, } -/// Symcheck runs on the host but we want to verify that we find issues on all targets, so -/// the cross target may be specified. -fn target() -> String { - static TARGET: LazyLock = LazyLock::new(|| { - let target = match env::var("SYMCHECK_TEST_TARGET") { +impl TestTarget { + fn from_env() -> Self { + let triple = match env::var("SYMCHECK_TEST_TARGET") { Ok(t) => t, // Require on CI so we don't accidentally always test the native target _ if env::var("CI").is_ok() => panic!("SYMCHECK_TEST_TARGET must be set in CI"), @@ -114,13 +237,108 @@ fn target() -> String { Err(_) => env!("HOST").to_string(), }; - println!("using target {target}"); - target - }); + println!("using target {triple}"); + Self { triple } + } - TARGET.clone() + /// Build i -> o with optional additional configuration. + fn rustc_build(&self, i: &Path, o: &Path, mut f: impl FnMut(&mut Command) -> &mut Command) { + let mut cmd = Command::new("rustc"); + cmd.arg(i) + .arg("--target") + .arg(&self.triple) + .arg("--crate-type=lib") + .arg("-o") + .arg(o); + f(&mut cmd); + run(&mut cmd); + } + + /// Configure `cc` with the host and target. + fn cc_build(&self) -> cc::Build { + let mut b = cc::Build::new(); + b.host(env!("HOST")) + .target(&self.triple) + .opt_level(0) + .cargo_debug(true) + .cargo_metadata(false); + b + } + + fn symcheck_exe(&self) -> assert_cmd::Command { + let mut cmd = cargo_bin_cmd!(); + cmd.arg("--check"); + if self.no_os() { + cmd.arg("--no-os"); + } + cmd + } + + /// MSVC requires different flags for setting output path, account for that here. + fn set_bin_out_path<'a>(&self, cmd: &'a mut Command, out: &Path) -> &'a mut Command { + if self.cc_build().get_compiler().is_like_msvc() { + let mut exe_arg = OsString::from("/Fe"); + let mut obj_arg = OsString::from("/Fo"); + exe_arg.push(out); + obj_arg.push(out.with_extension("o")); + cmd.arg(exe_arg).arg(obj_arg) + } else { + cmd.arg("-o").arg(out) + } + } + + /// Based on `rustc_target`. + fn binary_obj_format(&self) -> BinaryFormat { + let t = &self.triple; + if t.contains("-windows-") || t.contains("-cygwin") { + // Coff for libraries, PE for executables. + BinaryFormat::Coff + } else if t.starts_with("wasm") { + BinaryFormat::Wasm + } else if t.contains("-aix") { + BinaryFormat::Xcoff + } else if t.contains("-apple-") { + BinaryFormat::MachO + } else { + BinaryFormat::Elf + } + } + + fn is_windows(&self) -> bool { + self.triple.contains("-windows-") + } + + fn is_msvc(&self) -> bool { + self.triple.contains("-windows-msvc") + } + + fn is_ppc64be(&self) -> bool { + self.triple.starts_with("powerpc64-") + } + + /// True if the target needs `--no-os` passed to symcheck. + fn no_os(&self) -> bool { + self.triple.contains("-none") + } + + /// True if the target supports (easily) building to a final executable. + fn supports_executables(&self) -> bool { + // Technically i686-pc-windows-gnu should work but it has nontrivial setup in CI. + !(self.no_os() + || self.triple == "wasm32-unknown-unknown" + || self.triple == "i686-pc-windows-gnu") + } } fn input_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/input") } + +#[track_caller] +fn run(cmd: &mut Command) { + eprintln!("+ {cmd:?}"); + let out = cmd.output().unwrap(); + println!("{}", String::from_utf8_lossy(&out.stdout)); + eprintln!("{}", String::from_utf8_lossy(&out.stderr)); + assert!(out.status.success(), "{:?}", out.status); +} diff --git a/library/compiler-builtins/crates/symbol-check/tests/input/good_bin.c b/library/compiler-builtins/crates/symbol-check/tests/input/good_bin.c new file mode 100644 index 000000000000..dba75b58af1a --- /dev/null +++ b/library/compiler-builtins/crates/symbol-check/tests/input/good_bin.c @@ -0,0 +1,3 @@ +/* empty main used to test binaries with compiler options */ + +int main() {} diff --git a/library/compiler-builtins/crates/symbol-check/tests/input/good.rs b/library/compiler-builtins/crates/symbol-check/tests/input/good_lib.rs similarity index 100% rename from library/compiler-builtins/crates/symbol-check/tests/input/good.rs rename to library/compiler-builtins/crates/symbol-check/tests/input/good_lib.rs diff --git a/library/compiler-builtins/crates/symbol-check/tests/input/has_exe_gnu_stack_section.c b/library/compiler-builtins/crates/symbol-check/tests/input/has_exe_gnu_stack_section.c new file mode 100644 index 000000000000..d4be217b5a06 --- /dev/null +++ b/library/compiler-builtins/crates/symbol-check/tests/input/has_exe_gnu_stack_section.c @@ -0,0 +1,16 @@ +/* A file that requires an executable stack and thus will have a + * `.note.GNU-stack` section with the executable bit set. + * + * GNU nested functions are the only way I could find to force an explicitly + * executable stack. Supported by GCC only, not Clang. + */ + +void intermediate(void (*)(int, int), int); + +void hack(int *array, int size) { + void store (int index, int value) { + array[index] = value; + } + + intermediate(store, size); +} diff --git a/library/compiler-builtins/crates/symbol-check/tests/input/missing_gnu_stack_section.S b/library/compiler-builtins/crates/symbol-check/tests/input/missing_gnu_stack_section.S new file mode 100644 index 000000000000..09bb761c40ba --- /dev/null +++ b/library/compiler-builtins/crates/symbol-check/tests/input/missing_gnu_stack_section.S @@ -0,0 +1,19 @@ +/* Create an object file with no `.note.GNU-stack` section. + * + * Assembly files do not get that section, meaning platform-default stack + * executability is implied (usually yes on Linux). + */ + +.global func + +#ifdef __wasm__ +.functype func () -> () +.type func, @function +#endif + +func: + nop + +#ifdef __wasm__ + end_function +#endif diff --git a/library/compiler-builtins/crates/util/Cargo.toml b/library/compiler-builtins/crates/util/Cargo.toml index c56e2cc12ea5..b0a365e4735b 100644 --- a/library/compiler-builtins/crates/util/Cargo.toml +++ b/library/compiler-builtins/crates/util/Cargo.toml @@ -6,6 +6,7 @@ publish = false license = "MIT OR Apache-2.0" [dependencies] +cfg-if.workspace = true libm.workspace = true libm-macros.workspace = true libm-test.workspace = true diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index 5972181531b2..70aa613f18d0 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -8,10 +8,11 @@ use std::num::ParseIntError; use std::str::FromStr; -use libm::support::{Hexf, hf32, hf64}; +use cfg_if::cfg_if; +use libm::support::{Float, Hexf, hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; -use libm_test::{MathOp, TupleCall}; +use libm_test::{Hex, MathOp, TupleCall}; #[cfg(feature = "build-mpfr")] use rug::az::{self, Az}; @@ -22,10 +23,16 @@ SUBCOMMAND: eval inputs... + x inputs... Evaulate the expression with a given basis. This can be useful for running routines with a debugger, or quickly checking input. Examples: * eval musl sinf 1.234 # print the results of musl sinf(1.234f32) * eval mpfr pow 1.234 2.432 # print the results of mpfr pow(1.234, 2.432) + + print inputs... + p inputs... + For each input, print it in different formats with various floating + point properties (normal, infinite, etc). "; fn main() { @@ -33,7 +40,8 @@ fn main() { let str_args = args.iter().map(|s| s.as_str()).collect::>(); match &str_args.as_slice()[1..] { - ["eval", basis, op, inputs @ ..] => do_eval(basis, op, inputs), + ["eval" | "x", basis, op, inputs @ ..] => do_eval(basis, op, inputs), + ["print" | "p", inputs @ ..] => do_classify(inputs), _ => { println!("{USAGE}\nunrecognized input `{str_args:?}`"); std::process::exit(1); @@ -106,6 +114,66 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { panic!("no operation matching {op}"); } +/// Print basic float information to stdout. +fn do_classify(inputs: &[&str]) { + for s in inputs { + if let Some(s) = s.strip_suffix("f16") { + cfg_if! { + if #[cfg(f16_enabled)] { + let s = s.trim_end_matches("_"); + let x: f16 = parse(&[s], 0); + classify_print(x); + continue; + } else { + panic!("parsing this type requires f16 support: `{s}`"); + } + } + }; + if let Some(s) = s.strip_suffix("f32") { + let s = s.trim_end_matches("_"); + let x: f32 = parse(&[s], 0); + classify_print(x); + continue; + } else if let Some(s) = s.strip_suffix("f64") { + let s = s.trim_end_matches("_"); + let x: f64 = parse(&[s], 0); + classify_print(x); + continue; + } + if let Some(s) = s.strip_suffix("f128") { + cfg_if! { + if #[cfg(all(f128_enabled, feature = "build-mpfr"))] { + let s = s.trim_end_matches("_"); + let x: f128 = parse_rug(&[s], 0); + classify_print(x); + continue; + } else { + panic!("parsing this type requires f128 support and \ + the `build-mpfr` feature: `{s}`"); + } + } + }; + panic!("float type must be specified with a `f*` suffix: `{s}`"); + } +} + +fn classify_print(x: F) +where + F: Float, + F::Int: Hex, +{ + println!("{x:?}"); + println!(" hex: {}", Hexf(x)); + println!(" bits: {}", x.to_bits().hex()); + println!(" nan: {}", x.is_nan()); + println!(" inf: {}", x.is_infinite()); + println!(" normal: {}", !x.is_subnormal()); + println!(" pos: {}", x.is_sign_positive()); + println!(" exp: {} {}", x.ex(), x.ex().hex()); + println!(" exp unbiased: {}", x.exp_unbiased()); + println!(" frac: {} {}", x.frac(), x.frac().hex()); +} + /// Parse a tuple from a space-delimited string. trait ParseTuple { fn parse(input: &[&str]) -> Self; @@ -232,11 +300,11 @@ fn parse(_input: &[&str]) -> Self { }; } +#[cfg(f16_enabled)] +impl_parse_tuple!(f16); impl_parse_tuple!(f32); impl_parse_tuple!(f64); -#[cfg(f16_enabled)] -impl_parse_tuple_via_rug!(f16); #[cfg(f128_enabled)] impl_parse_tuple_via_rug!(f128); diff --git a/library/compiler-builtins/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json index 4f796905b754..6bd395a84b66 100644 --- a/library/compiler-builtins/etc/function-definitions.json +++ b/library/compiler-builtins/etc/function-definitions.json @@ -560,16 +560,32 @@ }, "frexp": { "sources": [ - "libm/src/math/frexp.rs" + "libm/src/math/frexp.rs", + "libm/src/math/generic/frexp.rs" ], "type": "f64" }, "frexpf": { "sources": [ - "libm/src/math/frexpf.rs" + "libm/src/math/frexp.rs", + "libm/src/math/generic/frexp.rs" ], "type": "f32" }, + "frexpf128": { + "sources": [ + "libm/src/math/frexp.rs", + "libm/src/math/generic/frexp.rs" + ], + "type": "f128" + }, + "frexpf16": { + "sources": [ + "libm/src/math/frexp.rs", + "libm/src/math/generic/frexp.rs" + ], + "type": "f16" + }, "hypot": { "sources": [ "libm/src/math/hypot.rs" @@ -584,16 +600,32 @@ }, "ilogb": { "sources": [ + "libm/src/math/generic/ilogb.rs", "libm/src/math/ilogb.rs" ], "type": "f64" }, "ilogbf": { "sources": [ - "libm/src/math/ilogbf.rs" + "libm/src/math/generic/ilogb.rs", + "libm/src/math/ilogb.rs" ], "type": "f32" }, + "ilogbf128": { + "sources": [ + "libm/src/math/generic/ilogb.rs", + "libm/src/math/ilogb.rs" + ], + "type": "f128" + }, + "ilogbf16": { + "sources": [ + "libm/src/math/generic/ilogb.rs", + "libm/src/math/ilogb.rs" + ], + "type": "f16" + }, "j0": { "sources": [ "libm/src/math/j0.rs" diff --git a/library/compiler-builtins/etc/function-list.txt b/library/compiler-builtins/etc/function-list.txt index 1f226c8c0ff3..f7a694d10f95 100644 --- a/library/compiler-builtins/etc/function-list.txt +++ b/library/compiler-builtins/etc/function-list.txt @@ -84,10 +84,14 @@ fmodf128 fmodf16 frexp frexpf +frexpf128 +frexpf16 hypot hypotf ilogb ilogbf +ilogbf128 +ilogbf16 j0 j0f j1 diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 4f65504bd584..8a8c2b0a2ce0 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -9,7 +9,6 @@ license = "MIT OR Apache-2.0" anyhow.workspace = true # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { workspace = true, optional = true } -gungraun = { workspace = true, optional = true } indicatif.workspace = true libm = { workspace = true, default-features = true, features = ["unstable-public-internals"] } libm-macros.workspace = true @@ -20,14 +19,18 @@ rand_chacha.workspace = true rayon.workspace = true rug = { workspace = true, optional = true } +# Really dev dependencies, but those can't be optional +criterion = { workspace = true, optional = true } +gungraun = { workspace = true, optional = true } + [target.'cfg(target_family = "wasm")'.dependencies] getrandom = { workspace = true, features = ["wasm_js"] } +indicatif = { workspace = true, features = ["wasmbind"] } [build-dependencies] rand = { workspace = true, optional = true } [dev-dependencies] -criterion.workspace = true libtest-mimic.workspace = true [features] @@ -43,8 +46,10 @@ build-mpfr = ["dep:rug", "dep:gmp-mpfr-sys"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] -# Enable report generation without bringing in more dependencies by default -benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] +# Config for wall time benchmarks. Plotters and html_reports bring in extra +# deps so are off by default for CI. +benchmarking-reports = ["walltime", "criterion/plotters", "criterion/html_reports"] +walltime = ["dep:criterion"] # Enable icount benchmarks (requires gungraun-runner and valgrind locally) icount = ["dep:gungraun"] @@ -60,6 +65,7 @@ required-features = ["icount"] [[bench]] name = "random" harness = false +required-features = ["walltime"] [[test]] # No harness so that we can skip tests at runtime based on env. Prefixed with diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index fb856d9be451..617e9fb7ad21 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -331,10 +331,14 @@ fn icount_bench_print_hf128(x: f128) -> String { icount_bench_fmodf16_group, icount_bench_fmodf_group, icount_bench_frexp_group, + icount_bench_frexpf128_group, + icount_bench_frexpf16_group, icount_bench_frexpf_group, icount_bench_hypot_group, icount_bench_hypotf_group, icount_bench_ilogb_group, + icount_bench_ilogbf128_group, + icount_bench_ilogbf16_group, icount_bench_ilogbf_group, icount_bench_j0_group, icount_bench_j0f_group, diff --git a/library/compiler-builtins/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm-test/src/f8_impl.rs index 905c7d7fde92..9f19f518e2a3 100644 --- a/library/compiler-builtins/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm-test/src/f8_impl.rs @@ -25,12 +25,16 @@ impl Float for f8 { const NEG_ZERO: Self = Self(0b1_0000_000); const ONE: Self = Self(0b0_0111_000); const NEG_ONE: Self = Self(0b1_0111_000); - const MAX: Self = Self(0b0_1110_111); - const MIN: Self = Self(0b1_1110_111); const INFINITY: Self = Self(0b0_1111_000); const NEG_INFINITY: Self = Self(0b1_1111_000); + const MAX: Self = Self(0b0_1110_111); + const MIN: Self = Self(0b1_1110_111); + const NAN: Self = Self(0b0_1111_100); + const SNAN: Self = Self(0b0_1111_001); const NEG_NAN: Self = Self(0b1_1111_100); + const NEG_SNAN: Self = Self(0b1_1111_001); + const MIN_POSITIVE_NORMAL: Self = Self(1 << Self::SIG_BITS); // FIXME: incorrect values const EPSILON: Self = Self::ZERO; @@ -44,6 +48,7 @@ impl Float for f8 { const SIG_MASK: Self::Int = 0b0_0000_111; const EXP_MASK: Self::Int = 0b0_1111_000; const IMPLICIT_BIT: Self::Int = 0b0_0001_000; + const SIG_TOP_BIT: Self::Int = Self::IMPLICIT_BIT >> 1; fn to_bits(self) -> Self::Int { self.0 diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index 43b28722f2dd..66d7f6a282f6 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -460,7 +460,8 @@ fn fmodf16_cases() -> Vec> { vec![] } -fn frexp_cases() -> Vec> { +#[cfg(f16_enabled)] +fn frexpf16_cases() -> Vec> { vec![] } @@ -468,6 +469,15 @@ fn frexpf_cases() -> Vec> { vec![] } +fn frexp_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn frexpf128_cases() -> Vec> { + vec![] +} + fn hypot_cases() -> Vec> { vec![] } @@ -476,7 +486,8 @@ fn hypotf_cases() -> Vec> { vec![] } -fn ilogb_cases() -> Vec> { +#[cfg(f16_enabled)] +fn ilogbf16_cases() -> Vec> { vec![] } @@ -484,6 +495,15 @@ fn ilogbf_cases() -> Vec> { vec![] } +fn ilogb_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ilogbf128_cases() -> Vec> { + vec![] +} + fn j0_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs index 4ee88946d8ea..09a3766c6678 100644 --- a/library/compiler-builtins/libm-test/src/generate/random.rs +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -5,7 +5,7 @@ use libm::support::Float; use rand::distr::{Alphanumeric, StandardUniform}; use rand::prelude::Distribution; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use super::KnownSize; diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index 85f0a4da4a6e..91130f892b8a 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -162,8 +162,12 @@ fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { fmodf16, frexp, frexpf, + frexpf128, + frexpf16, ilogb, ilogbf, + ilogbf128, + ilogbf16, jn, jnf, ldexp, @@ -324,43 +328,6 @@ fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { } } - impl MpOp for crate::op::[]::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - let exp = this.frexp_mut(); - (prep_retval::(this, Ordering::Equal), exp) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - - // `get_exp` follows `frexp` for `0.5 <= |m| < 1.0`. Adjust the exponent by - // one to scale the significand to `1.0 <= |m| < 2.0`. - this.get_exp().map(|v| v - 1).unwrap_or_else(|| { - if this.is_infinite() { - i32::MAX - } else { - // Zero or NaN - i32::MIN - } - }) - } - } - impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; @@ -505,6 +472,43 @@ fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { } } + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let exp = this.frexp_mut(); + (prep_retval::(this, Ordering::Equal), exp) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + + // `get_exp` follows `frexp` for `0.5 <= |m| < 1.0`. Adjust the exponent by + // one to scale the significand to `1.0 <= |m| < 2.0`. + this.get_exp().map(|v| v - 1).unwrap_or_else(|| { + if this.is_infinite() { + i32::MAX + } else { + // Zero or NaN + i32::MIN + } + }) + } + } + // `ldexp` and `scalbn` are the same for binary floating point, so just forward all // methods. impl MpOp for crate::op::[]::Routine { diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index 5d52da168fe7..e99424414274 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -1,9 +1,10 @@ //! Configuration for skipping or changing the result for individual test cases (inputs) rather //! than ignoring entire tests. +use BaseName as Bn; use CheckBasis::{Mpfr, Musl}; +use Identifier as Id; use libm::support::CastFrom; -use {BaseName as Bn, Identifier as Id}; use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; @@ -222,6 +223,15 @@ fn check_float(input: (f32,), actual: F, expected: F, ctx: &CheckCtx) return XFAIL_NOCHECK; } + // the testing infrastructure doesn't account for allowed ulp in the case of overflow + if matches!(ctx.base_name, BaseName::Lgamma | BaseName::LgammaR) + && input.0 == 4.0850034e36 + && expected.is_infinite() + && actual == F::MAX + { + return XFAIL_NOCHECK; + } + // FIXME(correctness): lgammaf has high relative inaccuracy near its zeroes if matches!(ctx.base_name, BaseName::Lgamma | BaseName::LgammaR) && input.0 > -13.0625 diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index 278274d917b3..f8621a3734a4 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -260,7 +260,7 @@ fn validate_int(actual: I, expected: I, input: Input, ctx: &CheckCtx) Ok(()) } -impl_int!(u32, i32, u64, i64); +impl_int!(u16, i16, u32, i32, u64, i64, u128, i128); /* trait implementations for floats */ @@ -456,3 +456,15 @@ fn validate<'a>( (f32, f32); (f64, f64); ); + +#[cfg(f16_enabled)] +impl_tuples!( + (f16, i32); + (f16, f16); +); + +#[cfg(f128_enabled)] +impl_tuples!( + (f128, i32); + (f128, f128); +); diff --git a/library/compiler-builtins/libm-test/tests/u256.rs b/library/compiler-builtins/libm-test/tests/u256.rs index d1c5cfbcc586..e697945f4797 100644 --- a/library/compiler-builtins/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm-test/tests/u256.rs @@ -10,7 +10,7 @@ use libm_test::bigint_fuzz_iteration_count; use libm_test::generate::random::SEED; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use rug::Assign; use rug::integer::Order; diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 98202d1977dc..28e594dca1f9 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -17,7 +17,7 @@ rust-version = "1.67" [dev-dependencies] # FIXME(msrv): switch to `no-panic.workspace` when possible -no-panic = "0.1.35" +no-panic = "0.1.36" [features] default = ["arch"] diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 0bb669398657..1e6e0beb3e3e 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -202,6 +202,8 @@ pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) { (fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16); (fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16); (fn fmod(x: f16, y: f16) -> (f16); => fmodf16); + (fn frexp(x: f16) -> (f16, i32); => frexpf16); + (fn ilogb(x: f16) -> (i32); => ilogbf16); (fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16); (fn rint(x: f16) -> (f16); => rintf16); (fn round(x: f16) -> (f16); => roundf16); @@ -231,6 +233,8 @@ pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) { (fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128); (fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128); (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); + (fn frexp(x: f128) -> (f128, i32); => frexpf128); + (fn ilogb(x: f128) -> (i32); => ilogbf128); (fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128); (fn rint(x: f128) -> (f128); => rintf128); (fn round(x: f128) -> (f128); => roundf128); diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 08b71587f6de..d4c9e9665200 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -380,7 +380,7 @@ pub fn exp2(mut x: f64) -> f64 { let mut i0 = ui as u32; i0 = i0.wrapping_add(TBLSIZE as u32 / 2); let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; - let ki = div!(ku as i32, TBLSIZE as i32); + let ki = (ku as i32) / TBLSIZE as i32; i0 %= TBLSIZE as u32; let uf = f64::from_bits(ui) - redux; let mut z = x - uf; diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs index c4c1b0435dd2..ead9e6599f1b 100644 --- a/library/compiler-builtins/libm/src/math/fmin_fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -77,9 +77,12 @@ pub fn fmaxf128(x: f128, y: f128) -> f128 { #[cfg(test)] mod tests { use super::*; + use crate::support::hex_float::Hexi; use crate::support::{Float, Hexf}; fn fmin_spec_test(f: impl Fn(F, F) -> F) { + // Note that (YaN, sNaN) and (sNaN, YaN) results differ from 754-2008. This is intentional, + // see comments in the generic implementations. let cases = [ (F::ZERO, F::ZERO, F::ZERO), (F::ZERO, F::ONE, F::ZERO), @@ -88,6 +91,8 @@ fn fmin_spec_test(f: impl Fn(F, F) -> F) { (F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY), (F::ZERO, F::NAN, F::ZERO), (F::ZERO, F::NEG_NAN, F::ZERO), + (F::ZERO, F::SNAN, F::ZERO), + (F::ZERO, F::NEG_SNAN, F::ZERO), (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), (F::NEG_ZERO, F::ONE, F::NEG_ZERO), (F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE), @@ -95,6 +100,8 @@ fn fmin_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY), (F::NEG_ZERO, F::NAN, F::NEG_ZERO), (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::SNAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_SNAN, F::NEG_ZERO), (F::ONE, F::ZERO, F::ZERO), (F::ONE, F::NEG_ZERO, F::NEG_ZERO), (F::ONE, F::ONE, F::ONE), @@ -103,6 +110,8 @@ fn fmin_spec_test(f: impl Fn(F, F) -> F) { (F::ONE, F::NEG_INFINITY, F::NEG_INFINITY), (F::ONE, F::NAN, F::ONE), (F::ONE, F::NEG_NAN, F::ONE), + (F::ONE, F::SNAN, F::ONE), + (F::ONE, F::NEG_SNAN, F::ONE), (F::NEG_ONE, F::ZERO, F::NEG_ONE), (F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE), (F::NEG_ONE, F::ONE, F::NEG_ONE), @@ -111,6 +120,8 @@ fn fmin_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY), (F::NEG_ONE, F::NAN, F::NEG_ONE), (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), + (F::NEG_ONE, F::SNAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_SNAN, F::NEG_ONE), (F::INFINITY, F::ZERO, F::ZERO), (F::INFINITY, F::NEG_ZERO, F::NEG_ZERO), (F::INFINITY, F::ONE, F::ONE), @@ -119,6 +130,8 @@ fn fmin_spec_test(f: impl Fn(F, F) -> F) { (F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), (F::INFINITY, F::NAN, F::INFINITY), (F::INFINITY, F::NEG_NAN, F::INFINITY), + (F::INFINITY, F::SNAN, F::INFINITY), + (F::INFINITY, F::NEG_SNAN, F::INFINITY), (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY), (F::NEG_INFINITY, F::ONE, F::NEG_INFINITY), @@ -127,6 +140,8 @@ fn fmin_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::SNAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_SNAN, F::NEG_INFINITY), (F::NAN, F::ZERO, F::ZERO), (F::NAN, F::NEG_ZERO, F::NEG_ZERO), (F::NAN, F::ONE, F::ONE), @@ -140,6 +155,18 @@ fn fmin_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), (F::NEG_NAN, F::INFINITY, F::INFINITY), (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::SNAN, F::ZERO, F::ZERO), + (F::SNAN, F::NEG_ZERO, F::NEG_ZERO), + (F::SNAN, F::ONE, F::ONE), + (F::SNAN, F::NEG_ONE, F::NEG_ONE), + (F::SNAN, F::INFINITY, F::INFINITY), + (F::SNAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_SNAN, F::ZERO, F::ZERO), + (F::NEG_SNAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_SNAN, F::ONE, F::ONE), + (F::NEG_SNAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_SNAN, F::INFINITY, F::INFINITY), + (F::NEG_SNAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; for (x, y, res) in cases { @@ -147,12 +174,29 @@ fn fmin_spec_test(f: impl Fn(F, F) -> F) { assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); } - // Ordering between zeros and NaNs does not matter + // Ordering between zeros does not matter assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO); assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); - assert!(f(F::NAN, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); + + // Selection between NaNs does not matter, it just must be quiet + assert!(f(F::NAN, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_qnan()); + + // These operations should technically return a qnan, but LLVM optimizes out our + // `* 1.0` canonicalization. + assert!(f(F::NAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NAN, F::SNAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NEG_NAN, F::SNAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NEG_SNAN, F::SNAN).is_nan()); + assert!(f(F::SNAN, F::NAN).is_nan()); + assert!(f(F::SNAN, F::NAN).is_nan()); + assert!(f(F::SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::SNAN, F::NEG_SNAN).is_nan()); } #[test] @@ -186,6 +230,8 @@ fn fmax_spec_test(f: impl Fn(F, F) -> F) { (F::ZERO, F::NEG_INFINITY, F::ZERO), (F::ZERO, F::NAN, F::ZERO), (F::ZERO, F::NEG_NAN, F::ZERO), + (F::ZERO, F::SNAN, F::ZERO), + (F::ZERO, F::NEG_SNAN, F::ZERO), (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), (F::NEG_ZERO, F::ONE, F::ONE), (F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO), @@ -193,6 +239,8 @@ fn fmax_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO), (F::NEG_ZERO, F::NAN, F::NEG_ZERO), (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::SNAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_SNAN, F::NEG_ZERO), (F::ONE, F::ZERO, F::ONE), (F::ONE, F::NEG_ZERO, F::ONE), (F::ONE, F::ONE, F::ONE), @@ -201,6 +249,8 @@ fn fmax_spec_test(f: impl Fn(F, F) -> F) { (F::ONE, F::NEG_INFINITY, F::ONE), (F::ONE, F::NAN, F::ONE), (F::ONE, F::NEG_NAN, F::ONE), + (F::ONE, F::SNAN, F::ONE), + (F::ONE, F::NEG_SNAN, F::ONE), (F::NEG_ONE, F::ZERO, F::ZERO), (F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO), (F::NEG_ONE, F::ONE, F::ONE), @@ -209,6 +259,8 @@ fn fmax_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE), (F::NEG_ONE, F::NAN, F::NEG_ONE), (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), + (F::NEG_ONE, F::SNAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_SNAN, F::NEG_ONE), (F::INFINITY, F::ZERO, F::INFINITY), (F::INFINITY, F::NEG_ZERO, F::INFINITY), (F::INFINITY, F::ONE, F::INFINITY), @@ -217,6 +269,8 @@ fn fmax_spec_test(f: impl Fn(F, F) -> F) { (F::INFINITY, F::NEG_INFINITY, F::INFINITY), (F::INFINITY, F::NAN, F::INFINITY), (F::INFINITY, F::NEG_NAN, F::INFINITY), + (F::INFINITY, F::SNAN, F::INFINITY), + (F::INFINITY, F::NEG_SNAN, F::INFINITY), (F::NEG_INFINITY, F::ZERO, F::ZERO), (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO), (F::NEG_INFINITY, F::ONE, F::ONE), @@ -225,6 +279,8 @@ fn fmax_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::SNAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_SNAN, F::NEG_INFINITY), (F::NAN, F::ZERO, F::ZERO), (F::NAN, F::NEG_ZERO, F::NEG_ZERO), (F::NAN, F::ONE, F::ONE), @@ -238,19 +294,54 @@ fn fmax_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), (F::NEG_NAN, F::INFINITY, F::INFINITY), (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::SNAN, F::ZERO, F::ZERO), + (F::SNAN, F::NEG_ZERO, F::NEG_ZERO), + (F::SNAN, F::ONE, F::ONE), + (F::SNAN, F::NEG_ONE, F::NEG_ONE), + (F::SNAN, F::INFINITY, F::INFINITY), + (F::SNAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_SNAN, F::ZERO, F::ZERO), + (F::NEG_SNAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_SNAN, F::ONE, F::ONE), + (F::NEG_SNAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_SNAN, F::INFINITY, F::INFINITY), + (F::NEG_SNAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; for (x, y, res) in cases { let val = f(x, y); - assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); + assert_biteq!( + val, + res, + "fmax({}, {}) ({}, {})", + Hexf(x), + Hexf(y), + Hexi(x.to_bits()), + Hexi(y.to_bits()), + ); } - // Ordering between zeros and NaNs does not matter + // Ordering between zeros assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO); assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); - assert!(f(F::NAN, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); + + // Selection between NaNs does not matter, it just must be quiet + assert!(f(F::NAN, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_qnan()); + + assert!(f(F::NAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NAN, F::SNAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NEG_NAN, F::SNAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NEG_SNAN, F::SNAN).is_nan()); + assert!(f(F::SNAN, F::NAN).is_nan()); + assert!(f(F::SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::SNAN, F::NEG_SNAN).is_nan()); + assert!(f(F::SNAN, F::SNAN).is_nan()); } #[test] diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs index a3c9c9c3991b..ffc724e3a8d7 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs @@ -69,6 +69,7 @@ pub fn fmaximumf128(x: f128, y: f128) -> f128 { #[cfg(test)] mod tests { use super::*; + use crate::support::hex_float::Hexi; use crate::support::{Float, Hexf}; fn fminimum_spec_test(f: impl Fn(F, F) -> F) { @@ -122,29 +123,63 @@ fn fminimum_spec_test(f: impl Fn(F, F) -> F) { (F::NAN, F::INFINITY, F::NAN), (F::NAN, F::NEG_INFINITY, F::NAN), (F::NAN, F::NAN, F::NAN), + (F::NAN, F::SNAN, F::NAN), ]; for (x, y, res) in cases { let val = f(x, y); - assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); + assert_biteq!( + val, + res, + "fminimum({}, {}) ({}, {})", + Hexf(x), + Hexf(y), + Hexi(x.to_bits()), + Hexi(y.to_bits()), + ); } - // Ordering between NaNs does not matter - assert!(f(F::NAN, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NAN).is_nan()); - assert!(f(F::ZERO, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan()); - assert!(f(F::ONE, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan()); - assert!(f(F::INFINITY, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_NAN, F::ZERO).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan()); - assert!(f(F::NEG_NAN, F::ONE).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan()); - assert!(f(F::NEG_NAN, F::INFINITY).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); + // On platforms where operations only return a single canonical NaN (e.g. RISC-V), the + // result may not exactly match one of the inputs which is fine. + assert!(f(F::NAN, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NAN).is_qnan()); + assert!(f(F::ZERO, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_ZERO, F::NEG_NAN).is_qnan()); + assert!(f(F::ONE, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_ONE, F::NEG_NAN).is_qnan()); + assert!(f(F::INFINITY, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::ZERO).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_ZERO).is_qnan()); + assert!(f(F::NEG_NAN, F::ONE).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_ONE).is_qnan()); + assert!(f(F::NEG_NAN, F::INFINITY).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_qnan()); + + // These operations should technically return a qnan, but LLVM optimizes out our + // `* 1.0` canonicalization. + assert!(f(F::INFINITY, F::SNAN,).is_nan()); + assert!(f(F::NEG_INFINITY, F::SNAN,).is_nan()); + assert!(f(F::NEG_ONE, F::SNAN,).is_nan()); + assert!(f(F::NEG_SNAN, F::INFINITY).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_INFINITY).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_ONE).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_ZERO).is_nan()); + assert!(f(F::NEG_SNAN, F::ONE).is_nan()); + assert!(f(F::NEG_SNAN, F::ZERO).is_nan()); + assert!(f(F::NEG_ZERO, F::SNAN,).is_nan()); + assert!(f(F::ONE, F::SNAN,).is_nan()); + assert!(f(F::SNAN, F::INFINITY,).is_nan()); + assert!(f(F::SNAN, F::NEG_INFINITY,).is_nan()); + assert!(f(F::SNAN, F::NEG_ONE,).is_nan()); + assert!(f(F::SNAN, F::NEG_SNAN,).is_nan()); + assert!(f(F::SNAN, F::NEG_ZERO,).is_nan()); + assert!(f(F::SNAN, F::ONE,).is_nan()); + assert!(f(F::SNAN, F::SNAN,).is_nan()); + assert!(f(F::SNAN, F::ZERO,).is_nan()); + assert!(f(F::ZERO, F::SNAN,).is_nan()); } #[test] @@ -220,29 +255,63 @@ fn fmaximum_spec_test(f: impl Fn(F, F) -> F) { (F::NAN, F::INFINITY, F::NAN), (F::NAN, F::NEG_INFINITY, F::NAN), (F::NAN, F::NAN, F::NAN), + (F::NAN, F::SNAN, F::NAN), ]; for (x, y, res) in cases { let val = f(x, y); - assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); + assert_biteq!( + val, + res, + "fmaximum({}, {}) ({}, {})", + Hexf(x), + Hexf(y), + Hexi(x.to_bits()), + Hexi(y.to_bits()), + ); } - // Ordering between NaNs does not matter - assert!(f(F::NAN, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NAN).is_nan()); - assert!(f(F::ZERO, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan()); - assert!(f(F::ONE, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan()); - assert!(f(F::INFINITY, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_NAN, F::ZERO).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan()); - assert!(f(F::NEG_NAN, F::ONE).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan()); - assert!(f(F::NEG_NAN, F::INFINITY).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); + // On platforms where operations only return a single canonical NaN (e.g. RISC-V), the + // result may not exactly match one of the inputs which is fine. + assert!(f(F::NAN, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NAN).is_qnan()); + assert!(f(F::ZERO, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_ZERO, F::NEG_NAN).is_qnan()); + assert!(f(F::ONE, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_ONE, F::NEG_NAN).is_qnan()); + assert!(f(F::INFINITY, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::ZERO).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_ZERO).is_qnan()); + assert!(f(F::NEG_NAN, F::ONE).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_ONE).is_qnan()); + assert!(f(F::NEG_NAN, F::INFINITY).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_qnan()); + + // These operations should technically return a qnan, but LLVM optimizes out our + // `* 1.0` canonicalization. + assert!(f(F::INFINITY, F::SNAN,).is_nan()); + assert!(f(F::NEG_INFINITY, F::SNAN,).is_nan()); + assert!(f(F::NEG_ONE, F::SNAN,).is_nan()); + assert!(f(F::NEG_SNAN, F::INFINITY).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_INFINITY).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_ONE).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_ZERO).is_nan()); + assert!(f(F::NEG_SNAN, F::ONE).is_nan()); + assert!(f(F::NEG_SNAN, F::ZERO).is_nan()); + assert!(f(F::NEG_ZERO, F::SNAN,).is_nan()); + assert!(f(F::ONE, F::SNAN,).is_nan()); + assert!(f(F::SNAN, F::INFINITY,).is_nan()); + assert!(f(F::SNAN, F::NEG_INFINITY,).is_nan()); + assert!(f(F::SNAN, F::NEG_ONE,).is_nan()); + assert!(f(F::SNAN, F::NEG_SNAN,).is_nan()); + assert!(f(F::SNAN, F::NEG_ZERO,).is_nan()); + assert!(f(F::SNAN, F::ONE,).is_nan()); + assert!(f(F::SNAN, F::SNAN,).is_nan()); + assert!(f(F::SNAN, F::ZERO,).is_nan()); + assert!(f(F::ZERO, F::SNAN,).is_nan()); } #[test] diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs index 612cefe756e3..3157f8a3fee8 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs @@ -69,6 +69,7 @@ pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { #[cfg(test)] mod tests { use super::*; + use crate::support::hex_float::Hexi; use crate::support::{Float, Hexf}; fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { @@ -81,6 +82,8 @@ fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { (F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY), (F::ZERO, F::NAN, F::ZERO), (F::ZERO, F::NEG_NAN, F::ZERO), + (F::ZERO, F::SNAN, F::ZERO), + (F::ZERO, F::NEG_SNAN, F::ZERO), (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), (F::NEG_ZERO, F::ONE, F::NEG_ZERO), @@ -89,6 +92,8 @@ fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY), (F::NEG_ZERO, F::NAN, F::NEG_ZERO), (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::SNAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_SNAN, F::NEG_ZERO), (F::ONE, F::ZERO, F::ZERO), (F::ONE, F::NEG_ZERO, F::NEG_ZERO), (F::ONE, F::ONE, F::ONE), @@ -97,6 +102,8 @@ fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { (F::ONE, F::NEG_INFINITY, F::NEG_INFINITY), (F::ONE, F::NAN, F::ONE), (F::ONE, F::NEG_NAN, F::ONE), + (F::ONE, F::SNAN, F::ONE), + (F::ONE, F::NEG_SNAN, F::ONE), (F::NEG_ONE, F::ZERO, F::NEG_ONE), (F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE), (F::NEG_ONE, F::ONE, F::NEG_ONE), @@ -105,6 +112,8 @@ fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY), (F::NEG_ONE, F::NAN, F::NEG_ONE), (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), + (F::NEG_ONE, F::SNAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_SNAN, F::NEG_ONE), (F::INFINITY, F::ZERO, F::ZERO), (F::INFINITY, F::NEG_ZERO, F::NEG_ZERO), (F::INFINITY, F::ONE, F::ONE), @@ -113,6 +122,8 @@ fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { (F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), (F::INFINITY, F::NAN, F::INFINITY), (F::INFINITY, F::NEG_NAN, F::INFINITY), + (F::INFINITY, F::SNAN, F::INFINITY), + (F::INFINITY, F::NEG_SNAN, F::INFINITY), (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY), (F::NEG_INFINITY, F::ONE, F::NEG_INFINITY), @@ -121,6 +132,8 @@ fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::SNAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_SNAN, F::NEG_INFINITY), (F::NAN, F::ZERO, F::ZERO), (F::NAN, F::NEG_ZERO, F::NEG_ZERO), (F::NAN, F::ONE, F::ONE), @@ -134,17 +147,52 @@ fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), (F::NEG_NAN, F::INFINITY, F::INFINITY), (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::SNAN, F::ZERO, F::ZERO), + (F::SNAN, F::NEG_ZERO, F::NEG_ZERO), + (F::SNAN, F::ONE, F::ONE), + (F::SNAN, F::NEG_ONE, F::NEG_ONE), + (F::SNAN, F::INFINITY, F::INFINITY), + (F::SNAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_SNAN, F::ZERO, F::ZERO), + (F::NEG_SNAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_SNAN, F::ONE, F::ONE), + (F::NEG_SNAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_SNAN, F::INFINITY, F::INFINITY), + (F::NEG_SNAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; for (x, y, expected) in cases { let actual = f(x, y); - assert_biteq!(actual, expected, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + assert_biteq!( + actual, + expected, + "fminimum_num({}, {}) ({}, {})", + Hexf(x), + Hexf(y), + Hexi(x.to_bits()), + Hexi(y.to_bits()), + ); } - // Ordering between NaNs does not matter - assert!(f(F::NAN, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); + // Selection between NaNs does not matter, it just must be quiet + assert!(f(F::NAN, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_qnan()); + + // These operations should technically return a qnan, but LLVM optimizes out our + // `* 1.0` canonicalization. + assert!(f(F::NAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NAN, F::SNAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NEG_NAN, F::SNAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NEG_SNAN, F::SNAN).is_nan()); + assert!(f(F::SNAN, F::NAN).is_nan()); + assert!(f(F::SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::SNAN, F::NEG_SNAN).is_nan()); + assert!(f(F::SNAN, F::SNAN).is_nan()); } #[test] @@ -179,6 +227,8 @@ fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { (F::ZERO, F::NEG_INFINITY, F::ZERO), (F::ZERO, F::NAN, F::ZERO), (F::ZERO, F::NEG_NAN, F::ZERO), + (F::ZERO, F::SNAN, F::ZERO), + (F::ZERO, F::NEG_SNAN, F::ZERO), (F::NEG_ZERO, F::ZERO, F::ZERO), (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), (F::NEG_ZERO, F::ONE, F::ONE), @@ -187,6 +237,8 @@ fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO), (F::NEG_ZERO, F::NAN, F::NEG_ZERO), (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::SNAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_SNAN, F::NEG_ZERO), (F::ONE, F::ZERO, F::ONE), (F::ONE, F::NEG_ZERO, F::ONE), (F::ONE, F::ONE, F::ONE), @@ -195,6 +247,8 @@ fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { (F::ONE, F::NEG_INFINITY, F::ONE), (F::ONE, F::NAN, F::ONE), (F::ONE, F::NEG_NAN, F::ONE), + (F::ONE, F::SNAN, F::ONE), + (F::ONE, F::NEG_SNAN, F::ONE), (F::NEG_ONE, F::ZERO, F::ZERO), (F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO), (F::NEG_ONE, F::ONE, F::ONE), @@ -203,6 +257,8 @@ fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE), (F::NEG_ONE, F::NAN, F::NEG_ONE), (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), + (F::NEG_ONE, F::SNAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_SNAN, F::NEG_ONE), (F::INFINITY, F::ZERO, F::INFINITY), (F::INFINITY, F::NEG_ZERO, F::INFINITY), (F::INFINITY, F::ONE, F::INFINITY), @@ -211,6 +267,8 @@ fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { (F::INFINITY, F::NEG_INFINITY, F::INFINITY), (F::INFINITY, F::NAN, F::INFINITY), (F::INFINITY, F::NEG_NAN, F::INFINITY), + (F::INFINITY, F::SNAN, F::INFINITY), + (F::INFINITY, F::NEG_SNAN, F::INFINITY), (F::NEG_INFINITY, F::ZERO, F::ZERO), (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO), (F::NEG_INFINITY, F::ONE, F::ONE), @@ -219,6 +277,8 @@ fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::SNAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_SNAN, F::NEG_INFINITY), (F::NAN, F::ZERO, F::ZERO), (F::NAN, F::NEG_ZERO, F::NEG_ZERO), (F::NAN, F::ONE, F::ONE), @@ -232,17 +292,52 @@ fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), (F::NEG_NAN, F::INFINITY, F::INFINITY), (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::SNAN, F::ZERO, F::ZERO), + (F::SNAN, F::NEG_ZERO, F::NEG_ZERO), + (F::SNAN, F::ONE, F::ONE), + (F::SNAN, F::NEG_ONE, F::NEG_ONE), + (F::SNAN, F::INFINITY, F::INFINITY), + (F::SNAN, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_SNAN, F::ZERO, F::ZERO), + (F::NEG_SNAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_SNAN, F::ONE, F::ONE), + (F::NEG_SNAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_SNAN, F::INFINITY, F::INFINITY), + (F::NEG_SNAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; for (x, y, expected) in cases { let actual = f(x, y); - assert_biteq!(actual, expected, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + assert_biteq!( + actual, + expected, + "fmaximum_num({}, {}) ({}, {})", + Hexf(x), + Hexf(y), + Hexi(x.to_bits()), + Hexi(y.to_bits()), + ); } - // Ordering between NaNs does not matter - assert!(f(F::NAN, F::NEG_NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NAN).is_nan()); - assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); + // Selection between NaNs does not matter, it just must be quiet + assert!(f(F::NAN, F::NEG_NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NAN).is_qnan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_qnan()); + + // These operations should technically return a qnan, but LLVM optimizes out our + // `* 1.0` canonicalization. + assert!(f(F::NAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NAN, F::SNAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NEG_NAN, F::SNAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_SNAN, F::NEG_SNAN).is_nan()); + assert!(f(F::NEG_SNAN, F::SNAN).is_nan()); + assert!(f(F::SNAN, F::NAN).is_nan()); + assert!(f(F::SNAN, F::NEG_NAN).is_nan()); + assert!(f(F::SNAN, F::NEG_SNAN).is_nan()); + assert!(f(F::SNAN, F::SNAN).is_nan()); } #[test] diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs index 932111eebc95..af38915a3ac6 100644 --- a/library/compiler-builtins/libm/src/math/frexp.rs +++ b/library/compiler-builtins/libm/src/math/frexp.rs @@ -1,21 +1,34 @@ +/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2. +/// +/// That is, `x * 2^p` will represent the input value. +// Placeholder so we can have `frexpf16` in the `Float` trait. +#[cfg(f16_enabled)] +#[cfg_attr(assert_no_panic, no_panic::no_panic)] +pub fn frexpf16(x: f16) -> (f16, i32) { + super::generic::frexp(x) +} + +/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2. +/// +/// That is, `x * 2^p` will represent the input value. +#[cfg_attr(assert_no_panic, no_panic::no_panic)] +pub fn frexpf(x: f32) -> (f32, i32) { + super::generic::frexp(x) +} + +/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2. +/// +/// That is, `x * 2^p` will represent the input value. #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn frexp(x: f64) -> (f64, i32) { - let mut y = x.to_bits(); - let ee = ((y >> 52) & 0x7ff) as i32; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f64::from_bits(0x43f0000000000000); - let (x, e) = frexp(x * x1p64); - return (x, e - 64); - } - return (x, 0); - } else if ee == 0x7ff { - return (x, 0); - } - - let e = ee - 0x3fe; - y &= 0x800fffffffffffff; - y |= 0x3fe0000000000000; - return (f64::from_bits(y), e); + super::generic::frexp(x) +} + +/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2. +/// +/// That is, `x * 2^p` will represent the input value. +#[cfg(f128_enabled)] +#[cfg_attr(assert_no_panic, no_panic::no_panic)] +pub fn frexpf128(x: f128) -> (f128, i32) { + super::generic::frexp(x) } diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs deleted file mode 100644 index 904bf14f7b8e..000000000000 --- a/library/compiler-builtins/libm/src/math/frexpf.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[cfg_attr(assert_no_panic, no_panic::no_panic)] -pub fn frexpf(x: f32) -> (f32, i32) { - let mut y = x.to_bits(); - let ee: i32 = ((y >> 23) & 0xff) as i32; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f32::from_bits(0x5f800000); - let (x, e) = frexpf(x * x1p64); - return (x, e - 64); - } else { - return (x, 0); - } - } else if ee == 0xff { - return (x, 0); - } - - let e = ee - 0x7e; - y &= 0x807fffff; - y |= 0x3f000000; - (f32::from_bits(y), e) -} diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 1072ba7c29b6..5584f6503ef5 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -46,7 +46,7 @@ pub fn ceil_status(x: F) -> FpResult { F::from_bits(ix) } else { // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). - if ix & F::SIG_MASK == F::Int::ZERO { + if ix & !F::SIGN_MASK == F::Int::ZERO { status = Status::OK; } else { status = Status::INEXACT; @@ -72,103 +72,83 @@ mod tests { use super::*; use crate::support::Hexf; - /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [ - F::ZERO, - F::ONE, - F::NEG_ONE, - F::NEG_ZERO, - F::INFINITY, - F::NEG_INFINITY, - ]; - - for x in roundtrip { - let FpResult { val, status } = ceil_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = ceil_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } + macro_rules! cases { + ($f:ty) => { + [ + // roundtrip + (0.0, 0.0, Status::OK), + (-0.0, -0.0, Status::OK), + (1.0, 1.0, Status::OK), + (-1.0, -1.0, Status::OK), + (<$f>::INFINITY, <$f>::INFINITY, Status::OK), + (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), + // with rounding + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.5, 1.0, Status::INEXACT), + (-0.5, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.5, 2.0, Status::INEXACT), + (-1.5, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ] + }; } - /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + #[track_caller] + fn check(cases: &[(F, F, Status)]) { + for &(x, exp_res, exp_stat) in cases { + let FpResult { val, status } = ceil_status(x); + assert_biteq!(val, exp_res, "{x:?} {}", Hexf(x)); + assert_eq!( + status, + exp_stat, + "{x:?} {} -> {exp_res:?} {}", + Hexf(x), + Hexf(exp_res) + ); + } + } #[test] #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); + fn check_f16() { + check::(&cases!(f16)); + check::(&[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ]); } #[test] - fn sanity_check_f32() { - assert_eq!(ceil(1.1f32), 2.0); - assert_eq!(ceil(2.9f32), 3.0); + fn check_f32() { + check::(&cases!(f32)); + check::(&[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ]); } #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(ceil(1.1f64), 2.0); - assert_eq!(ceil(2.9f64), 3.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); + fn check_f64() { + check::(&cases!(f64)); + check::(&[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ]); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); + check::(&cases!(f128)); + check::(&[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ]); } } diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index e6dfd8866a42..7045229c0c75 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -26,7 +26,6 @@ pub fn floor_status(x: F) -> FpResult { return FpResult::ok(x); } - let status; let res = if e >= 0 { // |x| >= 1.0 let m = F::SIG_MASK >> e.unsigned(); @@ -35,9 +34,6 @@ pub fn floor_status(x: F) -> FpResult { return FpResult::ok(x); } - // Otherwise, raise an inexact exception. - status = Status::INEXACT; - if x.is_sign_negative() { ix += m; } @@ -45,26 +41,22 @@ pub fn floor_status(x: F) -> FpResult { ix &= !m; F::from_bits(ix) } else { - // |x| < 1.0, raise an inexact exception since truncation will happen. - if ix & F::SIG_MASK == F::Int::ZERO { - status = Status::OK; - } else { - status = Status::INEXACT; + // |x| < 1.0, zero or inexact with truncation + + if (ix & !F::SIGN_MASK) == F::Int::ZERO { + return FpResult::ok(x); } if x.is_sign_positive() { // 0.0 <= x < 1.0; rounding down goes toward +0.0. F::ZERO - } else if ix << 1 != zero { + } else { // -1.0 < x < 0.0; rounding down goes toward -1.0. F::NEG_ONE - } else { - // -0.0 remains unchanged - x } }; - FpResult::new(res, status) + FpResult::new(res, Status::INEXACT) } #[cfg(test)] @@ -72,86 +64,83 @@ mod tests { use super::*; use crate::support::Hexf; - /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [ - F::ZERO, - F::ONE, - F::NEG_ONE, - F::NEG_ZERO, - F::INFINITY, - F::NEG_INFINITY, - ]; - - for x in roundtrip { - let FpResult { val, status } = floor_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = floor_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } + macro_rules! cases { + ($f:ty) => { + [ + // roundtrip + (0.0, 0.0, Status::OK), + (-0.0, -0.0, Status::OK), + (1.0, 1.0, Status::OK), + (-1.0, -1.0, Status::OK), + (<$f>::INFINITY, <$f>::INFINITY, Status::OK), + (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), + // with rounding + (0.1, 0.0, Status::INEXACT), + (-0.1, -1.0, Status::INEXACT), + (0.5, 0.0, Status::INEXACT), + (-0.5, -1.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -2.0, Status::INEXACT), + (1.5, 1.0, Status::INEXACT), + (-1.5, -2.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ] + }; } - /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ + #[track_caller] + fn check(cases: &[(F, F, Status)]) { + for &(x, exp_res, exp_stat) in cases { + let FpResult { val, status } = floor_status(x); + assert_biteq!(val, exp_res, "{x:?} {}", Hexf(x)); + assert_eq!( + status, + exp_stat, + "{x:?} {} -> {exp_res:?} {}", + Hexf(x), + Hexf(exp_res) + ); + } + } #[test] #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); + fn check_f16() { + check::(&cases!(f16)); + check::(&[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ]); } #[test] - fn sanity_check_f32() { - assert_eq!(floor(0.5f32), 0.0); - assert_eq!(floor(1.1f32), 1.0); - assert_eq!(floor(2.9f32), 2.0); + fn check_f32() { + check::(&cases!(f32)); + check::(&[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ]); } #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -1.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -2.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(floor(1.1f64), 1.0); - assert_eq!(floor(2.9f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -1.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -2.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - ]; - spec_test::(&cases); + fn check_f64() { + check::(&cases!(f64)); + check::(&[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ]); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); + check::(&cases!(f128)); + check::(&[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ]); } } diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index b05804704d03..bdd46cc38a81 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -8,11 +8,15 @@ //! - Otherwise, either `x` or `y`, canonicalized //! - -0.0 and +0.0 may be disregarded (unlike newer operations) //! -//! Excluded from our implementation is sNaN handling. +//! We do not treat sNaN and qNaN differently; even though IEEE technically requires this, (a call +//! with sNaN should return qNaN rather than the other result), it breaks associativity so isn't +//! desired behavior. C23 does not differentiate between sNaN and qNaN, so we do not either. More +//! on the problems with `minNum` [here][minnum-removal]. //! -//! More on the differences: [link]. +//! IEEE also specifies that a sNaN in either argument should signal invalid, but we do not +//! implement this. //! -//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf +//! [minnum-removal]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf use crate::support::Float; diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 55a031e18ee8..1fa48f964804 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -7,7 +7,8 @@ //! - +0.0 if x and y are zero with opposite signs //! - qNaN if either operation is NaN //! -//! Excluded from our implementation is sNaN handling. +//! Note that the IEEE 754-2019 specifies that a sNaN in either argument should signal invalid, +//! but we do not implement this. use crate::support::Float; diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 2dc60b2d237f..c7ca50a89dc8 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -9,7 +9,8 @@ //! - Non-NaN if one operand is NaN //! - qNaN if both operands are NaNx //! -//! Excluded from our implementation is sNaN handling. +//! Note that the IEEE 754-2019 specifies that a sNaN in either argument should signal invalid, +//! but we do not implement this. use crate::support::Float; diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index e2245bf9e137..e7755e82345c 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -8,11 +8,15 @@ //! - Otherwise, either `x` or `y`, canonicalized //! - -0.0 and +0.0 may be disregarded (unlike newer operations) //! -//! Excluded from our implementation is sNaN handling. +//! We do not treat sNaN and qNaN differently; even though IEEE technically requires this, (a call +//! with sNaN should return qNaN rather than the other result), it breaks associativity so isn't +//! desired behavior. C23 does not differentiate between sNaN and qNaN, so we do not either. More +//! on the problems with `minNum` [here][minnum-removal]. //! -//! More on the differences: [link]. +//! IEEE also specifies that a sNaN in either argument should signal invalid, but we do not +//! implement this. //! -//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf +//! [minnum-removal]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf use crate::support::Float; diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index aa68b1291d42..82e72d644064 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -7,7 +7,8 @@ //! - -0.0 if x and y are zero with opposite signs //! - qNaN if either operation is NaN //! -//! Excluded from our implementation is sNaN handling. +//! Note that the IEEE 754-2019 specifies that a sNaN in either argument should signal invalid, +//! but we do not implement this. use crate::support::Float; diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 265bd4605ce3..5b5271b123ba 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -9,7 +9,8 @@ //! - Non-NaN if one operand is NaN //! - qNaN if both operands are NaNx //! -//! Excluded from our implementation is sNaN handling. +//! Note that the IEEE 754-2019 specifies that a sNaN in either argument should signal invalid, +//! but we do not implement this. use crate::support::Float; diff --git a/library/compiler-builtins/libm/src/math/generic/frexp.rs b/library/compiler-builtins/libm/src/math/generic/frexp.rs new file mode 100644 index 000000000000..cbf5b100ba0f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/frexp.rs @@ -0,0 +1,26 @@ +use super::super::{CastFrom, Float}; + +#[inline] +pub fn frexp(x: F) -> (F, i32) { + let mut ix = x.to_bits(); + let mut ee = x.ex() as i32; + + if ee == 0 { + if x == F::ZERO { + return (x, 0); + } + + // Subnormals, needs to be normalized first + ix &= F::SIG_MASK; + (ee, ix) = F::normalize(ix); + ix |= x.to_bits() & F::SIGN_MASK; + } else if ee == F::EXP_SAT as i32 { + // inf or NaN + return (x, 0); + } + + let e = ee - (F::EXP_BIAS as i32 - 1); + ix &= F::SIGN_MASK | F::SIG_MASK; + ix |= F::Int::cast_from(F::EXP_BIAS - 1) << F::SIG_BITS; + (F::from_bits(ix), e) +} diff --git a/library/compiler-builtins/libm/src/math/generic/ilogb.rs b/library/compiler-builtins/libm/src/math/generic/ilogb.rs new file mode 100644 index 000000000000..02a7d6b30b10 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/ilogb.rs @@ -0,0 +1,35 @@ +use super::super::{Float, MinInt}; + +const FP_ILOGBNAN: i32 = i32::MIN; +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +#[inline] +pub fn ilogb(x: F) -> i32 { + let zero = F::Int::ZERO; + let mut i = x.to_bits(); + let e = x.ex() as i32; + + if e == 0 { + i <<= F::EXP_BITS + 1; + if i == F::Int::ZERO { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -(F::EXP_BIAS as i32); + while i >> (F::BITS - 1) == zero { + e -= 1; + i <<= 1; + } + e + } else if e == F::EXP_SAT as i32 { + force_eval!(0.0 / 0.0); + if i << (F::EXP_BITS + 1) != zero { + FP_ILOGBNAN + } else { + i32::MAX + } + } else { + e - F::EXP_BIAS as i32 + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 9d497a03f544..114fcddf516e 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -15,6 +15,8 @@ mod fminimum; mod fminimum_num; mod fmod; +mod frexp; +mod ilogb; mod rint; mod round; mod scalbn; @@ -35,6 +37,8 @@ pub use fminimum::fminimum; pub use fminimum_num::fminimum_num; pub use fmod::fmod; +pub use frexp::frexp; +pub use ilogb::ilogb; pub use rint::rint_round; pub use round::round; pub use scalbn::scalbn; diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index d5b444d15dfc..7f18eb42e884 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -10,38 +10,34 @@ pub fn trunc(x: F) -> F { #[inline] pub fn trunc_status(x: F) -> FpResult { - let mut xi: F::Int = x.to_bits(); + let xi: F::Int = x.to_bits(); let e: i32 = x.exp_unbiased(); - // C1: The represented value has no fractional part, so no truncation is needed + // The represented value has no fractional part, so no truncation is needed if e >= F::SIG_BITS as i32 { return FpResult::ok(x); } - let mask = if e < 0 { - // C2: If the exponent is negative, the result will be zero so we mask out everything + let clear_mask = if e < 0 { + // If the exponent is negative, the result will be zero so we clear everything // except the sign. - F::SIGN_MASK + !F::SIGN_MASK } else { - // C3: Otherwise, we mask out the last `e` bits of the significand. - !(F::SIG_MASK >> e.unsigned()) + // Otherwise, we keep `e` fractional bits and clear the rest. + F::SIG_MASK >> e.unsigned() }; - // C4: If the to-be-masked-out portion is already zero, we have an exact result - if (xi & !mask) == IntTy::::ZERO { - return FpResult::ok(x); - } - - // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the - // result, and return. - - let status = if xi & F::SIG_MASK == F::Int::ZERO { + let cleared = xi & clear_mask; + let status = if cleared == IntTy::::ZERO { + // If the to-be-zeroed portion is already zero, we have an exact result. Status::OK } else { + // Otherwise the result is inexact and we will truncate, so indicate `FE_INEXACT`. Status::INEXACT }; - xi &= mask; - FpResult::new(F::from_bits(xi), status) + + // Now zero the bits we need to truncate and return. + FpResult::new(F::from_bits(xi ^ cleared), status) } #[cfg(test)] @@ -49,100 +45,83 @@ mod tests { use super::*; use crate::support::Hexf; - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [ - F::ZERO, - F::ONE, - F::NEG_ONE, - F::NEG_ZERO, - F::INFINITY, - F::NEG_INFINITY, - ]; - - for x in roundtrip { - let FpResult { val, status } = trunc_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = trunc_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } + macro_rules! cases { + ($f:ty) => { + [ + // roundtrip + (0.0, 0.0, Status::OK), + (-0.0, -0.0, Status::OK), + (1.0, 1.0, Status::OK), + (-1.0, -1.0, Status::OK), + (<$f>::INFINITY, <$f>::INFINITY, Status::OK), + (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), + // with rounding + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.5, 0.0, Status::INEXACT), + (-0.5, -0.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.5, 1.0, Status::INEXACT), + (-1.5, -1.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ] + }; } - /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ + #[track_caller] + fn check(cases: &[(F, F, Status)]) { + for &(x, exp_res, exp_stat) in cases { + let FpResult { val, status } = trunc_status(x); + assert_biteq!(val, exp_res, "{x:?} {}", Hexf(x)); + assert_eq!( + status, + exp_stat, + "{x:?} {} -> {exp_res:?} {}", + Hexf(x), + Hexf(exp_res) + ); + } + } #[test] #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); + fn check_f16() { + check::(&cases!(f16)); + check::(&[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ]); } #[test] - fn sanity_check_f32() { - assert_eq!(trunc(0.5f32), 0.0); - assert_eq!(trunc(1.1f32), 1.0); - assert_eq!(trunc(2.9f32), 2.0); + fn check_f32() { + check::(&cases!(f32)); + check::(&[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ]); } #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - - assert_biteq!(trunc(1.1f32), 1.0); - assert_biteq!(trunc(1.1f64), 1.0); - - // C1 - assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23")); - assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52")); - assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23")); - assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52")); - - // C2 - assert_biteq!(trunc(hf32!("0x1p-1")), 0.0); - assert_biteq!(trunc(hf64!("0x1p-1")), 0.0); - assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); - assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(trunc(1.1f64), 1.0); - assert_eq!(trunc(2.9f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); + fn check_f64() { + check::(&cases!(f64)); + check::(&[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ]); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); + check::(&cases!(f128)); + check::(&[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ]); } } diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index ef774f6ad3a6..4c3f0a6aa045 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -1,32 +1,25 @@ -const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; -const FP_ILOGB0: i32 = FP_ILOGBNAN; +/// Extract the binary exponent of `x`. +#[cfg(f16_enabled)] +#[cfg_attr(assert_no_panic, no_panic::no_panic)] +pub fn ilogbf16(x: f16) -> i32 { + super::generic::ilogb(x) +} +/// Extract the binary exponent of `x`. +#[cfg_attr(assert_no_panic, no_panic::no_panic)] +pub fn ilogbf(x: f32) -> i32 { + super::generic::ilogb(x) +} + +/// Extract the binary exponent of `x`. #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn ilogb(x: f64) -> i32 { - let mut i: u64 = x.to_bits(); - let e = ((i >> 52) & 0x7ff) as i32; - - if e == 0 { - i <<= 12; - if i == 0 { - force_eval!(0.0 / 0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x3ff; - while (i >> 63) == 0 { - e -= 1; - i <<= 1; - } - e - } else if e == 0x7ff { - force_eval!(0.0 / 0.0); - if (i << 12) != 0 { - FP_ILOGBNAN - } else { - i32::MAX - } - } else { - e - 0x3ff - } + super::generic::ilogb(x) +} + +/// Extract the binary exponent of `x`. +#[cfg(f128_enabled)] +#[cfg_attr(assert_no_panic, no_panic::no_panic)] +pub fn ilogbf128(x: f128) -> i32 { + super::generic::ilogb(x) } diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs deleted file mode 100644 index 5b0cb46ec558..000000000000 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ /dev/null @@ -1,28 +0,0 @@ -const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; -const FP_ILOGB0: i32 = FP_ILOGBNAN; - -#[cfg_attr(assert_no_panic, no_panic::no_panic)] -pub fn ilogbf(x: f32) -> i32 { - let mut i = x.to_bits(); - let e = ((i >> 23) & 0xff) as i32; - - if e == 0 { - i <<= 9; - if i == 0 { - force_eval!(0.0 / 0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x7f; - while (i >> 31) == 0 { - e -= 1; - i <<= 1; - } - e - } else if e == 0xff { - force_eval!(0.0 / 0.0); - if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX } - } else { - e - 0x7f - } -} diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs index 38eb270f6839..f3c6fef1464d 100644 --- a/library/compiler-builtins/libm/src/math/lgamma_r.rs +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -79,6 +79,7 @@ */ use super::{floor, k_cos, k_sin, log}; +use crate::support::unchecked_div_i32; const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ @@ -152,7 +153,8 @@ fn sin_pi(mut x: f64) -> f64 { x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as i32; - n = div!(n + 1, 2); + // SAFETY: nonzero divisor, nonnegative dividend (`n < 8`). + n = unsafe { unchecked_div_i32(n + 1, 2) }; x -= (n as f64) * 0.5; x *= PI; diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs index a0b6a678a670..5c087f14d7df 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf_r.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -14,6 +14,7 @@ */ use super::{floorf, k_cosf, k_sinf, logf}; +use crate::support::unchecked_div_isize; const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ @@ -88,7 +89,8 @@ fn sin_pi(mut x: f32) -> f32 { x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as isize; - n = div!(n + 1, 2); + // SAFETY: nonzero divisor, nonnegative dividend (`n < 8`). + n = unsafe { unchecked_div_isize(n + 1, 2) }; y = (x as f64) - (n as f64) * 0.5; y *= 3.14159265358979323846; match n { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 8eecfe5667d1..4bee4478164a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -58,24 +58,6 @@ macro_rules! i { }; } -// Temporary macro to avoid panic codegen for division (in debug mode too). At -// the time of this writing this is only used in a few places, and once -// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and -// the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(intrinsics_enabled)))] -macro_rules! div { - ($a:expr, $b:expr) => { - $a / $b - }; -} - -#[cfg(all(not(debug_assertions), intrinsics_enabled))] -macro_rules! div { - ($a:expr, $b:expr) => { - unsafe { core::intrinsics::unchecked_div($a, $b) } - }; -} - // `support` may be public for testing #[macro_use] #[cfg(feature = "unstable-public-internals")] @@ -166,11 +148,9 @@ macro_rules! div { mod fminimum_fmaximum_num; mod fmod; mod frexp; -mod frexpf; mod hypot; mod hypotf; mod ilogb; -mod ilogbf; mod j0; mod j0f; mod j1; @@ -260,12 +240,10 @@ macro_rules! div { pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; pub use self::fmod::{fmod, fmodf}; -pub use self::frexp::frexp; -pub use self::frexpf::frexpf; +pub use self::frexp::{frexp, frexpf}; pub use self::hypot::hypot; pub use self::hypotf::hypotf; -pub use self::ilogb::ilogb; -pub use self::ilogbf::ilogbf; +pub use self::ilogb::{ilogb, ilogbf}; pub use self::j0::{j0, y0}; pub use self::j0f::{j0f, y0f}; pub use self::j1::{j1, y1}; @@ -326,6 +304,8 @@ macro_rules! div { pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; pub use self::fmod::fmodf16; + pub use self::frexp::frexpf16; + pub use self::ilogb::ilogbf16; pub use self::ldexp::ldexpf16; pub use self::rint::rintf16; pub use self::round::roundf16; @@ -353,6 +333,8 @@ macro_rules! div { pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; pub use self::fmod::fmodf128; + pub use self::frexp::frexpf128; + pub use self::ilogb::ilogbf128; pub use self::ldexp::ldexpf128; pub use self::rint::rintf128; pub use self::round::roundf128; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index bb2c532916b2..841a51b84c27 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,4 +1,6 @@ #![allow(unused_unsafe)] +// FIXME(clippy): the suggested fix is bad but the code as-written could be better +#![allow(clippy::explicit_counter_loop)] /* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ /* * ==================================================== @@ -255,7 +257,7 @@ extern "C" fn floor(x: f64) -> f64 { /* determine jx,jv,q0, note that 3>q0 */ let jx = nx - 1; - let mut jv = div!(e0 - 3, 24); + let mut jv = (e0 - 3) / 24; if jv < 0 { jv = 0; } diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index c4beb5267f28..1d15abe54306 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -122,8 +122,6 @@ pub fn sincosf(x: f32) -> (f32, f32) { } } -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::sincosf; diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index 0c32f445c136..2eafed50a275 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -261,8 +261,6 @@ fn shr_u256() { #[test] #[should_panic] #[cfg(debug_assertions)] -// FIXME(ppc): ppc64le seems to have issues with `should_panic` tests. -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] fn shr_u256_overflow() { // Like regular shr, panic on overflow with debug assertions let _ = u256::MAX >> 256; diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs index 53ae32f658db..0f89799ed918 100644 --- a/library/compiler-builtins/libm/src/math/support/env.rs +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -49,10 +49,14 @@ pub enum Round { } /// IEEE 754 exception status flags. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct Status(u8); impl Status { + /* Note that if we ever store/load this to/from floating point control status registers, it + * may be worth making these values platform-dependent to line up with register layout + * to avoid bit swapping. For the time being, this isn't a concern. */ + /// Default status indicating no errors. pub const OK: Self = Self(0); @@ -74,7 +78,7 @@ impl Status { /// result is -inf. /// `x / y` when `x != 0.0` and `y == 0.0`, #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); + pub const DIVIDE_BY_ZERO: Self = Self(1 << 1); /// The result exceeds the maximum finite value. /// @@ -82,14 +86,14 @@ impl Status { /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and /// `Negative` round to signed maximum finite in one direction, signed infinity in the other. #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const OVERFLOW: Self = Self(1 << 3); + pub const OVERFLOW: Self = Self(1 << 2); /// The result is subnormal and lost precision. - pub const UNDERFLOW: Self = Self(1 << 4); + pub const UNDERFLOW: Self = Self(1 << 3); /// The finite-precision result does not match that of infinite precision, and the reason /// is not represented by one of the other flags. - pub const INEXACT: Self = Self(1 << 5); + pub const INEXACT: Self = Self(1 << 4); /// True if `UNDERFLOW` is set. #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] @@ -128,3 +132,38 @@ pub(crate) const fn with(self, rhs: Self) -> Self { Self(self.0 | rhs.0) } } + +#[cfg(any(test, feature = "unstable-public-internals"))] +impl core::fmt::Debug for Status { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // shift -> flag map + let names = &[ + "INVALID", + "DIVIDE_BY_ZERO", + "OVERFLOW", + "UNDERFLOW", + "INEXACT", + ]; + + write!(f, "Status(")?; + let mut any = false; + for shift in 0..u8::BITS { + if self.0 & (1 << shift) != 0 { + if any { + write!(f, " | ")?; + } + match names.get(shift as usize) { + Some(name) => write!(f, "{name}")?, + None => write!(f, "UNKNOWN(1 << {shift})")?, + } + any = true; + } + } + + if !any { + write!(f, "OK")?; + } + write!(f, ")")?; + Ok(()) + } +} diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 60c8bfca5165..944546601c9c 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -2,6 +2,12 @@ use super::int_traits::{CastFrom, Int, MinInt}; +/// Whether MIPS sNaN/qNaNs should be used. +/// +/// Note that MIPS is doing some general migration here, though this is only available on (rare) +/// modern MIPS hardware per discussion at . +const MIPS_NAN: bool = cfg!(target_arch = "mips") || cfg!(target_arch = "mips64"); + /// Trait for some basic operations on floats // #[allow(dead_code)] #[allow(dead_code)] // Some constants are only used with tests @@ -34,10 +40,16 @@ pub trait Float: const NEG_ONE: Self; const INFINITY: Self; const NEG_INFINITY: Self; - const NAN: Self; - const NEG_NAN: Self; const MAX: Self; const MIN: Self; + + /// Quiet NaN. + const NAN: Self; + /// Signaling NaN. + const SNAN: Self; + const NEG_NAN: Self; + const NEG_SNAN: Self; + const EPSILON: Self; const PI: Self; const NEG_PI: Self; @@ -84,6 +96,9 @@ pub trait Float: /// The implicit bit of the float format const IMPLICIT_BIT: Self::Int; + /// A mask for the top bit of the significand, useful for NaN ops. + const SIG_TOP_BIT: Self::Int; + /// Returns `self` transmuted to `Self::Int` fn to_bits(self) -> Self::Int; @@ -116,6 +131,24 @@ fn eq_repr(self, rhs: Self) -> bool { /// Returns true if the value is NaN. fn is_nan(self) -> bool; + fn is_qnan(self) -> bool { + if !self.is_nan() { + return false; + } + + let top = self.to_bits() & Self::SIG_TOP_BIT; + + if MIPS_NAN { + top == Self::Int::ZERO + } else { + top != Self::Int::ZERO + } + } + + fn is_snan(self) -> bool { + self.is_nan() && !self.is_qnan() + } + /// Returns true if the value is +inf or -inf. fn is_infinite(self) -> bool; @@ -176,7 +209,6 @@ fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { fn fma(self, y: Self, z: Self) -> Self; /// Returns (normalized exponent, normalized significand) - #[allow(dead_code)] fn normalize(significand: Self::Int) -> (i32, Self::Int); /// Returns a number that represents the sign of self. @@ -224,13 +256,28 @@ impl Float for $ty { const NEG_ONE: Self = -1.0; const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; - const NAN: Self = Self::NAN; - // NAN isn't guaranteed to be positive but it usually is. We only use this for - // tests. - const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); const MAX: Self = -Self::MIN; // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); + + // The default NaN seems to set one of the top two significand bits on most + // platforms (sNaN vs. qNaN). For mips, the significand is all 1s (with the + // exception of the signaling bit). + const NAN: Self = $from_bits(if MIPS_NAN { + Self::EXP_MASK | (Self::SIG_TOP_BIT - 1) + } else { + Self::EXP_MASK | Self::SIG_TOP_BIT + }); + const SNAN: Self = $from_bits(if MIPS_NAN { + Self::EXP_MASK | Self::SIG_MASK + } else { + Self::EXP_MASK | (Self::SIG_TOP_BIT >> 1) + }); + // NAN isn't guaranteed to be positive but it usually is. We only use these for + // tests. + const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); + const NEG_SNAN: Self = $from_bits($to_bits(Self::SNAN) | Self::SIGN_MASK); + const EPSILON: Self = <$ty>::EPSILON; // Exponent is a 1 in the LSB @@ -247,6 +294,7 @@ impl Float for $ty { const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; + const SIG_TOP_BIT: Self::Int = Self::IMPLICIT_BIT >> 1; fn to_bits(self) -> Self::Int { self.to_bits() @@ -295,10 +343,7 @@ fn fma(self, y: Self, z: Self) -> Self { } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) + (1i32.wrapping_sub(shift as i32), significand << shift) } } }; @@ -454,6 +499,17 @@ fn check_f16() { assert_eq!(f16::EXP_MAX, 15); assert_eq!(f16::EXP_MIN, -14); assert_eq!(f16::EXP_MIN_SUBNORM, -24); + assert_biteq!(f16::NAN, ::NAN); + // Value of NAN and FLT16_SNAN in C. We don't strictly need to match up, but it is good to + // be aware if there are platforms where we don't. + if MIPS_NAN { + assert_biteq!(f16::NAN, f16::from_bits(0x7fbf)); + assert_biteq!(f16::SNAN, f16::from_bits(0x7fff)); + } else { + assert_biteq!(f16::NAN, f16::from_bits(0x7e00)); + assert_biteq!(f16::SNAN, f16::from_bits(0x7d00)); + } + assert!(f16::NAN.is_qnan()); // `exp_unbiased` assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); @@ -480,6 +536,21 @@ fn check_f32() { assert_eq!(f32::EXP_MAX, 127); assert_eq!(f32::EXP_MIN, -126); assert_eq!(f32::EXP_MIN_SUBNORM, -149); + assert_biteq!(f32::NAN, ::NAN); + // Value of NAN and FLT_SNAN in C. We don't strictly need to match up, but it is good to + // be aware if there are platforms where we don't. + if MIPS_NAN { + assert_biteq!(f32::NAN, f32::from_bits(0x7fbfffff)); + assert_biteq!(f32::SNAN, f32::from_bits(0x7fffffff)); + } else { + assert_biteq!(f32::NAN, f32::from_bits(0x7fc00000)); + assert_biteq!(f32::SNAN, f32::from_bits(0x7fa00000)); + } + assert!(f32::NAN.is_qnan()); + // FIXME(rust-lang/rust#115567): x87 use in `is_snan` quiets the sNaN + if !cfg!(x86_no_sse) { + assert!(f32::SNAN.is_snan()); + } // `exp_unbiased` assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); @@ -510,6 +581,21 @@ fn check_f64() { assert_eq!(f64::EXP_MAX, 1023); assert_eq!(f64::EXP_MIN, -1022); assert_eq!(f64::EXP_MIN_SUBNORM, -1074); + assert_biteq!(f64::NAN, ::NAN); + // Value of NAN and DBL_SNAN in C. We don't strictly need to match up, but it is good to + // be aware if there are platforms where we don't. + if MIPS_NAN { + assert_biteq!(f64::NAN, f64::from_bits(0x7ff7ffffffffffff)); + assert_biteq!(f64::SNAN, f64::from_bits(0x7fffffffffffffff)); + } else { + assert_biteq!(f64::NAN, f64::from_bits(0x7ff8000000000000)); + assert_biteq!(f64::SNAN, f64::from_bits(0x7ff4000000000000)); + } + assert!(f64::NAN.is_qnan()); + // FIXME(rust-lang/rust#115567): x87 use in `is_snan` quiets the sNaN + if !cfg!(x86_no_sse) { + assert!(f64::SNAN.is_snan()); + } // `exp_unbiased` assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); @@ -541,6 +627,30 @@ fn check_f128() { assert_eq!(f128::EXP_MAX, 16383); assert_eq!(f128::EXP_MIN, -16382); assert_eq!(f128::EXP_MIN_SUBNORM, -16494); + assert_biteq!(f128::NAN, ::NAN); + // Value of NAN and FLT128_SNAN in C. We don't strictly need to match up, but it is good to + // be aware if there are platforms where we don't. + if MIPS_NAN { + assert_biteq!( + f128::NAN, + f128::from_bits(0x7fff7fffffffffffffffffffffffffff) + ); + assert_biteq!( + f128::SNAN, + f128::from_bits(0x7fffffffffffffffffffffffffffffff) + ); + } else { + assert_biteq!( + f128::NAN, + f128::from_bits(0x7fff8000000000000000000000000000) + ); + assert_biteq!( + f128::SNAN, + f128::from_bits(0x7fff4000000000000000000000000000) + ); + } + assert!(f128::NAN.is_qnan()); + assert!(f128::SNAN.is_snan()); // `exp_unbiased` assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 2f9369e50441..5be0d3159de3 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -328,7 +328,7 @@ const fn hex_digit(c: u8) -> Option { mod hex_fmt { use core::fmt; - use crate::support::Float; + use crate::support::{Float, Int}; /// Format a floating point number as its IEEE hex (`%a`) representation. pub struct Hexf(pub F); @@ -340,8 +340,10 @@ pub(super) fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::R write!(f, "-")?; } - if x.is_nan() { - return write!(f, "NaN"); + if x.is_snan() { + return write!(f, "sNaN"); + } else if x.is_nan() { + return write!(f, "qNaN"); } else if x.is_infinite() { return write!(f, "inf"); } else if *x == F::ZERO { @@ -419,7 +421,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let _ = f; unimplemented!() } else { - fmt::LowerHex::fmt(&self.0, f) + write!(f, "{:#010x}", self.0) } } } @@ -456,6 +458,53 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } } + + pub struct Hexi(pub F); + + impl fmt::LowerHex for Hexi { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "{:#0width$x}", self.0, width = ((I::BITS / 4) + 2) as usize) + } + } + } + } + + impl fmt::Debug for Hexi + where + Hexi: fmt::LowerHex, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } + } + } + + impl fmt::Display for Hexi + where + Hexi: fmt::LowerHex, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } + } + } } #[cfg(any(test, feature = "unstable-public-internals"))] @@ -464,6 +513,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[cfg(test)] mod parse_tests { extern crate std; + use std::string::String; use std::{format, println}; use super::*; @@ -512,6 +562,16 @@ fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> { } Ok(()) } + + #[cfg_attr(not(f16_enabled), expect(unused))] + pub fn canonicalize_snan_str(s: String) -> String { + if s.contains("sNaN") || s.contains("qNaN") { + s.replace("sNaN", "NaN").replace("qNaN", "NaN") + } else { + s + } + } + #[test] #[cfg(f16_enabled)] fn test_rounding() { @@ -519,7 +579,11 @@ fn test_rounding() { for i in -n..n { let u = i.rotate_right(11) as u32; let s = format!("{}", Hexf(f32::from_bits(u))); - assert!(rounding_properties(&s).is_ok()); + let s = canonicalize_snan_str(s); + match rounding_properties(&s) { + Ok(()) => (), + Err(e) => panic!("failed rounding properties for `{s}`: {e:?}"), + } } } @@ -846,8 +910,6 @@ fn test_macros() { } #[cfg(test)] -// FIXME(ppc): something with `should_panic` tests cause a SIGILL with ppc64le -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] mod tests_panicking { extern crate std; use super::*; @@ -1054,8 +1116,11 @@ fn test_f16() { use std::format; // Exhaustively check that `f16` roundtrips. for x in 0..=u16::MAX { + use super::parse_tests::canonicalize_snan_str; + let f = f16::from_bits(x); let s = format!("{}", Hexf(f)); + let s = canonicalize_snan_str(s); let from_s = hf16(&s); if f.is_nan() && from_s.is_nan() { @@ -1074,6 +1139,8 @@ fn test_f16() { #[cfg(f16_enabled)] fn test_f16_to_f32() { use std::format; + + use super::parse_tests::canonicalize_snan_str; // Exhaustively check that these are equivalent for all `f16`: // - `f16 -> f32` // - `f16 -> str -> f32` @@ -1082,8 +1149,10 @@ fn test_f16_to_f32() { for x in 0..=u16::MAX { let f16 = f16::from_bits(x); let s16 = format!("{}", Hexf(f16)); + let s16 = canonicalize_snan_str(s16); let f32 = f16 as f32; let s32 = format!("{}", Hexf(f32)); + let s32 = canonicalize_snan_str(s32); let a = hf32(&s16); let b = hf32(&s32); @@ -1124,8 +1193,17 @@ fn spot_checks() { assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f32::NAN).to_string(), "NaN"); - assert_eq!(Hexf(f64::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f32::NAN).to_string(), "qNaN"); + assert_eq!(Hexf(f64::NAN).to_string(), "qNaN"); + assert_eq!(Hexf(f32::NEG_NAN).to_string(), "-qNaN"); + assert_eq!(Hexf(f64::NEG_NAN).to_string(), "-qNaN"); + if !cfg!(x86_no_sse) { + // FIXME(rust-lang/rust#115567): calls quiet the sNaN + assert_eq!(Hexf(f32::SNAN).to_string(), "sNaN"); + assert_eq!(Hexf(f64::SNAN).to_string(), "sNaN"); + assert_eq!(Hexf(f32::NEG_SNAN).to_string(), "-sNaN"); + assert_eq!(Hexf(f64::NEG_SNAN).to_string(), "-sNaN"); + } assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); @@ -1139,7 +1217,9 @@ fn spot_checks() { assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15"); assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0"); assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f16::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f16::NAN).to_string(), "qNaN"); + assert_eq!(Hexf(f16::SNAN).to_string(), "sNaN"); + assert_eq!(Hexf(f16::NEG_NAN).to_string(), "-qNaN"); assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); } @@ -1156,7 +1236,9 @@ fn spot_checks() { ); assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f128::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f128::NAN).to_string(), "qNaN"); + assert_eq!(Hexf(f128::SNAN).to_string(), "sNaN"); + assert_eq!(Hexf(f128::NEG_NAN).to_string(), "-qNaN"); assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf"); } diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 15ab010dc8d5..9dc872cdc150 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -35,5 +35,38 @@ /// Hint to the compiler that the current path is cold. pub fn cold_path() { #[cfg(intrinsics_enabled)] - core::intrinsics::cold_path(); + core::hint::cold_path(); +} + +/// # Safety +/// +/// `y` must not be zero and the result must not overflow (`x > i32::MIN`). +pub unsafe fn unchecked_div_i32(x: i32, y: i32) -> i32 { + cfg_if! { + if #[cfg(all(not(debug_assertions), intrinsics_enabled))] { + // Temporary macro to avoid panic codegen for division (in debug mode too). At + // the time of this writing this is only used in a few places, and once + // rust-lang/rust#72751 is fixed then this macro will no longer be necessary and + // the native `/` operator can be used and panics won't be codegen'd. + // + // Note: I am not sure whether the above comment is still up to date, we need + // to double check whether panics are elided where we use this. + unsafe { core::intrinsics::unchecked_div(x, y) } + } else { + x / y + } + } +} + +/// # Safety +/// +/// `y` must not be zero and the result must not overflow (`x > isize::MIN`). +pub unsafe fn unchecked_div_isize(x: isize, y: isize) -> isize { + cfg_if! { + if #[cfg(all(not(debug_assertions), intrinsics_enabled))] { + unsafe { core::intrinsics::unchecked_div(x, y) } + } else { + x / y + } + } } diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index 41415d9d1258..c526842470c8 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -23,6 +23,7 @@ most ideas and constants are from boost and python */ use super::{exp, floor, k_cos, k_sin, pow}; +use crate::support::unchecked_div_isize; const PI: f64 = 3.141592653589793238462643383279502884; @@ -37,7 +38,8 @@ fn sinpi(mut x: f64) -> f64 { /* reduce x into [-.25,.25] */ n = (4.0 * x) as isize; - n = div!(n + 1, 2); + // SAFETY: nonzero divisor, nonnegative dividend (`n < 8`). + n = unsafe { unchecked_div_isize(n + 1, 2) }; x -= (n as f64) * 0.5; x *= PI; diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index bf3d3e0a5aca..e97398aa5dc4 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -19,7 +19,7 @@ /// /// # Example /// -/// ``` +/// ```standalone_crate /// use std::alloc::{GlobalAlloc, Layout}; /// use std::cell::UnsafeCell; /// use std::ptr::null_mut; diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 011a90348226..66f5310db831 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -6,8 +6,8 @@ use crate::error::Error; use crate::intrinsics::{unchecked_add, unchecked_mul, unchecked_sub}; -use crate::mem::SizedTypeProperties; -use crate::ptr::{Alignment, NonNull}; +use crate::mem::{Alignment, SizedTypeProperties}; +use crate::ptr::NonNull; use crate::{assert_unsafe_precondition, fmt, mem}; /// Layout of a block of memory. @@ -268,7 +268,7 @@ pub const fn for_value(t: &T) -> Self { #[must_use] #[inline] pub const fn dangling_ptr(&self) -> NonNull { - NonNull::without_provenance(self.align.as_nonzero()) + NonNull::without_provenance(self.align.as_nonzero_usize()) } /// Creates a layout describing the record that can hold a value diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 959407b75348..18310cf98918 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -100,6 +100,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// A memory block which is [*currently allocated*] may be passed to /// any method of the allocator that accepts such an argument. /// +/// Additionally, any memory block returned by the allocator must +/// satisfy the allocation invariants described in `core::ptr`. +/// In particular, if a block has base address `p` and size `n`, +/// then `p as usize + n <= usize::MAX` must hold. +/// +/// This ensures that pointer arithmetic within the allocation +/// (for example, `ptr.add(len)`) cannot overflow the address space. /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 4a2cf1527744..b11684157890 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -405,7 +405,8 @@ fn index_mut(&mut self, index: I) -> &mut Self::Output { /// Implements comparison of arrays [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for [T; N] { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialOrd for [T; N] { #[inline] fn partial_cmp(&self, other: &[T; N]) -> Option { PartialOrd::partial_cmp(&&self[..], &&other[..]) @@ -430,7 +431,8 @@ fn index_mut(&mut self, index: I) -> &mut Self::Output { /// Implements comparison of arrays [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for [T; N] { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Ord for [T; N] { #[inline] fn cmp(&self, other: &[T; N]) -> Ordering { Ord::cmp(&&self[..], &&other[..]) diff --git a/library/core/src/bstr/mod.rs b/library/core/src/bstr/mod.rs index 2be7dfc9bfdd..9d623d3af8b5 100644 --- a/library/core/src/bstr/mod.rs +++ b/library/core/src/bstr/mod.rs @@ -6,7 +6,7 @@ pub use traits::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord}; use crate::borrow::{Borrow, BorrowMut}; -use crate::fmt; +use crate::fmt::{self, Alignment}; use crate::ops::{Deref, DerefMut, DerefPure}; /// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not @@ -174,43 +174,85 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[unstable(feature = "bstr", issue = "134915")] impl fmt::Display for ByteStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let nchars: usize = self - .utf8_chunks() - .map(|chunk| { - chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 } - }) - .sum(); - - let padding = f.width().unwrap_or(0).saturating_sub(nchars); - let fill = f.fill(); - - let (lpad, rpad) = match f.align() { - Some(fmt::Alignment::Right) => (padding, 0), - Some(fmt::Alignment::Center) => { - let half = padding / 2; - (half, half + padding % 2) + fn emit(byte_str: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for chunk in byte_str.utf8_chunks() { + f.write_str(chunk.valid())?; + if !chunk.invalid().is_empty() { + f.write_str("\u{FFFD}")?; + } + } + + Ok(()) + } + + let requested_width = f.width().unwrap_or(0); + if requested_width == 0 && f.precision().is_none() { + // Avoid counting the characters if no truncation or padding was + // requested. + return emit(self, f); + } + + let (truncated, actual_width) = match f.precision() { + // The entire string is truncated away. Weird, but ok. + Some(0) => (ByteStr::new(&[]), 0), + // Advance through string until we run out of space. + Some(precision) => { + let mut remaining_width = precision; + let mut chunks = self.utf8_chunks(); + let mut current_width = 0; + let mut offset = 0; + loop { + let Some(chunk) = chunks.next() else { + // We reached the end of the string without running out + // of space, so print the entire string. + break (self, current_width); + }; + + let mut chars = chunk.valid().char_indices(); + let Err(remaining) = chars.advance_by(remaining_width) else { + // We've counted off `precision` characters, so truncate + // the string at the current offset. + break (&self[..offset + chars.offset()], precision); + }; + + offset += chunk.valid().len(); + current_width += remaining_width - remaining.get(); + remaining_width = remaining.get(); + + // `remaining_width` cannot be zero, there is still space + // remaining. So next, count the � character emitted for + // the invalid chunk (if it exists). + if !chunk.invalid().is_empty() { + offset += chunk.invalid().len(); + current_width += 1; + remaining_width -= 1; + + if remaining_width == 0 { + break (&self[..offset], precision); + } + } + } + } + // The string shouldn't be truncated at all, so just count the number + // of characters to calculate the padding. + None => { + let actual_width = self + .utf8_chunks() + .map(|chunk| { + chunk.valid().chars().count() + + if chunk.invalid().is_empty() { 0 } else { 1 } + }) + .sum(); + (self, actual_width) } - // Either alignment is not specified or it's left aligned - // which behaves the same with padding - _ => (0, padding), }; - for _ in 0..lpad { - write!(f, "{fill}")?; - } + // The width is originally stored as a 16-bit number, so this cannot fail. + let padding = u16::try_from(requested_width.saturating_sub(actual_width)).unwrap(); - for chunk in self.utf8_chunks() { - f.write_str(chunk.valid())?; - if !chunk.invalid().is_empty() { - f.write_str("\u{FFFD}")?; - } - } - - for _ in 0..rpad { - write!(f, "{fill}")?; - } - - Ok(()) + let post_padding = f.padding(padding, Alignment::Left)?; + emit(truncated, f)?; + post_padding.write(f) } } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index f31cadb546c9..d67693f9d0fc 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2718,18 +2718,6 @@ fn assert_coerce_unsized( let _: RefCell<&dyn Send> = d; } -#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinCoerceUnsized for UnsafeCell {} - -#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinCoerceUnsized for SyncUnsafeCell {} - -#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinCoerceUnsized for Cell {} - -#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinCoerceUnsized for RefCell {} - #[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] unsafe impl<'b, T: ?Sized> PinCoerceUnsized for Ref<'b, T> {} diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 28a76569c1d0..ae559e599f48 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -366,6 +366,16 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } +#[stable(feature = "from_wrapper_impls", since = "CURRENT_RUSTC_VERSION")] +impl From for LazyCell { + /// Constructs a `LazyCell` that starts already initialized + /// with the provided value. + #[inline] + fn from(value: T) -> Self { + Self { state: UnsafeCell::new(State::Init(value)) } + } +} + #[cold] #[inline(never)] const fn panic_poisoned() -> ! { diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 87b328c91287..46d48afbf5a1 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -778,7 +778,72 @@ pub const fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { pub fn is_alphabetic(self) -> bool { match self { 'a'..='z' | 'A'..='Z' => true, - c => c > '\x7f' && unicode::Alphabetic(c), + '\0'..='\u{A9}' => false, + _ => unicode::Alphabetic(self), + } + } + + /// Returns `true` if this `char` has the `Cased` property. + /// A character is cased if and only if it is uppercase, lowercase, or titlecase. + /// + /// `Cased` is described in Chapter 4 (Character Properties) of the [Unicode Standard] and + /// specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`]. + /// + /// [Unicode Standard]: https://www.unicode.org/versions/latest/ + /// [ucd]: https://www.unicode.org/reports/tr44/ + /// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(titlecase)] + /// assert!('A'.is_cased()); + /// assert!('a'.is_cased()); + /// assert!(!'京'.is_cased()); + /// ``` + #[must_use] + #[unstable(feature = "titlecase", issue = "153892")] + #[inline] + pub fn is_cased(self) -> bool { + match self { + 'a'..='z' | 'A'..='Z' => true, + '\0'..='\u{A9}' => false, + _ => unicode::Cased(self), + } + } + + /// Returns the case of this character: + /// [`Some(CharCase::Upper)`][`CharCase::Upper`] if [`self.is_uppercase()`][`char::is_uppercase`], + /// [`Some(CharCase::Lower)`][`CharCase::Lower`] if [`self.is_lowercase()`][`char::is_lowercase`], + /// [`Some(CharCase::Title)`][`CharCase::Title`] if [`self.is_titlecase()`][`char::is_titlecase`], and + /// `None` if [`!self.is_cased()`][`char::is_cased`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(titlecase)] + /// use core::char::CharCase; + /// assert_eq!('a'.case(), Some(CharCase::Lower)); + /// assert_eq!('δ'.case(), Some(CharCase::Lower)); + /// assert_eq!('A'.case(), Some(CharCase::Upper)); + /// assert_eq!('Δ'.case(), Some(CharCase::Upper)); + /// assert_eq!('Dž'.case(), Some(CharCase::Title)); + /// assert_eq!('中'.case(), None); + /// ``` + #[must_use] + #[unstable(feature = "titlecase", issue = "153892")] + #[inline] + pub fn case(self) -> Option { + match self { + 'a'..='z' => Some(CharCase::Lower), + 'A'..='Z' => Some(CharCase::Upper), + '\0'..='\u{A9}' => None, + _ if !unicode::Cased(self) => None, + _ if unicode::Lowercase(self) => Some(CharCase::Lower), + _ if unicode::Uppercase(self) => Some(CharCase::Upper), + _ => Some(CharCase::Title), } } @@ -819,7 +884,42 @@ pub fn is_alphabetic(self) -> bool { pub const fn is_lowercase(self) -> bool { match self { 'a'..='z' => true, - c => c > '\x7f' && unicode::Lowercase(c), + '\0'..='\u{A9}' => false, + _ => unicode::Lowercase(self), + } + } + + /// Returns `true` if this `char` has the general category for titlecase letters. + /// Conceptually, these characters consist of an uppercase portion followed by a lowercase portion. + /// + /// Titlecase letters (code points with the general category of `Lt`) are described in Chapter 4 + /// (Character Properties) of the [Unicode Standard] and specified in the [Unicode Character + /// Database][ucd] [`UnicodeData.txt`]. + /// + /// [Unicode Standard]: https://www.unicode.org/versions/latest/ + /// [ucd]: https://www.unicode.org/reports/tr44/ + /// [`UnicodeData.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(titlecase)] + /// assert!('Dž'.is_titlecase()); + /// assert!('ῼ'.is_titlecase()); + /// assert!(!'D'.is_titlecase()); + /// assert!(!'z'.is_titlecase()); + /// assert!(!'中'.is_titlecase()); + /// assert!(!' '.is_titlecase()); + /// ``` + #[must_use] + #[unstable(feature = "titlecase", issue = "153892")] + #[inline] + pub fn is_titlecase(self) -> bool { + match self { + '\0'..='\u{01C4}' => false, + _ => self.is_cased() && !self.is_lowercase() && !self.is_uppercase(), } } @@ -860,7 +960,8 @@ pub const fn is_lowercase(self) -> bool { pub const fn is_uppercase(self) -> bool { match self { 'A'..='Z' => true, - c => c > '\x7f' && unicode::Uppercase(c), + '\0'..='\u{BF}' => false, + _ => unicode::Uppercase(self), } } @@ -893,7 +994,8 @@ pub const fn is_uppercase(self) -> bool { pub const fn is_whitespace(self) -> bool { match self { ' ' | '\x09'..='\x0d' => true, - c => c > '\x7f' && unicode::White_Space(c), + '\0'..='\u{84}' => false, + _ => unicode::White_Space(self), } } @@ -920,10 +1022,10 @@ pub const fn is_whitespace(self) -> bool { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_alphanumeric(self) -> bool { - if self.is_ascii() { - self.is_ascii_alphanumeric() - } else { - unicode::Alphabetic(self) || unicode::N(self) + match self { + 'a'..='z' | 'A'..='Z' | '0'..='9' => true, + '\0'..='\u{A9}' => false, + _ => unicode::Alphabetic(self) || unicode::N(self), } } @@ -969,23 +1071,7 @@ pub fn is_control(self) -> bool { #[must_use] #[inline] pub(crate) fn is_grapheme_extended(self) -> bool { - !self.is_ascii() && unicode::Grapheme_Extend(self) - } - - /// Returns `true` if this `char` has the `Cased` property. - /// - /// `Cased` is described in Chapter 4 (Character Properties) of the [Unicode Standard] and - /// specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`]. - /// - /// [Unicode Standard]: https://www.unicode.org/versions/latest/ - /// [ucd]: https://www.unicode.org/reports/tr44/ - /// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt - #[must_use] - #[inline] - #[doc(hidden)] - #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] - pub fn is_cased(self) -> bool { - if self.is_ascii() { self.is_ascii_alphabetic() } else { unicode::Cased(self) } + self > '\u{02FF}' && unicode::Grapheme_Extend(self) } /// Returns `true` if this `char` has the `Case_Ignorable` property. @@ -1047,7 +1133,8 @@ pub fn is_case_ignorable(self) -> bool { pub fn is_numeric(self) -> bool { match self { '0'..='9' => true, - c => c > '\x7f' && unicode::N(c), + '\0'..='\u{B1}' => false, + _ => unicode::N(self), } } @@ -1110,7 +1197,7 @@ pub fn is_numeric(self) -> bool { /// // convert into themselves. /// assert_eq!('山'.to_lowercase().to_string(), "山"); /// ``` - #[must_use = "this returns the lowercase character as a new iterator, \ + #[must_use = "this returns the lowercased character as a new iterator, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1118,9 +1205,115 @@ pub fn to_lowercase(self) -> ToLowercase { ToLowercase(CaseMappingIter::new(conversions::to_lower(self))) } + /// Returns an iterator that yields the titlecase mapping of this `char` as one or more + /// `char`s. + /// + /// This is usually, but not always, equivalent to the uppercase mapping + /// returned by [`Self::to_uppercase`]. Prefer this method when seeking to capitalize + /// Only The First Letter of a word, but use [`Self::to_uppercase`] for ALL CAPS. + /// + /// If this `char` does not have a titlecase mapping, the iterator yields the same `char`. + /// + /// If this `char` has a one-to-one titlecase mapping given by the [Unicode Character + /// Database][ucd] [`UnicodeData.txt`], the iterator yields that `char`. + /// + /// [ucd]: https://www.unicode.org/reports/tr44/ + /// [`UnicodeData.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt + /// + /// If this `char` requires special considerations (e.g. multiple `char`s) the iterator yields + /// the `char`(s) given by [`SpecialCasing.txt`]. + /// + /// [`SpecialCasing.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt + /// + /// This operation performs an unconditional mapping without tailoring. That is, the conversion + /// is independent of context and language. + /// + /// In the [Unicode Standard], Chapter 4 (Character Properties) discusses case mapping in + /// general and Chapter 3 (Conformance) discusses the default algorithm for case conversion. + /// + /// [Unicode Standard]: https://www.unicode.org/versions/latest/ + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// #![feature(titlecase)] + /// for c in 'ß'.to_titlecase() { + /// print!("{c}"); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// #![feature(titlecase)] + /// println!("{}", 'ß'.to_titlecase()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("Ss"); + /// ``` + /// + /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): + /// + /// ``` + /// #![feature(titlecase)] + /// assert_eq!('c'.to_titlecase().to_string(), "C"); + /// assert_eq!('dž'.to_titlecase().to_string(), "Dž"); + /// assert_eq!('ῼ'.to_titlecase().to_string(), "ῼ"); + /// + /// // Sometimes the result is more than one character: + /// assert_eq!('ß'.to_titlecase().to_string(), "Ss"); + /// + /// // Characters that do not have separate cased forms + /// // convert into themselves. + /// assert_eq!('山'.to_titlecase().to_string(), "山"); + /// ``` + /// + /// # Note on locale + /// + /// In Turkish and Azeri, the equivalent of 'i' in Latin has five forms instead of two: + /// + /// * 'Dotless': I / ı, sometimes written ï + /// * 'Dotted': İ / i + /// + /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: + /// + /// ``` + /// #![feature(titlecase)] + /// let upper_i = 'i'.to_titlecase().to_string(); + /// ``` + /// + /// The value of `upper_i` here relies on the language of the text: if we're + /// in `en-US`, it should be `"I"`, but if we're in `tr-TR` or `az-AZ`, it should + /// be `"İ"`. `to_titlecase()` does not take this into account, and so: + /// + /// ``` + /// #![feature(titlecase)] + /// let upper_i = 'i'.to_titlecase().to_string(); + /// + /// assert_eq!(upper_i, "I"); + /// ``` + /// + /// holds across languages. + #[must_use = "this returns the titlecased character as a new iterator, \ + without modifying the original"] + #[unstable(feature = "titlecase", issue = "153892")] + #[inline] + pub fn to_titlecase(self) -> ToTitlecase { + ToTitlecase(CaseMappingIter::new(conversions::to_title(self))) + } + /// Returns an iterator that yields the uppercase mapping of this `char` as one or more /// `char`s. /// + /// Prefer this method when converting a word into ALL CAPS, but consider [`Self::to_titlecase`] + /// instead if you seek to capitalize Only The First Letter. + /// /// If this `char` does not have an uppercase mapping, the iterator yields the same `char`. /// /// If this `char` has a one-to-one uppercase mapping given by the [Unicode Character @@ -1170,9 +1363,11 @@ pub fn to_lowercase(self) -> ToLowercase { /// /// ``` /// assert_eq!('c'.to_uppercase().to_string(), "C"); + /// assert_eq!('dž'.to_uppercase().to_string(), "DŽ"); /// /// // Sometimes the result is more than one character: /// assert_eq!('ſt'.to_uppercase().to_string(), "ST"); + /// assert_eq!('ῼ'.to_uppercase().to_string(), "ΩΙ"); /// /// // Characters that do not have both uppercase and lowercase /// // convert into themselves. @@ -1181,7 +1376,7 @@ pub fn to_lowercase(self) -> ToLowercase { /// /// # Note on locale /// - /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two: + /// In Turkish and Azeri, the equivalent of 'i' in Latin has five forms instead of two: /// /// * 'Dotless': I / ı, sometimes written ï /// * 'Dotted': İ / i @@ -1193,7 +1388,7 @@ pub fn to_lowercase(self) -> ToLowercase { /// ``` /// /// The value of `upper_i` here relies on the language of the text: if we're - /// in `en-US`, it should be `"I"`, but if we're in `tr_TR`, it should + /// in `en-US`, it should be `"I"`, but if we're in `tr-TR` or `az-AZ`, it should /// be `"İ"`. `to_uppercase()` does not take this into account, and so: /// /// ``` @@ -1203,7 +1398,7 @@ pub fn to_lowercase(self) -> ToLowercase { /// ``` /// /// holds across languages. - #[must_use = "this returns the uppercase character as a new iterator, \ + #[must_use = "this returns the uppercased character as a new iterator, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1446,7 +1641,7 @@ pub const fn make_ascii_lowercase(&mut self) { #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] pub const fn is_ascii_alphabetic(&self) -> bool { - matches!(*self, 'A'..='Z' | 'a'..='z') + matches!(*self, 'a'..='z' | 'A'..='Z') } /// Checks if the value is an ASCII uppercase character: diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 82a3f6f916be..3231c4193064 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -363,13 +363,21 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } macro_rules! casemappingiter_impls { - ($(#[$attr:meta])* $ITER_NAME:ident) => { + ( + #[$stab:meta] + #[$dendstab:meta] + #[$fusedstab:meta] + #[$exactstab:meta] + #[$displaystab:meta] + $(#[$attr:meta])* + $ITER_NAME:ident + ) => { $(#[$attr])* - #[stable(feature = "rust1", since = "1.0.0")] + #[$stab] #[derive(Debug, Clone)] pub struct $ITER_NAME(CaseMappingIter); - #[stable(feature = "rust1", since = "1.0.0")] + #[$stab] impl Iterator for $ITER_NAME { type Item = char; fn next(&mut self) -> Option { @@ -405,7 +413,7 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { } } - #[stable(feature = "case_mapping_double_ended", since = "1.59.0")] + #[$dendstab] impl DoubleEndedIterator for $ITER_NAME { fn next_back(&mut self) -> Option { self.0.next_back() @@ -423,10 +431,10 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { } } - #[stable(feature = "fused", since = "1.26.0")] + #[$fusedstab] impl FusedIterator for $ITER_NAME {} - #[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")] + #[$exactstab] impl ExactSizeIterator for $ITER_NAME { fn len(&self) -> usize { self.0.len() @@ -453,7 +461,7 @@ unsafe impl TrustedRandomAccessNoCoerce for $ITER_NAME { #[unstable(feature = "std_internals", issue = "none")] unsafe impl TrustedRandomAccess for $ITER_NAME {} - #[stable(feature = "char_struct_display", since = "1.16.0")] + #[$displaystab] impl fmt::Display for $ITER_NAME { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -464,16 +472,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } casemappingiter_impls! { - /// Returns an iterator that yields the lowercase equivalent of a `char`. - /// - /// This `struct` is created by the [`to_lowercase`] method on [`char`]. See - /// its documentation for more. - /// - /// [`to_lowercase`]: char::to_lowercase - ToLowercase -} - -casemappingiter_impls! { + #[stable(feature = "rust1", since = "1.0.0")] + #[stable(feature = "case_mapping_double_ended", since = "1.59.0")] + #[stable(feature = "fused", since = "1.26.0")] + #[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")] + #[stable(feature = "char_struct_display", since = "1.16.0")] /// Returns an iterator that yields the uppercase equivalent of a `char`. /// /// This `struct` is created by the [`to_uppercase`] method on [`char`]. See @@ -483,6 +486,36 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ToUppercase } +casemappingiter_impls! { + #[unstable(feature = "titlecase", issue = "153892")] + #[unstable(feature = "titlecase", issue = "153892")] + #[unstable(feature = "titlecase", issue = "153892")] + #[unstable(feature = "titlecase", issue = "153892")] + #[unstable(feature = "titlecase", issue = "153892")] + /// Returns an iterator that yields the titlecase equivalent of a `char`. + /// + /// This `struct` is created by the [`to_titlecase`] method on [`char`]. See + /// its documentation for more. + /// + /// [`to_titlecase`]: char::to_titlecase + ToTitlecase +} + +casemappingiter_impls! { + #[stable(feature = "rust1", since = "1.0.0")] + #[stable(feature = "case_mapping_double_ended", since = "1.59.0")] + #[stable(feature = "fused", since = "1.26.0")] + #[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")] + #[stable(feature = "char_struct_display", since = "1.16.0")] + /// Returns an iterator that yields the lowercase equivalent of a `char`. + /// + /// This `struct` is created by the [`to_lowercase`] method on [`char`]. See + /// its documentation for more. + /// + /// [`to_lowercase`]: char::to_lowercase + ToLowercase +} + #[derive(Debug, Clone)] struct CaseMappingIter(core::array::IntoIter); @@ -603,3 +636,23 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { #[stable(feature = "u8_from_char", since = "1.59.0")] impl Error for TryFromCharError {} + +/// The case of a cased character, +/// as returned by [`char::case`]. +/// +/// Titlecase characters conceptually are composed of an uppercase portion +/// followed by a lowercase portion. +/// The variant discriminants represent this: +/// the most significant bit represents whether the case +/// conceptually starts as uppercase, while the least significant bit +/// represents whether it conceptually ends as uppercase. +#[unstable(feature = "titlecase", issue = "153892")] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum CharCase { + /// Lowercase. Corresponds to the `Lowercase` Unicode property. + Lower = 0b00, + /// Titlecase. Corresponds to the `Titlecase_Letter` Unicode general category. + Title = 0b10, + /// Uppercase. Corresponds to the `Uppercase` Unicode property. + Upper = 0b11, +} diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index b3dc435dda17..49d7487c2803 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -357,6 +357,7 @@ fn assert_fields_are_eq(&self) {} } /// Derive macro generating an impl of the trait [`Eq`]. +/// The behavior of this macro is described in detail [here](Eq#derivable). #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics, derive_eq_internals, structural_match)] diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 40d61de50aaf..b80980219b1e 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -70,8 +70,8 @@ fn from(b: bool) -> Self { /// Implement `From<$small>` for `$large` macro_rules! impl_from { - ($small:ty => $large:ty, #[$attr:meta]) => { - #[$attr] + ($small:ty => $large:ty, $(#[$attrs:meta]),+) => { + $(#[$attrs])+ #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<$small> for $large { #[doc = concat!("Converts from [`", stringify!($small), "`] to [`", stringify!($large), "`] losslessly.")] @@ -157,8 +157,7 @@ fn from(small: $small) -> Self { impl_from!(i16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -// FIXME(f128): This impl would allow using `f128` on stable before it is stabilised. -// impl_from!(i64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); // unsigned integer -> float impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); @@ -170,8 +169,7 @@ fn from(small: $small) -> Self { impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -// FIXME(f128): This impl would allow using `f128` on stable before it is stabilised. -// impl_from!(u64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); // float -> float // FIXME(f16,f128): adding additional `From<{float}>` impls to `f32` breaks inference. See diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 5fc97d9a69ef..62b3d75d7a77 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -716,7 +716,7 @@ fn index(&self, index: ops::RangeFrom) -> &CStr { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl ops::Index> for CStr { type Output = CStr; diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index b6dfe3a54184..f0f58a0f8343 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -244,7 +244,7 @@ pub(crate) const fn duplicate(&self) -> Self { #[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")] impl<'f> const Clone for VaList<'f> { - #[inline] + #[inline] // Avoid codegen when not used to help backends that don't support VaList. fn clone(&self) -> Self { // We only implement Clone and not Copy because some future target might not be able to // implement Copy (e.g. because it allocates). For the same reason we use an intrinsic @@ -256,6 +256,7 @@ fn clone(&self) -> Self { #[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")] impl<'f> const Drop for VaList<'f> { + #[inline] // Avoid codegen when not used to help backends that don't support VaList. fn drop(&mut self) { // SAFETY: this variable argument list is being dropped, so won't be read from again. unsafe { va_end(self) } @@ -326,7 +327,7 @@ impl<'f> VaList<'f> { /// /// Calling this function with an incompatible type, an invalid value, or when there /// are no more variable arguments, is unsound. - #[inline] + #[inline] // Avoid codegen when not used to help backends that don't support VaList. #[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")] pub const unsafe fn arg(&mut self) -> T { // SAFETY: the caller must uphold the safety contract for `va_arg`. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 05d8e0d84f05..ecd1e34078e2 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1037,9 +1037,10 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - crate_local, + all(crate_local, not(Self = "{union}")), note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`" ), + on(all(crate_local, Self = "{union}"), note = "manually `impl {This} for {Self}`"), on( from_desugaring = "FormatLiteral", label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`" diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index d3d6495e75a2..e9302a6127f5 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -594,6 +594,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Include wasm32 in here since it doesn't reflect the native pointer size, and // often cares strongly about getting a smaller code size. #[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] +#[doc(auto_cfg = false)] mod imp { use super::*; impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64); @@ -601,6 +602,7 @@ mod imp { } #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))] +#[doc(auto_cfg = false)] mod imp { use super::*; impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32); @@ -823,7 +825,7 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { let mut remain = n; // Format per four digits from the lookup table. - for quad_index in (0..4).rev() { + for quad_index in (1..4).rev() { // pull two pairs let quad = remain % 1_00_00; remain /= 1_00_00; @@ -834,6 +836,14 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { buf[quad_index * 4 + OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); buf[quad_index * 4 + OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); } + + // final two pairs + let pair1 = (remain / 100) as usize; + let pair2 = (remain % 100) as usize; + buf[OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]); + buf[OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]); + buf[OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); + buf[OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); } /// Euclidean division plus remainder with constant 1E16 basically consumes 16 diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs index c48c3f2ba281..106493fd3e81 100644 --- a/library/core/src/future/async_drop.rs +++ b/library/core/src/future/async_drop.rs @@ -41,6 +41,15 @@ pub trait AsyncDrop { } /// Async drop. +/// +/// # Safety +/// +/// The pointer `_to_drop` must be valid for both reads and writes, +/// not only for the duration of this function call, +/// but also until the returned future has completed. +/// See [ptr::drop_in_place] for additional safety concerns. +/// +/// [ptr::drop_in_place]: crate::ptr::drop_in_place() #[unstable(feature = "async_drop", issue = "126482")] #[lang = "async_drop_in_place"] pub async unsafe fn async_drop_in_place(_to_drop: *mut T) { diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 03ed04dc5a66..a8e01e6e78b4 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -514,7 +514,7 @@ pub const fn black_box(dummy: T) -> T { /// macro_rules! make_error { /// ($($args:expr),*) => { /// core::hint::must_use({ -/// let error = $crate::make_error(core::format_args!($($args),*)); +/// let error = make_error(core::format_args!($($args),*)); /// error /// }) /// }; diff --git a/library/core/src/intrinsics/bounds.rs b/library/core/src/intrinsics/bounds.rs index 353908598d40..21705005ed0a 100644 --- a/library/core/src/intrinsics/bounds.rs +++ b/library/core/src/intrinsics/bounds.rs @@ -39,3 +39,14 @@ impl ChangePointee for *mut T { impl ChangePointee for *const T { type Output = *const U; } + +/// Built-in float types (f16, f32, f64 and f128). +/// +/// # Safety +/// Must actually *be* such a type. +pub unsafe trait FloatPrimitive: Sized + Copy {} + +unsafe impl FloatPrimitive for f16 {} +unsafe impl FloatPrimitive for f32 {} +unsafe impl FloatPrimitive for f64 {} +unsafe impl FloatPrimitive for f128 {} diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 939298268c93..7659e0042b37 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -62,7 +62,9 @@ //! //! # Examples //! -//! ```rust +#![cfg_attr(panic = "unwind", doc = "```rust")] +// This test can't support panic=abort because it generates an UnwindContinue MIR terminator. +#![cfg_attr(panic = "abort", doc = "```ignore")] //! #![feature(core_intrinsics, custom_mir)] //! #![allow(internal_features)] //! #![allow(unused_assignments)] diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 7e9adc1e8d57..6f9d35130016 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1573,7 +1573,7 @@ pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fadd_fast(a: T, b: T) -> T; +pub unsafe fn fadd_fast(a: T, b: T) -> T; /// Float subtraction that allows optimizations based on algebraic rules. /// Requires that inputs and output of the operation are finite, causing UB otherwise. @@ -1581,7 +1581,7 @@ pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fsub_fast(a: T, b: T) -> T; +pub unsafe fn fsub_fast(a: T, b: T) -> T; /// Float multiplication that allows optimizations based on algebraic rules. /// Requires that inputs and output of the operation are finite, causing UB otherwise. @@ -1589,7 +1589,7 @@ pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmul_fast(a: T, b: T) -> T; +pub unsafe fn fmul_fast(a: T, b: T) -> T; /// Float division that allows optimizations based on algebraic rules. /// Requires that inputs and output of the operation are finite, causing UB otherwise. @@ -1597,7 +1597,7 @@ pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fdiv_fast(a: T, b: T) -> T; +pub unsafe fn fdiv_fast(a: T, b: T) -> T; /// Float remainder that allows optimizations based on algebraic rules. /// Requires that inputs and output of the operation are finite, causing UB otherwise. @@ -1605,7 +1605,7 @@ pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn frem_fast(a: T, b: T) -> T; +pub unsafe fn frem_fast(a: T, b: T) -> T; /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range /// () @@ -1613,42 +1613,43 @@ pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn float_to_int_unchecked(value: Float) -> Int; +pub unsafe fn float_to_int_unchecked(value: Float) +-> Int; /// Float addition that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_add`], [`f32::algebraic_add`], [`f64::algebraic_add`] and [`f128::algebraic_add`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn fadd_algebraic(a: T, b: T) -> T; +pub const fn fadd_algebraic(a: T, b: T) -> T; /// Float subtraction that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_sub`], [`f32::algebraic_sub`], [`f64::algebraic_sub`] and [`f128::algebraic_sub`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn fsub_algebraic(a: T, b: T) -> T; +pub const fn fsub_algebraic(a: T, b: T) -> T; /// Float multiplication that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_mul`], [`f32::algebraic_mul`], [`f64::algebraic_mul`] and [`f128::algebraic_mul`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn fmul_algebraic(a: T, b: T) -> T; +pub const fn fmul_algebraic(a: T, b: T) -> T; /// Float division that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_div`], [`f32::algebraic_div`], [`f64::algebraic_div`] and [`f128::algebraic_div`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn fdiv_algebraic(a: T, b: T) -> T; +pub const fn fdiv_algebraic(a: T, b: T) -> T; /// Float remainder that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_rem`], [`f32::algebraic_rem`], [`f64::algebraic_rem`] and [`f128::algebraic_rem`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn frem_algebraic(a: T, b: T) -> T; +pub const fn frem_algebraic(a: T, b: T) -> T; /// Returns the number of bits set in an integer type `T` /// @@ -2502,14 +2503,6 @@ const fn compiletime$(<$($binders)*>)?($($arg: $ty),*) $( -> $ret )? { /// particular value, ever. However, the compiler will generally make it /// return `true` only if the value of the argument is actually known. /// -/// # Stability concerns -/// -/// While it is safe to call, this intrinsic may behave differently in -/// a `const` context than otherwise. See the [`const_eval_select()`] -/// documentation for an explanation of the issues this can cause. Unlike -/// `const_eval_select`, this intrinsic isn't guaranteed to behave -/// deterministically even in a `const` context. -/// /// # Type Requirements /// /// `T` must be either a `bool`, a `char`, a primitive numeric type (e.g. `f32`, @@ -2590,6 +2583,12 @@ pub const fn is_val_statically_known(_arg: T) -> bool { /// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`crate::ub_checks::assert_unsafe_precondition`]. +/// +/// # Consteval +/// +/// In consteval, this function currently returns `true`. This is because the value of the `ub_checks` +/// configuration can differ across crates, but we need this function to always return the same +/// value in consteval in order to avoid unsoundness. #[rustc_intrinsic_const_stable_indirect] // just for UB checks #[inline(always)] #[rustc_intrinsic] @@ -2609,6 +2608,12 @@ pub const fn ub_checks() -> bool { /// `#[inline]`), gating assertions on `overflow_checks()` rather than `cfg!(overflow_checks)` means that /// assertions are enabled whenever the *user crate* has overflow checks enabled. However if the /// user has overflow checks disabled, the checks will still get optimized out. +/// +/// # Consteval +/// +/// In consteval, this function currently returns `true`. This is because the value of the `overflow_checks` +/// configuration can differ across crates, but we need this function to always return the same +/// value in consteval in order to avoid unsoundness. #[inline(always)] #[rustc_intrinsic] pub const fn overflow_checks() -> bool { @@ -2987,6 +2992,8 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) /// Returns the minimum of two `f16` values, ignoring NaN. /// +/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed +/// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` /// and `-0.0`), either input may be returned non-deterministically. @@ -2999,10 +3006,19 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) /// The stabilized version of this intrinsic is [`f16::min`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn minnumf16(x: f16, y: f16) -> f16; +pub const fn minimum_number_nsz_f16(x: f16, y: f16) -> f16 { + if x.is_nan() || y <= x { + y + } else { + // Either y > x or y is a NaN. + x + } +} /// Returns the minimum of two `f32` values, ignoring NaN. /// +/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed +/// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` /// and `-0.0`), either input may be returned non-deterministically. @@ -3016,10 +3032,19 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn minnumf32(x: f32, y: f32) -> f32; +pub const fn minimum_number_nsz_f32(x: f32, y: f32) -> f32 { + if x.is_nan() || y <= x { + y + } else { + // Either y > x or y is a NaN. + x + } +} /// Returns the minimum of two `f64` values, ignoring NaN. /// +/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed +/// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` /// and `-0.0`), either input may be returned non-deterministically. @@ -3033,10 +3058,19 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn minnumf64(x: f64, y: f64) -> f64; +pub const fn minimum_number_nsz_f64(x: f64, y: f64) -> f64 { + if x.is_nan() || y <= x { + y + } else { + // Either y > x or y is a NaN. + x + } +} /// Returns the minimum of two `f128` values, ignoring NaN. /// +/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed +/// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` /// and `-0.0`), either input may be returned non-deterministically. @@ -3049,7 +3083,14 @@ pub const fn aggregate_raw_ptr(data: D, meta: M) /// The stabilized version of this intrinsic is [`f128::min`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn minnumf128(x: f128, y: f128) -> f128; +pub const fn minimum_number_nsz_f128(x: f128, y: f128) -> f128 { + if x.is_nan() || y <= x { + y + } else { + // Either y > x or y is a NaN. + x + } +} /// Returns the minimum of two `f16` values, propagating NaN. /// @@ -3153,6 +3194,8 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { /// Returns the maximum of two `f16` values, ignoring NaN. /// +/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed +/// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` /// and `-0.0`), either input may be returned non-deterministically. @@ -3165,10 +3208,19 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { /// The stabilized version of this intrinsic is [`f16::max`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn maxnumf16(x: f16, y: f16) -> f16; +pub const fn maximum_number_nsz_f16(x: f16, y: f16) -> f16 { + if x.is_nan() || y >= x { + y + } else { + // Either y < x or y is a NaN. + x + } +} /// Returns the maximum of two `f32` values, ignoring NaN. /// +/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed +/// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` /// and `-0.0`), either input may be returned non-deterministically. @@ -3182,10 +3234,19 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn maxnumf32(x: f32, y: f32) -> f32; +pub const fn maximum_number_nsz_f32(x: f32, y: f32) -> f32 { + if x.is_nan() || y >= x { + y + } else { + // Either y < x or y is a NaN. + x + } +} /// Returns the maximum of two `f64` values, ignoring NaN. /// +/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed +/// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` /// and `-0.0`), either input may be returned non-deterministically. @@ -3199,10 +3260,19 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn maxnumf64(x: f64, y: f64) -> f64; +pub const fn maximum_number_nsz_f64(x: f64, y: f64) -> f64 { + if x.is_nan() || y >= x { + y + } else { + // Either y < x or y is a NaN. + x + } +} /// Returns the maximum of two `f128` values, ignoring NaN. /// +/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed +/// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` /// and `-0.0`), either input may be returned non-deterministically. @@ -3215,7 +3285,14 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { /// The stabilized version of this intrinsic is [`f128::max`]. #[rustc_nounwind] #[rustc_intrinsic] -pub const fn maxnumf128(x: f128, y: f128) -> f128; +pub const fn maximum_number_nsz_f128(x: f128, y: f128) -> f128 { + if x.is_nan() || y >= x { + y + } else { + // Either y < x or y is a NaN. + x + } +} /// Returns the maximum of two `f16` values, propagating NaN. /// @@ -3313,39 +3390,14 @@ pub const fn maximumf128(x: f128, y: f128) -> f128 { } } -/// Returns the absolute value of an `f16`. +/// Returns the absolute value of a floating-point value. /// -/// The stabilized version of this intrinsic is -/// [`f16::abs`](../../std/primitive.f16.html#method.abs) -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn fabsf16(x: f16) -> f16; - -/// Returns the absolute value of an `f32`. -/// -/// The stabilized version of this intrinsic is -/// [`f32::abs`](../../std/primitive.f32.html#method.abs) +/// The stabilized versions of this intrinsic are available on the float +/// primitives via the `abs` method. For example, [`f32::abs`]. #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn fabsf32(x: f32) -> f32; - -/// Returns the absolute value of an `f64`. -/// -/// The stabilized version of this intrinsic is -/// [`f64::abs`](../../std/primitive.f64.html#method.abs) -#[rustc_nounwind] -#[rustc_intrinsic_const_stable_indirect] -#[rustc_intrinsic] -pub const fn fabsf64(x: f64) -> f64; - -/// Returns the absolute value of an `f128`. -/// -/// The stabilized version of this intrinsic is -/// [`f128::abs`](../../std/primitive.f128.html#method.abs) -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn fabsf128(x: f128) -> f128; +pub const fn fabs(x: T) -> T; /// Copies the sign from `y` to `x` for `f16` values. /// diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 5fb2102c319e..ae86690dc418 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -62,6 +62,7 @@ /// Adds two simd vectors elementwise. /// /// `T` must be a vector of integers or floats. +/// For integers, wrapping arithmetic is used. #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn simd_add(x: T, y: T) -> T; @@ -69,6 +70,7 @@ /// Subtracts `rhs` from `lhs` elementwise. /// /// `T` must be a vector of integers or floats. +/// For integers, wrapping arithmetic is used. #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn simd_sub(lhs: T, rhs: T) -> T; @@ -76,6 +78,7 @@ /// Multiplies two simd vectors elementwise. /// /// `T` must be a vector of integers or floats. +/// For integers, wrapping arithmetic is used. #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn simd_mul(x: T, y: T) -> T; @@ -233,8 +236,7 @@ /// Negates a vector elementwise. /// /// `T` must be a vector of integers or floats. -/// -/// Rust panics for `-::Min` due to overflow, but it is not UB with this intrinsic. +/// For integers, wrapping arithmetic is used. #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn simd_neg(x: T) -> T; @@ -250,19 +252,27 @@ /// /// `T` must be a vector of floating-point primitive types. /// -/// Follows IEEE-754 `minNum` semantics. +/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed +/// zeros deterministically. In particular, for each vector lane: +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn simd_fmin(x: T, y: T) -> T; +pub const unsafe fn simd_minimum_number_nsz(x: T, y: T) -> T; /// Returns the maximum of two vectors, elementwise. /// /// `T` must be a vector of floating-point primitive types. /// -/// Follows IEEE-754 `maxNum` semantics. +/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed +/// zeros deterministically. In particular, for each vector lane: +/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If +/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` +/// and `-0.0`), either input may be returned non-deterministically. #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn simd_fmax(x: T, y: T) -> T; +pub const unsafe fn simd_maximum_number_nsz(x: T, y: T) -> T; /// Tests elementwise equality of two vectors. /// diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index bb94ed0a0a17..f64dea2df862 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -1,5 +1,4 @@ use crate::fmt; -use crate::iter::{Fuse, FusedIterator}; /// An iterator adapter that places a separator between all elements. /// @@ -14,15 +13,7 @@ pub struct Intersperse started: bool, separator: I::Item, next_item: Option, - iter: Fuse, -} - -#[unstable(feature = "iter_intersperse", issue = "79524")] -impl FusedIterator for Intersperse -where - I: FusedIterator, - I::Item: Clone, -{ + iter: I, } impl Intersperse @@ -30,7 +21,7 @@ impl Intersperse I::Item: Clone, { pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self { - Self { started: false, separator, next_item: None, iter: iter.fuse() } + Self { started: false, separator, next_item: None, iter } } } @@ -57,8 +48,9 @@ fn next(&mut self) -> Option { } } } else { - self.started = true; - self.iter.next() + let item = self.iter.next(); + self.started = item.is_some(); + item } } @@ -95,15 +87,7 @@ pub struct IntersperseWith started: bool, separator: G, next_item: Option, - iter: Fuse, -} - -#[unstable(feature = "iter_intersperse", issue = "79524")] -impl FusedIterator for IntersperseWith -where - I: FusedIterator, - G: FnMut() -> I::Item, -{ + iter: I, } #[unstable(feature = "iter_intersperse", issue = "79524")] @@ -146,7 +130,7 @@ impl IntersperseWith G: FnMut() -> I::Item, { pub(in crate::iter) fn new(iter: I, separator: G) -> Self { - Self { started: false, separator, next_item: None, iter: iter.fuse() } + Self { started: false, separator, next_item: None, iter } } } @@ -173,8 +157,9 @@ fn next(&mut self) -> Option { } } } else { - self.started = true; - self.iter.next() + let item = self.iter.next(); + self.started = item.is_some(); + item } } diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index cef556319143..9398fbbe8a1c 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -14,10 +14,7 @@ pub struct MapWindows { } struct MapWindowsInner { - // We fuse the inner iterator because there shouldn't be "holes" in - // the sliding window. Once the iterator returns a `None`, we make - // our `MapWindows` iterator return `None` forever. - iter: Option, + iter: I, // Since iterators are assumed lazy, i.e. it only yields an item when // `Iterator::next()` is called, and `MapWindows` is not an exception. // @@ -26,7 +23,7 @@ struct MapWindowsInner { // we collect the first `N` items yielded from the inner iterator and // put it into the buffer. // - // When the inner iterator has returned a `None` (i.e. fused), we take + // When the inner iterator has returned a `None`, we take // away this `buffer` and leave it `None` to reclaim its resources. // // FIXME: should we shrink the size of `buffer` using niche optimization? @@ -64,19 +61,16 @@ pub(in crate::iter) fn new(iter: I, f: F) -> Self { impl MapWindowsInner { #[inline] fn new(iter: I) -> Self { - Self { iter: Some(iter), buffer: None } + Self { iter, buffer: None } } fn next_window(&mut self) -> Option<&[I::Item; N]> { - let iter = self.iter.as_mut()?; match self.buffer { // It is the first time to advance. We collect // the first `N` items from `self.iter` to initialize `self.buffer`. - None => self.buffer = Buffer::try_from_iter(iter), - Some(ref mut buffer) => match iter.next() { + None => self.buffer = Buffer::try_from_iter(&mut self.iter), + Some(ref mut buffer) => match self.iter.next() { None => { - // Fuse the inner iterator since it yields a `None`. - self.iter.take(); self.buffer.take(); } // Advance the iterator. We first call `next` before changing our buffer @@ -89,8 +83,7 @@ fn new(iter: I) -> Self { } fn size_hint(&self) -> (usize, Option) { - let Some(ref iter) = self.iter else { return (0, Some(0)) }; - let (lo, hi) = iter.size_hint(); + let (lo, hi) = self.iter.size_hint(); if self.buffer.is_some() { // If the first `N` items are already yielded by the inner iterator, // the size hint is then equal to the that of the inner iterator's. @@ -253,12 +246,10 @@ fn size_hint(&self) -> (usize, Option) { } } -// Note that even if the inner iterator not fused, the `MapWindows` is still fused, -// because we don't allow "holes" in the mapping window. #[unstable(feature = "iter_map_windows", issue = "87155")] impl FusedIterator for MapWindows where - I: Iterator, + I: FusedIterator, F: FnMut(&[I::Item; N]) -> R, { } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index d0b89fdbb584..ca950a138f31 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -155,6 +155,9 @@ pub(crate) fn try_process(iter: I, mut f: F) -> ChangeOutputType< for<'a> F: FnMut(GenericShunt<'a, I, R>) -> U, R: Residual, { + // FIXME(#11084): we might be able to get rid of GenericShunt in favor of + // Iterator::scan, as performance should be comparable + let mut residual = None; let shunt = GenericShunt { iter, residual: &mut residual }; let value = f(shunt); diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 350b5d31e894..951bb5d0029f 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -29,7 +29,8 @@ unsafe impl TrustedStep for $type {} unstable `Step` trait" )] #[unstable(feature = "step_trait", issue = "42168")] -pub trait Step: Clone + PartialOrd + Sized { +#[rustc_const_unstable(feature = "step_trait", issue = "42168")] +pub const trait Step: [const] Clone + [const] PartialOrd + Sized { /// Returns the bounds on the number of *successor* steps required to get from `start` to `end` /// like [`Iterator::size_hint()`][Iterator::size_hint()]. /// @@ -262,7 +263,8 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", issue = "42168")] - impl Step for $u_narrower { + #[rustc_const_unstable(feature = "step_trait", issue = "42168")] + impl const Step for $u_narrower { step_identical_methods!(); step_unsigned_methods!(); @@ -296,7 +298,8 @@ fn backward_checked(start: Self, n: usize) -> Option { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", issue = "42168")] - impl Step for $i_narrower { + #[rustc_const_unstable(feature = "step_trait", issue = "42168")] + impl const Step for $i_narrower { step_identical_methods!(); step_signed_methods!($u_narrower); @@ -362,7 +365,8 @@ fn backward_checked(start: Self, n: usize) -> Option { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", issue = "42168")] - impl Step for $u_wider { + #[rustc_const_unstable(feature = "step_trait", issue = "42168")] + impl const Step for $u_wider { step_identical_methods!(); step_unsigned_methods!(); @@ -392,7 +396,8 @@ fn backward_checked(start: Self, n: usize) -> Option { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", issue = "42168")] - impl Step for $i_wider { + #[rustc_const_unstable(feature = "step_trait", issue = "42168")] + impl const Step for $i_wider { step_identical_methods!(); step_signed_methods!($u_wider); @@ -449,7 +454,8 @@ fn backward_checked(start: Self, n: usize) -> Option { } #[unstable(feature = "step_trait", issue = "42168")] -impl Step for char { +#[rustc_const_unstable(feature = "step_trait", issue = "42168")] +impl const Step for char { #[inline] fn steps_between(&start: &char, &end: &char) -> (usize, Option) { let start = start as u32; @@ -536,7 +542,8 @@ unsafe fn backward_unchecked(start: char, count: usize) -> char { } #[unstable(feature = "step_trait", issue = "42168")] -impl Step for AsciiChar { +#[rustc_const_unstable(feature = "step_trait", issue = "42168")] +impl const Step for AsciiChar { #[inline] fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> (usize, Option) { Step::steps_between(&start.to_u8(), &end.to_u8()) @@ -578,7 +585,8 @@ unsafe fn backward_unchecked(start: AsciiChar, count: usize) -> AsciiChar { } #[unstable(feature = "step_trait", issue = "42168")] -impl Step for Ipv4Addr { +#[rustc_const_unstable(feature = "step_trait", issue = "42168")] +impl const Step for Ipv4Addr { #[inline] fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> (usize, Option) { u32::steps_between(&start.to_bits(), &end.to_bits()) @@ -610,7 +618,8 @@ unsafe fn backward_unchecked(start: Ipv4Addr, count: usize) -> Ipv4Addr { } #[unstable(feature = "step_trait", issue = "42168")] -impl Step for Ipv6Addr { +#[rustc_const_unstable(feature = "step_trait", issue = "42168")] +impl const Step for Ipv6Addr { #[inline] fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> (usize, Option) { u128::steps_between(&start.to_bits(), &end.to_bits()) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 2e82f4577182..943e869d7438 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -635,11 +635,24 @@ fn zip(self, other: U) -> Zip /// of the original iterator. /// /// Specifically on fused iterators, it is guaranteed that the new iterator - /// places a copy of `separator` between adjacent `Some(_)` items. However, - /// for non-fused iterators, [`intersperse`] will create a new iterator that - /// is a fused version of the original iterator and place a copy of `separator` - /// between adjacent `Some(_)` items. This behavior for non-fused iterators - /// is subject to change. + /// places a copy of `separator` between *adjacent* `Some(_)` items. For non-fused iterators, + /// it is guaranteed that [`intersperse`] will create a new iterator that places a copy + /// of `separator` between `Some(_)` items, particularly just right before the subsequent + /// `Some(_)` item. + /// + /// For example, consider the following non-fused iterator: + /// + /// ```text + /// Some(1) -> Some(2) -> None -> Some(3) -> Some(4) -> ... + /// ``` + /// + /// If this non-fused iterator were to be interspersed with `0`, + /// then the interspersed iterator will produce: + /// + /// ```text + /// Some(1) -> Some(0) -> Some(2) -> None -> Some(0) -> Some(3) -> Some(0) -> + /// Some(4) -> ... + /// ``` /// /// In case `separator` does not implement [`Clone`] or needs to be /// computed every time, use [`intersperse_with`]. @@ -688,10 +701,23 @@ fn intersperse(self, separator: Self::Item) -> Intersperse /// /// Specifically on fused iterators, it is guaranteed that the new iterator /// places an item generated by `separator` between adjacent `Some(_)` items. - /// However, for non-fused iterators, [`intersperse_with`] will create a new - /// iterator that is a fused version of the original iterator and place an item - /// generated by `separator` between adjacent `Some(_)` items. This - /// behavior for non-fused iterators is subject to change. + /// For non-fused iterators, it is guaranteed that [`intersperse_with`] will + /// create a new iterator that places an item generated by `separator` between `Some(_)` + /// items, particularly just right before the subsequent `Some(_)` item. + /// + /// For example, consider the following non-fused iterator: + /// + /// ```text + /// Some(1) -> Some(2) -> None -> Some(3) -> Some(4) -> ... + /// ``` + /// + /// If this non-fused iterator were to be interspersed with a `separator` closure + /// that returns `0` repeatedly, the interspersed iterator will produce: + /// + /// ```text + /// Some(1) -> Some(0) -> Some(2) -> None -> Some(0) -> Some(3) -> Some(0) -> + /// Some(4) -> ... + /// ``` /// /// The `separator` closure will be called exactly once each time an item /// is placed between two adjacent items from the underlying iterator; @@ -1631,11 +1657,6 @@ fn flatten(self) -> Flatten /// items yielded by `self`). If 𝑘 is less than `N`, this method yields an /// empty iterator. /// - /// The returned iterator implements [`FusedIterator`], because once `self` - /// returns `None`, even if it returns a `Some(T)` again in the next iterations, - /// we cannot put it into a contiguous array buffer, and thus the returned iterator - /// should be fused. - /// /// [`slice::windows()`]: slice::windows /// [`FusedIterator`]: crate::iter::FusedIterator /// @@ -1696,7 +1717,7 @@ fn flatten(self) -> Flatten /// assert_eq!(it.next(), None); /// ``` /// - /// For non-fused iterators, they are fused after `map_windows`. + /// For non-fused iterators, the window is reset after `None` is yielded. /// /// ``` /// #![feature(iter_map_windows)] @@ -1713,11 +1734,11 @@ fn flatten(self) -> Flatten /// let val = self.state; /// self.state = self.state + 1; /// - /// // yields `0..5` first, then only even numbers since `6..`. - /// if val < 5 || val % 2 == 0 { - /// Some(val) - /// } else { + /// // Skip every 5th number + /// if (val + 1) % 5 == 0 { /// None + /// } else { + /// Some(val) /// } /// } /// } @@ -1725,32 +1746,35 @@ fn flatten(self) -> Flatten /// /// let mut iter = NonFusedIterator::default(); /// - /// // yields 0..5 first. /// assert_eq!(iter.next(), Some(0)); /// assert_eq!(iter.next(), Some(1)); /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), Some(3)); - /// assert_eq!(iter.next(), Some(4)); - /// // then we can see our iterator going back and forth /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next(), Some(5)); /// assert_eq!(iter.next(), Some(6)); - /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next(), Some(7)); /// assert_eq!(iter.next(), Some(8)); /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next(), Some(10)); + /// assert_eq!(iter.next(), Some(11)); /// - /// // however, with `.map_windows()`, it is fused. /// let mut iter = NonFusedIterator::default() /// .map_windows(|arr: &[_; 2]| *arr); /// /// assert_eq!(iter.next(), Some([0, 1])); /// assert_eq!(iter.next(), Some([1, 2])); /// assert_eq!(iter.next(), Some([2, 3])); - /// assert_eq!(iter.next(), Some([3, 4])); /// assert_eq!(iter.next(), None); /// - /// // it will always return `None` after the first time. - /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next(), Some([5, 6])); + /// assert_eq!(iter.next(), Some([6, 7])); + /// assert_eq!(iter.next(), Some([7, 8])); /// assert_eq!(iter.next(), None); + /// + /// assert_eq!(iter.next(), Some([10, 11])); + /// assert_eq!(iter.next(), Some([11, 12])); + /// assert_eq!(iter.next(), Some([12, 13])); /// assert_eq!(iter.next(), None); /// ``` #[inline] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6ce1432011b4..35f93d8fb33b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -48,7 +48,7 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut, duplicate_features))) )] #![doc(rust_logo)] #![doc(auto_cfg(hide( @@ -107,8 +107,6 @@ #![feature(core_intrinsics)] #![feature(coverage_attribute)] #![feature(disjoint_bitor)] -#![feature(internal_impls_macro)] -#![feature(link_cfg)] #![feature(offset_of_enum)] #![feature(panic_internals)] #![feature(pattern_type_macro)] @@ -144,6 +142,7 @@ #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] +#![feature(link_cfg)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] #![feature(macro_metavar_expr_concat)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 49e1acd0b90f..7f35e94d3df3 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -124,8 +124,6 @@ macro_rules! assert_ne { }; } -// FIXME add back debug_assert_matches doc link after bootstrap. - /// Asserts that an expression matches the provided pattern. /// /// This macro is generally preferable to `assert!(matches!(value, pattern))`, because it can print @@ -137,9 +135,11 @@ macro_rules! assert_ne { /// otherwise this macro will panic. /// /// Assertions are always checked in both debug and release builds, and cannot -/// be disabled. See `debug_assert_matches!` for assertions that are disabled in +/// be disabled. See [`debug_assert_matches!`] for assertions that are disabled in /// release builds by default. /// +/// [`debug_assert_matches!`]: crate::debug_assert_matches +/// /// On panic, this macro will print the value of the expression with its debug representation. /// /// Like [`assert!`], this macro has a second form, where a custom panic message can be provided. diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 818dad6bce2f..c79e8fc4060c 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -52,9 +52,6 @@ /// u32, /// } /// ``` -#[unstable(feature = "internal_impls_macro", issue = "none")] -// Allow implementations of `UnsizedConstParamTy` even though std cannot use that feature. -#[allow_internal_unstable(unsized_const_params)] macro marker_impls { ( $(#[$($meta:tt)*])* $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => { $(#[$($meta)*])* impl< $($($bounds)*)? > $Trait for $T {} @@ -1080,7 +1077,7 @@ pub trait Tuple {} /// that all fields are also `ConstParamTy`, which implies that recursively, all fields /// are `StructuralPartialEq`. #[lang = "const_param_ty"] -#[unstable(feature = "unsized_const_params", issue = "95174")] +#[unstable(feature = "const_param_ty_trait", issue = "95174", implied_by = "unsized_const_params")] #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] #[allow(multiple_supertrait_upcastable)] // We name this differently than the derive macro so that the `adt_const_params` can @@ -1090,7 +1087,7 @@ pub trait ConstParamTy_: StructuralPartialEq + Eq {} /// Derive macro generating an impl of the trait `ConstParamTy`. #[rustc_builtin_macro] -#[allow_internal_unstable(unsized_const_params)] +#[allow_internal_unstable(const_param_ty_trait)] #[unstable(feature = "adt_const_params", issue = "95174")] pub macro ConstParamTy($item:item) { /* compiler built-in */ diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/mem/alignment.rs similarity index 91% rename from library/core/src/ptr/alignment.rs rename to library/core/src/mem/alignment.rs index b106314f14d1..a8c4c8ea78ff 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/mem/alignment.rs @@ -11,7 +11,8 @@ /// Note that particularly large alignments, while representable in this type, /// are likely not to be supported by actual allocators and linkers. #[unstable(feature = "ptr_alignment_type", issue = "102070")] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[repr(transparent)] pub struct Alignment { // This field is never used directly (nor is the enum), @@ -37,7 +38,7 @@ impl Alignment { /// /// ``` /// #![feature(ptr_alignment_type)] - /// use std::ptr::Alignment; + /// use std::mem::Alignment; /// /// assert_eq!(Alignment::MIN.as_usize(), 1); /// ``` @@ -65,7 +66,7 @@ pub const fn of() -> Self { /// /// ``` /// #![feature(ptr_alignment_type)] - /// use std::ptr::Alignment; + /// use std::mem::Alignment; /// /// assert_eq!(Alignment::of_val(&5i32).as_usize(), 4); /// ``` @@ -112,14 +113,13 @@ pub const fn of_val(val: &T) -> Self { /// /// ``` /// #![feature(ptr_alignment_type)] - /// use std::ptr::Alignment; + /// use std::mem::Alignment; /// /// assert_eq!(unsafe { Alignment::of_val_raw(&5i32) }.as_usize(), 4); /// ``` #[inline] #[must_use] #[unstable(feature = "ptr_alignment_type", issue = "102070")] - // #[unstable(feature = "layout_for_ptr", issue = "69835")] pub const unsafe fn of_val_raw(val: *const T) -> Self { // SAFETY: precondition propagated to the caller let align = unsafe { mem::align_of_val_raw(val) }; @@ -169,16 +169,28 @@ pub const fn new(align: usize) -> Option { #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] pub const fn as_usize(self) -> usize { - // Going through `as_nonzero` helps this be more clearly the inverse of + // Going through `as_nonzero_usize` helps this be more clearly the inverse of // `new_unchecked`, letting MIR optimizations fold it away. - self.as_nonzero().get() + self.as_nonzero_usize().get() + } + + /// Returns the alignment as a [NonZero]<[usize]>. + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[deprecated( + since = "CURRENT_RUSTC_VERSION", + note = "renamed to `as_nonzero_usize`", + suggestion = "as_nonzero_usize" + )] + #[inline] + pub const fn as_nonzero(self) -> NonZero { + self.as_nonzero_usize() } /// Returns the alignment as a [NonZero]<[usize]>. #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] - pub const fn as_nonzero(self) -> NonZero { + pub const fn as_nonzero_usize(self) -> NonZero { // This transmutes directly to avoid the UbCheck in `NonZero::new_unchecked` // since there's no way for the user to trip that check anyway -- the // validity invariant of the type would have to have been broken earlier -- @@ -204,7 +216,7 @@ pub const fn as_nonzero(self) -> NonZero { #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] pub const fn log2(self) -> u32 { - self.as_nonzero().trailing_zeros() + self.as_nonzero_usize().trailing_zeros() } /// Returns a bit mask that can be used to match this alignment. @@ -214,9 +226,10 @@ pub const fn log2(self) -> u32 { /// # Examples /// /// ``` - /// #![feature(ptr_alignment_type)] /// #![feature(ptr_mask)] - /// use std::ptr::{Alignment, NonNull}; + /// #![feature(ptr_alignment_type)] + /// use std::mem::Alignment; + /// use std::ptr::NonNull; /// /// #[repr(align(1))] struct Align1(u8); /// #[repr(align(2))] struct Align2(u16); @@ -246,7 +259,7 @@ pub(crate) const fn max(a: Self, b: Self) -> Self { #[unstable(feature = "ptr_alignment_type", issue = "102070")] impl fmt::Debug for Alignment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2()) + write!(f, "{:?} (1 << {:?})", self.as_nonzero_usize(), self.log2()) } } @@ -277,7 +290,7 @@ fn try_from(align: usize) -> Result { impl const From for NonZero { #[inline] fn from(align: Alignment) -> NonZero { - align.as_nonzero() + align.as_nonzero_usize() } } @@ -291,15 +304,17 @@ fn from(align: Alignment) -> usize { } #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl cmp::Ord for Alignment { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const cmp::Ord for Alignment { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { - self.as_nonzero().get().cmp(&other.as_nonzero().get()) + self.as_nonzero_usize().cmp(&other.as_nonzero_usize()) } } #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl cmp::PartialOrd for Alignment { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const cmp::PartialOrd for Alignment { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) @@ -310,7 +325,7 @@ fn partial_cmp(&self, other: &Self) -> Option { impl hash::Hash for Alignment { #[inline] fn hash(&self, state: &mut H) { - self.as_nonzero().hash(state) + self.as_nonzero_usize().hash(state) } } @@ -324,7 +339,8 @@ fn default() -> Alignment { } #[cfg(target_pointer_width = "16")] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, @@ -346,7 +362,8 @@ enum AlignmentEnum { } #[cfg(target_pointer_width = "32")] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, @@ -384,7 +401,8 @@ enum AlignmentEnum { } #[cfg(target_pointer_width = "64")] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index ad6479f84c73..7e2c6b9b3bcb 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -8,11 +8,11 @@ /// /// # Initialization invariant /// -/// The compiler, in general, assumes that a variable is properly initialized +/// The compiler, in general, assumes that a variable is [properly initialized or "valid"][validity] /// according to the requirements of the variable's type. For example, a variable of /// reference type must be aligned and non-null. This is an invariant that must /// *always* be upheld, even in unsafe code. As a consequence, zero-initializing a -/// variable of reference type causes instantaneous [undefined behavior][ub], +/// variable of reference type causes instantaneous undefined behavior, /// no matter whether that reference ever gets used to access memory: /// /// ```rust,no_run @@ -53,6 +53,11 @@ /// // The equivalent code with `MaybeUninit`: /// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️ /// ``` +/// +/// Conversely, sometimes it is okay to not initialize *all* bytes of a `MaybeUninit` +/// before calling `assume_init`. For instance, padding bytes do not have to be initialized. +/// See the field-by-field struct initialization example below for a case of that. +/// /// On top of that, remember that most types have additional invariants beyond merely /// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] /// is considered initialized (under the current implementation; this does not constitute @@ -197,7 +202,12 @@ /// ); /// ``` /// [`&raw mut`]: https://doc.rust-lang.org/reference/types/pointer.html#r-type.pointer.raw.constructor -/// [ub]: ../../reference/behavior-considered-undefined.html +/// [validity]: ../../reference/behavior-considered-undefined.html#r-undefined.validity +/// +/// Note that we have not initialized the padding, but that's fine -- it does not have to be +/// initialized. In fact, even if we had initialized the padding in `uninit`, those bytes would be +/// lost when copying the result: no matter the contents of the padding bytes in `uninit`, they will +/// always be uninitialized in `foo`. /// /// # Layout /// @@ -657,11 +667,18 @@ pub const fn as_mut_ptr(&mut self) -> *mut T { /// # Safety /// /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes immediate undefined - /// behavior. The [type-level documentation][inv] contains more information about - /// this initialization invariant. + /// state, i.e., a state that is considered ["valid" for type `T`][validity]. Calling this when + /// the content is not yet fully initialized causes immediate undefined behavior. The + /// [type-level documentation][inv] contains more information about this initialization + /// invariant. + /// + /// It is a common mistake to assume that this function is safe to call on integers because they + /// can hold all bit patterns. It is also a common mistake to think that calling this function + /// is UB if any byte is uninitialized. Both of these assumptions are wrong. If that is + /// surprising to you, please read the [type-level documentation][inv]. /// /// [inv]: #initialization-invariant + /// [validity]: ../../reference/behavior-considered-undefined.html#r-undefined.validity /// /// On top of that, remember that most types have additional invariants beyond merely /// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] @@ -689,12 +706,13 @@ pub const fn as_mut_ptr(&mut self) -> *mut T { /// *Incorrect* usage of this method: /// /// ```rust,no_run + /// # #![allow(invalid_value)] /// use std::mem::MaybeUninit; /// - /// let x = MaybeUninit::>::uninit(); - /// let x_init = unsafe { x.assume_init() }; - /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️ + /// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️ /// ``` + /// + /// See the [type-level documentation][#examples] for more examples. #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_assume_init_by_value", since = "1.59.0")] #[inline(always)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index d8521e79006e..a987970c9bcc 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1,7 +1,32 @@ -//! Basic functions for dealing with memory. +//! Basic functions for dealing with memory, values, and types. //! -//! This module contains functions for querying the size and alignment of -//! types, initializing and manipulating memory. +//! The contents of this module can be seen as belonging to a few families: +//! +//! * [`drop`], [`replace`], [`swap`], and [`take`] +//! are safe functions for moving values in particular ways. +//! They are useful in everyday Rust code. +//! +//! * [`size_of`], [`size_of_val`], [`align_of`], [`align_of_val`], and [`offset_of`] +//! give information about the representation of values in memory. +//! +//! * [`discriminant`] +//! allows comparing the variants of [`enum`] values while ignoring their fields. +//! +//! * [`forget`] and [`ManuallyDrop`] +//! prevent destructors from running, which is used in certain kinds of ownership transfer. +//! [`needs_drop`] +//! tells you whether a type’s destructor even does anything. +//! +//! * [`transmute`], [`transmute_copy`], and [`MaybeUninit`] +//! convert and construct values in [`unsafe`] ways. +//! +//! See also the [`alloc`] and [`ptr`] modules for more primitive operations on memory. +//! +// core::alloc exists but doesn’t contain all the items we want to discuss +//! [`alloc`]: ../../std/alloc/index.html +//! [`enum`]: ../../std/keyword.enum.html +//! [`ptr`]: crate::ptr +//! [`unsafe`]: ../../std/keyword.unsafe.html #![stable(feature = "rust1", since = "1.0.0")] @@ -9,9 +34,12 @@ use crate::clone::TrivialClone; use crate::marker::{Destruct, DiscriminantKind}; use crate::panic::const_assert; -use crate::ptr::Alignment; use crate::{clone, cmp, fmt, hash, intrinsics, ptr}; +mod alignment; +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +pub use alignment::Alignment; + mod manually_drop; #[stable(feature = "manually_drop", since = "1.20.0")] pub use manually_drop::ManuallyDrop; diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index a1bfd774710d..db94f52c4e8d 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -68,7 +68,8 @@ pub enum IpAddr { /// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` #[rustc_diagnostic_item = "Ipv4Addr"] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv4Addr { octets: [u8; 4], @@ -161,7 +162,8 @@ fn hash(&self, state: &mut H) { /// assert_eq!(localhost.is_loopback(), true); /// ``` #[rustc_diagnostic_item = "Ipv6Addr"] -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy)] +#[derive_const(Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { octets: [u8; 16], @@ -177,15 +179,17 @@ fn hash(&self, state: &mut H) { } } -/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. +/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2], +/// which updates [IETF RFC 4291 section 2.7]. /// /// # Stability Guarantees /// -/// Not all possible values for a multicast scope have been assigned. -/// Future RFCs may introduce new scopes, which will be added as variants to this enum; -/// because of this the enum is marked as `#[non_exhaustive]`. +/// Scopes 0 and F are currently reserved by IETF, and may be assigned in the future. +/// For this reason, the enum variants for those two scopes are not currently nameable. +/// You can still check for them in your code using `as` casts. /// /// # Examples +/// /// ``` /// #![feature(ip)] /// @@ -204,32 +208,76 @@ fn hash(&self, state: &mut H) { /// Some(SiteLocal) => println!("Site-Local scope"), /// Some(OrganizationLocal) => println!("Organization-Local scope"), /// Some(Global) => println!("Global scope"), -/// Some(_) => println!("Unknown scope"), +/// Some(s) => { +/// let snum = s as u8; +/// if matches!(0x0 | 0xF, snum) { +/// println!("Reserved scope {snum:X}") +/// } else { +/// println!("Unassigned scope {snum:X}") +/// } +/// } /// None => println!("Not a multicast address!") /// } -/// /// ``` /// /// [IPv6 multicast address]: Ipv6Addr /// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 -#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +/// [IETF RFC 4291 section 2.7]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.7 +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[unstable(feature = "ip", issue = "27709")] -#[non_exhaustive] pub enum Ipv6MulticastScope { + /// Reserved by IETF. + #[doc(hidden)] + #[unstable( + feature = "ip_multicast_reserved", + reason = "not yet assigned by IETF", + issue = "none" + )] + Reserved0 = 0x0, /// Interface-Local scope. - InterfaceLocal, + InterfaceLocal = 0x1, /// Link-Local scope. - LinkLocal, + LinkLocal = 0x2, /// Realm-Local scope. - RealmLocal, + RealmLocal = 0x3, /// Admin-Local scope. - AdminLocal, + AdminLocal = 0x4, /// Site-Local scope. - SiteLocal, + SiteLocal = 0x5, + + /// Scope 6. Unassigned, available for administrators + /// to define additional multicast regions. + Unassigned6 = 0x6, + /// Scope 7. Unassigned, available for administrators + /// to define additional multicast regions. + Unassigned7 = 0x7, /// Organization-Local scope. - OrganizationLocal, + OrganizationLocal = 0x8, + /// Scope 9. Unassigned, available for administrators + /// to define additional multicast regions. + Unassigned9 = 0x9, + /// Scope A. Unassigned, available for administrators + /// to define additional multicast regions. + UnassignedA = 0xA, + /// Scope B. Unassigned, available for administrators + /// to define additional multicast regions. + UnassignedB = 0xB, + /// Scope C. Unassigned, available for administrators + /// to define additional multicast regions. + UnassignedC = 0xC, + /// Scope D. Unassigned, available for administrators + /// to define additional multicast regions. + UnassignedD = 0xD, /// Global scope. - Global, + Global = 0xE, + /// Reserved by IETF. + #[doc(hidden)] + #[unstable( + feature = "ip_multicast_reserved", + reason = "not yet assigned by IETF", + issue = "none" + )] + ReservedF = 0xF, } impl IpAddr { @@ -1183,7 +1231,8 @@ fn eq(&self, other: &IpAddr) -> bool { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Ipv4Addr { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialOrd for Ipv4Addr { #[inline] fn partial_cmp(&self, other: &Ipv4Addr) -> Option { Some(self.cmp(other)) @@ -1213,7 +1262,8 @@ fn partial_cmp(&self, other: &IpAddr) -> Option { } #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Ipv4Addr { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Ord for Ipv4Addr { #[inline] fn cmp(&self, other: &Ipv4Addr) -> Ordering { self.octets.cmp(&other.octets) @@ -1848,14 +1898,23 @@ pub const fn is_unicast_global(&self) -> bool { pub const fn multicast_scope(&self) -> Option { if self.is_multicast() { match self.segments()[0] & 0x000f { - 1 => Some(Ipv6MulticastScope::InterfaceLocal), - 2 => Some(Ipv6MulticastScope::LinkLocal), - 3 => Some(Ipv6MulticastScope::RealmLocal), - 4 => Some(Ipv6MulticastScope::AdminLocal), - 5 => Some(Ipv6MulticastScope::SiteLocal), - 8 => Some(Ipv6MulticastScope::OrganizationLocal), - 14 => Some(Ipv6MulticastScope::Global), - _ => None, + 0x0 => Some(Ipv6MulticastScope::Reserved0), + 0x1 => Some(Ipv6MulticastScope::InterfaceLocal), + 0x2 => Some(Ipv6MulticastScope::LinkLocal), + 0x3 => Some(Ipv6MulticastScope::RealmLocal), + 0x4 => Some(Ipv6MulticastScope::AdminLocal), + 0x5 => Some(Ipv6MulticastScope::SiteLocal), + 0x6 => Some(Ipv6MulticastScope::Unassigned6), + 0x7 => Some(Ipv6MulticastScope::Unassigned7), + 0x8 => Some(Ipv6MulticastScope::OrganizationLocal), + 0x9 => Some(Ipv6MulticastScope::Unassigned9), + 0xA => Some(Ipv6MulticastScope::UnassignedA), + 0xB => Some(Ipv6MulticastScope::UnassignedB), + 0xC => Some(Ipv6MulticastScope::UnassignedC), + 0xD => Some(Ipv6MulticastScope::UnassignedD), + 0xE => Some(Ipv6MulticastScope::Global), + 0xF => Some(Ipv6MulticastScope::ReservedF), + _ => unreachable!(), } } else { None @@ -2177,7 +2236,8 @@ fn eq(&self, other: &Ipv6Addr) -> bool { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Ipv6Addr { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialOrd for Ipv6Addr { #[inline] fn partial_cmp(&self, other: &Ipv6Addr) -> Option { Some(self.cmp(other)) @@ -2207,7 +2267,8 @@ fn partial_cmp(&self, other: &IpAddr) -> Option { } #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Ipv6Addr { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Ord for Ipv6Addr { #[inline] fn cmp(&self, other: &Ipv6Addr) -> Ordering { self.segments().cmp(&other.segments()) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 03bc5f20d7e9..d833653fdba6 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -790,7 +790,7 @@ pub const fn to_radians(self) -> f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn max(self, other: f128) -> f128 { - intrinsics::maxnumf128(self, other) + intrinsics::maximum_number_nsz_f128(self, other) } /// Returns the minimum of the two numbers, ignoring NaN. @@ -821,7 +821,7 @@ pub const fn max(self, other: f128) -> f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn min(self, other: f128) -> f128 { - intrinsics::minnumf128(self, other) + intrinsics::minimum_number_nsz_f128(self, other) } /// Returns the maximum of the two numbers, propagating NaN. @@ -1409,7 +1409,7 @@ pub fn clamp_magnitude(self, limit: f128) -> f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn abs(self) -> Self { - intrinsics::fabsf128(self) + intrinsics::fabs(self) } /// Returns a number that represents the sign of `self`. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 1ffaf3b0ce44..b0664abcdc73 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -784,7 +784,7 @@ pub const fn to_radians(self) -> f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn max(self, other: f16) -> f16 { - intrinsics::maxnumf16(self, other) + intrinsics::maximum_number_nsz_f16(self, other) } /// Returns the minimum of the two numbers, ignoring NaN. @@ -815,7 +815,7 @@ pub const fn max(self, other: f16) -> f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn min(self, other: f16) -> f16 { - intrinsics::minnumf16(self, other) + intrinsics::minimum_number_nsz_f16(self, other) } /// Returns the maximum of the two numbers, propagating NaN. @@ -1393,7 +1393,7 @@ pub fn clamp_magnitude(self, limit: f16) -> f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn abs(self) -> Self { - intrinsics::fabsf16(self) + intrinsics::fabs(self) } /// Returns a number that represents the sign of `self`. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 4f560201196c..b85bd2b27158 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -990,7 +990,7 @@ pub const fn to_radians(self) -> f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn max(self, other: f32) -> f32 { - intrinsics::maxnumf32(self, other) + intrinsics::maximum_number_nsz_f32(self, other) } /// Returns the minimum of the two numbers, ignoring NaN. @@ -1017,7 +1017,7 @@ pub const fn max(self, other: f32) -> f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn min(self, other: f32) -> f32 { - intrinsics::minnumf32(self, other) + intrinsics::minimum_number_nsz_f32(self, other) } /// Returns the maximum of the two numbers, propagating NaN. @@ -1568,7 +1568,7 @@ pub fn clamp_magnitude(self, limit: f32) -> f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f32 { - intrinsics::fabsf32(self) + intrinsics::fabs(self) } /// Returns a number that represents the sign of `self`. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 061a73ae5f64..3e7c1e792ace 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1008,7 +1008,7 @@ pub const fn to_radians(self) -> f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn max(self, other: f64) -> f64 { - intrinsics::maxnumf64(self, other) + intrinsics::maximum_number_nsz_f64(self, other) } /// Returns the minimum of the two numbers, ignoring NaN. @@ -1035,7 +1035,7 @@ pub const fn max(self, other: f64) -> f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn min(self, other: f64) -> f64 { - intrinsics::minnumf64(self, other) + intrinsics::minimum_number_nsz_f64(self, other) } /// Returns the maximum of the two numbers, propagating NaN. @@ -1566,7 +1566,7 @@ pub fn clamp_magnitude(self, limit: f64) -> f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f64 { - intrinsics::fabsf64(self) + intrinsics::fabs(self) } /// Returns a number that represents the sign of `self`. diff --git a/library/core/src/num/imp/dec2flt/decimal.rs b/library/core/src/num/imp/dec2flt/decimal.rs index 27a53d4b9e75..c9b0cc531b38 100644 --- a/library/core/src/num/imp/dec2flt/decimal.rs +++ b/library/core/src/num/imp/dec2flt/decimal.rs @@ -1,6 +1,6 @@ //! Representation of a float as the significant digits and exponent. -use dec2flt::float::RawFloat; +use dec2flt::Lemire; use dec2flt::fpu::set_precision; use crate::num::imp::dec2flt; @@ -36,7 +36,7 @@ pub struct Decimal { impl Decimal { /// Detect if the float can be accurately reconstructed from native floats. #[inline] - fn can_use_fast_path(&self) -> bool { + fn can_use_fast_path(&self) -> bool { F::MIN_EXPONENT_FAST_PATH <= self.exponent && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH && self.mantissa <= F::MAX_MANTISSA_FAST_PATH @@ -53,7 +53,7 @@ fn can_use_fast_path(&self) -> bool { /// /// There is an exception: disguised fast-path cases, where we can shift /// powers-of-10 from the exponent to the significant digits. - pub fn try_fast_path(&self) -> Option { + pub fn try_fast_path(&self) -> Option { // Here we need to work around . // The fast path crucially depends on arithmetic being rounded to the correct number of bits // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision diff --git a/library/core/src/num/imp/dec2flt/lemire.rs b/library/core/src/num/imp/dec2flt/lemire.rs index c3f2723509d0..f89d16c84347 100644 --- a/library/core/src/num/imp/dec2flt/lemire.rs +++ b/library/core/src/num/imp/dec2flt/lemire.rs @@ -1,10 +1,9 @@ //! Implementation of the Eisel-Lemire algorithm. use dec2flt::common::BiasedFp; -use dec2flt::float::RawFloat; use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE}; -use crate::num::imp::dec2flt; +use crate::num::imp::{Float, dec2flt}; /// Compute w * 10^q using an extended-precision float representation. /// @@ -24,7 +23,7 @@ /// at a Gigabyte per Second" in section 5, "Fast Algorithm", and /// section 6, "Exact Numbers And Ties", available online: /// . -pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { +pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { let fp_zero = BiasedFp::zero_pow2(0); let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER); let fp_error = BiasedFp::zero_pow2(-1); diff --git a/library/core/src/num/imp/dec2flt/mod.rs b/library/core/src/num/imp/dec2flt/mod.rs index 3f5724add62b..76b8d416ee0f 100644 --- a/library/core/src/num/imp/dec2flt/mod.rs +++ b/library/core/src/num/imp/dec2flt/mod.rs @@ -88,24 +88,104 @@ )] use common::BiasedFp; -use float::RawFloat; use lemire::compute_float; use parse::{parse_inf_nan, parse_number}; use slow::parse_long_mantissa; +use crate::f64; use crate::num::ParseFloatError; use crate::num::float_parse::FloatErrorKind; +use crate::num::imp::FloatExt; mod common; pub mod decimal; pub mod decimal_seq; mod fpu; -mod slow; -mod table; -// float is used in flt2dec, and all are used in unit tests. -pub mod float; pub mod lemire; pub mod parse; +mod slow; +mod table; + +/// Extension to `Float` that are necessary for parsing using the Lemire method. +/// +/// See the parent module's doc comment for why this is necessary. +/// +/// Not intended for use outside of the `dec2flt` module. +#[doc(hidden)] +pub trait Lemire: FloatExt { + /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` + // assuming FLT_EVAL_METHOD = 0 + const MAX_EXPONENT_FAST_PATH: i64 = { + let log2_5 = f64::consts::LOG2_10 - 1.0; + (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 + }; + + /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` + const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; + + /// Maximum exponent that can be represented for a disguised-fast path case. + /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` + const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = + Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; + + /// Maximum mantissa for the fast-path (`1 << 53` for f64). + const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; + + /// Gets a small power-of-ten for fast-path multiplication. + fn pow10_fast_path(exponent: usize) -> Self; + + /// Converts integer into float through an as cast. + /// This is only called in the fast-path algorithm, and therefore + /// will not lose precision, since the value will always have + /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. + fn from_u64(v: u64) -> Self; +} + +#[cfg(target_has_reliable_f16)] +impl Lemire for f16 { + fn pow10_fast_path(exponent: usize) -> Self { + #[allow(clippy::use_self)] + const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.]; + TABLE[exponent & 7] + } + + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } +} + +impl Lemire for f32 { + fn pow10_fast_path(exponent: usize) -> Self { + #[allow(clippy::use_self)] + const TABLE: [f32; 16] = + [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.]; + TABLE[exponent & 15] + } + + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } +} + +impl Lemire for f64 { + fn pow10_fast_path(exponent: usize) -> Self { + const TABLE: [f64; 32] = [ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, + 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0., + ]; + TABLE[exponent & 31] + } + + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } +} #[inline] pub(super) fn pfe_empty() -> ParseFloatError { @@ -120,7 +200,7 @@ pub fn pfe_invalid() -> ParseFloatError { } /// Converts a `BiasedFp` to the closest machine float type. -fn biased_fp_to_float(x: BiasedFp) -> F { +fn biased_fp_to_float(x: BiasedFp) -> F { let mut word = x.m; word |= (x.p_biased as u64) << F::SIG_BITS; F::from_u64_bits(word) @@ -128,7 +208,7 @@ fn biased_fp_to_float(x: BiasedFp) -> F { /// Converts a decimal string into a floating point number. #[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above -pub fn dec2flt(s: &str) -> Result { +pub fn dec2flt(s: &str) -> Result { let mut s = s.as_bytes(); let Some(&c) = s.first() else { return Err(pfe_empty()) }; let negative = c == b'-'; diff --git a/library/core/src/num/imp/dec2flt/parse.rs b/library/core/src/num/imp/dec2flt/parse.rs index e4049bc164c6..ee55eadbc7b9 100644 --- a/library/core/src/num/imp/dec2flt/parse.rs +++ b/library/core/src/num/imp/dec2flt/parse.rs @@ -2,9 +2,8 @@ use dec2flt::common::{ByteSlice, is_8digits}; use dec2flt::decimal::Decimal; -use dec2flt::float::RawFloat; -use crate::num::imp::dec2flt; +use crate::num::imp::{Float, dec2flt}; const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000; @@ -197,7 +196,7 @@ pub fn parse_number(s: &[u8]) -> Option { } /// Try to parse a special, non-finite float. -pub(crate) fn parse_inf_nan(s: &[u8], negative: bool) -> Option { +pub(crate) fn parse_inf_nan(s: &[u8], negative: bool) -> Option { // Since a valid string has at most the length 8, we can load // all relevant characters into a u64 and work from there. // This also generates much better code. diff --git a/library/core/src/num/imp/dec2flt/slow.rs b/library/core/src/num/imp/dec2flt/slow.rs index 089b12f5be22..f1b2525cf38e 100644 --- a/library/core/src/num/imp/dec2flt/slow.rs +++ b/library/core/src/num/imp/dec2flt/slow.rs @@ -2,9 +2,8 @@ use dec2flt::common::BiasedFp; use dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; -use dec2flt::float::RawFloat; -use crate::num::imp::dec2flt; +use crate::num::imp::{Float, dec2flt}; /// Parse the significant digits and biased, binary exponent of a float. /// @@ -25,7 +24,7 @@ /// /// The algorithms described here are based on "Processing Long Numbers Quickly", /// available here: . -pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { +pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { const MAX_SHIFT: usize = 60; const NUM_POWERS: usize = 19; const POWERS: [u8; 19] = diff --git a/library/core/src/num/imp/flt2dec/decoder.rs b/library/core/src/num/imp/flt2dec/decoder.rs index 3d6ad6608efe..5ccc91f4c9fa 100644 --- a/library/core/src/num/imp/flt2dec/decoder.rs +++ b/library/core/src/num/imp/flt2dec/decoder.rs @@ -1,7 +1,7 @@ //! Decodes a floating-point value into individual parts and error ranges. use crate::num::FpCategory; -use crate::num::imp::dec2flt::float::RawFloat; +use crate::num::imp::FloatExt; /// Decoded unsigned finite value, such that: /// @@ -40,7 +40,7 @@ pub enum FullDecoded { } /// A floating point type which can be `decode`d. -pub trait DecodableFloat: RawFloat + Copy { +pub trait DecodableFloat: FloatExt + Copy { /// The minimum positive normalized value. fn min_pos_norm_value() -> Self; } diff --git a/library/core/src/num/imp/mod.rs b/library/core/src/num/imp/mod.rs index d35409f91bde..6fccfd1c238e 100644 --- a/library/core/src/num/imp/mod.rs +++ b/library/core/src/num/imp/mod.rs @@ -16,3 +16,6 @@ pub(crate) mod int_sqrt; pub(crate) mod libm; pub(crate) mod overflow_panic; +mod traits; + +pub use traits::{Float, FloatExt, Int}; diff --git a/library/core/src/num/imp/dec2flt/float.rs b/library/core/src/num/imp/traits.rs similarity index 72% rename from library/core/src/num/imp/dec2flt/float.rs rename to library/core/src/num/imp/traits.rs index 21aabdc8addb..7b84f7a4a5aa 100644 --- a/library/core/src/num/imp/dec2flt/float.rs +++ b/library/core/src/num/imp/traits.rs @@ -1,10 +1,14 @@ -//! Helper trait for generic float types. +//! Numeric traits used for internal implementations. -use core::f64; +#![doc(hidden)] +#![unstable( + feature = "num_internals", + reason = "internal routines only exposed for testing", + issue = "none" +)] -use crate::fmt::{Debug, LowerExp}; use crate::num::FpCategory; -use crate::ops::{self, Add, Div, Mul, Neg}; +use crate::{f64, fmt, ops}; /// Lossy `as` casting between two types. pub trait CastInto: Copy { @@ -12,11 +16,11 @@ pub trait CastInto: Copy { } /// Collection of traits that allow us to be generic over integer size. -pub trait Integer: +pub trait Int: Sized + Clone + Copy - + Debug + + fmt::Debug + ops::Shr + ops::Shl + ops::BitAnd @@ -37,7 +41,7 @@ fn cast(self) -> i16 { } } - impl Integer for $ty { + impl Int for $ty { const ZERO: Self = 0; const ONE: Self = 1; } @@ -48,27 +52,22 @@ impl Integer for $ty { int!(u16, u32, u64); /// A helper trait to avoid duplicating basically all the conversion code for IEEE floats. -/// -/// See the parent module's doc comment for why this is necessary. -/// -/// Should **never ever** be implemented for other types or be used outside the `dec2flt` module. #[doc(hidden)] -pub trait RawFloat: +pub trait Float: Sized - + Div - + Neg - + Mul - + Add - + LowerExp + + ops::Div + + ops::Neg + + ops::Mul + + ops::Add + + fmt::Debug + PartialEq + PartialOrd + Default + Clone + Copy - + Debug { /// The unsigned integer with the same size as the float - type Int: Integer + Into; + type Int: Int + Into; /* general constants */ @@ -128,8 +127,6 @@ pub trait RawFloat: const MIN_EXPONENT_ROUND_TO_EVEN: i32; const MAX_EXPONENT_ROUND_TO_EVEN: i32; - /* limits related to Fast pathing */ - /// Largest decimal exponent for a non-infinite value. /// /// This is the max exponent in binary converted to the max exponent in decimal. Allows fast @@ -151,41 +148,19 @@ pub trait RawFloat: /// compile time since intermediates exceed the range of an `f64`. const SMALLEST_POWER_OF_TEN: i32; - /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` - // assuming FLT_EVAL_METHOD = 0 - const MAX_EXPONENT_FAST_PATH: i64 = { - let log2_5 = f64::consts::LOG2_10 - 1.0; - (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 - }; - - /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` - const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; - - /// Maximum exponent that can be represented for a disguised-fast path case. - /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` - const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = - Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; - - /// Maximum mantissa for the fast-path (`1 << 53` for f64). - const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; - - /// Converts integer into float through an as cast. - /// This is only called in the fast-path algorithm, and therefore - /// will not lose precision, since the value will always have - /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. - fn from_u64(v: u64) -> Self; - - /// Performs a raw transmutation from an integer. - fn from_u64_bits(v: u64) -> Self; - - /// Gets a small power-of-ten for fast-path multiplication. - fn pow10_fast_path(exponent: usize) -> Self; - /// Returns the category that this number falls into. fn classify(self) -> FpCategory; /// Transmute to the integer representation fn to_bits(self) -> Self::Int; +} + +/// Items that ideally would be on `Float`, but don't apply to all float types because they +/// rely on the mantissa fitting into a `u64` (which isn't true for `f128`). +#[doc(hidden)] +pub trait FloatExt: Float { + /// Performs a raw transmutation from an integer. + fn from_u64_bits(v: u64) -> Self; /// Returns the mantissa, exponent and sign as integers. /// @@ -219,7 +194,7 @@ const fn pow2_to_pow10(a: i64) -> i64 { } #[cfg(target_has_reliable_f16)] -impl RawFloat for f16 { +impl Float for f16 { type Int = u16; const INFINITY: Self = Self::INFINITY; @@ -236,23 +211,6 @@ impl RawFloat for f16 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5; const SMALLEST_POWER_OF_TEN: i32 = -27; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } - - #[inline] - fn from_u64_bits(v: u64) -> Self { - Self::from_bits((v & 0xFFFF) as u16) - } - - fn pow10_fast_path(exponent: usize) -> Self { - #[allow(clippy::use_self)] - const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.]; - TABLE[exponent & 7] - } - fn to_bits(self) -> Self::Int { self.to_bits() } @@ -262,7 +220,15 @@ fn classify(self) -> FpCategory { } } -impl RawFloat for f32 { +#[cfg(target_has_reliable_f16)] +impl FloatExt for f16 { + #[inline] + fn from_u64_bits(v: u64) -> Self { + Self::from_bits((v & 0xFFFF) as u16) + } +} + +impl Float for f32 { type Int = u32; const INFINITY: Self = f32::INFINITY; @@ -279,24 +245,6 @@ impl RawFloat for f32 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10; const SMALLEST_POWER_OF_TEN: i32 = -65; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } - - #[inline] - fn from_u64_bits(v: u64) -> Self { - f32::from_bits((v & 0xFFFFFFFF) as u32) - } - - fn pow10_fast_path(exponent: usize) -> Self { - #[allow(clippy::use_self)] - const TABLE: [f32; 16] = - [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.]; - TABLE[exponent & 15] - } - fn to_bits(self) -> Self::Int { self.to_bits() } @@ -306,7 +254,14 @@ fn classify(self) -> FpCategory { } } -impl RawFloat for f64 { +impl FloatExt for f32 { + #[inline] + fn from_u64_bits(v: u64) -> Self { + f32::from_bits((v & 0xFFFFFFFF) as u32) + } +} + +impl Float for f64 { type Int = u64; const INFINITY: Self = Self::INFINITY; @@ -323,25 +278,6 @@ impl RawFloat for f64 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23; const SMALLEST_POWER_OF_TEN: i32 = -342; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } - - #[inline] - fn from_u64_bits(v: u64) -> Self { - f64::from_bits(v) - } - - fn pow10_fast_path(exponent: usize) -> Self { - const TABLE: [f64; 32] = [ - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, - 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0., - ]; - TABLE[exponent & 31] - } - fn to_bits(self) -> Self::Int { self.to_bits() } @@ -350,3 +286,10 @@ fn classify(self) -> FpCategory { self.classify() } } + +impl FloatExt for f64 { + #[inline] + fn from_u64_bits(v: u64) -> Self { + f64::from_bits(v) + } +} diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index ae8324c13f0c..27dbe6d3f1d8 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -447,7 +447,7 @@ pub const fn rotate_right(self, n: u32) -> Self { pub const fn funnel_shl(self, rhs: Self, n: u32) -> Self { assert!(n < Self::BITS, "attempt to funnel shift left with overflow"); // SAFETY: just checked that `shift` is in-range - unsafe { intrinsics::unchecked_funnel_shl(self, rhs, n) } + unsafe { self.unchecked_funnel_shl(rhs, n) } } /// Performs a right funnel shift (concatenates `self` and `rhs`, with `self` @@ -482,7 +482,61 @@ pub const fn funnel_shl(self, rhs: Self, n: u32) -> Self { pub const fn funnel_shr(self, rhs: Self, n: u32) -> Self { assert!(n < Self::BITS, "attempt to funnel shift right with overflow"); // SAFETY: just checked that `shift` is in-range - unsafe { intrinsics::unchecked_funnel_shr(self, rhs, n) } + unsafe { self.unchecked_funnel_shr(rhs, n) } + } + + /// Unchecked funnel shift left. + /// + /// # Safety + /// + /// This results in undefined behavior if `n` is greater than or equal to + #[doc = concat!("`", stringify!($SelfT) , "::BITS`,")] + /// i.e. when [`funnel_shl`](Self::funnel_shl) would panic. + /// + #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")] + #[unstable(feature = "funnel_shifts", issue = "145686")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + #[track_caller] + pub const unsafe fn unchecked_funnel_shl(self, low: Self, n: u32) -> Self { + assert_unsafe_precondition!( + check_language_ub, + concat!(stringify!($SelfT), "::unchecked_funnel_shl cannot overflow"), + (n: u32 = n) => n < <$ActualT>::BITS, + ); + + // SAFETY: this is guaranteed to be safe by the caller. + unsafe { + intrinsics::unchecked_funnel_shl(self, low, n) + } + } + + /// Unchecked funnel shift right. + /// + /// # Safety + /// + /// This results in undefined behavior if `n` is greater than or equal to + #[doc = concat!("`", stringify!($SelfT) , "::BITS`,")] + /// i.e. when [`funnel_shr`](Self::funnel_shr) would panic. + /// + #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")] + #[unstable(feature = "funnel_shifts", issue = "145686")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + #[track_caller] + pub const unsafe fn unchecked_funnel_shr(self, low: Self, n: u32) -> Self { + assert_unsafe_precondition!( + check_language_ub, + concat!(stringify!($SelfT), "::unchecked_funnel_shr cannot overflow"), + (n: u32 = n) => n < <$ActualT>::BITS, + ); + + // SAFETY: this is guaranteed to be safe by the caller. + unsafe { + intrinsics::unchecked_funnel_shr(self, low, n) + } } /// Performs a carry-less multiplication, returning the lower bits. diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 6c6479c99845..aec52424af3c 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -716,6 +716,7 @@ impl const Neg for $t { type Output = $t; #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn neg(self) -> $t { -self } } diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index 0cd61b073738..e347a20d2d86 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -484,6 +484,7 @@ impl const Shl<$f> for $t { type Output = $t; #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn shl(self, other: $f) -> $t { self << other @@ -606,6 +607,7 @@ impl const Shr<$f> for $t { type Output = $t; #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn shr(self, other: $f) -> $t { self >> other @@ -958,6 +960,7 @@ macro_rules! shl_assign_impl { #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const ShlAssign<$f> for $t { #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn shl_assign(&mut self, other: $f) { *self <<= other @@ -1044,6 +1047,7 @@ macro_rules! shr_assign_impl { #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const ShrAssign<$f> for $t { #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn shr_assign(&mut self, other: $f) { *self >>= other diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 3dc53941977c..d4dd33b94819 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1777,7 +1777,7 @@ pub fn get_or_insert(&mut self, value: T) -> &mut T { #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] pub const fn get_or_insert_default(&mut self) -> &mut T where - T: [const] Default + [const] Destruct, + T: [const] Default, { self.get_or_insert_with(T::default) } @@ -1805,10 +1805,25 @@ pub const fn get_or_insert_default(&mut self) -> &mut T pub const fn get_or_insert_with(&mut self, f: F) -> &mut T where F: [const] FnOnce() -> T + [const] Destruct, - T: [const] Destruct, { if let None = self { - *self = Some(f()); + // The effect of the following statement is identical to + // *self = Some(f()); + // except that it does not drop the old value of `*self`. This is not a leak, because + // we just checked that the old value is `None`, which contains no fields to drop. + // This implementation strategy + // + // * avoids needing a `T: [const] Destruct` bound, to the benefit of `const` callers, + // * and avoids possibly compiling needless drop code (as would sometimes happen in the + // previous implementation), to the benefit of non-`const` callers. + // + // FIXME(const-hack): It would be nice if this weird trick were made obsolete + // (though that is likely to be hard/wontfix). + // + // It could also be expressed as `unsafe { core::ptr::write(self, Some(f())) }`, but + // no reason is currently known to use additional unsafe code here. + + mem::forget(mem::replace(self, Some(f()))); } // SAFETY: a `None` variant for `self` would have been replaced by a `Some` @@ -2743,9 +2758,6 @@ impl> FromIterator> for Option { /// so the final value of `shared` is 6 (= `3 + 2 + 1`), not 16. #[inline] fn from_iter>>(iter: I) -> Option { - // FIXME(#11084): This could be replaced with Iterator::scan when this - // performance bug is closed. - iter::try_process(iter.into_iter(), |i| i.collect()) } } diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 21dbd09f4960..20f85b5ca9cd 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -2,6 +2,7 @@ use crate::cell::UnsafeCell; use crate::fmt; use crate::future::Future; +use crate::marker::PointeeSized; use crate::ops::{Deref, DerefMut}; use crate::pin::Pin; use crate::ptr::{NonNull, Unique}; @@ -178,17 +179,17 @@ // * Our custom AssertUnwindSafe wrapper is indeed unwind safe #[stable(feature = "catch_unwind", since = "1.9.0")] -impl !UnwindSafe for &mut T {} +impl !UnwindSafe for &mut T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for &T {} +impl UnwindSafe for &T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for *const T {} +impl UnwindSafe for *const T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for *mut T {} +impl UnwindSafe for *mut T {} #[unstable(feature = "ptr_internals", issue = "none")] -impl UnwindSafe for Unique {} +impl UnwindSafe for Unique {} #[stable(feature = "nonnull", since = "1.25.0")] -impl UnwindSafe for NonNull {} +impl UnwindSafe for NonNull {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for AssertUnwindSafe {} @@ -313,3 +314,16 @@ fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } } + +/// If a value's type is already `UnwindSafe`, +/// wrapping it in `AssertUnwindSafe` is never incorrect. +#[stable(feature = "from_wrapper_impls", since = "CURRENT_RUSTC_VERSION")] +impl From for AssertUnwindSafe +where + T: UnwindSafe, +{ + #[inline(always)] + fn from(value: T) -> Self { + Self(value) + } +} diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index c4981facc04c..ffdcd9fad49a 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -600,7 +600,7 @@ //! automatically called [`Pin::get_unchecked_mut`]. //! //! This can never cause a problem in purely safe code because creating a pinning pointer to -//! a type which has an address-sensitive (thus does not implement `Unpin`) requires `unsafe`, +//! a type which has address-sensitive states (and thus does not implement `Unpin`) requires `unsafe`, //! but it is important to note that choosing to take advantage of pinning-related guarantees //! to justify validity in the implementation of your type has consequences for that type's //! [`Drop`][Drop] implementation as well: if an element of your type could have been pinned, @@ -1829,9 +1829,10 @@ impl DispatchFromDyn> for Pin /// /// # Safety /// -/// If this type implements `Deref`, then the concrete type returned by `deref` -/// and `deref_mut` must not change without a modification. The following -/// operations are not considered modifications: +/// Given a pointer of this type, the concrete type returned by its +/// `deref` method and (if it implements `DerefMut`) its `deref_mut` method +/// must be the same type and must not change without a modification. +/// The following operations are not considered modifications: /// /// * Moving the pointer. /// * Performing unsizing coercions on the pointer. @@ -1842,7 +1843,7 @@ impl DispatchFromDyn> for Pin /// to. The concrete type of a slice is an array of the same element type and /// the length specified in the metadata. The concrete type of a sized type /// is the type itself. -pub unsafe trait PinCoerceUnsized {} +pub unsafe trait PinCoerceUnsized: Deref {} #[stable(feature = "pin", since = "1.33.0")] unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a T {} @@ -1853,12 +1854,6 @@ unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a mut T {} #[stable(feature = "pin", since = "1.33.0")] unsafe impl PinCoerceUnsized for Pin {} -#[stable(feature = "pin", since = "1.33.0")] -unsafe impl PinCoerceUnsized for *const T {} - -#[stable(feature = "pin", since = "1.33.0")] -unsafe impl PinCoerceUnsized for *mut T {} - /// Constructs a [Pin]<[&mut] T>, by pinning a `value: T` locally. /// /// Unlike [`Box::pin`], this does not create a new heap allocation. As explained diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 48e1e206a313..ddeb1ccc72af 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -412,9 +412,10 @@ use crate::num::NonZero; use crate::{fmt, hash, intrinsics, ub_checks}; -mod alignment; #[unstable(feature = "ptr_alignment_type", issue = "102070")] -pub use alignment::Alignment; +#[deprecated(since = "CURRENT_RUSTC_VERSION", note = "moved from `ptr` to `mem`")] +/// Deprecated re-export of [mem::Alignment]. +pub type Alignment = mem::Alignment; mod metadata; #[unstable(feature = "ptr_metadata", issue = "81513")] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 8be7d3a9ae92..90f27ca8bdb0 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -4,7 +4,6 @@ use crate::mem::{MaybeUninit, SizedTypeProperties, transmute}; use crate::num::NonZero; use crate::ops::{CoerceUnsized, DispatchFromDyn}; -use crate::pin::PinCoerceUnsized; use crate::ptr::Unique; use crate::slice::{self, SliceIndex}; use crate::ub_checks::assert_unsafe_precondition; @@ -128,8 +127,8 @@ pub const fn without_provenance(addr: NonZero) -> Self { #[must_use] #[inline] pub const fn dangling() -> Self { - let align = crate::ptr::Alignment::of::(); - NonNull::without_provenance(align.as_nonzero()) + let align = crate::mem::Alignment::of::(); + NonNull::without_provenance(align.as_nonzero_usize()) } /// Converts an address back to a mutable pointer, picking up some previously 'exposed' @@ -139,8 +138,9 @@ pub const fn dangling() -> Self { /// /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. #[stable(feature = "nonnull_provenance", since = "1.89.0")] + #[rustc_const_unstable(feature = "const_nonnull_with_exposed_provenance", issue = "154215")] #[inline] - pub fn with_exposed_provenance(addr: NonZero) -> Self { + pub const fn with_exposed_provenance(addr: NonZero) -> Self { // SAFETY: we know `addr` is non-zero. unsafe { let ptr = crate::ptr::with_exposed_provenance_mut(addr.get()); @@ -1692,9 +1692,6 @@ impl CoerceUnsized> for NonNull #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl DispatchFromDyn> for NonNull where T: Unsize {} -#[stable(feature = "pin", since = "1.33.0")] -unsafe impl PinCoerceUnsized for NonNull {} - #[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index 3160c9de4b7e..6e55f0e71bec 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -2,7 +2,6 @@ use crate::fmt; use crate::marker::{PhantomData, PointeeSized, Unsize}; use crate::ops::{CoerceUnsized, DispatchFromDyn}; -use crate::pin::PinCoerceUnsized; use crate::ptr::NonNull; /// A wrapper around a raw non-null `*mut T` that indicates that the possessor @@ -176,9 +175,6 @@ impl CoerceUnsized> for Unique wh #[unstable(feature = "ptr_internals", issue = "none")] impl DispatchFromDyn> for Unique where T: Unsize {} -#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinCoerceUnsized for Unique {} - #[unstable(feature = "ptr_internals", issue = "none")] impl fmt::Debug for Unique { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/core/src/range.rs b/library/core/src/range.rs index d12a4ef43e49..2007533e68e5 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -24,12 +24,15 @@ #[unstable(feature = "new_range_api", issue = "125687")] pub mod legacy; +#[doc(inline)] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] +pub use iter::RangeFromIter; #[doc(inline)] #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] pub use iter::RangeInclusiveIter; #[doc(inline)] #[unstable(feature = "new_range_api", issue = "125687")] -pub use iter::{RangeFromIter, RangeIter}; +pub use iter::RangeIter; // FIXME(#125687): re-exports temporarily removed // Because re-exports of stable items (Bound, RangeBounds, RangeFull, RangeTo) @@ -416,14 +419,13 @@ fn from(value: legacy::RangeInclusive) -> Self { /// /// The `RangeFrom` `start..` contains all values with `x >= start`. /// -/// *Note*: Overflow in the [`Iterator`] implementation (when the contained +/// *Note*: Overflow in the [`IntoIterator`] implementation (when the contained /// data type reaches its numerical limit) is allowed to panic, wrap, or /// saturate. This behavior is defined by the implementation of the [`Step`] /// trait. For primitive integers, this follows the normal rules, and respects -/// the overflow checks profile (panic in debug, wrap in release). Note also -/// that overflow happens earlier than you might assume: the overflow happens -/// in the call to `next` that yields the maximum value, as the range must be -/// set to a state to yield the next value. +/// the overflow checks profile (panic in debug, wrap in release). Unlike +/// its legacy counterpart, the iterator will only panic after yielding the +/// maximum value when overflow checks are enabled. /// /// [`Step`]: crate::iter::Step /// @@ -432,7 +434,6 @@ fn from(value: legacy::RangeInclusive) -> Self { /// The `start..` syntax is a `RangeFrom`: /// /// ``` -/// #![feature(new_range_api)] /// use core::range::RangeFrom; /// /// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 }); @@ -441,14 +442,14 @@ fn from(value: legacy::RangeInclusive) -> Self { #[lang = "RangeFromCopy"] #[derive(Copy, Hash)] #[derive_const(Clone, PartialEq, Eq)] -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] pub struct RangeFrom { /// The lower bound of the range (inclusive). - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] pub start: Idx, } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for RangeFrom { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.start.fmt(fmt)?; @@ -465,7 +466,6 @@ impl RangeFrom { /// # Examples /// /// ``` - /// #![feature(new_range_api)] /// use core::range::RangeFrom; /// /// let mut i = RangeFrom::from(3..).iter().map(|n| n*n); @@ -473,7 +473,7 @@ impl RangeFrom { /// assert_eq!(i.next(), Some(16)); /// assert_eq!(i.next(), Some(25)); /// ``` - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn iter(&self) -> RangeFromIter { self.clone().into_iter() @@ -486,7 +486,6 @@ impl> RangeFrom { /// # Examples /// /// ``` - /// #![feature(new_range_api)] /// use core::range::RangeFrom; /// /// assert!(!RangeFrom::from(3..).contains(&2)); @@ -498,7 +497,7 @@ impl> RangeFrom { /// assert!(!RangeFrom::from(f32::NAN..).contains(&0.5)); /// ``` #[inline] - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn contains(&self, item: &U) -> bool where @@ -509,7 +508,7 @@ pub const fn contains(&self, item: &U) -> bool } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const RangeBounds for RangeFrom { fn start_bound(&self) -> Bound<&T> { @@ -526,7 +525,7 @@ fn end_bound(&self) -> Bound<&T> { /// If you need to use this implementation where `T` is unsized, /// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound], /// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`. -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const RangeBounds for RangeFrom<&T> { fn start_bound(&self) -> Bound<&T> { @@ -537,8 +536,7 @@ fn end_bound(&self) -> Bound<&T> { } } -// #[unstable(feature = "range_into_bounds", issue = "136903")] -#[unstable(feature = "new_range_api", issue = "125687")] +#[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const IntoBounds for RangeFrom { fn into_bounds(self) -> (Bound, Bound) { @@ -547,7 +545,6 @@ fn into_bounds(self) -> (Bound, Bound) { } #[unstable(feature = "one_sided_range", issue = "69780")] -// #[unstable(feature = "new_range_api", issue = "125687")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const OneSidedRange for RangeFrom where @@ -558,7 +555,7 @@ fn bound(self) -> (OneSidedRangeBound, T) { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] impl const From> for legacy::RangeFrom { #[inline] @@ -566,7 +563,7 @@ fn from(value: RangeFrom) -> Self { Self { start: value.start } } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] impl const From> for RangeFrom { #[inline] @@ -584,7 +581,7 @@ fn from(value: legacy::RangeFrom) -> Self { /// /// The `..=last` syntax is a `RangeToInclusive`: /// -/// ``` +/// ```standalone_crate /// #![feature(new_range)] /// assert_eq!((..=5), std::range::RangeToInclusive { last: 5 }); /// ``` @@ -697,7 +694,6 @@ fn end_bound(&self) -> Bound<&T> { } } -// #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] #[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const IntoBounds for RangeToInclusive { @@ -706,7 +702,6 @@ fn into_bounds(self) -> (Bound, Bound) { } } -// #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] #[unstable(feature = "one_sided_range", issue = "69780")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const OneSidedRange for RangeToInclusive diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs index c1d4fbbd23ad..c29b498bd25f 100644 --- a/library/core/src/range/iter.rs +++ b/library/core/src/range/iter.rs @@ -11,8 +11,23 @@ pub struct RangeIter(legacy::Range); impl RangeIter { - #[unstable(feature = "new_range_api", issue = "125687")] + #[unstable(feature = "new_range_remainder", issue = "154458")] /// Returns the remainder of the range being iterated over. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_range_api)] + /// #![feature(new_range_remainder)] + /// + /// let range = core::range::Range::from(3..11); + /// let mut iter = range.into_iter(); + /// assert_eq!(iter.clone().remainder(), range); + /// iter.next(); + /// assert_eq!(iter.clone().remainder(), core::range::Range::from(4..11)); + /// iter.by_ref().for_each(drop); + /// assert!(iter.remainder().is_empty()); + /// ``` pub fn remainder(self) -> Range { Range { start: self.0.start, end: self.0.end } } @@ -161,7 +176,21 @@ impl RangeInclusiveIter { /// Returns the remainder of the range being iterated over. /// /// If the iterator is exhausted or empty, returns `None`. - #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] + /// + /// # Examples + /// + /// ``` + /// #![feature(new_range_remainder)] + /// + /// let range = core::range::RangeInclusive::from(3..=11); + /// let mut iter = range.into_iter(); + /// assert_eq!(iter.clone().remainder().unwrap(), range); + /// iter.next(); + /// assert_eq!(iter.clone().remainder().unwrap(), core::range::RangeInclusive::from(4..=11)); + /// iter.by_ref().for_each(drop); + /// assert!(iter.remainder().is_none()); + /// ``` + #[unstable(feature = "new_range_remainder", issue = "154458")] pub fn remainder(self) -> Option> { if self.0.is_empty() { return None; @@ -294,46 +323,75 @@ impl ExactSizeIterator for RangeInclusiveIter<$t> { } } /// By-value [`RangeFrom`] iterator. -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[derive(Debug, Clone)] pub struct RangeFromIter { start: A, - /// Whether the first element of the iterator has yielded. + /// Whether the maximum value of the iterator has yielded. /// Only used when overflow checks are enabled. - first: bool, + exhausted: bool, } impl RangeFromIter { /// Returns the remainder of the range being iterated over. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_range_remainder)] + /// + /// let range = core::range::RangeFrom::from(3..); + /// let mut iter = range.into_iter(); + /// assert_eq!(iter.clone().remainder(), range); + /// iter.next(); + /// assert_eq!(iter.remainder(), core::range::RangeFrom::from(4..)); + /// ``` #[inline] #[rustc_inherit_overflow_checks] - #[unstable(feature = "new_range_api", issue = "125687")] + #[unstable(feature = "new_range_remainder", issue = "154458")] pub fn remainder(self) -> RangeFrom { - if intrinsics::overflow_checks() { - if !self.first { - return RangeFrom { start: Step::forward(self.start, 1) }; - } + // Need to handle this case even if overflow-checks are disabled, + // because a `RangeFromIter` could be exhausted in a crate with + // overflow-checks enabled, but then passed to a crate with them + // disabled before this is called. + if self.exhausted { + return RangeFrom { start: Step::forward(self.start, 1) }; } RangeFrom { start: self.start } } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl Iterator for RangeFromIter { type Item = A; #[inline] #[rustc_inherit_overflow_checks] fn next(&mut self) -> Option { - if intrinsics::overflow_checks() { - if self.first { - self.first = false; - return Some(self.start.clone()); - } - + if self.exhausted { + // This should panic if overflow checks are enabled, since + // `forward_checked` returned `None` in prior iteration. self.start = Step::forward(self.start.clone(), 1); - return Some(self.start.clone()); + + // If we get here, if means this iterator was exhausted by a crate + // with overflow-checks enabled, but now we're iterating in a crate with + // overflow-checks disabled. Since we successfully incremented `self.start` + // above (in many cases this will wrap around to MIN), we now unset + // the flag so we don't repeat this process in the next iteration. + // + // This could also happen if `forward_checked` returned None but + // (for whatever reason, not applicable to any std implementors) + // `forward` doesn't panic when overflow-checks are enabled. In that + // case, this is also the correct behavior. + self.exhausted = false; + } + if intrinsics::overflow_checks() { + let Some(n) = Step::forward_checked(self.start.clone(), 1) else { + self.exhausted = true; + return Some(self.start.clone()); + }; + return Some(mem::replace(&mut self.start, n)); } let n = Step::forward(self.start.clone(), 1); @@ -348,18 +406,22 @@ fn size_hint(&self) -> (usize, Option) { #[inline] #[rustc_inherit_overflow_checks] fn nth(&mut self, n: usize) -> Option { + // Typically `forward` will cause an overflow-check panic here, + // but unset the exhausted flag to handle the uncommon cases. + // See the comments in `next` for more details. + if self.exhausted { + self.start = Step::forward(self.start.clone(), 1); + self.exhausted = false; + } if intrinsics::overflow_checks() { - if self.first { - self.first = false; - - let plus_n = Step::forward(self.start.clone(), n); - self.start = plus_n.clone(); - return Some(plus_n); - } - let plus_n = Step::forward(self.start.clone(), n); - self.start = Step::forward(plus_n.clone(), 1); - return Some(self.start.clone()); + if let Some(plus_n1) = Step::forward_checked(plus_n.clone(), 1) { + self.start = plus_n1; + } else { + self.start = plus_n.clone(); + self.exhausted = true; + } + return Some(plus_n); } let plus_n = Step::forward(self.start.clone(), n); @@ -371,15 +433,15 @@ fn nth(&mut self, n: usize) -> Option { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for RangeFromIter {} -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for RangeFromIter {} -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl IntoIterator for RangeFrom { type Item = A; type IntoIter = RangeFromIter; fn into_iter(self) -> Self::IntoIter { - RangeFromIter { start: self.start, first: true } + RangeFromIter { start: self.start, exhausted: false } } } diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 2390ca74a8e0..69a01eef88f9 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -3,7 +3,9 @@ use super::{from_raw_parts, memchr}; use crate::ascii; use crate::cmp::{self, BytewiseEq, Ordering}; +use crate::convert::Infallible; use crate::intrinsics::compare_bytes; +use crate::marker::Destruct; use crate::mem::SizedTypeProperties; use crate::num::NonZero; use crate::ops::ControlFlow; @@ -33,7 +35,8 @@ impl const Eq for [T] {} /// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for [T] { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Ord for [T] { fn cmp(&self, other: &[T]) -> Ordering { SliceOrd::compare(self, other) } @@ -52,7 +55,8 @@ const fn as_underlying(x: ControlFlow) -> u8 { /// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for [T] { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialOrd for [T] { #[inline] fn partial_cmp(&self, other: &[T]) -> Option { SlicePartialOrd::partial_compare(self, other) @@ -175,19 +179,31 @@ const trait SliceChain: Sized { type AlwaysBreak = ControlFlow; -impl SlicePartialOrd for A { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SlicePartialOrd for A { default fn partial_compare(left: &[A], right: &[A]) -> Option { - let elem_chain = |a, b| match PartialOrd::partial_cmp(a, b) { - Some(Ordering::Equal) => ControlFlow::Continue(()), - non_eq => ControlFlow::Break(non_eq), - }; - let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::partial_cmp(a, b)); + // FIXME(const-hack): revert this to a const closure once possible + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + const fn elem_chain(a: &A, b: &A) -> ControlFlow> { + match PartialOrd::partial_cmp(a, b) { + Some(Ordering::Equal) => ControlFlow::Continue(()), + non_eq => ControlFlow::Break(non_eq), + } + } + + // FIXME(const-hack): revert this to a const closure once possible + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + const fn len_chain(a: &usize, b: &usize) -> ControlFlow, Infallible> { + ControlFlow::Break(usize::partial_cmp(a, b)) + } + let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain); b } } -impl SliceChain for A { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SliceChain for A { default fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow { chaining_impl(left, right, PartialOrd::__chaining_lt, usize::__chaining_lt) } @@ -202,12 +218,13 @@ impl SliceChain for A { } } +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] #[inline] -fn chaining_impl<'l, 'r, A: PartialOrd, B, C>( +const fn chaining_impl<'l, 'r, A: PartialOrd, B, C>( left: &'l [A], right: &'r [A], - elem_chain: impl Fn(&'l A, &'r A) -> ControlFlow, - len_chain: impl for<'a> FnOnce(&'a usize, &'a usize) -> ControlFlow, + elem_chain: impl [const] Fn(&'l A, &'r A) -> ControlFlow + [const] Destruct, + len_chain: impl for<'a> [const] FnOnce(&'a usize, &'a usize) -> ControlFlow + [const] Destruct, ) -> ControlFlow { let l = cmp::min(left.len(), right.len()); @@ -216,8 +233,11 @@ fn chaining_impl<'l, 'r, A: PartialOrd, B, C>( let lhs = &left[..l]; let rhs = &right[..l]; - for i in 0..l { + // FIXME(const-hack): revert this to `for i in 0..l` once `impl const Iterator for Range` + let mut i: usize = 0; + while i < l { elem_chain(&lhs[i], &rhs[i])?; + i += 1; } len_chain(&left.len(), &right.len()) @@ -270,13 +290,24 @@ const trait SliceOrd: Sized { fn compare(left: &[Self], right: &[Self]) -> Ordering; } -impl SliceOrd for A { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SliceOrd for A { default fn compare(left: &[Self], right: &[Self]) -> Ordering { - let elem_chain = |a, b| match Ord::cmp(a, b) { - Ordering::Equal => ControlFlow::Continue(()), - non_eq => ControlFlow::Break(non_eq), - }; - let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::cmp(a, b)); + // FIXME(const-hack): revert this to a const closure once possible + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + const fn elem_chain(a: &A, b: &A) -> ControlFlow { + match Ord::cmp(a, b) { + Ordering::Equal => ControlFlow::Continue(()), + non_eq => ControlFlow::Break(non_eq), + } + } + + // FIXME(const-hack): revert this to a const closure once possible + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + const fn len_chain(a: &usize, b: &usize) -> ControlFlow { + ControlFlow::Break(usize::cmp(a, b)) + } + let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain); b } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 1709bc7c0984..b30f82a5783a 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -131,7 +131,7 @@ impl Sealed for range::Range {} impl Sealed for range::RangeInclusive {} #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] impl Sealed for range::RangeToInclusive {} - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] impl Sealed for range::RangeFrom {} impl Sealed for ops::IndexRange {} @@ -588,7 +588,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] unsafe impl const SliceIndex<[T]> for range::RangeFrom { type Output = [T]; diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 98354643aa40..0d52bfb8c9aa 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -81,25 +81,21 @@ const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! { #[track_caller] fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { - const MAX_DISPLAY_LENGTH: usize = 256; - let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH); - let s_trunc = &s[..trunc_len]; - let ellipsis = if trunc_len < s.len() { "[...]" } else { "" }; let len = s.len(); // 1. begin is OOB. if begin > len { - panic!("start byte index {begin} is out of bounds of `{s_trunc}`{ellipsis}"); + panic!("start byte index {begin} is out of bounds for string of length {len}"); } // 2. end is OOB. if end > len { - panic!("end byte index {end} is out of bounds of `{s_trunc}`{ellipsis}"); + panic!("end byte index {end} is out of bounds for string of length {len}"); } // 3. range is backwards. if begin > end { - panic!("begin > end ({begin} > {end}) when slicing `{s_trunc}`{ellipsis}") + panic!("byte range starts at {begin} but ends at {end}"); } // 4. begin is inside a character. @@ -109,7 +105,7 @@ fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { let range = floor..ceil; let ch = s[floor..ceil].chars().next().unwrap(); panic!( - "start byte index {begin} is not a char boundary; it is inside {ch:?} (bytes {range:?}) of `{s_trunc}`{ellipsis}" + "start byte index {begin} is not a char boundary; it is inside {ch:?} (bytes {range:?} of string)" ) } @@ -120,7 +116,7 @@ fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { let range = floor..ceil; let ch = s[floor..ceil].chars().next().unwrap(); panic!( - "end byte index {end} is not a char boundary; it is inside {ch:?} (bytes {range:?}) of `{s_trunc}`{ellipsis}" + "end byte index {end} is not a char boundary; it is inside {ch:?} (bytes {range:?} of string)" ) } @@ -128,7 +124,7 @@ fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { // This test cannot be combined with 2. above because for cases like // `"abcαβγ"[4..9]` the error is that 4 is inside 'α', not that 9 is OOB. debug_assert_eq!(end, len); - panic!("end byte index {end} is out of bounds of `{s_trunc}`{ellipsis}"); + panic!("end byte index {end} is out of bounds for string of length {len}"); } impl str { diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 88a8a9764cbc..336f074883d2 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -555,7 +555,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_from_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] unsafe impl const SliceIndex for range::RangeFrom { type Output = str; diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs index c71fa754e68f..22a1166fdf16 100644 --- a/library/core/src/unicode/mod.rs +++ b/library/core/src/unicode/mod.rs @@ -4,12 +4,12 @@ // for use in alloc, not re-exported in std. #[rustfmt::skip] -pub use unicode_data::case_ignorable::lookup as Case_Ignorable; -pub use unicode_data::cased::lookup as Cased; pub use unicode_data::conversions; #[rustfmt::skip] pub(crate) use unicode_data::alphabetic::lookup as Alphabetic; +pub(crate) use unicode_data::case_ignorable::lookup as Case_Ignorable; +pub(crate) use unicode_data::cased::lookup as Cased; pub(crate) use unicode_data::grapheme_extend::lookup as Grapheme_Extend; pub(crate) use unicode_data::lowercase::lookup as Lowercase; pub(crate) use unicode_data::n::lookup as N; @@ -19,7 +19,7 @@ pub(crate) mod printable; #[allow(unreachable_pub)] -mod unicode_data; +pub mod unicode_data; /// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of /// `char` and `str` methods are based on. diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index 429b60a68f43..f602cd5c5b6b 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -7,9 +7,10 @@ // N : 463 bytes, 1914 codepoints in 145 ranges (U+0000B2 - U+01FBFA) using skiplist // Uppercase : 799 bytes, 1980 codepoints in 659 ranges (U+0000C0 - U+01F18A) using bitset // White_Space : 256 bytes, 19 codepoints in 8 ranges (U+000085 - U+003001) using cascading -// to_lower : 11708 bytes -// to_upper : 13656 bytes -// Total : 31911 bytes +// to_lower : 1112 bytes, 1462 codepoints in 185 ranges (U+0000C0 - U+01E921) using 2-level LUT +// to_upper : 1998 bytes, 1554 codepoints in 299 ranges (U+0000B5 - U+01E943) using 2-level LUT +// to_title : 340 bytes, 135 codepoints in 49 ranges (U+0000DF - U+00FB17) using 2-level LUT +// Total : 9997 bytes #[inline(always)] const fn bitset_search< @@ -758,833 +759,453 @@ pub const fn lookup(c: char) -> bool { #[rustfmt::skip] pub mod conversions { - const INDEX_MASK: u32 = 0x400000; + + + use crate::ops::RangeInclusive; + + struct L1Lut { + l2_luts: [L2Lut; 2], + } + + struct L2Lut { + singles: &'static [(Range, i16)], + multis: &'static [(u16, [u16; 3])], + } + + #[derive(Copy, Clone)] + struct Range { + start: u16, + len: u8, + parity: bool, + } + + impl Range { + const fn new(range: RangeInclusive, parity: bool) -> Self { + let start = *range.start(); + let end = *range.end(); + assert!(start <= end); + + let len = end - start; + assert!(len <= 255); + + Self { start, len: len as u8, parity } + } + + const fn singleton(start: u16) -> Self { + Self::new(start..=start, false) + } + + const fn step_by_1(range: RangeInclusive) -> Self { + Self::new(range, false) + } + + const fn step_by_2(range: RangeInclusive) -> Self { + Self::new(range, true) + } + + const fn start(&self) -> u16 { + self.start + } + + const fn end(&self) -> u16 { + self.start + self.len as u16 + } + } + + fn deconstruct(c: char) -> (u16, u16) { + let c = c as u32; + let plane = (c >> 16) as u16; + let low = c as u16; + (plane, low) + } + + unsafe fn reconstruct(plane: u16, low: u16) -> char { + // SAFETY: The caller must ensure that the result is a valid `char`. + unsafe { char::from_u32_unchecked(((plane as u32) << 16) | (low as u32)) } + } + + fn lookup(input: char, l1_lut: &L1Lut) -> Option<[char; 3]> { + let (input_high, input_low) = deconstruct(input); + let Some(l2_lut) = l1_lut.l2_luts.get(input_high as usize) else { + return None; + }; + + let idx = l2_lut.singles.binary_search_by(|(range, _)| { + use crate::cmp::Ordering; + + if input_low < range.start() { + Ordering::Greater + } else if input_low > range.end() { + Ordering::Less + } else { + Ordering::Equal + } + }); + + if let Ok(idx) = idx { + // SAFETY: binary search guarantees that the index is in bounds. + let &(range, output_delta) = unsafe { l2_lut.singles.get_unchecked(idx) }; + let mask = range.parity as u16; + if input_low & mask == range.start() & mask { + let output_low = input_low.wrapping_add_signed(output_delta); + // SAFETY: Table data are guaranteed to be valid Unicode. + let output = unsafe { reconstruct(input_high, output_low) }; + return Some([output, '\0', '\0']); + } + }; + + if let Ok(idx) = l2_lut.multis.binary_search_by_key(&input_low, |&(p, _)| p) { + // SAFETY: binary search guarantees that the index is in bounds. + let &(_, output_lows) = unsafe { l2_lut.multis.get_unchecked(idx) }; + // SAFETY: Table data are guaranteed to be valid Unicode. + let output = output_lows.map(|output_low| unsafe { reconstruct(input_high, output_low) }); + return Some(output); + }; + + None + } pub fn to_lower(c: char) -> [char; 3] { - if c.is_ascii() { - [(c as u8).to_ascii_lowercase() as char, '\0', '\0'] - } else { - LOWERCASE_TABLE - .binary_search_by(|&(key, _)| key.cmp(&c)) - .map(|i| { - // SAFETY: i is the result of the binary search - let u = unsafe { LOWERCASE_TABLE.get_unchecked(i) }.1; - char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { - // SAFETY: Index comes from statically generated table - unsafe { *LOWERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } - }) - }) - .unwrap_or([c, '\0', '\0']) + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Lowercased%253A%5D-%5B%253AASCII%253A%5D&abb=on + if c < '\u{C0}' { + return [c.to_ascii_lowercase(), '\0', '\0']; } + + lookup(c, &LOWERCASE_LUT).unwrap_or([c, '\0', '\0']) } pub fn to_upper(c: char) -> [char; 3] { - if c.is_ascii() { - [(c as u8).to_ascii_uppercase() as char, '\0', '\0'] - } else { - UPPERCASE_TABLE - .binary_search_by(|&(key, _)| key.cmp(&c)) - .map(|i| { - // SAFETY: i is the result of the binary search - let u = unsafe { UPPERCASE_TABLE.get_unchecked(i) }.1; - char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { - // SAFETY: Index comes from statically generated table - unsafe { *UPPERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } - }) - }) - .unwrap_or([c, '\0', '\0']) + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Uppercased%253A%5D-%5B%253AASCII%253A%5D&abb=on + if c < '\u{B5}' { + return [c.to_ascii_uppercase(), '\0', '\0']; } + + lookup(c, &UPPERCASE_LUT).unwrap_or([c, '\0', '\0']) } - static LOWERCASE_TABLE: &[(char, u32); 1462] = &[ - ('\u{c0}', 224), ('\u{c1}', 225), ('\u{c2}', 226), ('\u{c3}', 227), ('\u{c4}', 228), - ('\u{c5}', 229), ('\u{c6}', 230), ('\u{c7}', 231), ('\u{c8}', 232), ('\u{c9}', 233), - ('\u{ca}', 234), ('\u{cb}', 235), ('\u{cc}', 236), ('\u{cd}', 237), ('\u{ce}', 238), - ('\u{cf}', 239), ('\u{d0}', 240), ('\u{d1}', 241), ('\u{d2}', 242), ('\u{d3}', 243), - ('\u{d4}', 244), ('\u{d5}', 245), ('\u{d6}', 246), ('\u{d8}', 248), ('\u{d9}', 249), - ('\u{da}', 250), ('\u{db}', 251), ('\u{dc}', 252), ('\u{dd}', 253), ('\u{de}', 254), - ('\u{100}', 257), ('\u{102}', 259), ('\u{104}', 261), ('\u{106}', 263), ('\u{108}', 265), - ('\u{10a}', 267), ('\u{10c}', 269), ('\u{10e}', 271), ('\u{110}', 273), ('\u{112}', 275), - ('\u{114}', 277), ('\u{116}', 279), ('\u{118}', 281), ('\u{11a}', 283), ('\u{11c}', 285), - ('\u{11e}', 287), ('\u{120}', 289), ('\u{122}', 291), ('\u{124}', 293), ('\u{126}', 295), - ('\u{128}', 297), ('\u{12a}', 299), ('\u{12c}', 301), ('\u{12e}', 303), - ('\u{130}', 4194304), ('\u{132}', 307), ('\u{134}', 309), ('\u{136}', 311), - ('\u{139}', 314), ('\u{13b}', 316), ('\u{13d}', 318), ('\u{13f}', 320), ('\u{141}', 322), - ('\u{143}', 324), ('\u{145}', 326), ('\u{147}', 328), ('\u{14a}', 331), ('\u{14c}', 333), - ('\u{14e}', 335), ('\u{150}', 337), ('\u{152}', 339), ('\u{154}', 341), ('\u{156}', 343), - ('\u{158}', 345), ('\u{15a}', 347), ('\u{15c}', 349), ('\u{15e}', 351), ('\u{160}', 353), - ('\u{162}', 355), ('\u{164}', 357), ('\u{166}', 359), ('\u{168}', 361), ('\u{16a}', 363), - ('\u{16c}', 365), ('\u{16e}', 367), ('\u{170}', 369), ('\u{172}', 371), ('\u{174}', 373), - ('\u{176}', 375), ('\u{178}', 255), ('\u{179}', 378), ('\u{17b}', 380), ('\u{17d}', 382), - ('\u{181}', 595), ('\u{182}', 387), ('\u{184}', 389), ('\u{186}', 596), ('\u{187}', 392), - ('\u{189}', 598), ('\u{18a}', 599), ('\u{18b}', 396), ('\u{18e}', 477), ('\u{18f}', 601), - ('\u{190}', 603), ('\u{191}', 402), ('\u{193}', 608), ('\u{194}', 611), ('\u{196}', 617), - ('\u{197}', 616), ('\u{198}', 409), ('\u{19c}', 623), ('\u{19d}', 626), ('\u{19f}', 629), - ('\u{1a0}', 417), ('\u{1a2}', 419), ('\u{1a4}', 421), ('\u{1a6}', 640), ('\u{1a7}', 424), - ('\u{1a9}', 643), ('\u{1ac}', 429), ('\u{1ae}', 648), ('\u{1af}', 432), ('\u{1b1}', 650), - ('\u{1b2}', 651), ('\u{1b3}', 436), ('\u{1b5}', 438), ('\u{1b7}', 658), ('\u{1b8}', 441), - ('\u{1bc}', 445), ('\u{1c4}', 454), ('\u{1c5}', 454), ('\u{1c7}', 457), ('\u{1c8}', 457), - ('\u{1ca}', 460), ('\u{1cb}', 460), ('\u{1cd}', 462), ('\u{1cf}', 464), ('\u{1d1}', 466), - ('\u{1d3}', 468), ('\u{1d5}', 470), ('\u{1d7}', 472), ('\u{1d9}', 474), ('\u{1db}', 476), - ('\u{1de}', 479), ('\u{1e0}', 481), ('\u{1e2}', 483), ('\u{1e4}', 485), ('\u{1e6}', 487), - ('\u{1e8}', 489), ('\u{1ea}', 491), ('\u{1ec}', 493), ('\u{1ee}', 495), ('\u{1f1}', 499), - ('\u{1f2}', 499), ('\u{1f4}', 501), ('\u{1f6}', 405), ('\u{1f7}', 447), ('\u{1f8}', 505), - ('\u{1fa}', 507), ('\u{1fc}', 509), ('\u{1fe}', 511), ('\u{200}', 513), ('\u{202}', 515), - ('\u{204}', 517), ('\u{206}', 519), ('\u{208}', 521), ('\u{20a}', 523), ('\u{20c}', 525), - ('\u{20e}', 527), ('\u{210}', 529), ('\u{212}', 531), ('\u{214}', 533), ('\u{216}', 535), - ('\u{218}', 537), ('\u{21a}', 539), ('\u{21c}', 541), ('\u{21e}', 543), ('\u{220}', 414), - ('\u{222}', 547), ('\u{224}', 549), ('\u{226}', 551), ('\u{228}', 553), ('\u{22a}', 555), - ('\u{22c}', 557), ('\u{22e}', 559), ('\u{230}', 561), ('\u{232}', 563), ('\u{23a}', 11365), - ('\u{23b}', 572), ('\u{23d}', 410), ('\u{23e}', 11366), ('\u{241}', 578), ('\u{243}', 384), - ('\u{244}', 649), ('\u{245}', 652), ('\u{246}', 583), ('\u{248}', 585), ('\u{24a}', 587), - ('\u{24c}', 589), ('\u{24e}', 591), ('\u{370}', 881), ('\u{372}', 883), ('\u{376}', 887), - ('\u{37f}', 1011), ('\u{386}', 940), ('\u{388}', 941), ('\u{389}', 942), ('\u{38a}', 943), - ('\u{38c}', 972), ('\u{38e}', 973), ('\u{38f}', 974), ('\u{391}', 945), ('\u{392}', 946), - ('\u{393}', 947), ('\u{394}', 948), ('\u{395}', 949), ('\u{396}', 950), ('\u{397}', 951), - ('\u{398}', 952), ('\u{399}', 953), ('\u{39a}', 954), ('\u{39b}', 955), ('\u{39c}', 956), - ('\u{39d}', 957), ('\u{39e}', 958), ('\u{39f}', 959), ('\u{3a0}', 960), ('\u{3a1}', 961), - ('\u{3a3}', 963), ('\u{3a4}', 964), ('\u{3a5}', 965), ('\u{3a6}', 966), ('\u{3a7}', 967), - ('\u{3a8}', 968), ('\u{3a9}', 969), ('\u{3aa}', 970), ('\u{3ab}', 971), ('\u{3cf}', 983), - ('\u{3d8}', 985), ('\u{3da}', 987), ('\u{3dc}', 989), ('\u{3de}', 991), ('\u{3e0}', 993), - ('\u{3e2}', 995), ('\u{3e4}', 997), ('\u{3e6}', 999), ('\u{3e8}', 1001), ('\u{3ea}', 1003), - ('\u{3ec}', 1005), ('\u{3ee}', 1007), ('\u{3f4}', 952), ('\u{3f7}', 1016), - ('\u{3f9}', 1010), ('\u{3fa}', 1019), ('\u{3fd}', 891), ('\u{3fe}', 892), ('\u{3ff}', 893), - ('\u{400}', 1104), ('\u{401}', 1105), ('\u{402}', 1106), ('\u{403}', 1107), - ('\u{404}', 1108), ('\u{405}', 1109), ('\u{406}', 1110), ('\u{407}', 1111), - ('\u{408}', 1112), ('\u{409}', 1113), ('\u{40a}', 1114), ('\u{40b}', 1115), - ('\u{40c}', 1116), ('\u{40d}', 1117), ('\u{40e}', 1118), ('\u{40f}', 1119), - ('\u{410}', 1072), ('\u{411}', 1073), ('\u{412}', 1074), ('\u{413}', 1075), - ('\u{414}', 1076), ('\u{415}', 1077), ('\u{416}', 1078), ('\u{417}', 1079), - ('\u{418}', 1080), ('\u{419}', 1081), ('\u{41a}', 1082), ('\u{41b}', 1083), - ('\u{41c}', 1084), ('\u{41d}', 1085), ('\u{41e}', 1086), ('\u{41f}', 1087), - ('\u{420}', 1088), ('\u{421}', 1089), ('\u{422}', 1090), ('\u{423}', 1091), - ('\u{424}', 1092), ('\u{425}', 1093), ('\u{426}', 1094), ('\u{427}', 1095), - ('\u{428}', 1096), ('\u{429}', 1097), ('\u{42a}', 1098), ('\u{42b}', 1099), - ('\u{42c}', 1100), ('\u{42d}', 1101), ('\u{42e}', 1102), ('\u{42f}', 1103), - ('\u{460}', 1121), ('\u{462}', 1123), ('\u{464}', 1125), ('\u{466}', 1127), - ('\u{468}', 1129), ('\u{46a}', 1131), ('\u{46c}', 1133), ('\u{46e}', 1135), - ('\u{470}', 1137), ('\u{472}', 1139), ('\u{474}', 1141), ('\u{476}', 1143), - ('\u{478}', 1145), ('\u{47a}', 1147), ('\u{47c}', 1149), ('\u{47e}', 1151), - ('\u{480}', 1153), ('\u{48a}', 1163), ('\u{48c}', 1165), ('\u{48e}', 1167), - ('\u{490}', 1169), ('\u{492}', 1171), ('\u{494}', 1173), ('\u{496}', 1175), - ('\u{498}', 1177), ('\u{49a}', 1179), ('\u{49c}', 1181), ('\u{49e}', 1183), - ('\u{4a0}', 1185), ('\u{4a2}', 1187), ('\u{4a4}', 1189), ('\u{4a6}', 1191), - ('\u{4a8}', 1193), ('\u{4aa}', 1195), ('\u{4ac}', 1197), ('\u{4ae}', 1199), - ('\u{4b0}', 1201), ('\u{4b2}', 1203), ('\u{4b4}', 1205), ('\u{4b6}', 1207), - ('\u{4b8}', 1209), ('\u{4ba}', 1211), ('\u{4bc}', 1213), ('\u{4be}', 1215), - ('\u{4c0}', 1231), ('\u{4c1}', 1218), ('\u{4c3}', 1220), ('\u{4c5}', 1222), - ('\u{4c7}', 1224), ('\u{4c9}', 1226), ('\u{4cb}', 1228), ('\u{4cd}', 1230), - ('\u{4d0}', 1233), ('\u{4d2}', 1235), ('\u{4d4}', 1237), ('\u{4d6}', 1239), - ('\u{4d8}', 1241), ('\u{4da}', 1243), ('\u{4dc}', 1245), ('\u{4de}', 1247), - ('\u{4e0}', 1249), ('\u{4e2}', 1251), ('\u{4e4}', 1253), ('\u{4e6}', 1255), - ('\u{4e8}', 1257), ('\u{4ea}', 1259), ('\u{4ec}', 1261), ('\u{4ee}', 1263), - ('\u{4f0}', 1265), ('\u{4f2}', 1267), ('\u{4f4}', 1269), ('\u{4f6}', 1271), - ('\u{4f8}', 1273), ('\u{4fa}', 1275), ('\u{4fc}', 1277), ('\u{4fe}', 1279), - ('\u{500}', 1281), ('\u{502}', 1283), ('\u{504}', 1285), ('\u{506}', 1287), - ('\u{508}', 1289), ('\u{50a}', 1291), ('\u{50c}', 1293), ('\u{50e}', 1295), - ('\u{510}', 1297), ('\u{512}', 1299), ('\u{514}', 1301), ('\u{516}', 1303), - ('\u{518}', 1305), ('\u{51a}', 1307), ('\u{51c}', 1309), ('\u{51e}', 1311), - ('\u{520}', 1313), ('\u{522}', 1315), ('\u{524}', 1317), ('\u{526}', 1319), - ('\u{528}', 1321), ('\u{52a}', 1323), ('\u{52c}', 1325), ('\u{52e}', 1327), - ('\u{531}', 1377), ('\u{532}', 1378), ('\u{533}', 1379), ('\u{534}', 1380), - ('\u{535}', 1381), ('\u{536}', 1382), ('\u{537}', 1383), ('\u{538}', 1384), - ('\u{539}', 1385), ('\u{53a}', 1386), ('\u{53b}', 1387), ('\u{53c}', 1388), - ('\u{53d}', 1389), ('\u{53e}', 1390), ('\u{53f}', 1391), ('\u{540}', 1392), - ('\u{541}', 1393), ('\u{542}', 1394), ('\u{543}', 1395), ('\u{544}', 1396), - ('\u{545}', 1397), ('\u{546}', 1398), ('\u{547}', 1399), ('\u{548}', 1400), - ('\u{549}', 1401), ('\u{54a}', 1402), ('\u{54b}', 1403), ('\u{54c}', 1404), - ('\u{54d}', 1405), ('\u{54e}', 1406), ('\u{54f}', 1407), ('\u{550}', 1408), - ('\u{551}', 1409), ('\u{552}', 1410), ('\u{553}', 1411), ('\u{554}', 1412), - ('\u{555}', 1413), ('\u{556}', 1414), ('\u{10a0}', 11520), ('\u{10a1}', 11521), - ('\u{10a2}', 11522), ('\u{10a3}', 11523), ('\u{10a4}', 11524), ('\u{10a5}', 11525), - ('\u{10a6}', 11526), ('\u{10a7}', 11527), ('\u{10a8}', 11528), ('\u{10a9}', 11529), - ('\u{10aa}', 11530), ('\u{10ab}', 11531), ('\u{10ac}', 11532), ('\u{10ad}', 11533), - ('\u{10ae}', 11534), ('\u{10af}', 11535), ('\u{10b0}', 11536), ('\u{10b1}', 11537), - ('\u{10b2}', 11538), ('\u{10b3}', 11539), ('\u{10b4}', 11540), ('\u{10b5}', 11541), - ('\u{10b6}', 11542), ('\u{10b7}', 11543), ('\u{10b8}', 11544), ('\u{10b9}', 11545), - ('\u{10ba}', 11546), ('\u{10bb}', 11547), ('\u{10bc}', 11548), ('\u{10bd}', 11549), - ('\u{10be}', 11550), ('\u{10bf}', 11551), ('\u{10c0}', 11552), ('\u{10c1}', 11553), - ('\u{10c2}', 11554), ('\u{10c3}', 11555), ('\u{10c4}', 11556), ('\u{10c5}', 11557), - ('\u{10c7}', 11559), ('\u{10cd}', 11565), ('\u{13a0}', 43888), ('\u{13a1}', 43889), - ('\u{13a2}', 43890), ('\u{13a3}', 43891), ('\u{13a4}', 43892), ('\u{13a5}', 43893), - ('\u{13a6}', 43894), ('\u{13a7}', 43895), ('\u{13a8}', 43896), ('\u{13a9}', 43897), - ('\u{13aa}', 43898), ('\u{13ab}', 43899), ('\u{13ac}', 43900), ('\u{13ad}', 43901), - ('\u{13ae}', 43902), ('\u{13af}', 43903), ('\u{13b0}', 43904), ('\u{13b1}', 43905), - ('\u{13b2}', 43906), ('\u{13b3}', 43907), ('\u{13b4}', 43908), ('\u{13b5}', 43909), - ('\u{13b6}', 43910), ('\u{13b7}', 43911), ('\u{13b8}', 43912), ('\u{13b9}', 43913), - ('\u{13ba}', 43914), ('\u{13bb}', 43915), ('\u{13bc}', 43916), ('\u{13bd}', 43917), - ('\u{13be}', 43918), ('\u{13bf}', 43919), ('\u{13c0}', 43920), ('\u{13c1}', 43921), - ('\u{13c2}', 43922), ('\u{13c3}', 43923), ('\u{13c4}', 43924), ('\u{13c5}', 43925), - ('\u{13c6}', 43926), ('\u{13c7}', 43927), ('\u{13c8}', 43928), ('\u{13c9}', 43929), - ('\u{13ca}', 43930), ('\u{13cb}', 43931), ('\u{13cc}', 43932), ('\u{13cd}', 43933), - ('\u{13ce}', 43934), ('\u{13cf}', 43935), ('\u{13d0}', 43936), ('\u{13d1}', 43937), - ('\u{13d2}', 43938), ('\u{13d3}', 43939), ('\u{13d4}', 43940), ('\u{13d5}', 43941), - ('\u{13d6}', 43942), ('\u{13d7}', 43943), ('\u{13d8}', 43944), ('\u{13d9}', 43945), - ('\u{13da}', 43946), ('\u{13db}', 43947), ('\u{13dc}', 43948), ('\u{13dd}', 43949), - ('\u{13de}', 43950), ('\u{13df}', 43951), ('\u{13e0}', 43952), ('\u{13e1}', 43953), - ('\u{13e2}', 43954), ('\u{13e3}', 43955), ('\u{13e4}', 43956), ('\u{13e5}', 43957), - ('\u{13e6}', 43958), ('\u{13e7}', 43959), ('\u{13e8}', 43960), ('\u{13e9}', 43961), - ('\u{13ea}', 43962), ('\u{13eb}', 43963), ('\u{13ec}', 43964), ('\u{13ed}', 43965), - ('\u{13ee}', 43966), ('\u{13ef}', 43967), ('\u{13f0}', 5112), ('\u{13f1}', 5113), - ('\u{13f2}', 5114), ('\u{13f3}', 5115), ('\u{13f4}', 5116), ('\u{13f5}', 5117), - ('\u{1c89}', 7306), ('\u{1c90}', 4304), ('\u{1c91}', 4305), ('\u{1c92}', 4306), - ('\u{1c93}', 4307), ('\u{1c94}', 4308), ('\u{1c95}', 4309), ('\u{1c96}', 4310), - ('\u{1c97}', 4311), ('\u{1c98}', 4312), ('\u{1c99}', 4313), ('\u{1c9a}', 4314), - ('\u{1c9b}', 4315), ('\u{1c9c}', 4316), ('\u{1c9d}', 4317), ('\u{1c9e}', 4318), - ('\u{1c9f}', 4319), ('\u{1ca0}', 4320), ('\u{1ca1}', 4321), ('\u{1ca2}', 4322), - ('\u{1ca3}', 4323), ('\u{1ca4}', 4324), ('\u{1ca5}', 4325), ('\u{1ca6}', 4326), - ('\u{1ca7}', 4327), ('\u{1ca8}', 4328), ('\u{1ca9}', 4329), ('\u{1caa}', 4330), - ('\u{1cab}', 4331), ('\u{1cac}', 4332), ('\u{1cad}', 4333), ('\u{1cae}', 4334), - ('\u{1caf}', 4335), ('\u{1cb0}', 4336), ('\u{1cb1}', 4337), ('\u{1cb2}', 4338), - ('\u{1cb3}', 4339), ('\u{1cb4}', 4340), ('\u{1cb5}', 4341), ('\u{1cb6}', 4342), - ('\u{1cb7}', 4343), ('\u{1cb8}', 4344), ('\u{1cb9}', 4345), ('\u{1cba}', 4346), - ('\u{1cbd}', 4349), ('\u{1cbe}', 4350), ('\u{1cbf}', 4351), ('\u{1e00}', 7681), - ('\u{1e02}', 7683), ('\u{1e04}', 7685), ('\u{1e06}', 7687), ('\u{1e08}', 7689), - ('\u{1e0a}', 7691), ('\u{1e0c}', 7693), ('\u{1e0e}', 7695), ('\u{1e10}', 7697), - ('\u{1e12}', 7699), ('\u{1e14}', 7701), ('\u{1e16}', 7703), ('\u{1e18}', 7705), - ('\u{1e1a}', 7707), ('\u{1e1c}', 7709), ('\u{1e1e}', 7711), ('\u{1e20}', 7713), - ('\u{1e22}', 7715), ('\u{1e24}', 7717), ('\u{1e26}', 7719), ('\u{1e28}', 7721), - ('\u{1e2a}', 7723), ('\u{1e2c}', 7725), ('\u{1e2e}', 7727), ('\u{1e30}', 7729), - ('\u{1e32}', 7731), ('\u{1e34}', 7733), ('\u{1e36}', 7735), ('\u{1e38}', 7737), - ('\u{1e3a}', 7739), ('\u{1e3c}', 7741), ('\u{1e3e}', 7743), ('\u{1e40}', 7745), - ('\u{1e42}', 7747), ('\u{1e44}', 7749), ('\u{1e46}', 7751), ('\u{1e48}', 7753), - ('\u{1e4a}', 7755), ('\u{1e4c}', 7757), ('\u{1e4e}', 7759), ('\u{1e50}', 7761), - ('\u{1e52}', 7763), ('\u{1e54}', 7765), ('\u{1e56}', 7767), ('\u{1e58}', 7769), - ('\u{1e5a}', 7771), ('\u{1e5c}', 7773), ('\u{1e5e}', 7775), ('\u{1e60}', 7777), - ('\u{1e62}', 7779), ('\u{1e64}', 7781), ('\u{1e66}', 7783), ('\u{1e68}', 7785), - ('\u{1e6a}', 7787), ('\u{1e6c}', 7789), ('\u{1e6e}', 7791), ('\u{1e70}', 7793), - ('\u{1e72}', 7795), ('\u{1e74}', 7797), ('\u{1e76}', 7799), ('\u{1e78}', 7801), - ('\u{1e7a}', 7803), ('\u{1e7c}', 7805), ('\u{1e7e}', 7807), ('\u{1e80}', 7809), - ('\u{1e82}', 7811), ('\u{1e84}', 7813), ('\u{1e86}', 7815), ('\u{1e88}', 7817), - ('\u{1e8a}', 7819), ('\u{1e8c}', 7821), ('\u{1e8e}', 7823), ('\u{1e90}', 7825), - ('\u{1e92}', 7827), ('\u{1e94}', 7829), ('\u{1e9e}', 223), ('\u{1ea0}', 7841), - ('\u{1ea2}', 7843), ('\u{1ea4}', 7845), ('\u{1ea6}', 7847), ('\u{1ea8}', 7849), - ('\u{1eaa}', 7851), ('\u{1eac}', 7853), ('\u{1eae}', 7855), ('\u{1eb0}', 7857), - ('\u{1eb2}', 7859), ('\u{1eb4}', 7861), ('\u{1eb6}', 7863), ('\u{1eb8}', 7865), - ('\u{1eba}', 7867), ('\u{1ebc}', 7869), ('\u{1ebe}', 7871), ('\u{1ec0}', 7873), - ('\u{1ec2}', 7875), ('\u{1ec4}', 7877), ('\u{1ec6}', 7879), ('\u{1ec8}', 7881), - ('\u{1eca}', 7883), ('\u{1ecc}', 7885), ('\u{1ece}', 7887), ('\u{1ed0}', 7889), - ('\u{1ed2}', 7891), ('\u{1ed4}', 7893), ('\u{1ed6}', 7895), ('\u{1ed8}', 7897), - ('\u{1eda}', 7899), ('\u{1edc}', 7901), ('\u{1ede}', 7903), ('\u{1ee0}', 7905), - ('\u{1ee2}', 7907), ('\u{1ee4}', 7909), ('\u{1ee6}', 7911), ('\u{1ee8}', 7913), - ('\u{1eea}', 7915), ('\u{1eec}', 7917), ('\u{1eee}', 7919), ('\u{1ef0}', 7921), - ('\u{1ef2}', 7923), ('\u{1ef4}', 7925), ('\u{1ef6}', 7927), ('\u{1ef8}', 7929), - ('\u{1efa}', 7931), ('\u{1efc}', 7933), ('\u{1efe}', 7935), ('\u{1f08}', 7936), - ('\u{1f09}', 7937), ('\u{1f0a}', 7938), ('\u{1f0b}', 7939), ('\u{1f0c}', 7940), - ('\u{1f0d}', 7941), ('\u{1f0e}', 7942), ('\u{1f0f}', 7943), ('\u{1f18}', 7952), - ('\u{1f19}', 7953), ('\u{1f1a}', 7954), ('\u{1f1b}', 7955), ('\u{1f1c}', 7956), - ('\u{1f1d}', 7957), ('\u{1f28}', 7968), ('\u{1f29}', 7969), ('\u{1f2a}', 7970), - ('\u{1f2b}', 7971), ('\u{1f2c}', 7972), ('\u{1f2d}', 7973), ('\u{1f2e}', 7974), - ('\u{1f2f}', 7975), ('\u{1f38}', 7984), ('\u{1f39}', 7985), ('\u{1f3a}', 7986), - ('\u{1f3b}', 7987), ('\u{1f3c}', 7988), ('\u{1f3d}', 7989), ('\u{1f3e}', 7990), - ('\u{1f3f}', 7991), ('\u{1f48}', 8000), ('\u{1f49}', 8001), ('\u{1f4a}', 8002), - ('\u{1f4b}', 8003), ('\u{1f4c}', 8004), ('\u{1f4d}', 8005), ('\u{1f59}', 8017), - ('\u{1f5b}', 8019), ('\u{1f5d}', 8021), ('\u{1f5f}', 8023), ('\u{1f68}', 8032), - ('\u{1f69}', 8033), ('\u{1f6a}', 8034), ('\u{1f6b}', 8035), ('\u{1f6c}', 8036), - ('\u{1f6d}', 8037), ('\u{1f6e}', 8038), ('\u{1f6f}', 8039), ('\u{1f88}', 8064), - ('\u{1f89}', 8065), ('\u{1f8a}', 8066), ('\u{1f8b}', 8067), ('\u{1f8c}', 8068), - ('\u{1f8d}', 8069), ('\u{1f8e}', 8070), ('\u{1f8f}', 8071), ('\u{1f98}', 8080), - ('\u{1f99}', 8081), ('\u{1f9a}', 8082), ('\u{1f9b}', 8083), ('\u{1f9c}', 8084), - ('\u{1f9d}', 8085), ('\u{1f9e}', 8086), ('\u{1f9f}', 8087), ('\u{1fa8}', 8096), - ('\u{1fa9}', 8097), ('\u{1faa}', 8098), ('\u{1fab}', 8099), ('\u{1fac}', 8100), - ('\u{1fad}', 8101), ('\u{1fae}', 8102), ('\u{1faf}', 8103), ('\u{1fb8}', 8112), - ('\u{1fb9}', 8113), ('\u{1fba}', 8048), ('\u{1fbb}', 8049), ('\u{1fbc}', 8115), - ('\u{1fc8}', 8050), ('\u{1fc9}', 8051), ('\u{1fca}', 8052), ('\u{1fcb}', 8053), - ('\u{1fcc}', 8131), ('\u{1fd8}', 8144), ('\u{1fd9}', 8145), ('\u{1fda}', 8054), - ('\u{1fdb}', 8055), ('\u{1fe8}', 8160), ('\u{1fe9}', 8161), ('\u{1fea}', 8058), - ('\u{1feb}', 8059), ('\u{1fec}', 8165), ('\u{1ff8}', 8056), ('\u{1ff9}', 8057), - ('\u{1ffa}', 8060), ('\u{1ffb}', 8061), ('\u{1ffc}', 8179), ('\u{2126}', 969), - ('\u{212a}', 107), ('\u{212b}', 229), ('\u{2132}', 8526), ('\u{2160}', 8560), - ('\u{2161}', 8561), ('\u{2162}', 8562), ('\u{2163}', 8563), ('\u{2164}', 8564), - ('\u{2165}', 8565), ('\u{2166}', 8566), ('\u{2167}', 8567), ('\u{2168}', 8568), - ('\u{2169}', 8569), ('\u{216a}', 8570), ('\u{216b}', 8571), ('\u{216c}', 8572), - ('\u{216d}', 8573), ('\u{216e}', 8574), ('\u{216f}', 8575), ('\u{2183}', 8580), - ('\u{24b6}', 9424), ('\u{24b7}', 9425), ('\u{24b8}', 9426), ('\u{24b9}', 9427), - ('\u{24ba}', 9428), ('\u{24bb}', 9429), ('\u{24bc}', 9430), ('\u{24bd}', 9431), - ('\u{24be}', 9432), ('\u{24bf}', 9433), ('\u{24c0}', 9434), ('\u{24c1}', 9435), - ('\u{24c2}', 9436), ('\u{24c3}', 9437), ('\u{24c4}', 9438), ('\u{24c5}', 9439), - ('\u{24c6}', 9440), ('\u{24c7}', 9441), ('\u{24c8}', 9442), ('\u{24c9}', 9443), - ('\u{24ca}', 9444), ('\u{24cb}', 9445), ('\u{24cc}', 9446), ('\u{24cd}', 9447), - ('\u{24ce}', 9448), ('\u{24cf}', 9449), ('\u{2c00}', 11312), ('\u{2c01}', 11313), - ('\u{2c02}', 11314), ('\u{2c03}', 11315), ('\u{2c04}', 11316), ('\u{2c05}', 11317), - ('\u{2c06}', 11318), ('\u{2c07}', 11319), ('\u{2c08}', 11320), ('\u{2c09}', 11321), - ('\u{2c0a}', 11322), ('\u{2c0b}', 11323), ('\u{2c0c}', 11324), ('\u{2c0d}', 11325), - ('\u{2c0e}', 11326), ('\u{2c0f}', 11327), ('\u{2c10}', 11328), ('\u{2c11}', 11329), - ('\u{2c12}', 11330), ('\u{2c13}', 11331), ('\u{2c14}', 11332), ('\u{2c15}', 11333), - ('\u{2c16}', 11334), ('\u{2c17}', 11335), ('\u{2c18}', 11336), ('\u{2c19}', 11337), - ('\u{2c1a}', 11338), ('\u{2c1b}', 11339), ('\u{2c1c}', 11340), ('\u{2c1d}', 11341), - ('\u{2c1e}', 11342), ('\u{2c1f}', 11343), ('\u{2c20}', 11344), ('\u{2c21}', 11345), - ('\u{2c22}', 11346), ('\u{2c23}', 11347), ('\u{2c24}', 11348), ('\u{2c25}', 11349), - ('\u{2c26}', 11350), ('\u{2c27}', 11351), ('\u{2c28}', 11352), ('\u{2c29}', 11353), - ('\u{2c2a}', 11354), ('\u{2c2b}', 11355), ('\u{2c2c}', 11356), ('\u{2c2d}', 11357), - ('\u{2c2e}', 11358), ('\u{2c2f}', 11359), ('\u{2c60}', 11361), ('\u{2c62}', 619), - ('\u{2c63}', 7549), ('\u{2c64}', 637), ('\u{2c67}', 11368), ('\u{2c69}', 11370), - ('\u{2c6b}', 11372), ('\u{2c6d}', 593), ('\u{2c6e}', 625), ('\u{2c6f}', 592), - ('\u{2c70}', 594), ('\u{2c72}', 11379), ('\u{2c75}', 11382), ('\u{2c7e}', 575), - ('\u{2c7f}', 576), ('\u{2c80}', 11393), ('\u{2c82}', 11395), ('\u{2c84}', 11397), - ('\u{2c86}', 11399), ('\u{2c88}', 11401), ('\u{2c8a}', 11403), ('\u{2c8c}', 11405), - ('\u{2c8e}', 11407), ('\u{2c90}', 11409), ('\u{2c92}', 11411), ('\u{2c94}', 11413), - ('\u{2c96}', 11415), ('\u{2c98}', 11417), ('\u{2c9a}', 11419), ('\u{2c9c}', 11421), - ('\u{2c9e}', 11423), ('\u{2ca0}', 11425), ('\u{2ca2}', 11427), ('\u{2ca4}', 11429), - ('\u{2ca6}', 11431), ('\u{2ca8}', 11433), ('\u{2caa}', 11435), ('\u{2cac}', 11437), - ('\u{2cae}', 11439), ('\u{2cb0}', 11441), ('\u{2cb2}', 11443), ('\u{2cb4}', 11445), - ('\u{2cb6}', 11447), ('\u{2cb8}', 11449), ('\u{2cba}', 11451), ('\u{2cbc}', 11453), - ('\u{2cbe}', 11455), ('\u{2cc0}', 11457), ('\u{2cc2}', 11459), ('\u{2cc4}', 11461), - ('\u{2cc6}', 11463), ('\u{2cc8}', 11465), ('\u{2cca}', 11467), ('\u{2ccc}', 11469), - ('\u{2cce}', 11471), ('\u{2cd0}', 11473), ('\u{2cd2}', 11475), ('\u{2cd4}', 11477), - ('\u{2cd6}', 11479), ('\u{2cd8}', 11481), ('\u{2cda}', 11483), ('\u{2cdc}', 11485), - ('\u{2cde}', 11487), ('\u{2ce0}', 11489), ('\u{2ce2}', 11491), ('\u{2ceb}', 11500), - ('\u{2ced}', 11502), ('\u{2cf2}', 11507), ('\u{a640}', 42561), ('\u{a642}', 42563), - ('\u{a644}', 42565), ('\u{a646}', 42567), ('\u{a648}', 42569), ('\u{a64a}', 42571), - ('\u{a64c}', 42573), ('\u{a64e}', 42575), ('\u{a650}', 42577), ('\u{a652}', 42579), - ('\u{a654}', 42581), ('\u{a656}', 42583), ('\u{a658}', 42585), ('\u{a65a}', 42587), - ('\u{a65c}', 42589), ('\u{a65e}', 42591), ('\u{a660}', 42593), ('\u{a662}', 42595), - ('\u{a664}', 42597), ('\u{a666}', 42599), ('\u{a668}', 42601), ('\u{a66a}', 42603), - ('\u{a66c}', 42605), ('\u{a680}', 42625), ('\u{a682}', 42627), ('\u{a684}', 42629), - ('\u{a686}', 42631), ('\u{a688}', 42633), ('\u{a68a}', 42635), ('\u{a68c}', 42637), - ('\u{a68e}', 42639), ('\u{a690}', 42641), ('\u{a692}', 42643), ('\u{a694}', 42645), - ('\u{a696}', 42647), ('\u{a698}', 42649), ('\u{a69a}', 42651), ('\u{a722}', 42787), - ('\u{a724}', 42789), ('\u{a726}', 42791), ('\u{a728}', 42793), ('\u{a72a}', 42795), - ('\u{a72c}', 42797), ('\u{a72e}', 42799), ('\u{a732}', 42803), ('\u{a734}', 42805), - ('\u{a736}', 42807), ('\u{a738}', 42809), ('\u{a73a}', 42811), ('\u{a73c}', 42813), - ('\u{a73e}', 42815), ('\u{a740}', 42817), ('\u{a742}', 42819), ('\u{a744}', 42821), - ('\u{a746}', 42823), ('\u{a748}', 42825), ('\u{a74a}', 42827), ('\u{a74c}', 42829), - ('\u{a74e}', 42831), ('\u{a750}', 42833), ('\u{a752}', 42835), ('\u{a754}', 42837), - ('\u{a756}', 42839), ('\u{a758}', 42841), ('\u{a75a}', 42843), ('\u{a75c}', 42845), - ('\u{a75e}', 42847), ('\u{a760}', 42849), ('\u{a762}', 42851), ('\u{a764}', 42853), - ('\u{a766}', 42855), ('\u{a768}', 42857), ('\u{a76a}', 42859), ('\u{a76c}', 42861), - ('\u{a76e}', 42863), ('\u{a779}', 42874), ('\u{a77b}', 42876), ('\u{a77d}', 7545), - ('\u{a77e}', 42879), ('\u{a780}', 42881), ('\u{a782}', 42883), ('\u{a784}', 42885), - ('\u{a786}', 42887), ('\u{a78b}', 42892), ('\u{a78d}', 613), ('\u{a790}', 42897), - ('\u{a792}', 42899), ('\u{a796}', 42903), ('\u{a798}', 42905), ('\u{a79a}', 42907), - ('\u{a79c}', 42909), ('\u{a79e}', 42911), ('\u{a7a0}', 42913), ('\u{a7a2}', 42915), - ('\u{a7a4}', 42917), ('\u{a7a6}', 42919), ('\u{a7a8}', 42921), ('\u{a7aa}', 614), - ('\u{a7ab}', 604), ('\u{a7ac}', 609), ('\u{a7ad}', 620), ('\u{a7ae}', 618), - ('\u{a7b0}', 670), ('\u{a7b1}', 647), ('\u{a7b2}', 669), ('\u{a7b3}', 43859), - ('\u{a7b4}', 42933), ('\u{a7b6}', 42935), ('\u{a7b8}', 42937), ('\u{a7ba}', 42939), - ('\u{a7bc}', 42941), ('\u{a7be}', 42943), ('\u{a7c0}', 42945), ('\u{a7c2}', 42947), - ('\u{a7c4}', 42900), ('\u{a7c5}', 642), ('\u{a7c6}', 7566), ('\u{a7c7}', 42952), - ('\u{a7c9}', 42954), ('\u{a7cb}', 612), ('\u{a7cc}', 42957), ('\u{a7ce}', 42959), - ('\u{a7d0}', 42961), ('\u{a7d2}', 42963), ('\u{a7d4}', 42965), ('\u{a7d6}', 42967), - ('\u{a7d8}', 42969), ('\u{a7da}', 42971), ('\u{a7dc}', 411), ('\u{a7f5}', 42998), - ('\u{ff21}', 65345), ('\u{ff22}', 65346), ('\u{ff23}', 65347), ('\u{ff24}', 65348), - ('\u{ff25}', 65349), ('\u{ff26}', 65350), ('\u{ff27}', 65351), ('\u{ff28}', 65352), - ('\u{ff29}', 65353), ('\u{ff2a}', 65354), ('\u{ff2b}', 65355), ('\u{ff2c}', 65356), - ('\u{ff2d}', 65357), ('\u{ff2e}', 65358), ('\u{ff2f}', 65359), ('\u{ff30}', 65360), - ('\u{ff31}', 65361), ('\u{ff32}', 65362), ('\u{ff33}', 65363), ('\u{ff34}', 65364), - ('\u{ff35}', 65365), ('\u{ff36}', 65366), ('\u{ff37}', 65367), ('\u{ff38}', 65368), - ('\u{ff39}', 65369), ('\u{ff3a}', 65370), ('\u{10400}', 66600), ('\u{10401}', 66601), - ('\u{10402}', 66602), ('\u{10403}', 66603), ('\u{10404}', 66604), ('\u{10405}', 66605), - ('\u{10406}', 66606), ('\u{10407}', 66607), ('\u{10408}', 66608), ('\u{10409}', 66609), - ('\u{1040a}', 66610), ('\u{1040b}', 66611), ('\u{1040c}', 66612), ('\u{1040d}', 66613), - ('\u{1040e}', 66614), ('\u{1040f}', 66615), ('\u{10410}', 66616), ('\u{10411}', 66617), - ('\u{10412}', 66618), ('\u{10413}', 66619), ('\u{10414}', 66620), ('\u{10415}', 66621), - ('\u{10416}', 66622), ('\u{10417}', 66623), ('\u{10418}', 66624), ('\u{10419}', 66625), - ('\u{1041a}', 66626), ('\u{1041b}', 66627), ('\u{1041c}', 66628), ('\u{1041d}', 66629), - ('\u{1041e}', 66630), ('\u{1041f}', 66631), ('\u{10420}', 66632), ('\u{10421}', 66633), - ('\u{10422}', 66634), ('\u{10423}', 66635), ('\u{10424}', 66636), ('\u{10425}', 66637), - ('\u{10426}', 66638), ('\u{10427}', 66639), ('\u{104b0}', 66776), ('\u{104b1}', 66777), - ('\u{104b2}', 66778), ('\u{104b3}', 66779), ('\u{104b4}', 66780), ('\u{104b5}', 66781), - ('\u{104b6}', 66782), ('\u{104b7}', 66783), ('\u{104b8}', 66784), ('\u{104b9}', 66785), - ('\u{104ba}', 66786), ('\u{104bb}', 66787), ('\u{104bc}', 66788), ('\u{104bd}', 66789), - ('\u{104be}', 66790), ('\u{104bf}', 66791), ('\u{104c0}', 66792), ('\u{104c1}', 66793), - ('\u{104c2}', 66794), ('\u{104c3}', 66795), ('\u{104c4}', 66796), ('\u{104c5}', 66797), - ('\u{104c6}', 66798), ('\u{104c7}', 66799), ('\u{104c8}', 66800), ('\u{104c9}', 66801), - ('\u{104ca}', 66802), ('\u{104cb}', 66803), ('\u{104cc}', 66804), ('\u{104cd}', 66805), - ('\u{104ce}', 66806), ('\u{104cf}', 66807), ('\u{104d0}', 66808), ('\u{104d1}', 66809), - ('\u{104d2}', 66810), ('\u{104d3}', 66811), ('\u{10570}', 66967), ('\u{10571}', 66968), - ('\u{10572}', 66969), ('\u{10573}', 66970), ('\u{10574}', 66971), ('\u{10575}', 66972), - ('\u{10576}', 66973), ('\u{10577}', 66974), ('\u{10578}', 66975), ('\u{10579}', 66976), - ('\u{1057a}', 66977), ('\u{1057c}', 66979), ('\u{1057d}', 66980), ('\u{1057e}', 66981), - ('\u{1057f}', 66982), ('\u{10580}', 66983), ('\u{10581}', 66984), ('\u{10582}', 66985), - ('\u{10583}', 66986), ('\u{10584}', 66987), ('\u{10585}', 66988), ('\u{10586}', 66989), - ('\u{10587}', 66990), ('\u{10588}', 66991), ('\u{10589}', 66992), ('\u{1058a}', 66993), - ('\u{1058c}', 66995), ('\u{1058d}', 66996), ('\u{1058e}', 66997), ('\u{1058f}', 66998), - ('\u{10590}', 66999), ('\u{10591}', 67000), ('\u{10592}', 67001), ('\u{10594}', 67003), - ('\u{10595}', 67004), ('\u{10c80}', 68800), ('\u{10c81}', 68801), ('\u{10c82}', 68802), - ('\u{10c83}', 68803), ('\u{10c84}', 68804), ('\u{10c85}', 68805), ('\u{10c86}', 68806), - ('\u{10c87}', 68807), ('\u{10c88}', 68808), ('\u{10c89}', 68809), ('\u{10c8a}', 68810), - ('\u{10c8b}', 68811), ('\u{10c8c}', 68812), ('\u{10c8d}', 68813), ('\u{10c8e}', 68814), - ('\u{10c8f}', 68815), ('\u{10c90}', 68816), ('\u{10c91}', 68817), ('\u{10c92}', 68818), - ('\u{10c93}', 68819), ('\u{10c94}', 68820), ('\u{10c95}', 68821), ('\u{10c96}', 68822), - ('\u{10c97}', 68823), ('\u{10c98}', 68824), ('\u{10c99}', 68825), ('\u{10c9a}', 68826), - ('\u{10c9b}', 68827), ('\u{10c9c}', 68828), ('\u{10c9d}', 68829), ('\u{10c9e}', 68830), - ('\u{10c9f}', 68831), ('\u{10ca0}', 68832), ('\u{10ca1}', 68833), ('\u{10ca2}', 68834), - ('\u{10ca3}', 68835), ('\u{10ca4}', 68836), ('\u{10ca5}', 68837), ('\u{10ca6}', 68838), - ('\u{10ca7}', 68839), ('\u{10ca8}', 68840), ('\u{10ca9}', 68841), ('\u{10caa}', 68842), - ('\u{10cab}', 68843), ('\u{10cac}', 68844), ('\u{10cad}', 68845), ('\u{10cae}', 68846), - ('\u{10caf}', 68847), ('\u{10cb0}', 68848), ('\u{10cb1}', 68849), ('\u{10cb2}', 68850), - ('\u{10d50}', 68976), ('\u{10d51}', 68977), ('\u{10d52}', 68978), ('\u{10d53}', 68979), - ('\u{10d54}', 68980), ('\u{10d55}', 68981), ('\u{10d56}', 68982), ('\u{10d57}', 68983), - ('\u{10d58}', 68984), ('\u{10d59}', 68985), ('\u{10d5a}', 68986), ('\u{10d5b}', 68987), - ('\u{10d5c}', 68988), ('\u{10d5d}', 68989), ('\u{10d5e}', 68990), ('\u{10d5f}', 68991), - ('\u{10d60}', 68992), ('\u{10d61}', 68993), ('\u{10d62}', 68994), ('\u{10d63}', 68995), - ('\u{10d64}', 68996), ('\u{10d65}', 68997), ('\u{118a0}', 71872), ('\u{118a1}', 71873), - ('\u{118a2}', 71874), ('\u{118a3}', 71875), ('\u{118a4}', 71876), ('\u{118a5}', 71877), - ('\u{118a6}', 71878), ('\u{118a7}', 71879), ('\u{118a8}', 71880), ('\u{118a9}', 71881), - ('\u{118aa}', 71882), ('\u{118ab}', 71883), ('\u{118ac}', 71884), ('\u{118ad}', 71885), - ('\u{118ae}', 71886), ('\u{118af}', 71887), ('\u{118b0}', 71888), ('\u{118b1}', 71889), - ('\u{118b2}', 71890), ('\u{118b3}', 71891), ('\u{118b4}', 71892), ('\u{118b5}', 71893), - ('\u{118b6}', 71894), ('\u{118b7}', 71895), ('\u{118b8}', 71896), ('\u{118b9}', 71897), - ('\u{118ba}', 71898), ('\u{118bb}', 71899), ('\u{118bc}', 71900), ('\u{118bd}', 71901), - ('\u{118be}', 71902), ('\u{118bf}', 71903), ('\u{16e40}', 93792), ('\u{16e41}', 93793), - ('\u{16e42}', 93794), ('\u{16e43}', 93795), ('\u{16e44}', 93796), ('\u{16e45}', 93797), - ('\u{16e46}', 93798), ('\u{16e47}', 93799), ('\u{16e48}', 93800), ('\u{16e49}', 93801), - ('\u{16e4a}', 93802), ('\u{16e4b}', 93803), ('\u{16e4c}', 93804), ('\u{16e4d}', 93805), - ('\u{16e4e}', 93806), ('\u{16e4f}', 93807), ('\u{16e50}', 93808), ('\u{16e51}', 93809), - ('\u{16e52}', 93810), ('\u{16e53}', 93811), ('\u{16e54}', 93812), ('\u{16e55}', 93813), - ('\u{16e56}', 93814), ('\u{16e57}', 93815), ('\u{16e58}', 93816), ('\u{16e59}', 93817), - ('\u{16e5a}', 93818), ('\u{16e5b}', 93819), ('\u{16e5c}', 93820), ('\u{16e5d}', 93821), - ('\u{16e5e}', 93822), ('\u{16e5f}', 93823), ('\u{16ea0}', 93883), ('\u{16ea1}', 93884), - ('\u{16ea2}', 93885), ('\u{16ea3}', 93886), ('\u{16ea4}', 93887), ('\u{16ea5}', 93888), - ('\u{16ea6}', 93889), ('\u{16ea7}', 93890), ('\u{16ea8}', 93891), ('\u{16ea9}', 93892), - ('\u{16eaa}', 93893), ('\u{16eab}', 93894), ('\u{16eac}', 93895), ('\u{16ead}', 93896), - ('\u{16eae}', 93897), ('\u{16eaf}', 93898), ('\u{16eb0}', 93899), ('\u{16eb1}', 93900), - ('\u{16eb2}', 93901), ('\u{16eb3}', 93902), ('\u{16eb4}', 93903), ('\u{16eb5}', 93904), - ('\u{16eb6}', 93905), ('\u{16eb7}', 93906), ('\u{16eb8}', 93907), ('\u{1e900}', 125218), - ('\u{1e901}', 125219), ('\u{1e902}', 125220), ('\u{1e903}', 125221), ('\u{1e904}', 125222), - ('\u{1e905}', 125223), ('\u{1e906}', 125224), ('\u{1e907}', 125225), ('\u{1e908}', 125226), - ('\u{1e909}', 125227), ('\u{1e90a}', 125228), ('\u{1e90b}', 125229), ('\u{1e90c}', 125230), - ('\u{1e90d}', 125231), ('\u{1e90e}', 125232), ('\u{1e90f}', 125233), ('\u{1e910}', 125234), - ('\u{1e911}', 125235), ('\u{1e912}', 125236), ('\u{1e913}', 125237), ('\u{1e914}', 125238), - ('\u{1e915}', 125239), ('\u{1e916}', 125240), ('\u{1e917}', 125241), ('\u{1e918}', 125242), - ('\u{1e919}', 125243), ('\u{1e91a}', 125244), ('\u{1e91b}', 125245), ('\u{1e91c}', 125246), - ('\u{1e91d}', 125247), ('\u{1e91e}', 125248), ('\u{1e91f}', 125249), ('\u{1e920}', 125250), - ('\u{1e921}', 125251), - ]; + pub fn to_title(c: char) -> [char; 3] { + // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%253AChanges_When_Titlecased%253A%5D-%5B%253AASCII%253A%5D&abb=on + if c < '\u{B5}' { + return [c.to_ascii_uppercase(), '\0', '\0']; + } - static LOWERCASE_TABLE_MULTI: &[[char; 3]; 1] = &[ - ['i', '\u{307}', '\u{0}'], - ]; + lookup(c, &TITLECASE_LUT).or_else(|| lookup(c, &UPPERCASE_LUT)).unwrap_or([c, '\0', '\0']) + } - static UPPERCASE_TABLE: &[(char, u32); 1554] = &[ - ('\u{b5}', 924), ('\u{df}', 4194304), ('\u{e0}', 192), ('\u{e1}', 193), ('\u{e2}', 194), - ('\u{e3}', 195), ('\u{e4}', 196), ('\u{e5}', 197), ('\u{e6}', 198), ('\u{e7}', 199), - ('\u{e8}', 200), ('\u{e9}', 201), ('\u{ea}', 202), ('\u{eb}', 203), ('\u{ec}', 204), - ('\u{ed}', 205), ('\u{ee}', 206), ('\u{ef}', 207), ('\u{f0}', 208), ('\u{f1}', 209), - ('\u{f2}', 210), ('\u{f3}', 211), ('\u{f4}', 212), ('\u{f5}', 213), ('\u{f6}', 214), - ('\u{f8}', 216), ('\u{f9}', 217), ('\u{fa}', 218), ('\u{fb}', 219), ('\u{fc}', 220), - ('\u{fd}', 221), ('\u{fe}', 222), ('\u{ff}', 376), ('\u{101}', 256), ('\u{103}', 258), - ('\u{105}', 260), ('\u{107}', 262), ('\u{109}', 264), ('\u{10b}', 266), ('\u{10d}', 268), - ('\u{10f}', 270), ('\u{111}', 272), ('\u{113}', 274), ('\u{115}', 276), ('\u{117}', 278), - ('\u{119}', 280), ('\u{11b}', 282), ('\u{11d}', 284), ('\u{11f}', 286), ('\u{121}', 288), - ('\u{123}', 290), ('\u{125}', 292), ('\u{127}', 294), ('\u{129}', 296), ('\u{12b}', 298), - ('\u{12d}', 300), ('\u{12f}', 302), ('\u{131}', 73), ('\u{133}', 306), ('\u{135}', 308), - ('\u{137}', 310), ('\u{13a}', 313), ('\u{13c}', 315), ('\u{13e}', 317), ('\u{140}', 319), - ('\u{142}', 321), ('\u{144}', 323), ('\u{146}', 325), ('\u{148}', 327), - ('\u{149}', 4194305), ('\u{14b}', 330), ('\u{14d}', 332), ('\u{14f}', 334), - ('\u{151}', 336), ('\u{153}', 338), ('\u{155}', 340), ('\u{157}', 342), ('\u{159}', 344), - ('\u{15b}', 346), ('\u{15d}', 348), ('\u{15f}', 350), ('\u{161}', 352), ('\u{163}', 354), - ('\u{165}', 356), ('\u{167}', 358), ('\u{169}', 360), ('\u{16b}', 362), ('\u{16d}', 364), - ('\u{16f}', 366), ('\u{171}', 368), ('\u{173}', 370), ('\u{175}', 372), ('\u{177}', 374), - ('\u{17a}', 377), ('\u{17c}', 379), ('\u{17e}', 381), ('\u{17f}', 83), ('\u{180}', 579), - ('\u{183}', 386), ('\u{185}', 388), ('\u{188}', 391), ('\u{18c}', 395), ('\u{192}', 401), - ('\u{195}', 502), ('\u{199}', 408), ('\u{19a}', 573), ('\u{19b}', 42972), ('\u{19e}', 544), - ('\u{1a1}', 416), ('\u{1a3}', 418), ('\u{1a5}', 420), ('\u{1a8}', 423), ('\u{1ad}', 428), - ('\u{1b0}', 431), ('\u{1b4}', 435), ('\u{1b6}', 437), ('\u{1b9}', 440), ('\u{1bd}', 444), - ('\u{1bf}', 503), ('\u{1c5}', 452), ('\u{1c6}', 452), ('\u{1c8}', 455), ('\u{1c9}', 455), - ('\u{1cb}', 458), ('\u{1cc}', 458), ('\u{1ce}', 461), ('\u{1d0}', 463), ('\u{1d2}', 465), - ('\u{1d4}', 467), ('\u{1d6}', 469), ('\u{1d8}', 471), ('\u{1da}', 473), ('\u{1dc}', 475), - ('\u{1dd}', 398), ('\u{1df}', 478), ('\u{1e1}', 480), ('\u{1e3}', 482), ('\u{1e5}', 484), - ('\u{1e7}', 486), ('\u{1e9}', 488), ('\u{1eb}', 490), ('\u{1ed}', 492), ('\u{1ef}', 494), - ('\u{1f0}', 4194306), ('\u{1f2}', 497), ('\u{1f3}', 497), ('\u{1f5}', 500), - ('\u{1f9}', 504), ('\u{1fb}', 506), ('\u{1fd}', 508), ('\u{1ff}', 510), ('\u{201}', 512), - ('\u{203}', 514), ('\u{205}', 516), ('\u{207}', 518), ('\u{209}', 520), ('\u{20b}', 522), - ('\u{20d}', 524), ('\u{20f}', 526), ('\u{211}', 528), ('\u{213}', 530), ('\u{215}', 532), - ('\u{217}', 534), ('\u{219}', 536), ('\u{21b}', 538), ('\u{21d}', 540), ('\u{21f}', 542), - ('\u{223}', 546), ('\u{225}', 548), ('\u{227}', 550), ('\u{229}', 552), ('\u{22b}', 554), - ('\u{22d}', 556), ('\u{22f}', 558), ('\u{231}', 560), ('\u{233}', 562), ('\u{23c}', 571), - ('\u{23f}', 11390), ('\u{240}', 11391), ('\u{242}', 577), ('\u{247}', 582), - ('\u{249}', 584), ('\u{24b}', 586), ('\u{24d}', 588), ('\u{24f}', 590), ('\u{250}', 11375), - ('\u{251}', 11373), ('\u{252}', 11376), ('\u{253}', 385), ('\u{254}', 390), - ('\u{256}', 393), ('\u{257}', 394), ('\u{259}', 399), ('\u{25b}', 400), ('\u{25c}', 42923), - ('\u{260}', 403), ('\u{261}', 42924), ('\u{263}', 404), ('\u{264}', 42955), - ('\u{265}', 42893), ('\u{266}', 42922), ('\u{268}', 407), ('\u{269}', 406), - ('\u{26a}', 42926), ('\u{26b}', 11362), ('\u{26c}', 42925), ('\u{26f}', 412), - ('\u{271}', 11374), ('\u{272}', 413), ('\u{275}', 415), ('\u{27d}', 11364), - ('\u{280}', 422), ('\u{282}', 42949), ('\u{283}', 425), ('\u{287}', 42929), - ('\u{288}', 430), ('\u{289}', 580), ('\u{28a}', 433), ('\u{28b}', 434), ('\u{28c}', 581), - ('\u{292}', 439), ('\u{29d}', 42930), ('\u{29e}', 42928), ('\u{345}', 921), - ('\u{371}', 880), ('\u{373}', 882), ('\u{377}', 886), ('\u{37b}', 1021), ('\u{37c}', 1022), - ('\u{37d}', 1023), ('\u{390}', 4194307), ('\u{3ac}', 902), ('\u{3ad}', 904), - ('\u{3ae}', 905), ('\u{3af}', 906), ('\u{3b0}', 4194308), ('\u{3b1}', 913), - ('\u{3b2}', 914), ('\u{3b3}', 915), ('\u{3b4}', 916), ('\u{3b5}', 917), ('\u{3b6}', 918), - ('\u{3b7}', 919), ('\u{3b8}', 920), ('\u{3b9}', 921), ('\u{3ba}', 922), ('\u{3bb}', 923), - ('\u{3bc}', 924), ('\u{3bd}', 925), ('\u{3be}', 926), ('\u{3bf}', 927), ('\u{3c0}', 928), - ('\u{3c1}', 929), ('\u{3c2}', 931), ('\u{3c3}', 931), ('\u{3c4}', 932), ('\u{3c5}', 933), - ('\u{3c6}', 934), ('\u{3c7}', 935), ('\u{3c8}', 936), ('\u{3c9}', 937), ('\u{3ca}', 938), - ('\u{3cb}', 939), ('\u{3cc}', 908), ('\u{3cd}', 910), ('\u{3ce}', 911), ('\u{3d0}', 914), - ('\u{3d1}', 920), ('\u{3d5}', 934), ('\u{3d6}', 928), ('\u{3d7}', 975), ('\u{3d9}', 984), - ('\u{3db}', 986), ('\u{3dd}', 988), ('\u{3df}', 990), ('\u{3e1}', 992), ('\u{3e3}', 994), - ('\u{3e5}', 996), ('\u{3e7}', 998), ('\u{3e9}', 1000), ('\u{3eb}', 1002), ('\u{3ed}', 1004), - ('\u{3ef}', 1006), ('\u{3f0}', 922), ('\u{3f1}', 929), ('\u{3f2}', 1017), ('\u{3f3}', 895), - ('\u{3f5}', 917), ('\u{3f8}', 1015), ('\u{3fb}', 1018), ('\u{430}', 1040), - ('\u{431}', 1041), ('\u{432}', 1042), ('\u{433}', 1043), ('\u{434}', 1044), - ('\u{435}', 1045), ('\u{436}', 1046), ('\u{437}', 1047), ('\u{438}', 1048), - ('\u{439}', 1049), ('\u{43a}', 1050), ('\u{43b}', 1051), ('\u{43c}', 1052), - ('\u{43d}', 1053), ('\u{43e}', 1054), ('\u{43f}', 1055), ('\u{440}', 1056), - ('\u{441}', 1057), ('\u{442}', 1058), ('\u{443}', 1059), ('\u{444}', 1060), - ('\u{445}', 1061), ('\u{446}', 1062), ('\u{447}', 1063), ('\u{448}', 1064), - ('\u{449}', 1065), ('\u{44a}', 1066), ('\u{44b}', 1067), ('\u{44c}', 1068), - ('\u{44d}', 1069), ('\u{44e}', 1070), ('\u{44f}', 1071), ('\u{450}', 1024), - ('\u{451}', 1025), ('\u{452}', 1026), ('\u{453}', 1027), ('\u{454}', 1028), - ('\u{455}', 1029), ('\u{456}', 1030), ('\u{457}', 1031), ('\u{458}', 1032), - ('\u{459}', 1033), ('\u{45a}', 1034), ('\u{45b}', 1035), ('\u{45c}', 1036), - ('\u{45d}', 1037), ('\u{45e}', 1038), ('\u{45f}', 1039), ('\u{461}', 1120), - ('\u{463}', 1122), ('\u{465}', 1124), ('\u{467}', 1126), ('\u{469}', 1128), - ('\u{46b}', 1130), ('\u{46d}', 1132), ('\u{46f}', 1134), ('\u{471}', 1136), - ('\u{473}', 1138), ('\u{475}', 1140), ('\u{477}', 1142), ('\u{479}', 1144), - ('\u{47b}', 1146), ('\u{47d}', 1148), ('\u{47f}', 1150), ('\u{481}', 1152), - ('\u{48b}', 1162), ('\u{48d}', 1164), ('\u{48f}', 1166), ('\u{491}', 1168), - ('\u{493}', 1170), ('\u{495}', 1172), ('\u{497}', 1174), ('\u{499}', 1176), - ('\u{49b}', 1178), ('\u{49d}', 1180), ('\u{49f}', 1182), ('\u{4a1}', 1184), - ('\u{4a3}', 1186), ('\u{4a5}', 1188), ('\u{4a7}', 1190), ('\u{4a9}', 1192), - ('\u{4ab}', 1194), ('\u{4ad}', 1196), ('\u{4af}', 1198), ('\u{4b1}', 1200), - ('\u{4b3}', 1202), ('\u{4b5}', 1204), ('\u{4b7}', 1206), ('\u{4b9}', 1208), - ('\u{4bb}', 1210), ('\u{4bd}', 1212), ('\u{4bf}', 1214), ('\u{4c2}', 1217), - ('\u{4c4}', 1219), ('\u{4c6}', 1221), ('\u{4c8}', 1223), ('\u{4ca}', 1225), - ('\u{4cc}', 1227), ('\u{4ce}', 1229), ('\u{4cf}', 1216), ('\u{4d1}', 1232), - ('\u{4d3}', 1234), ('\u{4d5}', 1236), ('\u{4d7}', 1238), ('\u{4d9}', 1240), - ('\u{4db}', 1242), ('\u{4dd}', 1244), ('\u{4df}', 1246), ('\u{4e1}', 1248), - ('\u{4e3}', 1250), ('\u{4e5}', 1252), ('\u{4e7}', 1254), ('\u{4e9}', 1256), - ('\u{4eb}', 1258), ('\u{4ed}', 1260), ('\u{4ef}', 1262), ('\u{4f1}', 1264), - ('\u{4f3}', 1266), ('\u{4f5}', 1268), ('\u{4f7}', 1270), ('\u{4f9}', 1272), - ('\u{4fb}', 1274), ('\u{4fd}', 1276), ('\u{4ff}', 1278), ('\u{501}', 1280), - ('\u{503}', 1282), ('\u{505}', 1284), ('\u{507}', 1286), ('\u{509}', 1288), - ('\u{50b}', 1290), ('\u{50d}', 1292), ('\u{50f}', 1294), ('\u{511}', 1296), - ('\u{513}', 1298), ('\u{515}', 1300), ('\u{517}', 1302), ('\u{519}', 1304), - ('\u{51b}', 1306), ('\u{51d}', 1308), ('\u{51f}', 1310), ('\u{521}', 1312), - ('\u{523}', 1314), ('\u{525}', 1316), ('\u{527}', 1318), ('\u{529}', 1320), - ('\u{52b}', 1322), ('\u{52d}', 1324), ('\u{52f}', 1326), ('\u{561}', 1329), - ('\u{562}', 1330), ('\u{563}', 1331), ('\u{564}', 1332), ('\u{565}', 1333), - ('\u{566}', 1334), ('\u{567}', 1335), ('\u{568}', 1336), ('\u{569}', 1337), - ('\u{56a}', 1338), ('\u{56b}', 1339), ('\u{56c}', 1340), ('\u{56d}', 1341), - ('\u{56e}', 1342), ('\u{56f}', 1343), ('\u{570}', 1344), ('\u{571}', 1345), - ('\u{572}', 1346), ('\u{573}', 1347), ('\u{574}', 1348), ('\u{575}', 1349), - ('\u{576}', 1350), ('\u{577}', 1351), ('\u{578}', 1352), ('\u{579}', 1353), - ('\u{57a}', 1354), ('\u{57b}', 1355), ('\u{57c}', 1356), ('\u{57d}', 1357), - ('\u{57e}', 1358), ('\u{57f}', 1359), ('\u{580}', 1360), ('\u{581}', 1361), - ('\u{582}', 1362), ('\u{583}', 1363), ('\u{584}', 1364), ('\u{585}', 1365), - ('\u{586}', 1366), ('\u{587}', 4194309), ('\u{10d0}', 7312), ('\u{10d1}', 7313), - ('\u{10d2}', 7314), ('\u{10d3}', 7315), ('\u{10d4}', 7316), ('\u{10d5}', 7317), - ('\u{10d6}', 7318), ('\u{10d7}', 7319), ('\u{10d8}', 7320), ('\u{10d9}', 7321), - ('\u{10da}', 7322), ('\u{10db}', 7323), ('\u{10dc}', 7324), ('\u{10dd}', 7325), - ('\u{10de}', 7326), ('\u{10df}', 7327), ('\u{10e0}', 7328), ('\u{10e1}', 7329), - ('\u{10e2}', 7330), ('\u{10e3}', 7331), ('\u{10e4}', 7332), ('\u{10e5}', 7333), - ('\u{10e6}', 7334), ('\u{10e7}', 7335), ('\u{10e8}', 7336), ('\u{10e9}', 7337), - ('\u{10ea}', 7338), ('\u{10eb}', 7339), ('\u{10ec}', 7340), ('\u{10ed}', 7341), - ('\u{10ee}', 7342), ('\u{10ef}', 7343), ('\u{10f0}', 7344), ('\u{10f1}', 7345), - ('\u{10f2}', 7346), ('\u{10f3}', 7347), ('\u{10f4}', 7348), ('\u{10f5}', 7349), - ('\u{10f6}', 7350), ('\u{10f7}', 7351), ('\u{10f8}', 7352), ('\u{10f9}', 7353), - ('\u{10fa}', 7354), ('\u{10fd}', 7357), ('\u{10fe}', 7358), ('\u{10ff}', 7359), - ('\u{13f8}', 5104), ('\u{13f9}', 5105), ('\u{13fa}', 5106), ('\u{13fb}', 5107), - ('\u{13fc}', 5108), ('\u{13fd}', 5109), ('\u{1c80}', 1042), ('\u{1c81}', 1044), - ('\u{1c82}', 1054), ('\u{1c83}', 1057), ('\u{1c84}', 1058), ('\u{1c85}', 1058), - ('\u{1c86}', 1066), ('\u{1c87}', 1122), ('\u{1c88}', 42570), ('\u{1c8a}', 7305), - ('\u{1d79}', 42877), ('\u{1d7d}', 11363), ('\u{1d8e}', 42950), ('\u{1e01}', 7680), - ('\u{1e03}', 7682), ('\u{1e05}', 7684), ('\u{1e07}', 7686), ('\u{1e09}', 7688), - ('\u{1e0b}', 7690), ('\u{1e0d}', 7692), ('\u{1e0f}', 7694), ('\u{1e11}', 7696), - ('\u{1e13}', 7698), ('\u{1e15}', 7700), ('\u{1e17}', 7702), ('\u{1e19}', 7704), - ('\u{1e1b}', 7706), ('\u{1e1d}', 7708), ('\u{1e1f}', 7710), ('\u{1e21}', 7712), - ('\u{1e23}', 7714), ('\u{1e25}', 7716), ('\u{1e27}', 7718), ('\u{1e29}', 7720), - ('\u{1e2b}', 7722), ('\u{1e2d}', 7724), ('\u{1e2f}', 7726), ('\u{1e31}', 7728), - ('\u{1e33}', 7730), ('\u{1e35}', 7732), ('\u{1e37}', 7734), ('\u{1e39}', 7736), - ('\u{1e3b}', 7738), ('\u{1e3d}', 7740), ('\u{1e3f}', 7742), ('\u{1e41}', 7744), - ('\u{1e43}', 7746), ('\u{1e45}', 7748), ('\u{1e47}', 7750), ('\u{1e49}', 7752), - ('\u{1e4b}', 7754), ('\u{1e4d}', 7756), ('\u{1e4f}', 7758), ('\u{1e51}', 7760), - ('\u{1e53}', 7762), ('\u{1e55}', 7764), ('\u{1e57}', 7766), ('\u{1e59}', 7768), - ('\u{1e5b}', 7770), ('\u{1e5d}', 7772), ('\u{1e5f}', 7774), ('\u{1e61}', 7776), - ('\u{1e63}', 7778), ('\u{1e65}', 7780), ('\u{1e67}', 7782), ('\u{1e69}', 7784), - ('\u{1e6b}', 7786), ('\u{1e6d}', 7788), ('\u{1e6f}', 7790), ('\u{1e71}', 7792), - ('\u{1e73}', 7794), ('\u{1e75}', 7796), ('\u{1e77}', 7798), ('\u{1e79}', 7800), - ('\u{1e7b}', 7802), ('\u{1e7d}', 7804), ('\u{1e7f}', 7806), ('\u{1e81}', 7808), - ('\u{1e83}', 7810), ('\u{1e85}', 7812), ('\u{1e87}', 7814), ('\u{1e89}', 7816), - ('\u{1e8b}', 7818), ('\u{1e8d}', 7820), ('\u{1e8f}', 7822), ('\u{1e91}', 7824), - ('\u{1e93}', 7826), ('\u{1e95}', 7828), ('\u{1e96}', 4194310), ('\u{1e97}', 4194311), - ('\u{1e98}', 4194312), ('\u{1e99}', 4194313), ('\u{1e9a}', 4194314), ('\u{1e9b}', 7776), - ('\u{1ea1}', 7840), ('\u{1ea3}', 7842), ('\u{1ea5}', 7844), ('\u{1ea7}', 7846), - ('\u{1ea9}', 7848), ('\u{1eab}', 7850), ('\u{1ead}', 7852), ('\u{1eaf}', 7854), - ('\u{1eb1}', 7856), ('\u{1eb3}', 7858), ('\u{1eb5}', 7860), ('\u{1eb7}', 7862), - ('\u{1eb9}', 7864), ('\u{1ebb}', 7866), ('\u{1ebd}', 7868), ('\u{1ebf}', 7870), - ('\u{1ec1}', 7872), ('\u{1ec3}', 7874), ('\u{1ec5}', 7876), ('\u{1ec7}', 7878), - ('\u{1ec9}', 7880), ('\u{1ecb}', 7882), ('\u{1ecd}', 7884), ('\u{1ecf}', 7886), - ('\u{1ed1}', 7888), ('\u{1ed3}', 7890), ('\u{1ed5}', 7892), ('\u{1ed7}', 7894), - ('\u{1ed9}', 7896), ('\u{1edb}', 7898), ('\u{1edd}', 7900), ('\u{1edf}', 7902), - ('\u{1ee1}', 7904), ('\u{1ee3}', 7906), ('\u{1ee5}', 7908), ('\u{1ee7}', 7910), - ('\u{1ee9}', 7912), ('\u{1eeb}', 7914), ('\u{1eed}', 7916), ('\u{1eef}', 7918), - ('\u{1ef1}', 7920), ('\u{1ef3}', 7922), ('\u{1ef5}', 7924), ('\u{1ef7}', 7926), - ('\u{1ef9}', 7928), ('\u{1efb}', 7930), ('\u{1efd}', 7932), ('\u{1eff}', 7934), - ('\u{1f00}', 7944), ('\u{1f01}', 7945), ('\u{1f02}', 7946), ('\u{1f03}', 7947), - ('\u{1f04}', 7948), ('\u{1f05}', 7949), ('\u{1f06}', 7950), ('\u{1f07}', 7951), - ('\u{1f10}', 7960), ('\u{1f11}', 7961), ('\u{1f12}', 7962), ('\u{1f13}', 7963), - ('\u{1f14}', 7964), ('\u{1f15}', 7965), ('\u{1f20}', 7976), ('\u{1f21}', 7977), - ('\u{1f22}', 7978), ('\u{1f23}', 7979), ('\u{1f24}', 7980), ('\u{1f25}', 7981), - ('\u{1f26}', 7982), ('\u{1f27}', 7983), ('\u{1f30}', 7992), ('\u{1f31}', 7993), - ('\u{1f32}', 7994), ('\u{1f33}', 7995), ('\u{1f34}', 7996), ('\u{1f35}', 7997), - ('\u{1f36}', 7998), ('\u{1f37}', 7999), ('\u{1f40}', 8008), ('\u{1f41}', 8009), - ('\u{1f42}', 8010), ('\u{1f43}', 8011), ('\u{1f44}', 8012), ('\u{1f45}', 8013), - ('\u{1f50}', 4194315), ('\u{1f51}', 8025), ('\u{1f52}', 4194316), ('\u{1f53}', 8027), - ('\u{1f54}', 4194317), ('\u{1f55}', 8029), ('\u{1f56}', 4194318), ('\u{1f57}', 8031), - ('\u{1f60}', 8040), ('\u{1f61}', 8041), ('\u{1f62}', 8042), ('\u{1f63}', 8043), - ('\u{1f64}', 8044), ('\u{1f65}', 8045), ('\u{1f66}', 8046), ('\u{1f67}', 8047), - ('\u{1f70}', 8122), ('\u{1f71}', 8123), ('\u{1f72}', 8136), ('\u{1f73}', 8137), - ('\u{1f74}', 8138), ('\u{1f75}', 8139), ('\u{1f76}', 8154), ('\u{1f77}', 8155), - ('\u{1f78}', 8184), ('\u{1f79}', 8185), ('\u{1f7a}', 8170), ('\u{1f7b}', 8171), - ('\u{1f7c}', 8186), ('\u{1f7d}', 8187), ('\u{1f80}', 4194319), ('\u{1f81}', 4194320), - ('\u{1f82}', 4194321), ('\u{1f83}', 4194322), ('\u{1f84}', 4194323), ('\u{1f85}', 4194324), - ('\u{1f86}', 4194325), ('\u{1f87}', 4194326), ('\u{1f88}', 4194327), ('\u{1f89}', 4194328), - ('\u{1f8a}', 4194329), ('\u{1f8b}', 4194330), ('\u{1f8c}', 4194331), ('\u{1f8d}', 4194332), - ('\u{1f8e}', 4194333), ('\u{1f8f}', 4194334), ('\u{1f90}', 4194335), ('\u{1f91}', 4194336), - ('\u{1f92}', 4194337), ('\u{1f93}', 4194338), ('\u{1f94}', 4194339), ('\u{1f95}', 4194340), - ('\u{1f96}', 4194341), ('\u{1f97}', 4194342), ('\u{1f98}', 4194343), ('\u{1f99}', 4194344), - ('\u{1f9a}', 4194345), ('\u{1f9b}', 4194346), ('\u{1f9c}', 4194347), ('\u{1f9d}', 4194348), - ('\u{1f9e}', 4194349), ('\u{1f9f}', 4194350), ('\u{1fa0}', 4194351), ('\u{1fa1}', 4194352), - ('\u{1fa2}', 4194353), ('\u{1fa3}', 4194354), ('\u{1fa4}', 4194355), ('\u{1fa5}', 4194356), - ('\u{1fa6}', 4194357), ('\u{1fa7}', 4194358), ('\u{1fa8}', 4194359), ('\u{1fa9}', 4194360), - ('\u{1faa}', 4194361), ('\u{1fab}', 4194362), ('\u{1fac}', 4194363), ('\u{1fad}', 4194364), - ('\u{1fae}', 4194365), ('\u{1faf}', 4194366), ('\u{1fb0}', 8120), ('\u{1fb1}', 8121), - ('\u{1fb2}', 4194367), ('\u{1fb3}', 4194368), ('\u{1fb4}', 4194369), ('\u{1fb6}', 4194370), - ('\u{1fb7}', 4194371), ('\u{1fbc}', 4194372), ('\u{1fbe}', 921), ('\u{1fc2}', 4194373), - ('\u{1fc3}', 4194374), ('\u{1fc4}', 4194375), ('\u{1fc6}', 4194376), ('\u{1fc7}', 4194377), - ('\u{1fcc}', 4194378), ('\u{1fd0}', 8152), ('\u{1fd1}', 8153), ('\u{1fd2}', 4194379), - ('\u{1fd3}', 4194380), ('\u{1fd6}', 4194381), ('\u{1fd7}', 4194382), ('\u{1fe0}', 8168), - ('\u{1fe1}', 8169), ('\u{1fe2}', 4194383), ('\u{1fe3}', 4194384), ('\u{1fe4}', 4194385), - ('\u{1fe5}', 8172), ('\u{1fe6}', 4194386), ('\u{1fe7}', 4194387), ('\u{1ff2}', 4194388), - ('\u{1ff3}', 4194389), ('\u{1ff4}', 4194390), ('\u{1ff6}', 4194391), ('\u{1ff7}', 4194392), - ('\u{1ffc}', 4194393), ('\u{214e}', 8498), ('\u{2170}', 8544), ('\u{2171}', 8545), - ('\u{2172}', 8546), ('\u{2173}', 8547), ('\u{2174}', 8548), ('\u{2175}', 8549), - ('\u{2176}', 8550), ('\u{2177}', 8551), ('\u{2178}', 8552), ('\u{2179}', 8553), - ('\u{217a}', 8554), ('\u{217b}', 8555), ('\u{217c}', 8556), ('\u{217d}', 8557), - ('\u{217e}', 8558), ('\u{217f}', 8559), ('\u{2184}', 8579), ('\u{24d0}', 9398), - ('\u{24d1}', 9399), ('\u{24d2}', 9400), ('\u{24d3}', 9401), ('\u{24d4}', 9402), - ('\u{24d5}', 9403), ('\u{24d6}', 9404), ('\u{24d7}', 9405), ('\u{24d8}', 9406), - ('\u{24d9}', 9407), ('\u{24da}', 9408), ('\u{24db}', 9409), ('\u{24dc}', 9410), - ('\u{24dd}', 9411), ('\u{24de}', 9412), ('\u{24df}', 9413), ('\u{24e0}', 9414), - ('\u{24e1}', 9415), ('\u{24e2}', 9416), ('\u{24e3}', 9417), ('\u{24e4}', 9418), - ('\u{24e5}', 9419), ('\u{24e6}', 9420), ('\u{24e7}', 9421), ('\u{24e8}', 9422), - ('\u{24e9}', 9423), ('\u{2c30}', 11264), ('\u{2c31}', 11265), ('\u{2c32}', 11266), - ('\u{2c33}', 11267), ('\u{2c34}', 11268), ('\u{2c35}', 11269), ('\u{2c36}', 11270), - ('\u{2c37}', 11271), ('\u{2c38}', 11272), ('\u{2c39}', 11273), ('\u{2c3a}', 11274), - ('\u{2c3b}', 11275), ('\u{2c3c}', 11276), ('\u{2c3d}', 11277), ('\u{2c3e}', 11278), - ('\u{2c3f}', 11279), ('\u{2c40}', 11280), ('\u{2c41}', 11281), ('\u{2c42}', 11282), - ('\u{2c43}', 11283), ('\u{2c44}', 11284), ('\u{2c45}', 11285), ('\u{2c46}', 11286), - ('\u{2c47}', 11287), ('\u{2c48}', 11288), ('\u{2c49}', 11289), ('\u{2c4a}', 11290), - ('\u{2c4b}', 11291), ('\u{2c4c}', 11292), ('\u{2c4d}', 11293), ('\u{2c4e}', 11294), - ('\u{2c4f}', 11295), ('\u{2c50}', 11296), ('\u{2c51}', 11297), ('\u{2c52}', 11298), - ('\u{2c53}', 11299), ('\u{2c54}', 11300), ('\u{2c55}', 11301), ('\u{2c56}', 11302), - ('\u{2c57}', 11303), ('\u{2c58}', 11304), ('\u{2c59}', 11305), ('\u{2c5a}', 11306), - ('\u{2c5b}', 11307), ('\u{2c5c}', 11308), ('\u{2c5d}', 11309), ('\u{2c5e}', 11310), - ('\u{2c5f}', 11311), ('\u{2c61}', 11360), ('\u{2c65}', 570), ('\u{2c66}', 574), - ('\u{2c68}', 11367), ('\u{2c6a}', 11369), ('\u{2c6c}', 11371), ('\u{2c73}', 11378), - ('\u{2c76}', 11381), ('\u{2c81}', 11392), ('\u{2c83}', 11394), ('\u{2c85}', 11396), - ('\u{2c87}', 11398), ('\u{2c89}', 11400), ('\u{2c8b}', 11402), ('\u{2c8d}', 11404), - ('\u{2c8f}', 11406), ('\u{2c91}', 11408), ('\u{2c93}', 11410), ('\u{2c95}', 11412), - ('\u{2c97}', 11414), ('\u{2c99}', 11416), ('\u{2c9b}', 11418), ('\u{2c9d}', 11420), - ('\u{2c9f}', 11422), ('\u{2ca1}', 11424), ('\u{2ca3}', 11426), ('\u{2ca5}', 11428), - ('\u{2ca7}', 11430), ('\u{2ca9}', 11432), ('\u{2cab}', 11434), ('\u{2cad}', 11436), - ('\u{2caf}', 11438), ('\u{2cb1}', 11440), ('\u{2cb3}', 11442), ('\u{2cb5}', 11444), - ('\u{2cb7}', 11446), ('\u{2cb9}', 11448), ('\u{2cbb}', 11450), ('\u{2cbd}', 11452), - ('\u{2cbf}', 11454), ('\u{2cc1}', 11456), ('\u{2cc3}', 11458), ('\u{2cc5}', 11460), - ('\u{2cc7}', 11462), ('\u{2cc9}', 11464), ('\u{2ccb}', 11466), ('\u{2ccd}', 11468), - ('\u{2ccf}', 11470), ('\u{2cd1}', 11472), ('\u{2cd3}', 11474), ('\u{2cd5}', 11476), - ('\u{2cd7}', 11478), ('\u{2cd9}', 11480), ('\u{2cdb}', 11482), ('\u{2cdd}', 11484), - ('\u{2cdf}', 11486), ('\u{2ce1}', 11488), ('\u{2ce3}', 11490), ('\u{2cec}', 11499), - ('\u{2cee}', 11501), ('\u{2cf3}', 11506), ('\u{2d00}', 4256), ('\u{2d01}', 4257), - ('\u{2d02}', 4258), ('\u{2d03}', 4259), ('\u{2d04}', 4260), ('\u{2d05}', 4261), - ('\u{2d06}', 4262), ('\u{2d07}', 4263), ('\u{2d08}', 4264), ('\u{2d09}', 4265), - ('\u{2d0a}', 4266), ('\u{2d0b}', 4267), ('\u{2d0c}', 4268), ('\u{2d0d}', 4269), - ('\u{2d0e}', 4270), ('\u{2d0f}', 4271), ('\u{2d10}', 4272), ('\u{2d11}', 4273), - ('\u{2d12}', 4274), ('\u{2d13}', 4275), ('\u{2d14}', 4276), ('\u{2d15}', 4277), - ('\u{2d16}', 4278), ('\u{2d17}', 4279), ('\u{2d18}', 4280), ('\u{2d19}', 4281), - ('\u{2d1a}', 4282), ('\u{2d1b}', 4283), ('\u{2d1c}', 4284), ('\u{2d1d}', 4285), - ('\u{2d1e}', 4286), ('\u{2d1f}', 4287), ('\u{2d20}', 4288), ('\u{2d21}', 4289), - ('\u{2d22}', 4290), ('\u{2d23}', 4291), ('\u{2d24}', 4292), ('\u{2d25}', 4293), - ('\u{2d27}', 4295), ('\u{2d2d}', 4301), ('\u{a641}', 42560), ('\u{a643}', 42562), - ('\u{a645}', 42564), ('\u{a647}', 42566), ('\u{a649}', 42568), ('\u{a64b}', 42570), - ('\u{a64d}', 42572), ('\u{a64f}', 42574), ('\u{a651}', 42576), ('\u{a653}', 42578), - ('\u{a655}', 42580), ('\u{a657}', 42582), ('\u{a659}', 42584), ('\u{a65b}', 42586), - ('\u{a65d}', 42588), ('\u{a65f}', 42590), ('\u{a661}', 42592), ('\u{a663}', 42594), - ('\u{a665}', 42596), ('\u{a667}', 42598), ('\u{a669}', 42600), ('\u{a66b}', 42602), - ('\u{a66d}', 42604), ('\u{a681}', 42624), ('\u{a683}', 42626), ('\u{a685}', 42628), - ('\u{a687}', 42630), ('\u{a689}', 42632), ('\u{a68b}', 42634), ('\u{a68d}', 42636), - ('\u{a68f}', 42638), ('\u{a691}', 42640), ('\u{a693}', 42642), ('\u{a695}', 42644), - ('\u{a697}', 42646), ('\u{a699}', 42648), ('\u{a69b}', 42650), ('\u{a723}', 42786), - ('\u{a725}', 42788), ('\u{a727}', 42790), ('\u{a729}', 42792), ('\u{a72b}', 42794), - ('\u{a72d}', 42796), ('\u{a72f}', 42798), ('\u{a733}', 42802), ('\u{a735}', 42804), - ('\u{a737}', 42806), ('\u{a739}', 42808), ('\u{a73b}', 42810), ('\u{a73d}', 42812), - ('\u{a73f}', 42814), ('\u{a741}', 42816), ('\u{a743}', 42818), ('\u{a745}', 42820), - ('\u{a747}', 42822), ('\u{a749}', 42824), ('\u{a74b}', 42826), ('\u{a74d}', 42828), - ('\u{a74f}', 42830), ('\u{a751}', 42832), ('\u{a753}', 42834), ('\u{a755}', 42836), - ('\u{a757}', 42838), ('\u{a759}', 42840), ('\u{a75b}', 42842), ('\u{a75d}', 42844), - ('\u{a75f}', 42846), ('\u{a761}', 42848), ('\u{a763}', 42850), ('\u{a765}', 42852), - ('\u{a767}', 42854), ('\u{a769}', 42856), ('\u{a76b}', 42858), ('\u{a76d}', 42860), - ('\u{a76f}', 42862), ('\u{a77a}', 42873), ('\u{a77c}', 42875), ('\u{a77f}', 42878), - ('\u{a781}', 42880), ('\u{a783}', 42882), ('\u{a785}', 42884), ('\u{a787}', 42886), - ('\u{a78c}', 42891), ('\u{a791}', 42896), ('\u{a793}', 42898), ('\u{a794}', 42948), - ('\u{a797}', 42902), ('\u{a799}', 42904), ('\u{a79b}', 42906), ('\u{a79d}', 42908), - ('\u{a79f}', 42910), ('\u{a7a1}', 42912), ('\u{a7a3}', 42914), ('\u{a7a5}', 42916), - ('\u{a7a7}', 42918), ('\u{a7a9}', 42920), ('\u{a7b5}', 42932), ('\u{a7b7}', 42934), - ('\u{a7b9}', 42936), ('\u{a7bb}', 42938), ('\u{a7bd}', 42940), ('\u{a7bf}', 42942), - ('\u{a7c1}', 42944), ('\u{a7c3}', 42946), ('\u{a7c8}', 42951), ('\u{a7ca}', 42953), - ('\u{a7cd}', 42956), ('\u{a7cf}', 42958), ('\u{a7d1}', 42960), ('\u{a7d3}', 42962), - ('\u{a7d5}', 42964), ('\u{a7d7}', 42966), ('\u{a7d9}', 42968), ('\u{a7db}', 42970), - ('\u{a7f6}', 42997), ('\u{ab53}', 42931), ('\u{ab70}', 5024), ('\u{ab71}', 5025), - ('\u{ab72}', 5026), ('\u{ab73}', 5027), ('\u{ab74}', 5028), ('\u{ab75}', 5029), - ('\u{ab76}', 5030), ('\u{ab77}', 5031), ('\u{ab78}', 5032), ('\u{ab79}', 5033), - ('\u{ab7a}', 5034), ('\u{ab7b}', 5035), ('\u{ab7c}', 5036), ('\u{ab7d}', 5037), - ('\u{ab7e}', 5038), ('\u{ab7f}', 5039), ('\u{ab80}', 5040), ('\u{ab81}', 5041), - ('\u{ab82}', 5042), ('\u{ab83}', 5043), ('\u{ab84}', 5044), ('\u{ab85}', 5045), - ('\u{ab86}', 5046), ('\u{ab87}', 5047), ('\u{ab88}', 5048), ('\u{ab89}', 5049), - ('\u{ab8a}', 5050), ('\u{ab8b}', 5051), ('\u{ab8c}', 5052), ('\u{ab8d}', 5053), - ('\u{ab8e}', 5054), ('\u{ab8f}', 5055), ('\u{ab90}', 5056), ('\u{ab91}', 5057), - ('\u{ab92}', 5058), ('\u{ab93}', 5059), ('\u{ab94}', 5060), ('\u{ab95}', 5061), - ('\u{ab96}', 5062), ('\u{ab97}', 5063), ('\u{ab98}', 5064), ('\u{ab99}', 5065), - ('\u{ab9a}', 5066), ('\u{ab9b}', 5067), ('\u{ab9c}', 5068), ('\u{ab9d}', 5069), - ('\u{ab9e}', 5070), ('\u{ab9f}', 5071), ('\u{aba0}', 5072), ('\u{aba1}', 5073), - ('\u{aba2}', 5074), ('\u{aba3}', 5075), ('\u{aba4}', 5076), ('\u{aba5}', 5077), - ('\u{aba6}', 5078), ('\u{aba7}', 5079), ('\u{aba8}', 5080), ('\u{aba9}', 5081), - ('\u{abaa}', 5082), ('\u{abab}', 5083), ('\u{abac}', 5084), ('\u{abad}', 5085), - ('\u{abae}', 5086), ('\u{abaf}', 5087), ('\u{abb0}', 5088), ('\u{abb1}', 5089), - ('\u{abb2}', 5090), ('\u{abb3}', 5091), ('\u{abb4}', 5092), ('\u{abb5}', 5093), - ('\u{abb6}', 5094), ('\u{abb7}', 5095), ('\u{abb8}', 5096), ('\u{abb9}', 5097), - ('\u{abba}', 5098), ('\u{abbb}', 5099), ('\u{abbc}', 5100), ('\u{abbd}', 5101), - ('\u{abbe}', 5102), ('\u{abbf}', 5103), ('\u{fb00}', 4194394), ('\u{fb01}', 4194395), - ('\u{fb02}', 4194396), ('\u{fb03}', 4194397), ('\u{fb04}', 4194398), ('\u{fb05}', 4194399), - ('\u{fb06}', 4194400), ('\u{fb13}', 4194401), ('\u{fb14}', 4194402), ('\u{fb15}', 4194403), - ('\u{fb16}', 4194404), ('\u{fb17}', 4194405), ('\u{ff41}', 65313), ('\u{ff42}', 65314), - ('\u{ff43}', 65315), ('\u{ff44}', 65316), ('\u{ff45}', 65317), ('\u{ff46}', 65318), - ('\u{ff47}', 65319), ('\u{ff48}', 65320), ('\u{ff49}', 65321), ('\u{ff4a}', 65322), - ('\u{ff4b}', 65323), ('\u{ff4c}', 65324), ('\u{ff4d}', 65325), ('\u{ff4e}', 65326), - ('\u{ff4f}', 65327), ('\u{ff50}', 65328), ('\u{ff51}', 65329), ('\u{ff52}', 65330), - ('\u{ff53}', 65331), ('\u{ff54}', 65332), ('\u{ff55}', 65333), ('\u{ff56}', 65334), - ('\u{ff57}', 65335), ('\u{ff58}', 65336), ('\u{ff59}', 65337), ('\u{ff5a}', 65338), - ('\u{10428}', 66560), ('\u{10429}', 66561), ('\u{1042a}', 66562), ('\u{1042b}', 66563), - ('\u{1042c}', 66564), ('\u{1042d}', 66565), ('\u{1042e}', 66566), ('\u{1042f}', 66567), - ('\u{10430}', 66568), ('\u{10431}', 66569), ('\u{10432}', 66570), ('\u{10433}', 66571), - ('\u{10434}', 66572), ('\u{10435}', 66573), ('\u{10436}', 66574), ('\u{10437}', 66575), - ('\u{10438}', 66576), ('\u{10439}', 66577), ('\u{1043a}', 66578), ('\u{1043b}', 66579), - ('\u{1043c}', 66580), ('\u{1043d}', 66581), ('\u{1043e}', 66582), ('\u{1043f}', 66583), - ('\u{10440}', 66584), ('\u{10441}', 66585), ('\u{10442}', 66586), ('\u{10443}', 66587), - ('\u{10444}', 66588), ('\u{10445}', 66589), ('\u{10446}', 66590), ('\u{10447}', 66591), - ('\u{10448}', 66592), ('\u{10449}', 66593), ('\u{1044a}', 66594), ('\u{1044b}', 66595), - ('\u{1044c}', 66596), ('\u{1044d}', 66597), ('\u{1044e}', 66598), ('\u{1044f}', 66599), - ('\u{104d8}', 66736), ('\u{104d9}', 66737), ('\u{104da}', 66738), ('\u{104db}', 66739), - ('\u{104dc}', 66740), ('\u{104dd}', 66741), ('\u{104de}', 66742), ('\u{104df}', 66743), - ('\u{104e0}', 66744), ('\u{104e1}', 66745), ('\u{104e2}', 66746), ('\u{104e3}', 66747), - ('\u{104e4}', 66748), ('\u{104e5}', 66749), ('\u{104e6}', 66750), ('\u{104e7}', 66751), - ('\u{104e8}', 66752), ('\u{104e9}', 66753), ('\u{104ea}', 66754), ('\u{104eb}', 66755), - ('\u{104ec}', 66756), ('\u{104ed}', 66757), ('\u{104ee}', 66758), ('\u{104ef}', 66759), - ('\u{104f0}', 66760), ('\u{104f1}', 66761), ('\u{104f2}', 66762), ('\u{104f3}', 66763), - ('\u{104f4}', 66764), ('\u{104f5}', 66765), ('\u{104f6}', 66766), ('\u{104f7}', 66767), - ('\u{104f8}', 66768), ('\u{104f9}', 66769), ('\u{104fa}', 66770), ('\u{104fb}', 66771), - ('\u{10597}', 66928), ('\u{10598}', 66929), ('\u{10599}', 66930), ('\u{1059a}', 66931), - ('\u{1059b}', 66932), ('\u{1059c}', 66933), ('\u{1059d}', 66934), ('\u{1059e}', 66935), - ('\u{1059f}', 66936), ('\u{105a0}', 66937), ('\u{105a1}', 66938), ('\u{105a3}', 66940), - ('\u{105a4}', 66941), ('\u{105a5}', 66942), ('\u{105a6}', 66943), ('\u{105a7}', 66944), - ('\u{105a8}', 66945), ('\u{105a9}', 66946), ('\u{105aa}', 66947), ('\u{105ab}', 66948), - ('\u{105ac}', 66949), ('\u{105ad}', 66950), ('\u{105ae}', 66951), ('\u{105af}', 66952), - ('\u{105b0}', 66953), ('\u{105b1}', 66954), ('\u{105b3}', 66956), ('\u{105b4}', 66957), - ('\u{105b5}', 66958), ('\u{105b6}', 66959), ('\u{105b7}', 66960), ('\u{105b8}', 66961), - ('\u{105b9}', 66962), ('\u{105bb}', 66964), ('\u{105bc}', 66965), ('\u{10cc0}', 68736), - ('\u{10cc1}', 68737), ('\u{10cc2}', 68738), ('\u{10cc3}', 68739), ('\u{10cc4}', 68740), - ('\u{10cc5}', 68741), ('\u{10cc6}', 68742), ('\u{10cc7}', 68743), ('\u{10cc8}', 68744), - ('\u{10cc9}', 68745), ('\u{10cca}', 68746), ('\u{10ccb}', 68747), ('\u{10ccc}', 68748), - ('\u{10ccd}', 68749), ('\u{10cce}', 68750), ('\u{10ccf}', 68751), ('\u{10cd0}', 68752), - ('\u{10cd1}', 68753), ('\u{10cd2}', 68754), ('\u{10cd3}', 68755), ('\u{10cd4}', 68756), - ('\u{10cd5}', 68757), ('\u{10cd6}', 68758), ('\u{10cd7}', 68759), ('\u{10cd8}', 68760), - ('\u{10cd9}', 68761), ('\u{10cda}', 68762), ('\u{10cdb}', 68763), ('\u{10cdc}', 68764), - ('\u{10cdd}', 68765), ('\u{10cde}', 68766), ('\u{10cdf}', 68767), ('\u{10ce0}', 68768), - ('\u{10ce1}', 68769), ('\u{10ce2}', 68770), ('\u{10ce3}', 68771), ('\u{10ce4}', 68772), - ('\u{10ce5}', 68773), ('\u{10ce6}', 68774), ('\u{10ce7}', 68775), ('\u{10ce8}', 68776), - ('\u{10ce9}', 68777), ('\u{10cea}', 68778), ('\u{10ceb}', 68779), ('\u{10cec}', 68780), - ('\u{10ced}', 68781), ('\u{10cee}', 68782), ('\u{10cef}', 68783), ('\u{10cf0}', 68784), - ('\u{10cf1}', 68785), ('\u{10cf2}', 68786), ('\u{10d70}', 68944), ('\u{10d71}', 68945), - ('\u{10d72}', 68946), ('\u{10d73}', 68947), ('\u{10d74}', 68948), ('\u{10d75}', 68949), - ('\u{10d76}', 68950), ('\u{10d77}', 68951), ('\u{10d78}', 68952), ('\u{10d79}', 68953), - ('\u{10d7a}', 68954), ('\u{10d7b}', 68955), ('\u{10d7c}', 68956), ('\u{10d7d}', 68957), - ('\u{10d7e}', 68958), ('\u{10d7f}', 68959), ('\u{10d80}', 68960), ('\u{10d81}', 68961), - ('\u{10d82}', 68962), ('\u{10d83}', 68963), ('\u{10d84}', 68964), ('\u{10d85}', 68965), - ('\u{118c0}', 71840), ('\u{118c1}', 71841), ('\u{118c2}', 71842), ('\u{118c3}', 71843), - ('\u{118c4}', 71844), ('\u{118c5}', 71845), ('\u{118c6}', 71846), ('\u{118c7}', 71847), - ('\u{118c8}', 71848), ('\u{118c9}', 71849), ('\u{118ca}', 71850), ('\u{118cb}', 71851), - ('\u{118cc}', 71852), ('\u{118cd}', 71853), ('\u{118ce}', 71854), ('\u{118cf}', 71855), - ('\u{118d0}', 71856), ('\u{118d1}', 71857), ('\u{118d2}', 71858), ('\u{118d3}', 71859), - ('\u{118d4}', 71860), ('\u{118d5}', 71861), ('\u{118d6}', 71862), ('\u{118d7}', 71863), - ('\u{118d8}', 71864), ('\u{118d9}', 71865), ('\u{118da}', 71866), ('\u{118db}', 71867), - ('\u{118dc}', 71868), ('\u{118dd}', 71869), ('\u{118de}', 71870), ('\u{118df}', 71871), - ('\u{16e60}', 93760), ('\u{16e61}', 93761), ('\u{16e62}', 93762), ('\u{16e63}', 93763), - ('\u{16e64}', 93764), ('\u{16e65}', 93765), ('\u{16e66}', 93766), ('\u{16e67}', 93767), - ('\u{16e68}', 93768), ('\u{16e69}', 93769), ('\u{16e6a}', 93770), ('\u{16e6b}', 93771), - ('\u{16e6c}', 93772), ('\u{16e6d}', 93773), ('\u{16e6e}', 93774), ('\u{16e6f}', 93775), - ('\u{16e70}', 93776), ('\u{16e71}', 93777), ('\u{16e72}', 93778), ('\u{16e73}', 93779), - ('\u{16e74}', 93780), ('\u{16e75}', 93781), ('\u{16e76}', 93782), ('\u{16e77}', 93783), - ('\u{16e78}', 93784), ('\u{16e79}', 93785), ('\u{16e7a}', 93786), ('\u{16e7b}', 93787), - ('\u{16e7c}', 93788), ('\u{16e7d}', 93789), ('\u{16e7e}', 93790), ('\u{16e7f}', 93791), - ('\u{16ebb}', 93856), ('\u{16ebc}', 93857), ('\u{16ebd}', 93858), ('\u{16ebe}', 93859), - ('\u{16ebf}', 93860), ('\u{16ec0}', 93861), ('\u{16ec1}', 93862), ('\u{16ec2}', 93863), - ('\u{16ec3}', 93864), ('\u{16ec4}', 93865), ('\u{16ec5}', 93866), ('\u{16ec6}', 93867), - ('\u{16ec7}', 93868), ('\u{16ec8}', 93869), ('\u{16ec9}', 93870), ('\u{16eca}', 93871), - ('\u{16ecb}', 93872), ('\u{16ecc}', 93873), ('\u{16ecd}', 93874), ('\u{16ece}', 93875), - ('\u{16ecf}', 93876), ('\u{16ed0}', 93877), ('\u{16ed1}', 93878), ('\u{16ed2}', 93879), - ('\u{16ed3}', 93880), ('\u{1e922}', 125184), ('\u{1e923}', 125185), ('\u{1e924}', 125186), - ('\u{1e925}', 125187), ('\u{1e926}', 125188), ('\u{1e927}', 125189), ('\u{1e928}', 125190), - ('\u{1e929}', 125191), ('\u{1e92a}', 125192), ('\u{1e92b}', 125193), ('\u{1e92c}', 125194), - ('\u{1e92d}', 125195), ('\u{1e92e}', 125196), ('\u{1e92f}', 125197), ('\u{1e930}', 125198), - ('\u{1e931}', 125199), ('\u{1e932}', 125200), ('\u{1e933}', 125201), ('\u{1e934}', 125202), - ('\u{1e935}', 125203), ('\u{1e936}', 125204), ('\u{1e937}', 125205), ('\u{1e938}', 125206), - ('\u{1e939}', 125207), ('\u{1e93a}', 125208), ('\u{1e93b}', 125209), ('\u{1e93c}', 125210), - ('\u{1e93d}', 125211), ('\u{1e93e}', 125212), ('\u{1e93f}', 125213), ('\u{1e940}', 125214), - ('\u{1e941}', 125215), ('\u{1e942}', 125216), ('\u{1e943}', 125217), - ]; + static LOWERCASE_LUT: L1Lut = L1Lut { + l2_luts: [ + L2Lut { + singles: &[ // 172 entries, 1032 bytes + (Range::step_by_1(0x00c0..=0x00d6), 32), (Range::step_by_1(0x00d8..=0x00de), 32), + (Range::step_by_2(0x0100..=0x012e), 1), (Range::step_by_2(0x0132..=0x0136), 1), + (Range::step_by_2(0x0139..=0x0147), 1), (Range::step_by_2(0x014a..=0x0176), 1), + (Range::singleton(0x0178), -121), (Range::step_by_2(0x0179..=0x017d), 1), + (Range::singleton(0x0181), 210), (Range::step_by_2(0x0182..=0x0184), 1), + (Range::singleton(0x0186), 206), (Range::singleton(0x0187), 1), + (Range::step_by_1(0x0189..=0x018a), 205), (Range::singleton(0x018b), 1), + (Range::singleton(0x018e), 79), (Range::singleton(0x018f), 202), + (Range::singleton(0x0190), 203), (Range::singleton(0x0191), 1), + (Range::singleton(0x0193), 205), (Range::singleton(0x0194), 207), + (Range::singleton(0x0196), 211), (Range::singleton(0x0197), 209), + (Range::singleton(0x0198), 1), (Range::singleton(0x019c), 211), + (Range::singleton(0x019d), 213), (Range::singleton(0x019f), 214), + (Range::step_by_2(0x01a0..=0x01a4), 1), (Range::singleton(0x01a6), 218), + (Range::singleton(0x01a7), 1), (Range::singleton(0x01a9), 218), + (Range::singleton(0x01ac), 1), (Range::singleton(0x01ae), 218), + (Range::singleton(0x01af), 1), (Range::step_by_1(0x01b1..=0x01b2), 217), + (Range::step_by_2(0x01b3..=0x01b5), 1), (Range::singleton(0x01b7), 219), + (Range::singleton(0x01b8), 1), (Range::singleton(0x01bc), 1), (Range::singleton(0x01c4), 2), + (Range::singleton(0x01c5), 1), (Range::singleton(0x01c7), 2), (Range::singleton(0x01c8), 1), + (Range::singleton(0x01ca), 2), (Range::step_by_2(0x01cb..=0x01db), 1), + (Range::step_by_2(0x01de..=0x01ee), 1), (Range::singleton(0x01f1), 2), + (Range::step_by_2(0x01f2..=0x01f4), 1), (Range::singleton(0x01f6), -97), + (Range::singleton(0x01f7), -56), (Range::step_by_2(0x01f8..=0x021e), 1), + (Range::singleton(0x0220), -130), (Range::step_by_2(0x0222..=0x0232), 1), + (Range::singleton(0x023a), 10795), (Range::singleton(0x023b), 1), + (Range::singleton(0x023d), -163), (Range::singleton(0x023e), 10792), + (Range::singleton(0x0241), 1), (Range::singleton(0x0243), -195), + (Range::singleton(0x0244), 69), (Range::singleton(0x0245), 71), + (Range::step_by_2(0x0246..=0x024e), 1), (Range::step_by_2(0x0370..=0x0372), 1), + (Range::singleton(0x0376), 1), (Range::singleton(0x037f), 116), + (Range::singleton(0x0386), 38), (Range::step_by_1(0x0388..=0x038a), 37), + (Range::singleton(0x038c), 64), (Range::step_by_1(0x038e..=0x038f), 63), + (Range::step_by_1(0x0391..=0x03a1), 32), (Range::step_by_1(0x03a3..=0x03ab), 32), + (Range::singleton(0x03cf), 8), (Range::step_by_2(0x03d8..=0x03ee), 1), + (Range::singleton(0x03f4), -60), (Range::singleton(0x03f7), 1), + (Range::singleton(0x03f9), -7), (Range::singleton(0x03fa), 1), + (Range::step_by_1(0x03fd..=0x03ff), -130), (Range::step_by_1(0x0400..=0x040f), 80), + (Range::step_by_1(0x0410..=0x042f), 32), (Range::step_by_2(0x0460..=0x0480), 1), + (Range::step_by_2(0x048a..=0x04be), 1), (Range::singleton(0x04c0), 15), + (Range::step_by_2(0x04c1..=0x04cd), 1), (Range::step_by_2(0x04d0..=0x052e), 1), + (Range::step_by_1(0x0531..=0x0556), 48), (Range::step_by_1(0x10a0..=0x10c5), 7264), + (Range::singleton(0x10c7), 7264), (Range::singleton(0x10cd), 7264), + (Range::step_by_1(0x13a0..=0x13ef), -26672), (Range::step_by_1(0x13f0..=0x13f5), 8), + (Range::singleton(0x1c89), 1), (Range::step_by_1(0x1c90..=0x1cba), -3008), + (Range::step_by_1(0x1cbd..=0x1cbf), -3008), (Range::step_by_2(0x1e00..=0x1e94), 1), + (Range::singleton(0x1e9e), -7615), (Range::step_by_2(0x1ea0..=0x1efe), 1), + (Range::step_by_1(0x1f08..=0x1f0f), -8), (Range::step_by_1(0x1f18..=0x1f1d), -8), + (Range::step_by_1(0x1f28..=0x1f2f), -8), (Range::step_by_1(0x1f38..=0x1f3f), -8), + (Range::step_by_1(0x1f48..=0x1f4d), -8), (Range::step_by_2(0x1f59..=0x1f5f), -8), + (Range::step_by_1(0x1f68..=0x1f6f), -8), (Range::step_by_1(0x1f88..=0x1f8f), -8), + (Range::step_by_1(0x1f98..=0x1f9f), -8), (Range::step_by_1(0x1fa8..=0x1faf), -8), + (Range::step_by_1(0x1fb8..=0x1fb9), -8), (Range::step_by_1(0x1fba..=0x1fbb), -74), + (Range::singleton(0x1fbc), -9), (Range::step_by_1(0x1fc8..=0x1fcb), -86), + (Range::singleton(0x1fcc), -9), (Range::step_by_1(0x1fd8..=0x1fd9), -8), + (Range::step_by_1(0x1fda..=0x1fdb), -100), (Range::step_by_1(0x1fe8..=0x1fe9), -8), + (Range::step_by_1(0x1fea..=0x1feb), -112), (Range::singleton(0x1fec), -7), + (Range::step_by_1(0x1ff8..=0x1ff9), -128), (Range::step_by_1(0x1ffa..=0x1ffb), -126), + (Range::singleton(0x1ffc), -9), (Range::singleton(0x2126), -7517), + (Range::singleton(0x212a), -8383), (Range::singleton(0x212b), -8262), + (Range::singleton(0x2132), 28), (Range::step_by_1(0x2160..=0x216f), 16), + (Range::singleton(0x2183), 1), (Range::step_by_1(0x24b6..=0x24cf), 26), + (Range::step_by_1(0x2c00..=0x2c2f), 48), (Range::singleton(0x2c60), 1), + (Range::singleton(0x2c62), -10743), (Range::singleton(0x2c63), -3814), + (Range::singleton(0x2c64), -10727), (Range::step_by_2(0x2c67..=0x2c6b), 1), + (Range::singleton(0x2c6d), -10780), (Range::singleton(0x2c6e), -10749), + (Range::singleton(0x2c6f), -10783), (Range::singleton(0x2c70), -10782), + (Range::singleton(0x2c72), 1), (Range::singleton(0x2c75), 1), + (Range::step_by_1(0x2c7e..=0x2c7f), -10815), (Range::step_by_2(0x2c80..=0x2ce2), 1), + (Range::step_by_2(0x2ceb..=0x2ced), 1), (Range::singleton(0x2cf2), 1), + (Range::step_by_2(0xa640..=0xa66c), 1), (Range::step_by_2(0xa680..=0xa69a), 1), + (Range::step_by_2(0xa722..=0xa72e), 1), (Range::step_by_2(0xa732..=0xa76e), 1), + (Range::step_by_2(0xa779..=0xa77b), 1), (Range::singleton(0xa77d), 30204), + (Range::step_by_2(0xa77e..=0xa786), 1), (Range::singleton(0xa78b), 1), + (Range::singleton(0xa78d), 23256), (Range::step_by_2(0xa790..=0xa792), 1), + (Range::step_by_2(0xa796..=0xa7a8), 1), (Range::singleton(0xa7aa), 23228), + (Range::singleton(0xa7ab), 23217), (Range::singleton(0xa7ac), 23221), + (Range::singleton(0xa7ad), 23231), (Range::singleton(0xa7ae), 23228), + (Range::singleton(0xa7b0), 23278), (Range::singleton(0xa7b1), 23254), + (Range::singleton(0xa7b2), 23275), (Range::singleton(0xa7b3), 928), + (Range::step_by_2(0xa7b4..=0xa7c2), 1), (Range::singleton(0xa7c4), -48), + (Range::singleton(0xa7c5), 23229), (Range::singleton(0xa7c6), 30152), + (Range::step_by_2(0xa7c7..=0xa7c9), 1), (Range::singleton(0xa7cb), 23193), + (Range::step_by_2(0xa7cc..=0xa7da), 1), (Range::singleton(0xa7dc), 22975), + (Range::singleton(0xa7f5), 1), (Range::step_by_1(0xff21..=0xff3a), 32), + ], + multis: &[ // 1 entries, 8 bytes + (0x0130, [0x0069, 0x0307, 0x0000]), + ], + }, + L2Lut { + singles: &[ // 12 entries, 72 bytes + (Range::step_by_1(0x0400..=0x0427), 40), (Range::step_by_1(0x04b0..=0x04d3), 40), + (Range::step_by_1(0x0570..=0x057a), 39), (Range::step_by_1(0x057c..=0x058a), 39), + (Range::step_by_1(0x058c..=0x0592), 39), (Range::step_by_1(0x0594..=0x0595), 39), + (Range::step_by_1(0x0c80..=0x0cb2), 64), (Range::step_by_1(0x0d50..=0x0d65), 32), + (Range::step_by_1(0x18a0..=0x18bf), 32), (Range::step_by_1(0x6e40..=0x6e5f), 32), + (Range::step_by_1(0x6ea0..=0x6eb8), 27), (Range::step_by_1(0xe900..=0xe921), 34), + ], + multis: &[ // 0 entries, 0 bytes + ], + }, + ], + }; - static UPPERCASE_TABLE_MULTI: &[[char; 3]; 102] = &[ - ['S', 'S', '\u{0}'], ['\u{2bc}', 'N', '\u{0}'], ['J', '\u{30c}', '\u{0}'], - ['\u{399}', '\u{308}', '\u{301}'], ['\u{3a5}', '\u{308}', '\u{301}'], - ['\u{535}', '\u{552}', '\u{0}'], ['H', '\u{331}', '\u{0}'], ['T', '\u{308}', '\u{0}'], - ['W', '\u{30a}', '\u{0}'], ['Y', '\u{30a}', '\u{0}'], ['A', '\u{2be}', '\u{0}'], - ['\u{3a5}', '\u{313}', '\u{0}'], ['\u{3a5}', '\u{313}', '\u{300}'], - ['\u{3a5}', '\u{313}', '\u{301}'], ['\u{3a5}', '\u{313}', '\u{342}'], - ['\u{1f08}', '\u{399}', '\u{0}'], ['\u{1f09}', '\u{399}', '\u{0}'], - ['\u{1f0a}', '\u{399}', '\u{0}'], ['\u{1f0b}', '\u{399}', '\u{0}'], - ['\u{1f0c}', '\u{399}', '\u{0}'], ['\u{1f0d}', '\u{399}', '\u{0}'], - ['\u{1f0e}', '\u{399}', '\u{0}'], ['\u{1f0f}', '\u{399}', '\u{0}'], - ['\u{1f08}', '\u{399}', '\u{0}'], ['\u{1f09}', '\u{399}', '\u{0}'], - ['\u{1f0a}', '\u{399}', '\u{0}'], ['\u{1f0b}', '\u{399}', '\u{0}'], - ['\u{1f0c}', '\u{399}', '\u{0}'], ['\u{1f0d}', '\u{399}', '\u{0}'], - ['\u{1f0e}', '\u{399}', '\u{0}'], ['\u{1f0f}', '\u{399}', '\u{0}'], - ['\u{1f28}', '\u{399}', '\u{0}'], ['\u{1f29}', '\u{399}', '\u{0}'], - ['\u{1f2a}', '\u{399}', '\u{0}'], ['\u{1f2b}', '\u{399}', '\u{0}'], - ['\u{1f2c}', '\u{399}', '\u{0}'], ['\u{1f2d}', '\u{399}', '\u{0}'], - ['\u{1f2e}', '\u{399}', '\u{0}'], ['\u{1f2f}', '\u{399}', '\u{0}'], - ['\u{1f28}', '\u{399}', '\u{0}'], ['\u{1f29}', '\u{399}', '\u{0}'], - ['\u{1f2a}', '\u{399}', '\u{0}'], ['\u{1f2b}', '\u{399}', '\u{0}'], - ['\u{1f2c}', '\u{399}', '\u{0}'], ['\u{1f2d}', '\u{399}', '\u{0}'], - ['\u{1f2e}', '\u{399}', '\u{0}'], ['\u{1f2f}', '\u{399}', '\u{0}'], - ['\u{1f68}', '\u{399}', '\u{0}'], ['\u{1f69}', '\u{399}', '\u{0}'], - ['\u{1f6a}', '\u{399}', '\u{0}'], ['\u{1f6b}', '\u{399}', '\u{0}'], - ['\u{1f6c}', '\u{399}', '\u{0}'], ['\u{1f6d}', '\u{399}', '\u{0}'], - ['\u{1f6e}', '\u{399}', '\u{0}'], ['\u{1f6f}', '\u{399}', '\u{0}'], - ['\u{1f68}', '\u{399}', '\u{0}'], ['\u{1f69}', '\u{399}', '\u{0}'], - ['\u{1f6a}', '\u{399}', '\u{0}'], ['\u{1f6b}', '\u{399}', '\u{0}'], - ['\u{1f6c}', '\u{399}', '\u{0}'], ['\u{1f6d}', '\u{399}', '\u{0}'], - ['\u{1f6e}', '\u{399}', '\u{0}'], ['\u{1f6f}', '\u{399}', '\u{0}'], - ['\u{1fba}', '\u{399}', '\u{0}'], ['\u{391}', '\u{399}', '\u{0}'], - ['\u{386}', '\u{399}', '\u{0}'], ['\u{391}', '\u{342}', '\u{0}'], - ['\u{391}', '\u{342}', '\u{399}'], ['\u{391}', '\u{399}', '\u{0}'], - ['\u{1fca}', '\u{399}', '\u{0}'], ['\u{397}', '\u{399}', '\u{0}'], - ['\u{389}', '\u{399}', '\u{0}'], ['\u{397}', '\u{342}', '\u{0}'], - ['\u{397}', '\u{342}', '\u{399}'], ['\u{397}', '\u{399}', '\u{0}'], - ['\u{399}', '\u{308}', '\u{300}'], ['\u{399}', '\u{308}', '\u{301}'], - ['\u{399}', '\u{342}', '\u{0}'], ['\u{399}', '\u{308}', '\u{342}'], - ['\u{3a5}', '\u{308}', '\u{300}'], ['\u{3a5}', '\u{308}', '\u{301}'], - ['\u{3a1}', '\u{313}', '\u{0}'], ['\u{3a5}', '\u{342}', '\u{0}'], - ['\u{3a5}', '\u{308}', '\u{342}'], ['\u{1ffa}', '\u{399}', '\u{0}'], - ['\u{3a9}', '\u{399}', '\u{0}'], ['\u{38f}', '\u{399}', '\u{0}'], - ['\u{3a9}', '\u{342}', '\u{0}'], ['\u{3a9}', '\u{342}', '\u{399}'], - ['\u{3a9}', '\u{399}', '\u{0}'], ['F', 'F', '\u{0}'], ['F', 'I', '\u{0}'], - ['F', 'L', '\u{0}'], ['F', 'F', 'I'], ['F', 'F', 'L'], ['S', 'T', '\u{0}'], - ['S', 'T', '\u{0}'], ['\u{544}', '\u{546}', '\u{0}'], ['\u{544}', '\u{535}', '\u{0}'], - ['\u{544}', '\u{53b}', '\u{0}'], ['\u{54e}', '\u{546}', '\u{0}'], - ['\u{544}', '\u{53d}', '\u{0}'], - ]; + static UPPERCASE_LUT: L1Lut = L1Lut { + l2_luts: [ + L2Lut { + singles: &[ // 185 entries, 1110 bytes + (Range::singleton(0x00b5), 743), (Range::step_by_1(0x00e0..=0x00f6), -32), + (Range::step_by_1(0x00f8..=0x00fe), -32), (Range::singleton(0x00ff), 121), + (Range::step_by_2(0x0101..=0x012f), -1), (Range::singleton(0x0131), -232), + (Range::step_by_2(0x0133..=0x0137), -1), (Range::step_by_2(0x013a..=0x0148), -1), + (Range::step_by_2(0x014b..=0x0177), -1), (Range::step_by_2(0x017a..=0x017e), -1), + (Range::singleton(0x017f), -300), (Range::singleton(0x0180), 195), + (Range::step_by_2(0x0183..=0x0185), -1), (Range::singleton(0x0188), -1), + (Range::singleton(0x018c), -1), (Range::singleton(0x0192), -1), + (Range::singleton(0x0195), 97), (Range::singleton(0x0199), -1), + (Range::singleton(0x019a), 163), (Range::singleton(0x019b), -22975), + (Range::singleton(0x019e), 130), (Range::step_by_2(0x01a1..=0x01a5), -1), + (Range::singleton(0x01a8), -1), (Range::singleton(0x01ad), -1), + (Range::singleton(0x01b0), -1), (Range::step_by_2(0x01b4..=0x01b6), -1), + (Range::singleton(0x01b9), -1), (Range::singleton(0x01bd), -1), + (Range::singleton(0x01bf), 56), (Range::singleton(0x01c5), -1), + (Range::singleton(0x01c6), -2), (Range::singleton(0x01c8), -1), + (Range::singleton(0x01c9), -2), (Range::singleton(0x01cb), -1), + (Range::singleton(0x01cc), -2), (Range::step_by_2(0x01ce..=0x01dc), -1), + (Range::singleton(0x01dd), -79), (Range::step_by_2(0x01df..=0x01ef), -1), + (Range::singleton(0x01f2), -1), (Range::singleton(0x01f3), -2), + (Range::singleton(0x01f5), -1), (Range::step_by_2(0x01f9..=0x021f), -1), + (Range::step_by_2(0x0223..=0x0233), -1), (Range::singleton(0x023c), -1), + (Range::step_by_1(0x023f..=0x0240), 10815), (Range::singleton(0x0242), -1), + (Range::step_by_2(0x0247..=0x024f), -1), (Range::singleton(0x0250), 10783), + (Range::singleton(0x0251), 10780), (Range::singleton(0x0252), 10782), + (Range::singleton(0x0253), -210), (Range::singleton(0x0254), -206), + (Range::step_by_1(0x0256..=0x0257), -205), (Range::singleton(0x0259), -202), + (Range::singleton(0x025b), -203), (Range::singleton(0x025c), -23217), + (Range::singleton(0x0260), -205), (Range::singleton(0x0261), -23221), + (Range::singleton(0x0263), -207), (Range::singleton(0x0264), -23193), + (Range::singleton(0x0265), -23256), (Range::singleton(0x0266), -23228), + (Range::singleton(0x0268), -209), (Range::singleton(0x0269), -211), + (Range::singleton(0x026a), -23228), (Range::singleton(0x026b), 10743), + (Range::singleton(0x026c), -23231), (Range::singleton(0x026f), -211), + (Range::singleton(0x0271), 10749), (Range::singleton(0x0272), -213), + (Range::singleton(0x0275), -214), (Range::singleton(0x027d), 10727), + (Range::singleton(0x0280), -218), (Range::singleton(0x0282), -23229), + (Range::singleton(0x0283), -218), (Range::singleton(0x0287), -23254), + (Range::singleton(0x0288), -218), (Range::singleton(0x0289), -69), + (Range::step_by_1(0x028a..=0x028b), -217), (Range::singleton(0x028c), -71), + (Range::singleton(0x0292), -219), (Range::singleton(0x029d), -23275), + (Range::singleton(0x029e), -23278), (Range::singleton(0x0345), 84), + (Range::step_by_2(0x0371..=0x0373), -1), (Range::singleton(0x0377), -1), + (Range::step_by_1(0x037b..=0x037d), 130), (Range::singleton(0x03ac), -38), + (Range::step_by_1(0x03ad..=0x03af), -37), (Range::step_by_1(0x03b1..=0x03c1), -32), + (Range::singleton(0x03c2), -31), (Range::step_by_1(0x03c3..=0x03cb), -32), + (Range::singleton(0x03cc), -64), (Range::step_by_1(0x03cd..=0x03ce), -63), + (Range::singleton(0x03d0), -62), (Range::singleton(0x03d1), -57), + (Range::singleton(0x03d5), -47), (Range::singleton(0x03d6), -54), + (Range::singleton(0x03d7), -8), (Range::step_by_2(0x03d9..=0x03ef), -1), + (Range::singleton(0x03f0), -86), (Range::singleton(0x03f1), -80), + (Range::singleton(0x03f2), 7), (Range::singleton(0x03f3), -116), + (Range::singleton(0x03f5), -96), (Range::singleton(0x03f8), -1), + (Range::singleton(0x03fb), -1), (Range::step_by_1(0x0430..=0x044f), -32), + (Range::step_by_1(0x0450..=0x045f), -80), (Range::step_by_2(0x0461..=0x0481), -1), + (Range::step_by_2(0x048b..=0x04bf), -1), (Range::step_by_2(0x04c2..=0x04ce), -1), + (Range::singleton(0x04cf), -15), (Range::step_by_2(0x04d1..=0x052f), -1), + (Range::step_by_1(0x0561..=0x0586), -48), (Range::step_by_1(0x10d0..=0x10fa), 3008), + (Range::step_by_1(0x10fd..=0x10ff), 3008), (Range::step_by_1(0x13f8..=0x13fd), -8), + (Range::singleton(0x1c80), -6254), (Range::singleton(0x1c81), -6253), + (Range::singleton(0x1c82), -6244), (Range::step_by_1(0x1c83..=0x1c84), -6242), + (Range::singleton(0x1c85), -6243), (Range::singleton(0x1c86), -6236), + (Range::singleton(0x1c87), -6181), (Range::singleton(0x1c88), -30270), + (Range::singleton(0x1c8a), -1), (Range::singleton(0x1d79), -30204), + (Range::singleton(0x1d7d), 3814), (Range::singleton(0x1d8e), -30152), + (Range::step_by_2(0x1e01..=0x1e95), -1), (Range::singleton(0x1e9b), -59), + (Range::step_by_2(0x1ea1..=0x1eff), -1), (Range::step_by_1(0x1f00..=0x1f07), 8), + (Range::step_by_1(0x1f10..=0x1f15), 8), (Range::step_by_1(0x1f20..=0x1f27), 8), + (Range::step_by_1(0x1f30..=0x1f37), 8), (Range::step_by_1(0x1f40..=0x1f45), 8), + (Range::step_by_2(0x1f51..=0x1f57), 8), (Range::step_by_1(0x1f60..=0x1f67), 8), + (Range::step_by_1(0x1f70..=0x1f71), 74), (Range::step_by_1(0x1f72..=0x1f75), 86), + (Range::step_by_1(0x1f76..=0x1f77), 100), (Range::step_by_1(0x1f78..=0x1f79), 128), + (Range::step_by_1(0x1f7a..=0x1f7b), 112), (Range::step_by_1(0x1f7c..=0x1f7d), 126), + (Range::step_by_1(0x1fb0..=0x1fb1), 8), (Range::singleton(0x1fbe), -7205), + (Range::step_by_1(0x1fd0..=0x1fd1), 8), (Range::step_by_1(0x1fe0..=0x1fe1), 8), + (Range::singleton(0x1fe5), 7), (Range::singleton(0x214e), -28), + (Range::step_by_1(0x2170..=0x217f), -16), (Range::singleton(0x2184), -1), + (Range::step_by_1(0x24d0..=0x24e9), -26), (Range::step_by_1(0x2c30..=0x2c5f), -48), + (Range::singleton(0x2c61), -1), (Range::singleton(0x2c65), -10795), + (Range::singleton(0x2c66), -10792), (Range::step_by_2(0x2c68..=0x2c6c), -1), + (Range::singleton(0x2c73), -1), (Range::singleton(0x2c76), -1), + (Range::step_by_2(0x2c81..=0x2ce3), -1), (Range::step_by_2(0x2cec..=0x2cee), -1), + (Range::singleton(0x2cf3), -1), (Range::step_by_1(0x2d00..=0x2d25), -7264), + (Range::singleton(0x2d27), -7264), (Range::singleton(0x2d2d), -7264), + (Range::step_by_2(0xa641..=0xa66d), -1), (Range::step_by_2(0xa681..=0xa69b), -1), + (Range::step_by_2(0xa723..=0xa72f), -1), (Range::step_by_2(0xa733..=0xa76f), -1), + (Range::step_by_2(0xa77a..=0xa77c), -1), (Range::step_by_2(0xa77f..=0xa787), -1), + (Range::singleton(0xa78c), -1), (Range::step_by_2(0xa791..=0xa793), -1), + (Range::singleton(0xa794), 48), (Range::step_by_2(0xa797..=0xa7a9), -1), + (Range::step_by_2(0xa7b5..=0xa7c3), -1), (Range::step_by_2(0xa7c8..=0xa7ca), -1), + (Range::step_by_2(0xa7cd..=0xa7db), -1), (Range::singleton(0xa7f6), -1), + (Range::singleton(0xab53), -928), (Range::step_by_1(0xab70..=0xabbf), 26672), + (Range::step_by_1(0xff41..=0xff5a), -32), + ], + multis: &[ // 102 entries, 816 bytes + (0x00df, [0x0053, 0x0053, 0x0000]), (0x0149, [0x02bc, 0x004e, 0x0000]), + (0x01f0, [0x004a, 0x030c, 0x0000]), (0x0390, [0x0399, 0x0308, 0x0301]), + (0x03b0, [0x03a5, 0x0308, 0x0301]), (0x0587, [0x0535, 0x0552, 0x0000]), + (0x1e96, [0x0048, 0x0331, 0x0000]), (0x1e97, [0x0054, 0x0308, 0x0000]), + (0x1e98, [0x0057, 0x030a, 0x0000]), (0x1e99, [0x0059, 0x030a, 0x0000]), + (0x1e9a, [0x0041, 0x02be, 0x0000]), (0x1f50, [0x03a5, 0x0313, 0x0000]), + (0x1f52, [0x03a5, 0x0313, 0x0300]), (0x1f54, [0x03a5, 0x0313, 0x0301]), + (0x1f56, [0x03a5, 0x0313, 0x0342]), (0x1f80, [0x1f08, 0x0399, 0x0000]), + (0x1f81, [0x1f09, 0x0399, 0x0000]), (0x1f82, [0x1f0a, 0x0399, 0x0000]), + (0x1f83, [0x1f0b, 0x0399, 0x0000]), (0x1f84, [0x1f0c, 0x0399, 0x0000]), + (0x1f85, [0x1f0d, 0x0399, 0x0000]), (0x1f86, [0x1f0e, 0x0399, 0x0000]), + (0x1f87, [0x1f0f, 0x0399, 0x0000]), (0x1f88, [0x1f08, 0x0399, 0x0000]), + (0x1f89, [0x1f09, 0x0399, 0x0000]), (0x1f8a, [0x1f0a, 0x0399, 0x0000]), + (0x1f8b, [0x1f0b, 0x0399, 0x0000]), (0x1f8c, [0x1f0c, 0x0399, 0x0000]), + (0x1f8d, [0x1f0d, 0x0399, 0x0000]), (0x1f8e, [0x1f0e, 0x0399, 0x0000]), + (0x1f8f, [0x1f0f, 0x0399, 0x0000]), (0x1f90, [0x1f28, 0x0399, 0x0000]), + (0x1f91, [0x1f29, 0x0399, 0x0000]), (0x1f92, [0x1f2a, 0x0399, 0x0000]), + (0x1f93, [0x1f2b, 0x0399, 0x0000]), (0x1f94, [0x1f2c, 0x0399, 0x0000]), + (0x1f95, [0x1f2d, 0x0399, 0x0000]), (0x1f96, [0x1f2e, 0x0399, 0x0000]), + (0x1f97, [0x1f2f, 0x0399, 0x0000]), (0x1f98, [0x1f28, 0x0399, 0x0000]), + (0x1f99, [0x1f29, 0x0399, 0x0000]), (0x1f9a, [0x1f2a, 0x0399, 0x0000]), + (0x1f9b, [0x1f2b, 0x0399, 0x0000]), (0x1f9c, [0x1f2c, 0x0399, 0x0000]), + (0x1f9d, [0x1f2d, 0x0399, 0x0000]), (0x1f9e, [0x1f2e, 0x0399, 0x0000]), + (0x1f9f, [0x1f2f, 0x0399, 0x0000]), (0x1fa0, [0x1f68, 0x0399, 0x0000]), + (0x1fa1, [0x1f69, 0x0399, 0x0000]), (0x1fa2, [0x1f6a, 0x0399, 0x0000]), + (0x1fa3, [0x1f6b, 0x0399, 0x0000]), (0x1fa4, [0x1f6c, 0x0399, 0x0000]), + (0x1fa5, [0x1f6d, 0x0399, 0x0000]), (0x1fa6, [0x1f6e, 0x0399, 0x0000]), + (0x1fa7, [0x1f6f, 0x0399, 0x0000]), (0x1fa8, [0x1f68, 0x0399, 0x0000]), + (0x1fa9, [0x1f69, 0x0399, 0x0000]), (0x1faa, [0x1f6a, 0x0399, 0x0000]), + (0x1fab, [0x1f6b, 0x0399, 0x0000]), (0x1fac, [0x1f6c, 0x0399, 0x0000]), + (0x1fad, [0x1f6d, 0x0399, 0x0000]), (0x1fae, [0x1f6e, 0x0399, 0x0000]), + (0x1faf, [0x1f6f, 0x0399, 0x0000]), (0x1fb2, [0x1fba, 0x0399, 0x0000]), + (0x1fb3, [0x0391, 0x0399, 0x0000]), (0x1fb4, [0x0386, 0x0399, 0x0000]), + (0x1fb6, [0x0391, 0x0342, 0x0000]), (0x1fb7, [0x0391, 0x0342, 0x0399]), + (0x1fbc, [0x0391, 0x0399, 0x0000]), (0x1fc2, [0x1fca, 0x0399, 0x0000]), + (0x1fc3, [0x0397, 0x0399, 0x0000]), (0x1fc4, [0x0389, 0x0399, 0x0000]), + (0x1fc6, [0x0397, 0x0342, 0x0000]), (0x1fc7, [0x0397, 0x0342, 0x0399]), + (0x1fcc, [0x0397, 0x0399, 0x0000]), (0x1fd2, [0x0399, 0x0308, 0x0300]), + (0x1fd3, [0x0399, 0x0308, 0x0301]), (0x1fd6, [0x0399, 0x0342, 0x0000]), + (0x1fd7, [0x0399, 0x0308, 0x0342]), (0x1fe2, [0x03a5, 0x0308, 0x0300]), + (0x1fe3, [0x03a5, 0x0308, 0x0301]), (0x1fe4, [0x03a1, 0x0313, 0x0000]), + (0x1fe6, [0x03a5, 0x0342, 0x0000]), (0x1fe7, [0x03a5, 0x0308, 0x0342]), + (0x1ff2, [0x1ffa, 0x0399, 0x0000]), (0x1ff3, [0x03a9, 0x0399, 0x0000]), + (0x1ff4, [0x038f, 0x0399, 0x0000]), (0x1ff6, [0x03a9, 0x0342, 0x0000]), + (0x1ff7, [0x03a9, 0x0342, 0x0399]), (0x1ffc, [0x03a9, 0x0399, 0x0000]), + (0xfb00, [0x0046, 0x0046, 0x0000]), (0xfb01, [0x0046, 0x0049, 0x0000]), + (0xfb02, [0x0046, 0x004c, 0x0000]), (0xfb03, [0x0046, 0x0046, 0x0049]), + (0xfb04, [0x0046, 0x0046, 0x004c]), (0xfb05, [0x0053, 0x0054, 0x0000]), + (0xfb06, [0x0053, 0x0054, 0x0000]), (0xfb13, [0x0544, 0x0546, 0x0000]), + (0xfb14, [0x0544, 0x0535, 0x0000]), (0xfb15, [0x0544, 0x053b, 0x0000]), + (0xfb16, [0x054e, 0x0546, 0x0000]), (0xfb17, [0x0544, 0x053d, 0x0000]), + ], + }, + L2Lut { + singles: &[ // 12 entries, 72 bytes + (Range::step_by_1(0x0428..=0x044f), -40), (Range::step_by_1(0x04d8..=0x04fb), -40), + (Range::step_by_1(0x0597..=0x05a1), -39), (Range::step_by_1(0x05a3..=0x05b1), -39), + (Range::step_by_1(0x05b3..=0x05b9), -39), (Range::step_by_1(0x05bb..=0x05bc), -39), + (Range::step_by_1(0x0cc0..=0x0cf2), -64), (Range::step_by_1(0x0d70..=0x0d85), -32), + (Range::step_by_1(0x18c0..=0x18df), -32), (Range::step_by_1(0x6e60..=0x6e7f), -32), + (Range::step_by_1(0x6ebb..=0x6ed3), -27), (Range::step_by_1(0xe922..=0xe943), -34), + ], + multis: &[ // 0 entries, 0 bytes + ], + }, + ], + }; + + static TITLECASE_LUT: L1Lut = L1Lut { + l2_luts: [ + L2Lut { + singles: &[ // 26 entries, 156 bytes + (Range::singleton(0x01c4), 1), (Range::singleton(0x01c5), 0), + (Range::singleton(0x01c6), -1), (Range::singleton(0x01c7), 1), + (Range::singleton(0x01c8), 0), (Range::singleton(0x01c9), -1), + (Range::singleton(0x01ca), 1), (Range::singleton(0x01cb), 0), + (Range::singleton(0x01cc), -1), (Range::singleton(0x01f1), 1), + (Range::singleton(0x01f2), 0), (Range::singleton(0x01f3), -1), + (Range::step_by_1(0x10d0..=0x10fa), 0), (Range::step_by_1(0x10fd..=0x10ff), 0), + (Range::step_by_1(0x1f80..=0x1f87), 8), (Range::step_by_1(0x1f88..=0x1f8f), 0), + (Range::step_by_1(0x1f90..=0x1f97), 8), (Range::step_by_1(0x1f98..=0x1f9f), 0), + (Range::step_by_1(0x1fa0..=0x1fa7), 8), (Range::step_by_1(0x1fa8..=0x1faf), 0), + (Range::singleton(0x1fb3), 9), (Range::singleton(0x1fbc), 0), (Range::singleton(0x1fc3), 9), + (Range::singleton(0x1fcc), 0), (Range::singleton(0x1ff3), 9), (Range::singleton(0x1ffc), 0), + ], + multis: &[ // 23 entries, 184 bytes + (0x00df, [0x0053, 0x0073, 0x0000]), (0x0587, [0x0535, 0x0582, 0x0000]), + (0x1fb2, [0x1fba, 0x0345, 0x0000]), (0x1fb4, [0x0386, 0x0345, 0x0000]), + (0x1fb7, [0x0391, 0x0342, 0x0345]), (0x1fc2, [0x1fca, 0x0345, 0x0000]), + (0x1fc4, [0x0389, 0x0345, 0x0000]), (0x1fc7, [0x0397, 0x0342, 0x0345]), + (0x1ff2, [0x1ffa, 0x0345, 0x0000]), (0x1ff4, [0x038f, 0x0345, 0x0000]), + (0x1ff7, [0x03a9, 0x0342, 0x0345]), (0xfb00, [0x0046, 0x0066, 0x0000]), + (0xfb01, [0x0046, 0x0069, 0x0000]), (0xfb02, [0x0046, 0x006c, 0x0000]), + (0xfb03, [0x0046, 0x0066, 0x0069]), (0xfb04, [0x0046, 0x0066, 0x006c]), + (0xfb05, [0x0053, 0x0074, 0x0000]), (0xfb06, [0x0053, 0x0074, 0x0000]), + (0xfb13, [0x0544, 0x0576, 0x0000]), (0xfb14, [0x0544, 0x0565, 0x0000]), + (0xfb15, [0x0544, 0x056b, 0x0000]), (0xfb16, [0x054e, 0x0576, 0x0000]), + (0xfb17, [0x0544, 0x056d, 0x0000]), + ], + }, + L2Lut { + singles: &[ // 0 entries, 0 bytes + ], + multis: &[ // 0 entries, 0 bytes + ], + }, + ], + }; } diff --git a/library/core/src/wtf8.rs b/library/core/src/wtf8.rs index 7214918db6c3..a0978c3dafb4 100644 --- a/library/core/src/wtf8.rs +++ b/library/core/src/wtf8.rs @@ -484,11 +484,22 @@ unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { } } -/// Copied from core::str::raw::slice_error_fail #[inline(never)] fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { - assert!(begin <= end); - panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary"); + let len = s.len(); + if begin > len { + panic!("start byte index {begin} is out of bounds for string of length {len}"); + } + if end > len { + panic!("end byte index {end} is out of bounds for string of length {len}"); + } + if begin > end { + panic!("byte range starts at {begin} but ends at {end}"); + } + if !s.is_code_point_boundary(begin) { + panic!("byte index {begin} is not a code point boundary"); + } + panic!("byte index {end} is not a code point boundary"); } /// Iterator for the code points of a WTF-8 string. diff --git a/library/coretests/benches/lib.rs b/library/coretests/benches/lib.rs index 150b9b33f457..e8dc815a7dd0 100644 --- a/library/coretests/benches/lib.rs +++ b/library/coretests/benches/lib.rs @@ -1,6 +1,6 @@ // wasm32 does not support benches (no time). #![cfg(not(target_arch = "wasm32"))] -// Disabling in Miri as these would take too long. +// This is marked as `test = true` and hence picked up by `./x miri`, but that would be too slow. #![cfg(not(miri))] #![feature(flt2dec)] #![feature(test)] @@ -8,7 +8,9 @@ #![feature(iter_array_chunks)] #![feature(iter_next_chunk)] #![feature(iter_advance_by)] +#![feature(num_internals)] #![feature(uint_gather_scatter_bits)] +#![allow(internal_features)] extern crate test; diff --git a/library/coretests/tests/array.rs b/library/coretests/tests/array.rs index 2b4429092e98..43fed944e928 100644 --- a/library/coretests/tests/array.rs +++ b/library/coretests/tests/array.rs @@ -646,7 +646,7 @@ fn array_mixed_equality_integers() { #[test] fn array_mixed_equality_nans() { - let array3: [f32; 3] = [1.0, std::f32::NAN, 3.0]; + let array3: [f32; 3] = [1.0, f32::NAN, 3.0]; let slice3: &[f32] = &{ array3 }; assert!(!(array3 == slice3)); @@ -741,3 +741,18 @@ const fn maybe_doubler(x: usize) -> Option { struct Zst; assert_eq!([(); 10].try_map(|()| Some(Zst)), Some([const { Zst }; 10])); } + +#[test] +const fn extra_const_array_ops() { + let x: [u8; 4] = + { std::array::from_fn(const |i| i + 4).map(const |x| x * 2).map(const |x| x as _) }; + let y = 4; + struct Z(u16); + impl const Drop for Z { + fn drop(&mut self) {} + } + let w = Z(2); + let _x: [u8; 4] = { + std::array::from_fn(const |_| x[0] + y).map(const |x| x * (w.0 as u8)).map(const |x| x as _) + }; +} diff --git a/library/coretests/tests/bstr.rs b/library/coretests/tests/bstr.rs index cd4d69d6b337..dffc7e3f0349 100644 --- a/library/coretests/tests/bstr.rs +++ b/library/coretests/tests/bstr.rs @@ -49,4 +49,19 @@ fn test_display() { assert_eq!(&format!("{b2:->3}!"), "�(��!"); assert_eq!(&format!("{b2:-^3}!"), "�(��!"); assert_eq!(&format!("{b2:-^2}!"), "�(��!"); + + assert_eq!(&format!("{b1:.1}!"), &format!("{:.1}!", "abc")); + assert_eq!(&format!("{b1:.2}!"), &format!("{:.2}!", "abc")); + assert_eq!(&format!("{b1:.3}!"), &format!("{:.3}!", "abc")); + assert_eq!(&format!("{b1:-<5.2}!"), &format!("{:-<5.2}!", "abc")); + assert_eq!(&format!("{b1:-^5.2}!"), &format!("{:-^5.2}!", "abc")); + assert_eq!(&format!("{b1:->5.2}!"), &format!("{:->5.2}!", "abc")); + + assert_eq!(&format!("{b2:.1}!"), "�!"); + assert_eq!(&format!("{b2:.2}!"), "�(!"); + assert_eq!(&format!("{b2:.3}!"), "�(�!"); + assert_eq!(&format!("{b2:.4}!"), "�(��!"); + assert_eq!(&format!("{b2:-<6.3}!"), "�(�---!"); + assert_eq!(&format!("{b2:-^6.3}!"), "-�(�--!"); + assert_eq!(&format!("{b2:->6.3}!"), "---�(�!"); } diff --git a/library/coretests/tests/char.rs b/library/coretests/tests/char.rs index f0f6a2442928..877017f682c9 100644 --- a/library/coretests/tests/char.rs +++ b/library/coretests/tests/char.rs @@ -1,5 +1,6 @@ +use std::char::{self, CharCase}; +use std::str; use std::str::FromStr; -use std::{char, str}; #[test] fn test_convert() { @@ -39,6 +40,30 @@ fn test_from_str() { assert!(char::from_str("abc").is_err()); } +#[test] +fn test_is_cased() { + assert!('a'.is_cased()); + assert!('ö'.is_cased()); + assert!('ß'.is_cased()); + assert!('Ü'.is_cased()); + assert!('P'.is_cased()); + assert!('ª'.is_cased()); + assert!(!'攂'.is_cased()); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn test_char_case() { + for c in '\0'..='\u{10FFFF}' { + match c.case() { + None => assert!(!c.is_cased()), + Some(CharCase::Lower) => assert!(c.is_lowercase()), + Some(CharCase::Upper) => assert!(c.is_uppercase()), + Some(CharCase::Title) => assert!(c.is_titlecase()), + } + } +} + #[test] fn test_is_lowercase() { assert!('a'.is_lowercase()); @@ -48,6 +73,17 @@ fn test_is_lowercase() { assert!(!'P'.is_lowercase()); } +#[test] +fn test_is_titlecase() { + assert!('Dž'.is_titlecase()); + assert!('ᾨ'.is_titlecase()); + assert!(!'h'.is_titlecase()); + assert!(!'ä'.is_titlecase()); + assert!(!'ß'.is_titlecase()); + assert!(!'Ö'.is_titlecase()); + assert!(!'T'.is_titlecase()); +} + #[test] fn test_is_uppercase() { assert!(!'h'.is_uppercase()); @@ -57,6 +93,27 @@ fn test_is_uppercase() { assert!('T'.is_uppercase()); } +#[test] +fn titlecase_fast_path() { + for c in '\0'..='\u{01C4}' { + assert!(!(c.is_cased() && !c.is_lowercase() && !c.is_uppercase())) + } +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn at_most_one_case() { + for c in '\0'..='\u{10FFFF}' { + assert_eq!( + !c.is_cased() as u8 + + c.is_lowercase() as u8 + + c.is_uppercase() as u8 + + c.is_titlecase() as u8, + 1 + ); + } +} + #[test] fn test_is_whitespace() { assert!(' '.is_whitespace()); diff --git a/library/coretests/tests/iter/adapters/intersperse.rs b/library/coretests/tests/iter/adapters/intersperse.rs index df6be79308be..bcb7709077cd 100644 --- a/library/coretests/tests/iter/adapters/intersperse.rs +++ b/library/coretests/tests/iter/adapters/intersperse.rs @@ -153,10 +153,6 @@ fn test_try_fold_specialization_intersperse_err() { assert_eq!(iter.next(), None); } -// FIXME(iter_intersperse): `intersperse` current behavior may change for -// non-fused iterators, so this test will likely have to -// be adjusted; see PR #152855 and issue #79524 -// if `intersperse` doesn't change, remove this FIXME. #[test] fn test_non_fused_iterator_intersperse() { #[derive(Debug)] @@ -183,24 +179,26 @@ fn next(&mut self) -> Option { } let counter = 0; - // places a 2 between `Some(_)` items + // places a 1 between `Some(_)` items let non_fused_iter = TestCounter { counter }; - let mut intersperse_iter = non_fused_iter.intersperse(2); - // Since `intersperse` currently transforms the original - // iterator into a fused iterator, this intersperse_iter - // should always have `None` - for _ in 0..counter + 6 { - assert_eq!(intersperse_iter.next(), None); - } + let mut intersperse_iter = non_fused_iter.intersperse(1); + // Interspersed iter produces: + // `None` -> `Some(2)` -> `None` -> `Some(1)` -> Some(4)` -> `None` -> `Some(1)` -> + // `Some(6)` -> and then `None` endlessly + assert_eq!(intersperse_iter.next(), None); + assert_eq!(intersperse_iter.next(), Some(2)); + assert_eq!(intersperse_iter.next(), None); + assert_eq!(intersperse_iter.next(), Some(1)); + assert_eq!(intersperse_iter.next(), Some(4)); + assert_eq!(intersperse_iter.next(), None); + assert_eq!(intersperse_iter.next(), Some(1)); + assert_eq!(intersperse_iter.next(), Some(6)); + assert_eq!(intersperse_iter.next(), None); - // Extra check to make sure it is `None` after processing 6 items + // Extra check to make sure it is `None` after processing all items assert_eq!(intersperse_iter.next(), None); } -// FIXME(iter_intersperse): `intersperse` current behavior may change for -// non-fused iterators, so this test will likely have to -// be adjusted; see PR #152855 and issue #79524 -// if `intersperse` doesn't change, remove this FIXME. #[test] fn test_non_fused_iterator_intersperse_2() { #[derive(Debug)] @@ -228,35 +226,26 @@ fn next(&mut self) -> Option { } let counter = 0; - // places a 2 between `Some(_)` items + // places a 100 between `Some(_)` items let non_fused_iter = TestCounter { counter }; - let mut intersperse_iter = non_fused_iter.intersperse(2); - // Since `intersperse` currently transforms the original - // iterator into a fused iterator, this interspersed iter - // will be `Some(1)` -> `Some(2)` -> `Some(2)` -> and then - // `None` endlessly - let mut items_processed = 0; - for num in 0..counter + 6 { - if num < 3 { - if num % 2 != 0 { - assert_eq!(intersperse_iter.next(), Some(2)); - } else { - items_processed += 1; - assert_eq!(intersperse_iter.next(), Some(items_processed)); - } - } else { - assert_eq!(intersperse_iter.next(), None); - } - } + let mut intersperse_iter = non_fused_iter.intersperse(100); + // Interspersed iter produces: + // `Some(1)` -> `Some(100)` -> `Some(2)` -> `None` -> `Some(100)` + // -> `Some(4)` -> `Some(100)` -> `Some(5)` -> `None` endlessly + assert_eq!(intersperse_iter.next(), Some(1)); + assert_eq!(intersperse_iter.next(), Some(100)); + assert_eq!(intersperse_iter.next(), Some(2)); + assert_eq!(intersperse_iter.next(), None); + assert_eq!(intersperse_iter.next(), Some(100)); + assert_eq!(intersperse_iter.next(), Some(4)); + assert_eq!(intersperse_iter.next(), Some(100)); + assert_eq!(intersperse_iter.next(), Some(5)); + assert_eq!(intersperse_iter.next(), None); // Extra check to make sure it is `None` after processing 6 items assert_eq!(intersperse_iter.next(), None); } -// FIXME(iter_intersperse): `intersperse_with` current behavior may change for -// non-fused iterators, so this test will likely have to -// be adjusted; see PR #152855 and issue #79524 -// if `intersperse_with` doesn't change, remove this FIXME. #[test] fn test_non_fused_iterator_intersperse_with() { #[derive(Debug)] @@ -285,22 +274,24 @@ fn next(&mut self) -> Option { let counter = 0; let non_fused_iter = TestCounter { counter }; // places a 2 between `Some(_)` items - let mut intersperse_iter = non_fused_iter.intersperse_with(|| 2); - // Since `intersperse` currently transforms the original - // iterator into a fused iterator, this intersperse_iter - // should always have `None` - for _ in 0..counter + 6 { - assert_eq!(intersperse_iter.next(), None); - } + let mut intersperse_iter = non_fused_iter.intersperse_with(|| 1); + // Interspersed iter produces: + // `None` -> `Some(2)` -> `None` -> `Some(1)` -> Some(4)` -> `None` -> `Some(1)` -> + // `Some(6)` -> and then `None` endlessly + assert_eq!(intersperse_iter.next(), None); + assert_eq!(intersperse_iter.next(), Some(2)); + assert_eq!(intersperse_iter.next(), None); + assert_eq!(intersperse_iter.next(), Some(1)); + assert_eq!(intersperse_iter.next(), Some(4)); + assert_eq!(intersperse_iter.next(), None); + assert_eq!(intersperse_iter.next(), Some(1)); + assert_eq!(intersperse_iter.next(), Some(6)); + assert_eq!(intersperse_iter.next(), None); // Extra check to make sure it is `None` after processing 6 items assert_eq!(intersperse_iter.next(), None); } -// FIXME(iter_intersperse): `intersperse_with` current behavior may change for -// non-fused iterators, so this test will likely have to -// be adjusted; see PR #152855 and issue #79524 -// if `intersperse_with` doesn't change, remove this FIXME. #[test] fn test_non_fused_iterator_intersperse_with_2() { #[derive(Debug)] @@ -328,26 +319,21 @@ fn next(&mut self) -> Option { } let counter = 0; - // places a 2 between `Some(_)` items + // places a 100 between `Some(_)` items let non_fused_iter = TestCounter { counter }; - let mut intersperse_iter = non_fused_iter.intersperse(2); - // Since `intersperse` currently transforms the original - // iterator into a fused iterator, this interspersed iter - // will be `Some(1)` -> `Some(2)` -> `Some(2)` -> and then - // `None` endlessly - let mut items_processed = 0; - for num in 0..counter + 6 { - if num < 3 { - if num % 2 != 0 { - assert_eq!(intersperse_iter.next(), Some(2)); - } else { - items_processed += 1; - assert_eq!(intersperse_iter.next(), Some(items_processed)); - } - } else { - assert_eq!(intersperse_iter.next(), None); - } - } + let mut intersperse_iter = non_fused_iter.intersperse_with(|| 100); + // Interspersed iter produces: + // `Some(1)` -> `Some(100)` -> `Some(2)` -> `None` -> `Some(100)` + // -> `Some(4)` -> `Some(100)` -> `Some(5)` -> `None` endlessly + assert_eq!(intersperse_iter.next(), Some(1)); + assert_eq!(intersperse_iter.next(), Some(100)); + assert_eq!(intersperse_iter.next(), Some(2)); + assert_eq!(intersperse_iter.next(), None); + assert_eq!(intersperse_iter.next(), Some(100)); + assert_eq!(intersperse_iter.next(), Some(4)); + assert_eq!(intersperse_iter.next(), Some(100)); + assert_eq!(intersperse_iter.next(), Some(5)); + assert_eq!(intersperse_iter.next(), None); // Extra check to make sure it is `None` after processing 6 items assert_eq!(intersperse_iter.next(), None); diff --git a/library/coretests/tests/iter/adapters/map_windows.rs b/library/coretests/tests/iter/adapters/map_windows.rs index 01cebc9b27fd..994ec087e5e8 100644 --- a/library/coretests/tests/iter/adapters/map_windows.rs +++ b/library/coretests/tests/iter/adapters/map_windows.rs @@ -284,3 +284,29 @@ fn check_size_hint( check_size_hint::<5>((5, Some(5)), (1, Some(1))); check_size_hint::<5>((5, Some(10)), (1, Some(6))); } + +#[test] +fn test_unfused() { + #[derive(Default)] + struct UnfusedIter(usize); + impl Iterator for UnfusedIter { + type Item = usize; + + fn next(&mut self) -> Option { + let curr = self.0; + self.0 += 1; + if curr % 7 == 0 { None } else { Some(curr) } + } + } + + let mut iter = UnfusedIter(1).map_windows(|a: &[_; 3]| *a); + assert_eq!(iter.by_ref().collect::>(), vec![[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]); + assert_eq!( + iter.by_ref().collect::>(), + vec![[8, 9, 10], [9, 10, 11], [10, 11, 12], [11, 12, 13]] + ); + assert_eq!( + iter.by_ref().collect::>(), + vec![[15, 16, 17], [16, 17, 18], [17, 18, 19], [18, 19, 20]] + ); +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index d04b9a2d6e13..fba144c0e983 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -17,6 +17,7 @@ #![feature(const_bool)] #![feature(const_cell_traits)] #![feature(const_clone)] +#![feature(const_closures)] #![feature(const_cmp)] #![feature(const_convert)] #![feature(const_default)] @@ -88,6 +89,7 @@ #![feature(next_index)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(nonzero_from_str_radix)] +#![feature(num_internals)] #![feature(numfmt)] #![feature(one_sided_range)] #![feature(panic_internals)] @@ -111,6 +113,7 @@ #![feature(step_trait)] #![feature(str_internals)] #![feature(strict_provenance_lints)] +#![feature(titlecase)] #![feature(trusted_len)] #![feature(trusted_random_access)] #![feature(try_blocks)] @@ -120,6 +123,7 @@ #![feature(uint_bit_width)] #![feature(uint_carryless_mul)] #![feature(uint_gather_scatter_bits)] +#![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] #![feature(widening_mul)] @@ -180,7 +184,6 @@ fn $test() $block mod const_ptr; mod convert; mod ffi; -mod floats; mod fmt; mod future; mod hash; diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index 25e12435b472..0713c5c651fb 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -1,4 +1,5 @@ -use core::num::imp::dec2flt::float::RawFloat; +use core::num::imp::dec2flt::Lemire; +use core::num::imp::{Float, FloatExt}; use crate::num::{ldexp_f32, ldexp_f64}; @@ -56,57 +57,60 @@ fn test_f64_integer_decode() { #[test] #[cfg(target_has_reliable_f16)] fn test_f16_consts() { - assert_eq!(::INFINITY, f16::INFINITY); - assert_eq!(::NEG_INFINITY, -f16::INFINITY); - assert_eq!(::NAN.to_bits(), f16::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f16::NAN).to_bits()); - assert_eq!(::SIG_BITS, 10); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -22); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 5); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -4); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 4); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 7); - assert_eq!(::EXP_MIN, -14); - assert_eq!(::EXP_SAT, 0x1f); - assert_eq!(::SMALLEST_POWER_OF_TEN, -27); - assert_eq!(::LARGEST_POWER_OF_TEN, 4); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 2048); + assert_eq!(::INFINITY, f16::INFINITY); + assert_eq!(::NEG_INFINITY, -f16::INFINITY); + assert_eq!(::NAN.to_bits(), f16::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f16::NAN).to_bits()); + assert_eq!(::SIG_BITS, 10); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -22); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 5); + assert_eq!(::EXP_MIN, -14); + assert_eq!(::EXP_SAT, 0x1f); + assert_eq!(::SMALLEST_POWER_OF_TEN, -27); + assert_eq!(::LARGEST_POWER_OF_TEN, 4); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -4); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 4); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 7); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 2048); } #[test] fn test_f32_consts() { - assert_eq!(::INFINITY, f32::INFINITY); - assert_eq!(::NEG_INFINITY, -f32::INFINITY); - assert_eq!(::NAN.to_bits(), f32::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f32::NAN).to_bits()); - assert_eq!(::SIG_BITS, 23); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -17); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 10); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -10); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 10); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 17); - assert_eq!(::EXP_MIN, -126); - assert_eq!(::EXP_SAT, 0xff); - assert_eq!(::SMALLEST_POWER_OF_TEN, -65); - assert_eq!(::LARGEST_POWER_OF_TEN, 38); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 16777216); + assert_eq!(::INFINITY, f32::INFINITY); + assert_eq!(::NEG_INFINITY, -f32::INFINITY); + assert_eq!(::NAN.to_bits(), f32::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f32::NAN).to_bits()); + assert_eq!(::SIG_BITS, 23); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -17); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 10); + assert_eq!(::EXP_MIN, -126); + assert_eq!(::EXP_SAT, 0xff); + assert_eq!(::SMALLEST_POWER_OF_TEN, -65); + assert_eq!(::LARGEST_POWER_OF_TEN, 38); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -10); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 10); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 17); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 16777216); } #[test] fn test_f64_consts() { - assert_eq!(::INFINITY, f64::INFINITY); - assert_eq!(::NEG_INFINITY, -f64::INFINITY); - assert_eq!(::NAN.to_bits(), f64::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f64::NAN).to_bits()); - assert_eq!(::SIG_BITS, 52); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -4); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 23); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -22); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 22); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 37); - assert_eq!(::EXP_MIN, -1022); - assert_eq!(::EXP_SAT, 0x7ff); - assert_eq!(::SMALLEST_POWER_OF_TEN, -342); - assert_eq!(::LARGEST_POWER_OF_TEN, 308); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 9007199254740992); + assert_eq!(::INFINITY, f64::INFINITY); + assert_eq!(::NEG_INFINITY, -f64::INFINITY); + assert_eq!(::NAN.to_bits(), f64::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f64::NAN).to_bits()); + assert_eq!(::SIG_BITS, 52); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -4); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 23); + assert_eq!(::EXP_MIN, -1022); + assert_eq!(::EXP_SAT, 0x7ff); + assert_eq!(::SMALLEST_POWER_OF_TEN, -342); + assert_eq!(::LARGEST_POWER_OF_TEN, 308); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -22); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 22); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 37); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 9007199254740992); } diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs index e4ce533ba44d..e5a7ae346f42 100644 --- a/library/coretests/tests/num/dec2flt/lemire.rs +++ b/library/coretests/tests/num/dec2flt/lemire.rs @@ -1,6 +1,5 @@ -use core::num::imp::dec2flt; +use core::num::imp::{Float, dec2flt}; -use dec2flt::float::RawFloat; use dec2flt::lemire::compute_float; #[cfg(target_has_reliable_f16)] diff --git a/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs b/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs new file mode 100644 index 000000000000..2a82ae326c22 --- /dev/null +++ b/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs @@ -0,0 +1,166 @@ +//! IEEE 754 floating point compliance tests +//! +//! To understand IEEE 754's requirements on a programming language, one must understand that the +//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any +//! one component. That means the hardware, language, and even libraries are considered part of +//! conforming floating point support in a programming environment. +//! +//! A programming language's duty, accordingly, is: +//! 1. offer access to the hardware where the hardware offers support +//! 2. provide operations that fulfill the remaining requirements of the standard +//! 3. provide the ability to write additional software that can fulfill those requirements +//! +//! This may be fulfilled in any combination that the language sees fit. However, to claim that +//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without +//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined +//! as complete support for at least one specified floating point type as an "arithmetic" and +//! "interchange" format, plus specified type conversions to "external character sequences" and +//! integer types. +//! +//! For our purposes, +//! "interchange format" => f16, f32, f64, f128 +//! "arithmetic format" => f16, f32, f64, f128, and any "soft floats" +//! "external character sequence" => str from any float +//! "integer format" => {i,u}{8,16,32,64,128} +//! +//! None of these tests are against Rust's own implementation. They are only tests against the +//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. +//! Please consider this carefully when adding, removing, or reorganizing these tests. They are +//! here so that it is clear what tests are required by the standard and what can be changed. + +use core::fmt; +use core::str::FromStr; + +use crate::num::{assert_biteq, float_test}; + +/// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts +/// of the formatting infrastructure, which makes it ideal for testing here. +#[track_caller] +fn string_roundtrip(x: T) -> T +where + T: FromStr + fmt::Display, +{ + x.to_string().parse::().unwrap() +} + +// FIXME(f128): Tests are disabled while we don't have parsing / printing + +// We must preserve signs on all numbers. That includes zero. +// -0 and 0 are == normally, so test bit equality. +float_test! { + name: preserve_signed_zero, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + let neg0 = flt(-0.0); + let pos0 = flt(0.0); + assert_biteq!(neg0, string_roundtrip(neg0)); + assert_biteq!(pos0, string_roundtrip(pos0)); + assert_ne!(neg0.to_bits(), pos0.to_bits()); + } +} + +float_test! { + name: preserve_signed_infinity, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + let neg_inf = Float::NEG_INFINITY; + let pos_inf = Float::INFINITY; + assert_biteq!(neg_inf, string_roundtrip(neg_inf)); + assert_biteq!(pos_inf, string_roundtrip(pos_inf)); + assert_ne!(neg_inf.to_bits(), pos_inf.to_bits()); + } +} + +float_test! { + name: infinity_to_str, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + assert!( + match Float::INFINITY.to_string().to_lowercase().as_str() { + "+infinity" | "infinity" => true, + "+inf" | "inf" => true, + _ => false, + }, + "Infinity must write to a string as some casing of inf or infinity, with an optional +." + ); + assert!( + match Float::NEG_INFINITY.to_string().to_lowercase().as_str() { + "-infinity" | "-inf" => true, + _ => false, + }, + "Negative Infinity must write to a string as some casing of -inf or -infinity" + ); + } +} + +float_test! { + name: nan_to_str, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + assert!( + match Float::NAN.to_string().to_lowercase().as_str() { + "nan" | "+nan" | "-nan" => true, + _ => false, + }, + "NaNs must write to a string as some casing of nan." + ) + } +} + +float_test! { + name: infinity_from_str, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + // "+"?("inf"|"infinity") in any case => Infinity + assert_biteq!(Float::INFINITY, Float::from_str("infinity").unwrap()); + assert_biteq!(Float::INFINITY, Float::from_str("inf").unwrap()); + assert_biteq!(Float::INFINITY, Float::from_str("+infinity").unwrap()); + assert_biteq!(Float::INFINITY, Float::from_str("+inf").unwrap()); + // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd + assert_biteq!(Float::INFINITY, Float::from_str("+iNfInItY").unwrap()); + + // "-inf"|"-infinity" in any case => Negative Infinity + assert_biteq!(Float::NEG_INFINITY, Float::from_str("-infinity").unwrap()); + assert_biteq!(Float::NEG_INFINITY, Float::from_str("-inf").unwrap()); + assert_biteq!(Float::NEG_INFINITY, Float::from_str("-INF").unwrap()); + assert_biteq!(Float::NEG_INFINITY, Float::from_str("-INFinity").unwrap()); + + } +} + +float_test! { + name: qnan_from_str, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + // ("+"|"-"")?"s"?"nan" in any case => qNaN + assert!("nan".parse::().unwrap().is_nan()); + assert!("-nan".parse::().unwrap().is_nan()); + assert!("+nan".parse::().unwrap().is_nan()); + assert!("+NAN".parse::().unwrap().is_nan()); + assert!("-NaN".parse::().unwrap().is_nan()); + } +} diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/num/floats.rs similarity index 96% rename from library/coretests/tests/floats/mod.rs rename to library/coretests/tests/num/floats.rs index 3e39528dfbf4..d87f85094450 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/num/floats.rs @@ -1,7 +1,8 @@ +use std::hint::black_box; use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -trait TestableFloat: Sized { +pub(crate) trait TestableFloat: Sized { const BITS: u32; /// Unsigned int with the same size, for converting to/from bits. type Int; @@ -32,7 +33,7 @@ trait TestableFloat: Sized { const LNGAMMA_APPROX_LOOSE: Self = Self::APPROX; const ZERO: Self; const ONE: Self; - + const SNAN: Self; const MIN_POSITIVE_NORMAL: Self; const MAX_SUBNORMAL: Self; /// Smallest number @@ -82,6 +83,9 @@ impl TestableFloat for f16 { const LNGAMMA_APPROX_LOOSE: Self = 1e-1; const ZERO: Self = 0.0; const ONE: Self = 1.0; + // We rely on NAN having an all-0 payload, so the signaling bit is the least significant + // non-0 bit, and that gets toggled by the "-1". + const SNAN: Self = Self::from_bits(Self::NAN.to_bits() - 1); const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -125,6 +129,9 @@ impl TestableFloat for f32 { const LNGAMMA_APPROX_LOOSE: Self = if cfg!(miri) { 1e-2 } else { 1e-4 }; const ZERO: Self = 0.0; const ONE: Self = 1.0; + // We rely on NAN having an all-0 payload, so the signaling bit is the least significant + // non-0 bit, and that gets toggled by the "-1". + const SNAN: Self = Self::from_bits(Self::NAN.to_bits() - 1); const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -153,6 +160,9 @@ impl TestableFloat for f64 { const LNGAMMA_APPROX_LOOSE: Self = 1e-4; const ZERO: Self = 0.0; const ONE: Self = 1.0; + // We rely on NAN having an all-0 payload, so the signaling bit is the least significant + // non-0 bit, and that gets toggled by the "-1". + const SNAN: Self = Self::from_bits(Self::NAN.to_bits() - 1); const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -191,6 +201,9 @@ impl TestableFloat for f128 { const LNGAMMA_APPROX_LOOSE: Self = 1e-10; const ZERO: Self = 0.0; const ONE: Self = 1.0; + // We rely on NAN having an all-0 payload, so the signaling bit is the least significant + // non-0 bit, and that gets toggled by the "-1". + const SNAN: Self = Self::from_bits(Self::NAN.to_bits() - 1); const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -211,7 +224,7 @@ impl TestableFloat for f128 { } /// Determine the tolerance for values of the argument type. -const fn lim_for_ty(_x: T) -> T { +pub(crate) const fn lim_for_ty(_x: T) -> T { T::APPROX } @@ -219,7 +232,9 @@ const fn lim_for_ty(_x: T) -> T { /// Verify that floats are within a tolerance of each other. macro_rules! assert_approx_eq { - ($a:expr, $b:expr $(,)?) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; + ($a:expr, $b:expr $(,)?) => {{ + assert_approx_eq!($a, $b, $crate::num::floats::lim_for_ty($a)) + }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -257,8 +272,8 @@ macro_rules! assert_biteq { // We rely on the `Float` type being brought in scope by the macros below. l: Float = l, r: Float = r, - lb: ::Int = l.to_bits(), - rb: ::Int = r.to_bits(), + lb: ::Int = l.to_bits(), + rb: ::Int = r.to_bits(), width: usize = ((bits / 4) + 2) as usize, ); }}; @@ -299,6 +314,7 @@ macro_rules! float_test { test $test:block ) => { mod $name { + #[allow(unused_imports)] use super::*; #[test] @@ -347,6 +363,7 @@ const fn flt (x: Float) -> Float { x } $( $( #[$const_meta] )+ )? mod const_ { + #[allow(unused_imports)] use super::*; #[test] @@ -397,6 +414,9 @@ const fn flt (x: Float) -> Float { x } }; } +pub(crate) use assert_biteq; +pub(crate) use float_test; + float_test! { name: num, attrs: { @@ -668,11 +688,22 @@ const fn flt (x: Float) -> Float { x } assert_biteq!(flt(9.0).min(Float::NEG_INFINITY), Float::NEG_INFINITY); assert_biteq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); assert_biteq!(flt(-9.0).min(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_biteq!(Float::NAN.min(9.0), 9.0); - assert_biteq!(Float::NAN.min(-9.0), -9.0); - assert_biteq!(flt(9.0).min(Float::NAN), 9.0); - assert_biteq!(flt(-9.0).min(Float::NAN), -9.0); + // We add black_box for the NAN tests as that used to be able to trigger miscompilations. + assert_biteq!(Float::NAN.min(black_box(9.0)), 9.0); + assert_biteq!(black_box(Float::NAN).min(-9.0), -9.0); + assert_biteq!(flt(9.0).min(black_box(Float::NAN)), 9.0); + assert_biteq!(black_box(flt(-9.0)).min(Float::NAN), -9.0); assert!(Float::NAN.min(Float::NAN).is_nan()); + // FIXME(llvm21): LLVM miscompiles the fallback impl on aarch64 and likely other targets + // (https://github.com/llvm/llvm-project/issues/176624). When we require LLVM 22, + // remove the ui test `tests/ui/float/minmax.rs` and unconditionally enable the test here. + if cfg!(miri) { + assert_biteq!(Float::SNAN.min(black_box(9.0)), 9.0); + assert_biteq!(black_box(Float::SNAN).min(-9.0), -9.0); + assert_biteq!(flt(9.0).min(black_box(Float::SNAN)), 9.0); + assert_biteq!(black_box(flt(-9.0)).min(Float::SNAN), -9.0); + } + assert!(Float::SNAN.min(Float::SNAN).is_nan()); } } @@ -699,11 +730,22 @@ const fn flt (x: Float) -> Float { x } assert_biteq!(flt(9.0).max(Float::NEG_INFINITY), 9.0); assert_biteq!(Float::NEG_INFINITY.max(-9.0), -9.0); assert_biteq!(flt(-9.0).max(Float::NEG_INFINITY), -9.0); - assert_biteq!(Float::NAN.max(9.0), 9.0); - assert_biteq!(Float::NAN.max(-9.0), -9.0); - assert_biteq!(flt(9.0).max(Float::NAN), 9.0); - assert_biteq!(flt(-9.0).max(Float::NAN), -9.0); + // We add black_box for the NAN tests as that used to be able to trigger miscompilations. + assert_biteq!(Float::NAN.max(black_box(9.0)), 9.0); + assert_biteq!(black_box(Float::NAN).max(-9.0), -9.0); + assert_biteq!(flt(9.0).max(black_box(Float::NAN)), 9.0); + assert_biteq!(black_box(flt(-9.0)).max(Float::NAN), -9.0); assert!(Float::NAN.max(Float::NAN).is_nan()); + // FIXME(llvm21): LLVM miscompiles the fallback impl on aarch64 and likely other targets + // (https://github.com/llvm/llvm-project/issues/176624). When we require LLVM 22, + // remove the ui test `tests/ui/float/minmax.rs` and unconditionally enable the test here. + if cfg!(miri) { + assert_biteq!(Float::SNAN.max(black_box(9.0)), 9.0); + assert_biteq!(black_box(Float::SNAN).max(-9.0), -9.0); + assert_biteq!(flt(9.0).max(black_box(Float::SNAN)), 9.0); + assert_biteq!(black_box(flt(-9.0)).max(Float::SNAN), -9.0); + } + assert!(Float::SNAN.max(Float::SNAN).is_nan()); } } diff --git a/library/coretests/tests/num/ieee754.rs b/library/coretests/tests/num/ieee754.rs deleted file mode 100644 index b0f6a7545aa9..000000000000 --- a/library/coretests/tests/num/ieee754.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! IEEE 754 floating point compliance tests -//! -//! To understand IEEE 754's requirements on a programming language, one must understand that the -//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any -//! one component. That means the hardware, language, and even libraries are considered part of -//! conforming floating point support in a programming environment. -//! -//! A programming language's duty, accordingly, is: -//! 1. offer access to the hardware where the hardware offers support -//! 2. provide operations that fulfill the remaining requirements of the standard -//! 3. provide the ability to write additional software that can fulfill those requirements -//! -//! This may be fulfilled in any combination that the language sees fit. However, to claim that -//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without -//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined -//! as complete support for at least one specified floating point type as an "arithmetic" and -//! "interchange" format, plus specified type conversions to "external character sequences" and -//! integer types. -//! -//! For our purposes, -//! "interchange format" => f32, f64 -//! "arithmetic format" => f32, f64, and any "soft floats" -//! "external character sequence" => str from any float -//! "integer format" => {i,u}{8,16,32,64,128} -//! -//! None of these tests are against Rust's own implementation. They are only tests against the -//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. -//! Please consider this carefully when adding, removing, or reorganizing these tests. They are -//! here so that it is clear what tests are required by the standard and what can be changed. - -use ::core::str::FromStr; - -// IEEE 754 for many tests is applied to specific bit patterns. -// These generally are not applicable to NaN, however. -macro_rules! assert_biteq { - ($lhs:expr, $rhs:expr) => { - assert_eq!($lhs.to_bits(), $rhs.to_bits()) - }; -} - -// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts -// of the formatting infrastructure, which makes it ideal for testing here. -macro_rules! roundtrip { - ($f:expr => $t:ty) => { - ($f).to_string().parse::<$t>().unwrap() - }; -} - -macro_rules! assert_floats_roundtrip { - ($f:ident) => { - assert_biteq!(f32::$f, roundtrip!(f32::$f => f32)); - assert_biteq!(f64::$f, roundtrip!(f64::$f => f64)); - }; - ($f:expr) => { - assert_biteq!($f as f32, roundtrip!($f => f32)); - assert_biteq!($f as f64, roundtrip!($f => f64)); - } -} - -macro_rules! assert_floats_bitne { - ($lhs:ident, $rhs:ident) => { - assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits()); - assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits()); - }; - ($lhs:expr, $rhs:expr) => { - assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs)); - assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs)); - }; -} - -// We must preserve signs on all numbers. That includes zero. -// -0 and 0 are == normally, so test bit equality. -#[test] -fn preserve_signed_zero() { - assert_floats_roundtrip!(-0.0); - assert_floats_roundtrip!(0.0); - assert_floats_bitne!(0.0, -0.0); -} - -#[test] -fn preserve_signed_infinity() { - assert_floats_roundtrip!(INFINITY); - assert_floats_roundtrip!(NEG_INFINITY); - assert_floats_bitne!(INFINITY, NEG_INFINITY); -} - -#[test] -fn infinity_to_str() { - assert!(match f32::INFINITY.to_string().to_lowercase().as_str() { - "+infinity" | "infinity" => true, - "+inf" | "inf" => true, - _ => false, - }); - assert!( - match f64::INFINITY.to_string().to_lowercase().as_str() { - "+infinity" | "infinity" => true, - "+inf" | "inf" => true, - _ => false, - }, - "Infinity must write to a string as some casing of inf or infinity, with an optional +." - ); -} - -#[test] -fn neg_infinity_to_str() { - assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() { - "-infinity" | "-inf" => true, - _ => false, - }); - assert!( - match f64::NEG_INFINITY.to_string().to_lowercase().as_str() { - "-infinity" | "-inf" => true, - _ => false, - }, - "Negative Infinity must write to a string as some casing of -inf or -infinity" - ) -} - -#[test] -fn nan_to_str() { - assert!( - match f32::NAN.to_string().to_lowercase().as_str() { - "nan" | "+nan" | "-nan" => true, - _ => false, - }, - "NaNs must write to a string as some casing of nan." - ) -} - -// "+"?("inf"|"infinity") in any case => Infinity -#[test] -fn infinity_from_str() { - assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap()); - // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd - assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap()); -} - -// "-inf"|"-infinity" in any case => Negative Infinity -#[test] -fn neg_infinity_from_str() { - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap()); -} - -// ("+"|"-"")?"s"?"nan" in any case => qNaN -#[test] -fn qnan_from_str() { - assert!("nan".parse::().unwrap().is_nan()); - assert!("-nan".parse::().unwrap().is_nan()); - assert!("+nan".parse::().unwrap().is_nan()); - assert!("+NAN".parse::().unwrap().is_nan()); - assert!("-NaN".parse::().unwrap().is_nan()); -} diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index 37336f49ef1b..2b641f595eba 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -2,7 +2,8 @@ macro_rules! int_module { ($T:ident, $U:ident) => { use core::num::ParseIntError; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; - use core::$T::*; + const MAX: $T = $T::MAX; + const MIN: $T = $T::MIN; const UMAX: $U = $U::MAX; diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index 73b0e2333fee..e0214c6ae686 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -25,9 +25,10 @@ mod carryless_mul; mod const_from; mod dec2flt; +mod float_ieee754_flt2dec_dec2flt; mod float_iter_sum_identity; +mod floats; mod flt2dec; -mod ieee754; mod int_log; mod int_sqrt; mod midpoint; @@ -36,6 +37,8 @@ mod ops; mod wrapping; +use floats::{assert_biteq, float_test}; + /// Adds the attribute to all items in the block. macro_rules! cfg_block { ($(#[$attr:meta]{$($it:item)*})*) => {$($( diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 240c66fd5c71..8dfa0924bd36 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -2,15 +2,14 @@ macro_rules! uint_module { ($T:ident) => { use core::num::ParseIntError; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; - use core::$T::*; use crate::num; #[test] fn test_overflows() { - assert!(MAX > 0); - assert!(MIN <= 0); - assert!((MIN + MAX).wrapping_add(1) == 0); + assert!($T::MAX > 0); + assert!($T::MIN <= 0); + assert!(($T::MIN + $T::MAX).wrapping_add(1) == 0); } #[test] @@ -25,7 +24,7 @@ fn test_bitwise_operators() { assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T)); assert!(0b1110 as $T == (0b0111 as $T).shl(1)); assert!(0b0111 as $T == (0b1110 as $T).shr(1)); - assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not()); + assert!($T::MAX - (0b1011 as $T) == (0b1011 as $T).not()); } const A: $T = 0b0101100; @@ -361,7 +360,7 @@ fn test_pow() { assert_eq_const_safe!($T: R.wrapping_pow(2), 1 as $T); assert_eq_const_safe!(Option<$T>: R.checked_pow(2), None); assert_eq_const_safe!(($T, bool): R.overflowing_pow(2), (1 as $T, true)); - assert_eq_const_safe!($T: R.saturating_pow(2), MAX); + assert_eq_const_safe!($T: R.saturating_pow(2), $T::MAX); } } @@ -468,14 +467,14 @@ fn test_div_ceil() { fn test_next_multiple_of() { assert_eq_const_safe!($T: (16 as $T).next_multiple_of(8), 16); assert_eq_const_safe!($T: (23 as $T).next_multiple_of(8), 24); - assert_eq_const_safe!($T: MAX.next_multiple_of(1), MAX); + assert_eq_const_safe!($T: $T::MAX.next_multiple_of(1), $T::MAX); } fn test_checked_next_multiple_of() { assert_eq_const_safe!(Option<$T>: (16 as $T).checked_next_multiple_of(8), Some(16)); assert_eq_const_safe!(Option<$T>: (23 as $T).checked_next_multiple_of(8), Some(24)); assert_eq_const_safe!(Option<$T>: (1 as $T).checked_next_multiple_of(0), None); - assert_eq_const_safe!(Option<$T>: MAX.checked_next_multiple_of(2), None); + assert_eq_const_safe!(Option<$T>: $T::MAX.checked_next_multiple_of(2), None); } fn test_is_next_multiple_of() { diff --git a/library/coretests/tests/option.rs b/library/coretests/tests/option.rs index fc0f82ad6bb3..3df7afb4f3be 100644 --- a/library/coretests/tests/option.rs +++ b/library/coretests/tests/option.rs @@ -495,6 +495,30 @@ const fn option_const_mut() { */ } +/// Test that `Option::get_or_insert_default` is usable in const contexts, including with types that +/// do not satisfy `T: const Destruct`. +#[test] +fn const_get_or_insert_default() { + const OPT_DEFAULT: Option> = { + let mut x = None; + x.get_or_insert_default(); + x + }; + assert!(OPT_DEFAULT.is_some()); +} + +/// Test that `Option::get_or_insert_with` is usable in const contexts, including with types that +/// do not satisfy `T: const Destruct`. +#[test] +fn const_get_or_insert_with() { + const OPT_WITH: Option> = { + let mut x = None; + x.get_or_insert_with(Vec::new); + x + }; + assert!(OPT_WITH.is_some()); +} + #[test] fn test_unwrap_drop() { struct Dtor<'a> { diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs index b3fb06e710d4..37a729ae4f1c 100644 --- a/library/coretests/tests/pin.rs +++ b/library/coretests/tests/pin.rs @@ -45,22 +45,6 @@ mod pin_coerce_unsized { pub trait MyTrait {} impl MyTrait for String {} - // These Pins should continue to compile. - // Do note that these instances of Pin types cannot be used - // meaningfully because all methods require a Deref/DerefMut - // bounds on the pointer type and Cell, RefCell and UnsafeCell - // do not implement Deref/DerefMut. - - pub fn cell(arg: Pin>>) -> Pin>> { - arg - } - pub fn ref_cell(arg: Pin>>) -> Pin>> { - arg - } - pub fn unsafe_cell(arg: Pin>>) -> Pin>> { - arg - } - // These sensible Pin coercions are possible. pub fn pin_mut_ref(arg: Pin<&mut String>) -> Pin<&mut dyn MyTrait> { arg @@ -68,15 +52,6 @@ pub fn pin_mut_ref(arg: Pin<&mut String>) -> Pin<&mut dyn MyTrait> { pub fn pin_ref(arg: Pin<&String>) -> Pin<&dyn MyTrait> { arg } - pub fn pin_ptr(arg: Pin<*const String>) -> Pin<*const dyn MyTrait> { - arg - } - pub fn pin_ptr_mut(arg: Pin<*mut String>) -> Pin<*mut dyn MyTrait> { - arg - } - pub fn pin_non_null(arg: Pin>) -> Pin> { - arg - } pub fn nesting_pins(arg: Pin>) -> Pin> { arg } diff --git a/library/coretests/tests/unicode.rs b/library/coretests/tests/unicode.rs index bbace0ef66ca..a8a221db8f95 100644 --- a/library/coretests/tests/unicode.rs +++ b/library/coretests/tests/unicode.rs @@ -1,5 +1,126 @@ +use core::unicode::unicode_data; +use std::ops::RangeInclusive; + +mod test_data; + #[test] pub fn version() { let (major, _minor, _update) = core::char::UNICODE_VERSION; assert!(major >= 10); } + +#[track_caller] +fn test_boolean_property(ranges: &[RangeInclusive], lookup: fn(char) -> bool) { + let mut start = '\u{80}'; + for range in ranges { + for c in start..*range.start() { + assert!(!lookup(c), "{c:?}"); + } + for c in range.clone() { + assert!(lookup(c), "{c:?}"); + } + start = char::from_u32(*range.end() as u32 + 1).unwrap(); + } + for c in start..=char::MAX { + assert!(!lookup(c), "{c:?}"); + } +} + +#[track_caller] +fn test_case_mapping( + ranges: &[(char, [char; 3])], + lookup: fn(char) -> [char; 3], + fallback: fn(char) -> [char; 3], +) { + let mut start = '\u{80}'; + for &(key, val) in ranges { + for c in start..key { + assert_eq!(lookup(c), fallback(c), "{c:?}"); + } + assert_eq!(lookup(key), val, "{key:?}"); + start = char::from_u32(key as u32 + 1).unwrap(); + } + for c in start..=char::MAX { + assert_eq!(lookup(c), fallback(c), "{c:?}"); + } +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn alphabetic() { + test_boolean_property(test_data::ALPHABETIC, unicode_data::alphabetic::lookup); + test_boolean_property(test_data::ALPHABETIC, char::is_alphabetic); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn case_ignorable() { + test_boolean_property(test_data::CASE_IGNORABLE, unicode_data::case_ignorable::lookup); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn cased() { + test_boolean_property(test_data::CASED, unicode_data::cased::lookup); + test_boolean_property(test_data::CASED, char::is_cased); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn grapheme_extend() { + test_boolean_property(test_data::GRAPHEME_EXTEND, unicode_data::grapheme_extend::lookup); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn lowercase() { + test_boolean_property(test_data::LOWERCASE, unicode_data::lowercase::lookup); + test_boolean_property(test_data::LOWERCASE, char::is_lowercase); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn n() { + test_boolean_property(test_data::N, unicode_data::n::lookup); + test_boolean_property(test_data::N, char::is_numeric); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn uppercase() { + test_boolean_property(test_data::UPPERCASE, unicode_data::uppercase::lookup); + test_boolean_property(test_data::UPPERCASE, char::is_uppercase); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn white_space() { + test_boolean_property(test_data::WHITE_SPACE, unicode_data::white_space::lookup); + test_boolean_property(test_data::WHITE_SPACE, char::is_whitespace); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn to_lowercase() { + test_case_mapping(test_data::TO_LOWER, unicode_data::conversions::to_lower, |c| { + [c, '\0', '\0'] + }); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn to_uppercase() { + test_case_mapping(test_data::TO_UPPER, unicode_data::conversions::to_upper, |c| { + [c, '\0', '\0'] + }); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn to_titlecase() { + test_case_mapping( + test_data::TO_TITLE, + unicode_data::conversions::to_title, + unicode_data::conversions::to_upper, + ); +} diff --git a/library/coretests/tests/unicode/test_data.rs b/library/coretests/tests/unicode/test_data.rs new file mode 100644 index 000000000000..3071aedcae07 --- /dev/null +++ b/library/coretests/tests/unicode/test_data.rs @@ -0,0 +1,2980 @@ +//! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually! +// ignore-tidy-filelength + +use std::ops::RangeInclusive; + +#[rustfmt::skip] +pub(super) static ALPHABETIC: &[RangeInclusive; 759] = &[ + '\u{aa}'..='\u{aa}', '\u{b5}'..='\u{b5}', '\u{ba}'..='\u{ba}', '\u{c0}'..='\u{d6}', + '\u{d8}'..='\u{f6}', '\u{f8}'..='\u{2c1}', '\u{2c6}'..='\u{2d1}', '\u{2e0}'..='\u{2e4}', + '\u{2ec}'..='\u{2ec}', '\u{2ee}'..='\u{2ee}', '\u{345}'..='\u{345}', '\u{363}'..='\u{374}', + '\u{376}'..='\u{377}', '\u{37a}'..='\u{37d}', '\u{37f}'..='\u{37f}', '\u{386}'..='\u{386}', + '\u{388}'..='\u{38a}', '\u{38c}'..='\u{38c}', '\u{38e}'..='\u{3a1}', '\u{3a3}'..='\u{3f5}', + '\u{3f7}'..='\u{481}', '\u{48a}'..='\u{52f}', '\u{531}'..='\u{556}', '\u{559}'..='\u{559}', + '\u{560}'..='\u{588}', '\u{5b0}'..='\u{5bd}', '\u{5bf}'..='\u{5bf}', '\u{5c1}'..='\u{5c2}', + '\u{5c4}'..='\u{5c5}', '\u{5c7}'..='\u{5c7}', '\u{5d0}'..='\u{5ea}', '\u{5ef}'..='\u{5f2}', + '\u{610}'..='\u{61a}', '\u{620}'..='\u{657}', '\u{659}'..='\u{65f}', '\u{66e}'..='\u{6d3}', + '\u{6d5}'..='\u{6dc}', '\u{6e1}'..='\u{6e8}', '\u{6ed}'..='\u{6ef}', '\u{6fa}'..='\u{6fc}', + '\u{6ff}'..='\u{6ff}', '\u{710}'..='\u{73f}', '\u{74d}'..='\u{7b1}', '\u{7ca}'..='\u{7ea}', + '\u{7f4}'..='\u{7f5}', '\u{7fa}'..='\u{7fa}', '\u{800}'..='\u{817}', '\u{81a}'..='\u{82c}', + '\u{840}'..='\u{858}', '\u{860}'..='\u{86a}', '\u{870}'..='\u{887}', '\u{889}'..='\u{88f}', + '\u{897}'..='\u{897}', '\u{8a0}'..='\u{8c9}', '\u{8d4}'..='\u{8df}', '\u{8e3}'..='\u{8e9}', + '\u{8f0}'..='\u{93b}', '\u{93d}'..='\u{94c}', '\u{94e}'..='\u{950}', '\u{955}'..='\u{963}', + '\u{971}'..='\u{983}', '\u{985}'..='\u{98c}', '\u{98f}'..='\u{990}', '\u{993}'..='\u{9a8}', + '\u{9aa}'..='\u{9b0}', '\u{9b2}'..='\u{9b2}', '\u{9b6}'..='\u{9b9}', '\u{9bd}'..='\u{9c4}', + '\u{9c7}'..='\u{9c8}', '\u{9cb}'..='\u{9cc}', '\u{9ce}'..='\u{9ce}', '\u{9d7}'..='\u{9d7}', + '\u{9dc}'..='\u{9dd}', '\u{9df}'..='\u{9e3}', '\u{9f0}'..='\u{9f1}', '\u{9fc}'..='\u{9fc}', + '\u{a01}'..='\u{a03}', '\u{a05}'..='\u{a0a}', '\u{a0f}'..='\u{a10}', '\u{a13}'..='\u{a28}', + '\u{a2a}'..='\u{a30}', '\u{a32}'..='\u{a33}', '\u{a35}'..='\u{a36}', '\u{a38}'..='\u{a39}', + '\u{a3e}'..='\u{a42}', '\u{a47}'..='\u{a48}', '\u{a4b}'..='\u{a4c}', '\u{a51}'..='\u{a51}', + '\u{a59}'..='\u{a5c}', '\u{a5e}'..='\u{a5e}', '\u{a70}'..='\u{a75}', '\u{a81}'..='\u{a83}', + '\u{a85}'..='\u{a8d}', '\u{a8f}'..='\u{a91}', '\u{a93}'..='\u{aa8}', '\u{aaa}'..='\u{ab0}', + '\u{ab2}'..='\u{ab3}', '\u{ab5}'..='\u{ab9}', '\u{abd}'..='\u{ac5}', '\u{ac7}'..='\u{ac9}', + '\u{acb}'..='\u{acc}', '\u{ad0}'..='\u{ad0}', '\u{ae0}'..='\u{ae3}', '\u{af9}'..='\u{afc}', + '\u{b01}'..='\u{b03}', '\u{b05}'..='\u{b0c}', '\u{b0f}'..='\u{b10}', '\u{b13}'..='\u{b28}', + '\u{b2a}'..='\u{b30}', '\u{b32}'..='\u{b33}', '\u{b35}'..='\u{b39}', '\u{b3d}'..='\u{b44}', + '\u{b47}'..='\u{b48}', '\u{b4b}'..='\u{b4c}', '\u{b56}'..='\u{b57}', '\u{b5c}'..='\u{b5d}', + '\u{b5f}'..='\u{b63}', '\u{b71}'..='\u{b71}', '\u{b82}'..='\u{b83}', '\u{b85}'..='\u{b8a}', + '\u{b8e}'..='\u{b90}', '\u{b92}'..='\u{b95}', '\u{b99}'..='\u{b9a}', '\u{b9c}'..='\u{b9c}', + '\u{b9e}'..='\u{b9f}', '\u{ba3}'..='\u{ba4}', '\u{ba8}'..='\u{baa}', '\u{bae}'..='\u{bb9}', + '\u{bbe}'..='\u{bc2}', '\u{bc6}'..='\u{bc8}', '\u{bca}'..='\u{bcc}', '\u{bd0}'..='\u{bd0}', + '\u{bd7}'..='\u{bd7}', '\u{c00}'..='\u{c0c}', '\u{c0e}'..='\u{c10}', '\u{c12}'..='\u{c28}', + '\u{c2a}'..='\u{c39}', '\u{c3d}'..='\u{c44}', '\u{c46}'..='\u{c48}', '\u{c4a}'..='\u{c4c}', + '\u{c55}'..='\u{c56}', '\u{c58}'..='\u{c5a}', '\u{c5c}'..='\u{c5d}', '\u{c60}'..='\u{c63}', + '\u{c80}'..='\u{c83}', '\u{c85}'..='\u{c8c}', '\u{c8e}'..='\u{c90}', '\u{c92}'..='\u{ca8}', + '\u{caa}'..='\u{cb3}', '\u{cb5}'..='\u{cb9}', '\u{cbd}'..='\u{cc4}', '\u{cc6}'..='\u{cc8}', + '\u{cca}'..='\u{ccc}', '\u{cd5}'..='\u{cd6}', '\u{cdc}'..='\u{cde}', '\u{ce0}'..='\u{ce3}', + '\u{cf1}'..='\u{cf3}', '\u{d00}'..='\u{d0c}', '\u{d0e}'..='\u{d10}', '\u{d12}'..='\u{d3a}', + '\u{d3d}'..='\u{d44}', '\u{d46}'..='\u{d48}', '\u{d4a}'..='\u{d4c}', '\u{d4e}'..='\u{d4e}', + '\u{d54}'..='\u{d57}', '\u{d5f}'..='\u{d63}', '\u{d7a}'..='\u{d7f}', '\u{d81}'..='\u{d83}', + '\u{d85}'..='\u{d96}', '\u{d9a}'..='\u{db1}', '\u{db3}'..='\u{dbb}', '\u{dbd}'..='\u{dbd}', + '\u{dc0}'..='\u{dc6}', '\u{dcf}'..='\u{dd4}', '\u{dd6}'..='\u{dd6}', '\u{dd8}'..='\u{ddf}', + '\u{df2}'..='\u{df3}', '\u{e01}'..='\u{e3a}', '\u{e40}'..='\u{e46}', '\u{e4d}'..='\u{e4d}', + '\u{e81}'..='\u{e82}', '\u{e84}'..='\u{e84}', '\u{e86}'..='\u{e8a}', '\u{e8c}'..='\u{ea3}', + '\u{ea5}'..='\u{ea5}', '\u{ea7}'..='\u{eb9}', '\u{ebb}'..='\u{ebd}', '\u{ec0}'..='\u{ec4}', + '\u{ec6}'..='\u{ec6}', '\u{ecd}'..='\u{ecd}', '\u{edc}'..='\u{edf}', '\u{f00}'..='\u{f00}', + '\u{f40}'..='\u{f47}', '\u{f49}'..='\u{f6c}', '\u{f71}'..='\u{f83}', '\u{f88}'..='\u{f97}', + '\u{f99}'..='\u{fbc}', '\u{1000}'..='\u{1036}', '\u{1038}'..='\u{1038}', + '\u{103b}'..='\u{103f}', '\u{1050}'..='\u{108f}', '\u{109a}'..='\u{109d}', + '\u{10a0}'..='\u{10c5}', '\u{10c7}'..='\u{10c7}', '\u{10cd}'..='\u{10cd}', + '\u{10d0}'..='\u{10fa}', '\u{10fc}'..='\u{1248}', '\u{124a}'..='\u{124d}', + '\u{1250}'..='\u{1256}', '\u{1258}'..='\u{1258}', '\u{125a}'..='\u{125d}', + '\u{1260}'..='\u{1288}', '\u{128a}'..='\u{128d}', '\u{1290}'..='\u{12b0}', + '\u{12b2}'..='\u{12b5}', '\u{12b8}'..='\u{12be}', '\u{12c0}'..='\u{12c0}', + '\u{12c2}'..='\u{12c5}', '\u{12c8}'..='\u{12d6}', '\u{12d8}'..='\u{1310}', + '\u{1312}'..='\u{1315}', '\u{1318}'..='\u{135a}', '\u{1380}'..='\u{138f}', + '\u{13a0}'..='\u{13f5}', '\u{13f8}'..='\u{13fd}', '\u{1401}'..='\u{166c}', + '\u{166f}'..='\u{167f}', '\u{1681}'..='\u{169a}', '\u{16a0}'..='\u{16ea}', + '\u{16ee}'..='\u{16f8}', '\u{1700}'..='\u{1713}', '\u{171f}'..='\u{1733}', + '\u{1740}'..='\u{1753}', '\u{1760}'..='\u{176c}', '\u{176e}'..='\u{1770}', + '\u{1772}'..='\u{1773}', '\u{1780}'..='\u{17b3}', '\u{17b6}'..='\u{17c8}', + '\u{17d7}'..='\u{17d7}', '\u{17dc}'..='\u{17dc}', '\u{1820}'..='\u{1878}', + '\u{1880}'..='\u{18aa}', '\u{18b0}'..='\u{18f5}', '\u{1900}'..='\u{191e}', + '\u{1920}'..='\u{192b}', '\u{1930}'..='\u{1938}', '\u{1950}'..='\u{196d}', + '\u{1970}'..='\u{1974}', '\u{1980}'..='\u{19ab}', '\u{19b0}'..='\u{19c9}', + '\u{1a00}'..='\u{1a1b}', '\u{1a20}'..='\u{1a5e}', '\u{1a61}'..='\u{1a74}', + '\u{1aa7}'..='\u{1aa7}', '\u{1abf}'..='\u{1ac0}', '\u{1acc}'..='\u{1ace}', + '\u{1b00}'..='\u{1b33}', '\u{1b35}'..='\u{1b43}', '\u{1b45}'..='\u{1b4c}', + '\u{1b80}'..='\u{1ba9}', '\u{1bac}'..='\u{1baf}', '\u{1bba}'..='\u{1be5}', + '\u{1be7}'..='\u{1bf1}', '\u{1c00}'..='\u{1c36}', '\u{1c4d}'..='\u{1c4f}', + '\u{1c5a}'..='\u{1c7d}', '\u{1c80}'..='\u{1c8a}', '\u{1c90}'..='\u{1cba}', + '\u{1cbd}'..='\u{1cbf}', '\u{1ce9}'..='\u{1cec}', '\u{1cee}'..='\u{1cf3}', + '\u{1cf5}'..='\u{1cf6}', '\u{1cfa}'..='\u{1cfa}', '\u{1d00}'..='\u{1dbf}', + '\u{1dd3}'..='\u{1df4}', '\u{1e00}'..='\u{1f15}', '\u{1f18}'..='\u{1f1d}', + '\u{1f20}'..='\u{1f45}', '\u{1f48}'..='\u{1f4d}', '\u{1f50}'..='\u{1f57}', + '\u{1f59}'..='\u{1f59}', '\u{1f5b}'..='\u{1f5b}', '\u{1f5d}'..='\u{1f5d}', + '\u{1f5f}'..='\u{1f7d}', '\u{1f80}'..='\u{1fb4}', '\u{1fb6}'..='\u{1fbc}', + '\u{1fbe}'..='\u{1fbe}', '\u{1fc2}'..='\u{1fc4}', '\u{1fc6}'..='\u{1fcc}', + '\u{1fd0}'..='\u{1fd3}', '\u{1fd6}'..='\u{1fdb}', '\u{1fe0}'..='\u{1fec}', + '\u{1ff2}'..='\u{1ff4}', '\u{1ff6}'..='\u{1ffc}', '\u{2071}'..='\u{2071}', + '\u{207f}'..='\u{207f}', '\u{2090}'..='\u{209c}', '\u{2102}'..='\u{2102}', + '\u{2107}'..='\u{2107}', '\u{210a}'..='\u{2113}', '\u{2115}'..='\u{2115}', + '\u{2119}'..='\u{211d}', '\u{2124}'..='\u{2124}', '\u{2126}'..='\u{2126}', + '\u{2128}'..='\u{2128}', '\u{212a}'..='\u{212d}', '\u{212f}'..='\u{2139}', + '\u{213c}'..='\u{213f}', '\u{2145}'..='\u{2149}', '\u{214e}'..='\u{214e}', + '\u{2160}'..='\u{2188}', '\u{24b6}'..='\u{24e9}', '\u{2c00}'..='\u{2ce4}', + '\u{2ceb}'..='\u{2cee}', '\u{2cf2}'..='\u{2cf3}', '\u{2d00}'..='\u{2d25}', + '\u{2d27}'..='\u{2d27}', '\u{2d2d}'..='\u{2d2d}', '\u{2d30}'..='\u{2d67}', + '\u{2d6f}'..='\u{2d6f}', '\u{2d80}'..='\u{2d96}', '\u{2da0}'..='\u{2da6}', + '\u{2da8}'..='\u{2dae}', '\u{2db0}'..='\u{2db6}', '\u{2db8}'..='\u{2dbe}', + '\u{2dc0}'..='\u{2dc6}', '\u{2dc8}'..='\u{2dce}', '\u{2dd0}'..='\u{2dd6}', + '\u{2dd8}'..='\u{2dde}', '\u{2de0}'..='\u{2dff}', '\u{2e2f}'..='\u{2e2f}', + '\u{3005}'..='\u{3007}', '\u{3021}'..='\u{3029}', '\u{3031}'..='\u{3035}', + '\u{3038}'..='\u{303c}', '\u{3041}'..='\u{3096}', '\u{309d}'..='\u{309f}', + '\u{30a1}'..='\u{30fa}', '\u{30fc}'..='\u{30ff}', '\u{3105}'..='\u{312f}', + '\u{3131}'..='\u{318e}', '\u{31a0}'..='\u{31bf}', '\u{31f0}'..='\u{31ff}', + '\u{3400}'..='\u{4dbf}', '\u{4e00}'..='\u{a48c}', '\u{a4d0}'..='\u{a4fd}', + '\u{a500}'..='\u{a60c}', '\u{a610}'..='\u{a61f}', '\u{a62a}'..='\u{a62b}', + '\u{a640}'..='\u{a66e}', '\u{a674}'..='\u{a67b}', '\u{a67f}'..='\u{a6ef}', + '\u{a717}'..='\u{a71f}', '\u{a722}'..='\u{a788}', '\u{a78b}'..='\u{a7dc}', + '\u{a7f1}'..='\u{a805}', '\u{a807}'..='\u{a827}', '\u{a840}'..='\u{a873}', + '\u{a880}'..='\u{a8c3}', '\u{a8c5}'..='\u{a8c5}', '\u{a8f2}'..='\u{a8f7}', + '\u{a8fb}'..='\u{a8fb}', '\u{a8fd}'..='\u{a8ff}', '\u{a90a}'..='\u{a92a}', + '\u{a930}'..='\u{a952}', '\u{a960}'..='\u{a97c}', '\u{a980}'..='\u{a9b2}', + '\u{a9b4}'..='\u{a9bf}', '\u{a9cf}'..='\u{a9cf}', '\u{a9e0}'..='\u{a9ef}', + '\u{a9fa}'..='\u{a9fe}', '\u{aa00}'..='\u{aa36}', '\u{aa40}'..='\u{aa4d}', + '\u{aa60}'..='\u{aa76}', '\u{aa7a}'..='\u{aabe}', '\u{aac0}'..='\u{aac0}', + '\u{aac2}'..='\u{aac2}', '\u{aadb}'..='\u{aadd}', '\u{aae0}'..='\u{aaef}', + '\u{aaf2}'..='\u{aaf5}', '\u{ab01}'..='\u{ab06}', '\u{ab09}'..='\u{ab0e}', + '\u{ab11}'..='\u{ab16}', '\u{ab20}'..='\u{ab26}', '\u{ab28}'..='\u{ab2e}', + '\u{ab30}'..='\u{ab5a}', '\u{ab5c}'..='\u{ab69}', '\u{ab70}'..='\u{abea}', + '\u{ac00}'..='\u{d7a3}', '\u{d7b0}'..='\u{d7c6}', '\u{d7cb}'..='\u{d7fb}', + '\u{f900}'..='\u{fa6d}', '\u{fa70}'..='\u{fad9}', '\u{fb00}'..='\u{fb06}', + '\u{fb13}'..='\u{fb17}', '\u{fb1d}'..='\u{fb28}', '\u{fb2a}'..='\u{fb36}', + '\u{fb38}'..='\u{fb3c}', '\u{fb3e}'..='\u{fb3e}', '\u{fb40}'..='\u{fb41}', + '\u{fb43}'..='\u{fb44}', '\u{fb46}'..='\u{fbb1}', '\u{fbd3}'..='\u{fd3d}', + '\u{fd50}'..='\u{fd8f}', '\u{fd92}'..='\u{fdc7}', '\u{fdf0}'..='\u{fdfb}', + '\u{fe70}'..='\u{fe74}', '\u{fe76}'..='\u{fefc}', '\u{ff21}'..='\u{ff3a}', + '\u{ff41}'..='\u{ff5a}', '\u{ff66}'..='\u{ffbe}', '\u{ffc2}'..='\u{ffc7}', + '\u{ffca}'..='\u{ffcf}', '\u{ffd2}'..='\u{ffd7}', '\u{ffda}'..='\u{ffdc}', + '\u{10000}'..='\u{1000b}', '\u{1000d}'..='\u{10026}', '\u{10028}'..='\u{1003a}', + '\u{1003c}'..='\u{1003d}', '\u{1003f}'..='\u{1004d}', '\u{10050}'..='\u{1005d}', + '\u{10080}'..='\u{100fa}', '\u{10140}'..='\u{10174}', '\u{10280}'..='\u{1029c}', + '\u{102a0}'..='\u{102d0}', '\u{10300}'..='\u{1031f}', '\u{1032d}'..='\u{1034a}', + '\u{10350}'..='\u{1037a}', '\u{10380}'..='\u{1039d}', '\u{103a0}'..='\u{103c3}', + '\u{103c8}'..='\u{103cf}', '\u{103d1}'..='\u{103d5}', '\u{10400}'..='\u{1049d}', + '\u{104b0}'..='\u{104d3}', '\u{104d8}'..='\u{104fb}', '\u{10500}'..='\u{10527}', + '\u{10530}'..='\u{10563}', '\u{10570}'..='\u{1057a}', '\u{1057c}'..='\u{1058a}', + '\u{1058c}'..='\u{10592}', '\u{10594}'..='\u{10595}', '\u{10597}'..='\u{105a1}', + '\u{105a3}'..='\u{105b1}', '\u{105b3}'..='\u{105b9}', '\u{105bb}'..='\u{105bc}', + '\u{105c0}'..='\u{105f3}', '\u{10600}'..='\u{10736}', '\u{10740}'..='\u{10755}', + '\u{10760}'..='\u{10767}', '\u{10780}'..='\u{10785}', '\u{10787}'..='\u{107b0}', + '\u{107b2}'..='\u{107ba}', '\u{10800}'..='\u{10805}', '\u{10808}'..='\u{10808}', + '\u{1080a}'..='\u{10835}', '\u{10837}'..='\u{10838}', '\u{1083c}'..='\u{1083c}', + '\u{1083f}'..='\u{10855}', '\u{10860}'..='\u{10876}', '\u{10880}'..='\u{1089e}', + '\u{108e0}'..='\u{108f2}', '\u{108f4}'..='\u{108f5}', '\u{10900}'..='\u{10915}', + '\u{10920}'..='\u{10939}', '\u{10940}'..='\u{10959}', '\u{10980}'..='\u{109b7}', + '\u{109be}'..='\u{109bf}', '\u{10a00}'..='\u{10a03}', '\u{10a05}'..='\u{10a06}', + '\u{10a0c}'..='\u{10a13}', '\u{10a15}'..='\u{10a17}', '\u{10a19}'..='\u{10a35}', + '\u{10a60}'..='\u{10a7c}', '\u{10a80}'..='\u{10a9c}', '\u{10ac0}'..='\u{10ac7}', + '\u{10ac9}'..='\u{10ae4}', '\u{10b00}'..='\u{10b35}', '\u{10b40}'..='\u{10b55}', + '\u{10b60}'..='\u{10b72}', '\u{10b80}'..='\u{10b91}', '\u{10c00}'..='\u{10c48}', + '\u{10c80}'..='\u{10cb2}', '\u{10cc0}'..='\u{10cf2}', '\u{10d00}'..='\u{10d27}', + '\u{10d4a}'..='\u{10d65}', '\u{10d69}'..='\u{10d69}', '\u{10d6f}'..='\u{10d85}', + '\u{10e80}'..='\u{10ea9}', '\u{10eab}'..='\u{10eac}', '\u{10eb0}'..='\u{10eb1}', + '\u{10ec2}'..='\u{10ec7}', '\u{10efa}'..='\u{10efc}', '\u{10f00}'..='\u{10f1c}', + '\u{10f27}'..='\u{10f27}', '\u{10f30}'..='\u{10f45}', '\u{10f70}'..='\u{10f81}', + '\u{10fb0}'..='\u{10fc4}', '\u{10fe0}'..='\u{10ff6}', '\u{11000}'..='\u{11045}', + '\u{11071}'..='\u{11075}', '\u{11080}'..='\u{110b8}', '\u{110c2}'..='\u{110c2}', + '\u{110d0}'..='\u{110e8}', '\u{11100}'..='\u{11132}', '\u{11144}'..='\u{11147}', + '\u{11150}'..='\u{11172}', '\u{11176}'..='\u{11176}', '\u{11180}'..='\u{111bf}', + '\u{111c1}'..='\u{111c4}', '\u{111ce}'..='\u{111cf}', '\u{111da}'..='\u{111da}', + '\u{111dc}'..='\u{111dc}', '\u{11200}'..='\u{11211}', '\u{11213}'..='\u{11234}', + '\u{11237}'..='\u{11237}', '\u{1123e}'..='\u{11241}', '\u{11280}'..='\u{11286}', + '\u{11288}'..='\u{11288}', '\u{1128a}'..='\u{1128d}', '\u{1128f}'..='\u{1129d}', + '\u{1129f}'..='\u{112a8}', '\u{112b0}'..='\u{112e8}', '\u{11300}'..='\u{11303}', + '\u{11305}'..='\u{1130c}', '\u{1130f}'..='\u{11310}', '\u{11313}'..='\u{11328}', + '\u{1132a}'..='\u{11330}', '\u{11332}'..='\u{11333}', '\u{11335}'..='\u{11339}', + '\u{1133d}'..='\u{11344}', '\u{11347}'..='\u{11348}', '\u{1134b}'..='\u{1134c}', + '\u{11350}'..='\u{11350}', '\u{11357}'..='\u{11357}', '\u{1135d}'..='\u{11363}', + '\u{11380}'..='\u{11389}', '\u{1138b}'..='\u{1138b}', '\u{1138e}'..='\u{1138e}', + '\u{11390}'..='\u{113b5}', '\u{113b7}'..='\u{113c0}', '\u{113c2}'..='\u{113c2}', + '\u{113c5}'..='\u{113c5}', '\u{113c7}'..='\u{113ca}', '\u{113cc}'..='\u{113cd}', + '\u{113d1}'..='\u{113d1}', '\u{113d3}'..='\u{113d3}', '\u{11400}'..='\u{11441}', + '\u{11443}'..='\u{11445}', '\u{11447}'..='\u{1144a}', '\u{1145f}'..='\u{11461}', + '\u{11480}'..='\u{114c1}', '\u{114c4}'..='\u{114c5}', '\u{114c7}'..='\u{114c7}', + '\u{11580}'..='\u{115b5}', '\u{115b8}'..='\u{115be}', '\u{115d8}'..='\u{115dd}', + '\u{11600}'..='\u{1163e}', '\u{11640}'..='\u{11640}', '\u{11644}'..='\u{11644}', + '\u{11680}'..='\u{116b5}', '\u{116b8}'..='\u{116b8}', '\u{11700}'..='\u{1171a}', + '\u{1171d}'..='\u{1172a}', '\u{11740}'..='\u{11746}', '\u{11800}'..='\u{11838}', + '\u{118a0}'..='\u{118df}', '\u{118ff}'..='\u{11906}', '\u{11909}'..='\u{11909}', + '\u{1190c}'..='\u{11913}', '\u{11915}'..='\u{11916}', '\u{11918}'..='\u{11935}', + '\u{11937}'..='\u{11938}', '\u{1193b}'..='\u{1193c}', '\u{1193f}'..='\u{11942}', + '\u{119a0}'..='\u{119a7}', '\u{119aa}'..='\u{119d7}', '\u{119da}'..='\u{119df}', + '\u{119e1}'..='\u{119e1}', '\u{119e3}'..='\u{119e4}', '\u{11a00}'..='\u{11a32}', + '\u{11a35}'..='\u{11a3e}', '\u{11a50}'..='\u{11a97}', '\u{11a9d}'..='\u{11a9d}', + '\u{11ab0}'..='\u{11af8}', '\u{11b60}'..='\u{11b67}', '\u{11bc0}'..='\u{11be0}', + '\u{11c00}'..='\u{11c08}', '\u{11c0a}'..='\u{11c36}', '\u{11c38}'..='\u{11c3e}', + '\u{11c40}'..='\u{11c40}', '\u{11c72}'..='\u{11c8f}', '\u{11c92}'..='\u{11ca7}', + '\u{11ca9}'..='\u{11cb6}', '\u{11d00}'..='\u{11d06}', '\u{11d08}'..='\u{11d09}', + '\u{11d0b}'..='\u{11d36}', '\u{11d3a}'..='\u{11d3a}', '\u{11d3c}'..='\u{11d3d}', + '\u{11d3f}'..='\u{11d41}', '\u{11d43}'..='\u{11d43}', '\u{11d46}'..='\u{11d47}', + '\u{11d60}'..='\u{11d65}', '\u{11d67}'..='\u{11d68}', '\u{11d6a}'..='\u{11d8e}', + '\u{11d90}'..='\u{11d91}', '\u{11d93}'..='\u{11d96}', '\u{11d98}'..='\u{11d98}', + '\u{11db0}'..='\u{11ddb}', '\u{11ee0}'..='\u{11ef6}', '\u{11f00}'..='\u{11f10}', + '\u{11f12}'..='\u{11f3a}', '\u{11f3e}'..='\u{11f40}', '\u{11fb0}'..='\u{11fb0}', + '\u{12000}'..='\u{12399}', '\u{12400}'..='\u{1246e}', '\u{12480}'..='\u{12543}', + '\u{12f90}'..='\u{12ff0}', '\u{13000}'..='\u{1342f}', '\u{13441}'..='\u{13446}', + '\u{13460}'..='\u{143fa}', '\u{14400}'..='\u{14646}', '\u{16100}'..='\u{1612e}', + '\u{16800}'..='\u{16a38}', '\u{16a40}'..='\u{16a5e}', '\u{16a70}'..='\u{16abe}', + '\u{16ad0}'..='\u{16aed}', '\u{16b00}'..='\u{16b2f}', '\u{16b40}'..='\u{16b43}', + '\u{16b63}'..='\u{16b77}', '\u{16b7d}'..='\u{16b8f}', '\u{16d40}'..='\u{16d6c}', + '\u{16e40}'..='\u{16e7f}', '\u{16ea0}'..='\u{16eb8}', '\u{16ebb}'..='\u{16ed3}', + '\u{16f00}'..='\u{16f4a}', '\u{16f4f}'..='\u{16f87}', '\u{16f8f}'..='\u{16f9f}', + '\u{16fe0}'..='\u{16fe1}', '\u{16fe3}'..='\u{16fe3}', '\u{16ff0}'..='\u{16ff6}', + '\u{17000}'..='\u{18cd5}', '\u{18cff}'..='\u{18d1e}', '\u{18d80}'..='\u{18df2}', + '\u{1aff0}'..='\u{1aff3}', '\u{1aff5}'..='\u{1affb}', '\u{1affd}'..='\u{1affe}', + '\u{1b000}'..='\u{1b122}', '\u{1b132}'..='\u{1b132}', '\u{1b150}'..='\u{1b152}', + '\u{1b155}'..='\u{1b155}', '\u{1b164}'..='\u{1b167}', '\u{1b170}'..='\u{1b2fb}', + '\u{1bc00}'..='\u{1bc6a}', '\u{1bc70}'..='\u{1bc7c}', '\u{1bc80}'..='\u{1bc88}', + '\u{1bc90}'..='\u{1bc99}', '\u{1bc9e}'..='\u{1bc9e}', '\u{1d400}'..='\u{1d454}', + '\u{1d456}'..='\u{1d49c}', '\u{1d49e}'..='\u{1d49f}', '\u{1d4a2}'..='\u{1d4a2}', + '\u{1d4a5}'..='\u{1d4a6}', '\u{1d4a9}'..='\u{1d4ac}', '\u{1d4ae}'..='\u{1d4b9}', + '\u{1d4bb}'..='\u{1d4bb}', '\u{1d4bd}'..='\u{1d4c3}', '\u{1d4c5}'..='\u{1d505}', + '\u{1d507}'..='\u{1d50a}', '\u{1d50d}'..='\u{1d514}', '\u{1d516}'..='\u{1d51c}', + '\u{1d51e}'..='\u{1d539}', '\u{1d53b}'..='\u{1d53e}', '\u{1d540}'..='\u{1d544}', + '\u{1d546}'..='\u{1d546}', '\u{1d54a}'..='\u{1d550}', '\u{1d552}'..='\u{1d6a5}', + '\u{1d6a8}'..='\u{1d6c0}', '\u{1d6c2}'..='\u{1d6da}', '\u{1d6dc}'..='\u{1d6fa}', + '\u{1d6fc}'..='\u{1d714}', '\u{1d716}'..='\u{1d734}', '\u{1d736}'..='\u{1d74e}', + '\u{1d750}'..='\u{1d76e}', '\u{1d770}'..='\u{1d788}', '\u{1d78a}'..='\u{1d7a8}', + '\u{1d7aa}'..='\u{1d7c2}', '\u{1d7c4}'..='\u{1d7cb}', '\u{1df00}'..='\u{1df1e}', + '\u{1df25}'..='\u{1df2a}', '\u{1e000}'..='\u{1e006}', '\u{1e008}'..='\u{1e018}', + '\u{1e01b}'..='\u{1e021}', '\u{1e023}'..='\u{1e024}', '\u{1e026}'..='\u{1e02a}', + '\u{1e030}'..='\u{1e06d}', '\u{1e08f}'..='\u{1e08f}', '\u{1e100}'..='\u{1e12c}', + '\u{1e137}'..='\u{1e13d}', '\u{1e14e}'..='\u{1e14e}', '\u{1e290}'..='\u{1e2ad}', + '\u{1e2c0}'..='\u{1e2eb}', '\u{1e4d0}'..='\u{1e4eb}', '\u{1e5d0}'..='\u{1e5ed}', + '\u{1e5f0}'..='\u{1e5f0}', '\u{1e6c0}'..='\u{1e6de}', '\u{1e6e0}'..='\u{1e6f5}', + '\u{1e6fe}'..='\u{1e6ff}', '\u{1e7e0}'..='\u{1e7e6}', '\u{1e7e8}'..='\u{1e7eb}', + '\u{1e7ed}'..='\u{1e7ee}', '\u{1e7f0}'..='\u{1e7fe}', '\u{1e800}'..='\u{1e8c4}', + '\u{1e900}'..='\u{1e943}', '\u{1e947}'..='\u{1e947}', '\u{1e94b}'..='\u{1e94b}', + '\u{1ee00}'..='\u{1ee03}', '\u{1ee05}'..='\u{1ee1f}', '\u{1ee21}'..='\u{1ee22}', + '\u{1ee24}'..='\u{1ee24}', '\u{1ee27}'..='\u{1ee27}', '\u{1ee29}'..='\u{1ee32}', + '\u{1ee34}'..='\u{1ee37}', '\u{1ee39}'..='\u{1ee39}', '\u{1ee3b}'..='\u{1ee3b}', + '\u{1ee42}'..='\u{1ee42}', '\u{1ee47}'..='\u{1ee47}', '\u{1ee49}'..='\u{1ee49}', + '\u{1ee4b}'..='\u{1ee4b}', '\u{1ee4d}'..='\u{1ee4f}', '\u{1ee51}'..='\u{1ee52}', + '\u{1ee54}'..='\u{1ee54}', '\u{1ee57}'..='\u{1ee57}', '\u{1ee59}'..='\u{1ee59}', + '\u{1ee5b}'..='\u{1ee5b}', '\u{1ee5d}'..='\u{1ee5d}', '\u{1ee5f}'..='\u{1ee5f}', + '\u{1ee61}'..='\u{1ee62}', '\u{1ee64}'..='\u{1ee64}', '\u{1ee67}'..='\u{1ee6a}', + '\u{1ee6c}'..='\u{1ee72}', '\u{1ee74}'..='\u{1ee77}', '\u{1ee79}'..='\u{1ee7c}', + '\u{1ee7e}'..='\u{1ee7e}', '\u{1ee80}'..='\u{1ee89}', '\u{1ee8b}'..='\u{1ee9b}', + '\u{1eea1}'..='\u{1eea3}', '\u{1eea5}'..='\u{1eea9}', '\u{1eeab}'..='\u{1eebb}', + '\u{1f130}'..='\u{1f149}', '\u{1f150}'..='\u{1f169}', '\u{1f170}'..='\u{1f189}', + '\u{20000}'..='\u{2a6df}', '\u{2a700}'..='\u{2b81d}', '\u{2b820}'..='\u{2cead}', + '\u{2ceb0}'..='\u{2ebe0}', '\u{2ebf0}'..='\u{2ee5d}', '\u{2f800}'..='\u{2fa1d}', + '\u{30000}'..='\u{3134a}', '\u{31350}'..='\u{33479}', +]; + +#[rustfmt::skip] +pub(super) static CASE_IGNORABLE: &[RangeInclusive; 459] = &[ + '\u{a8}'..='\u{a8}', '\u{ad}'..='\u{ad}', '\u{af}'..='\u{af}', '\u{b4}'..='\u{b4}', + '\u{b7}'..='\u{b8}', '\u{2b0}'..='\u{36f}', '\u{374}'..='\u{375}', '\u{37a}'..='\u{37a}', + '\u{384}'..='\u{385}', '\u{387}'..='\u{387}', '\u{483}'..='\u{489}', '\u{559}'..='\u{559}', + '\u{55f}'..='\u{55f}', '\u{591}'..='\u{5bd}', '\u{5bf}'..='\u{5bf}', '\u{5c1}'..='\u{5c2}', + '\u{5c4}'..='\u{5c5}', '\u{5c7}'..='\u{5c7}', '\u{5f4}'..='\u{5f4}', '\u{600}'..='\u{605}', + '\u{610}'..='\u{61a}', '\u{61c}'..='\u{61c}', '\u{640}'..='\u{640}', '\u{64b}'..='\u{65f}', + '\u{670}'..='\u{670}', '\u{6d6}'..='\u{6dd}', '\u{6df}'..='\u{6e8}', '\u{6ea}'..='\u{6ed}', + '\u{70f}'..='\u{70f}', '\u{711}'..='\u{711}', '\u{730}'..='\u{74a}', '\u{7a6}'..='\u{7b0}', + '\u{7eb}'..='\u{7f5}', '\u{7fa}'..='\u{7fa}', '\u{7fd}'..='\u{7fd}', '\u{816}'..='\u{82d}', + '\u{859}'..='\u{85b}', '\u{888}'..='\u{888}', '\u{890}'..='\u{891}', '\u{897}'..='\u{89f}', + '\u{8c9}'..='\u{902}', '\u{93a}'..='\u{93a}', '\u{93c}'..='\u{93c}', '\u{941}'..='\u{948}', + '\u{94d}'..='\u{94d}', '\u{951}'..='\u{957}', '\u{962}'..='\u{963}', '\u{971}'..='\u{971}', + '\u{981}'..='\u{981}', '\u{9bc}'..='\u{9bc}', '\u{9c1}'..='\u{9c4}', '\u{9cd}'..='\u{9cd}', + '\u{9e2}'..='\u{9e3}', '\u{9fe}'..='\u{9fe}', '\u{a01}'..='\u{a02}', '\u{a3c}'..='\u{a3c}', + '\u{a41}'..='\u{a42}', '\u{a47}'..='\u{a48}', '\u{a4b}'..='\u{a4d}', '\u{a51}'..='\u{a51}', + '\u{a70}'..='\u{a71}', '\u{a75}'..='\u{a75}', '\u{a81}'..='\u{a82}', '\u{abc}'..='\u{abc}', + '\u{ac1}'..='\u{ac5}', '\u{ac7}'..='\u{ac8}', '\u{acd}'..='\u{acd}', '\u{ae2}'..='\u{ae3}', + '\u{afa}'..='\u{aff}', '\u{b01}'..='\u{b01}', '\u{b3c}'..='\u{b3c}', '\u{b3f}'..='\u{b3f}', + '\u{b41}'..='\u{b44}', '\u{b4d}'..='\u{b4d}', '\u{b55}'..='\u{b56}', '\u{b62}'..='\u{b63}', + '\u{b82}'..='\u{b82}', '\u{bc0}'..='\u{bc0}', '\u{bcd}'..='\u{bcd}', '\u{c00}'..='\u{c00}', + '\u{c04}'..='\u{c04}', '\u{c3c}'..='\u{c3c}', '\u{c3e}'..='\u{c40}', '\u{c46}'..='\u{c48}', + '\u{c4a}'..='\u{c4d}', '\u{c55}'..='\u{c56}', '\u{c62}'..='\u{c63}', '\u{c81}'..='\u{c81}', + '\u{cbc}'..='\u{cbc}', '\u{cbf}'..='\u{cbf}', '\u{cc6}'..='\u{cc6}', '\u{ccc}'..='\u{ccd}', + '\u{ce2}'..='\u{ce3}', '\u{d00}'..='\u{d01}', '\u{d3b}'..='\u{d3c}', '\u{d41}'..='\u{d44}', + '\u{d4d}'..='\u{d4d}', '\u{d62}'..='\u{d63}', '\u{d81}'..='\u{d81}', '\u{dca}'..='\u{dca}', + '\u{dd2}'..='\u{dd4}', '\u{dd6}'..='\u{dd6}', '\u{e31}'..='\u{e31}', '\u{e34}'..='\u{e3a}', + '\u{e46}'..='\u{e4e}', '\u{eb1}'..='\u{eb1}', '\u{eb4}'..='\u{ebc}', '\u{ec6}'..='\u{ec6}', + '\u{ec8}'..='\u{ece}', '\u{f18}'..='\u{f19}', '\u{f35}'..='\u{f35}', '\u{f37}'..='\u{f37}', + '\u{f39}'..='\u{f39}', '\u{f71}'..='\u{f7e}', '\u{f80}'..='\u{f84}', '\u{f86}'..='\u{f87}', + '\u{f8d}'..='\u{f97}', '\u{f99}'..='\u{fbc}', '\u{fc6}'..='\u{fc6}', + '\u{102d}'..='\u{1030}', '\u{1032}'..='\u{1037}', '\u{1039}'..='\u{103a}', + '\u{103d}'..='\u{103e}', '\u{1058}'..='\u{1059}', '\u{105e}'..='\u{1060}', + '\u{1071}'..='\u{1074}', '\u{1082}'..='\u{1082}', '\u{1085}'..='\u{1086}', + '\u{108d}'..='\u{108d}', '\u{109d}'..='\u{109d}', '\u{10fc}'..='\u{10fc}', + '\u{135d}'..='\u{135f}', '\u{1712}'..='\u{1714}', '\u{1732}'..='\u{1733}', + '\u{1752}'..='\u{1753}', '\u{1772}'..='\u{1773}', '\u{17b4}'..='\u{17b5}', + '\u{17b7}'..='\u{17bd}', '\u{17c6}'..='\u{17c6}', '\u{17c9}'..='\u{17d3}', + '\u{17d7}'..='\u{17d7}', '\u{17dd}'..='\u{17dd}', '\u{180b}'..='\u{180f}', + '\u{1843}'..='\u{1843}', '\u{1885}'..='\u{1886}', '\u{18a9}'..='\u{18a9}', + '\u{1920}'..='\u{1922}', '\u{1927}'..='\u{1928}', '\u{1932}'..='\u{1932}', + '\u{1939}'..='\u{193b}', '\u{1a17}'..='\u{1a18}', '\u{1a1b}'..='\u{1a1b}', + '\u{1a56}'..='\u{1a56}', '\u{1a58}'..='\u{1a5e}', '\u{1a60}'..='\u{1a60}', + '\u{1a62}'..='\u{1a62}', '\u{1a65}'..='\u{1a6c}', '\u{1a73}'..='\u{1a7c}', + '\u{1a7f}'..='\u{1a7f}', '\u{1aa7}'..='\u{1aa7}', '\u{1ab0}'..='\u{1add}', + '\u{1ae0}'..='\u{1aeb}', '\u{1b00}'..='\u{1b03}', '\u{1b34}'..='\u{1b34}', + '\u{1b36}'..='\u{1b3a}', '\u{1b3c}'..='\u{1b3c}', '\u{1b42}'..='\u{1b42}', + '\u{1b6b}'..='\u{1b73}', '\u{1b80}'..='\u{1b81}', '\u{1ba2}'..='\u{1ba5}', + '\u{1ba8}'..='\u{1ba9}', '\u{1bab}'..='\u{1bad}', '\u{1be6}'..='\u{1be6}', + '\u{1be8}'..='\u{1be9}', '\u{1bed}'..='\u{1bed}', '\u{1bef}'..='\u{1bf1}', + '\u{1c2c}'..='\u{1c33}', '\u{1c36}'..='\u{1c37}', '\u{1c78}'..='\u{1c7d}', + '\u{1cd0}'..='\u{1cd2}', '\u{1cd4}'..='\u{1ce0}', '\u{1ce2}'..='\u{1ce8}', + '\u{1ced}'..='\u{1ced}', '\u{1cf4}'..='\u{1cf4}', '\u{1cf8}'..='\u{1cf9}', + '\u{1d2c}'..='\u{1d6a}', '\u{1d78}'..='\u{1d78}', '\u{1d9b}'..='\u{1dff}', + '\u{1fbd}'..='\u{1fbd}', '\u{1fbf}'..='\u{1fc1}', '\u{1fcd}'..='\u{1fcf}', + '\u{1fdd}'..='\u{1fdf}', '\u{1fed}'..='\u{1fef}', '\u{1ffd}'..='\u{1ffe}', + '\u{200b}'..='\u{200f}', '\u{2018}'..='\u{2019}', '\u{2024}'..='\u{2024}', + '\u{2027}'..='\u{2027}', '\u{202a}'..='\u{202e}', '\u{2060}'..='\u{2064}', + '\u{2066}'..='\u{206f}', '\u{2071}'..='\u{2071}', '\u{207f}'..='\u{207f}', + '\u{2090}'..='\u{209c}', '\u{20d0}'..='\u{20f0}', '\u{2c7c}'..='\u{2c7d}', + '\u{2cef}'..='\u{2cf1}', '\u{2d6f}'..='\u{2d6f}', '\u{2d7f}'..='\u{2d7f}', + '\u{2de0}'..='\u{2dff}', '\u{2e2f}'..='\u{2e2f}', '\u{3005}'..='\u{3005}', + '\u{302a}'..='\u{302d}', '\u{3031}'..='\u{3035}', '\u{303b}'..='\u{303b}', + '\u{3099}'..='\u{309e}', '\u{30fc}'..='\u{30fe}', '\u{a015}'..='\u{a015}', + '\u{a4f8}'..='\u{a4fd}', '\u{a60c}'..='\u{a60c}', '\u{a66f}'..='\u{a672}', + '\u{a674}'..='\u{a67d}', '\u{a67f}'..='\u{a67f}', '\u{a69c}'..='\u{a69f}', + '\u{a6f0}'..='\u{a6f1}', '\u{a700}'..='\u{a721}', '\u{a770}'..='\u{a770}', + '\u{a788}'..='\u{a78a}', '\u{a7f1}'..='\u{a7f4}', '\u{a7f8}'..='\u{a7f9}', + '\u{a802}'..='\u{a802}', '\u{a806}'..='\u{a806}', '\u{a80b}'..='\u{a80b}', + '\u{a825}'..='\u{a826}', '\u{a82c}'..='\u{a82c}', '\u{a8c4}'..='\u{a8c5}', + '\u{a8e0}'..='\u{a8f1}', '\u{a8ff}'..='\u{a8ff}', '\u{a926}'..='\u{a92d}', + '\u{a947}'..='\u{a951}', '\u{a980}'..='\u{a982}', '\u{a9b3}'..='\u{a9b3}', + '\u{a9b6}'..='\u{a9b9}', '\u{a9bc}'..='\u{a9bd}', '\u{a9cf}'..='\u{a9cf}', + '\u{a9e5}'..='\u{a9e6}', '\u{aa29}'..='\u{aa2e}', '\u{aa31}'..='\u{aa32}', + '\u{aa35}'..='\u{aa36}', '\u{aa43}'..='\u{aa43}', '\u{aa4c}'..='\u{aa4c}', + '\u{aa70}'..='\u{aa70}', '\u{aa7c}'..='\u{aa7c}', '\u{aab0}'..='\u{aab0}', + '\u{aab2}'..='\u{aab4}', '\u{aab7}'..='\u{aab8}', '\u{aabe}'..='\u{aabf}', + '\u{aac1}'..='\u{aac1}', '\u{aadd}'..='\u{aadd}', '\u{aaec}'..='\u{aaed}', + '\u{aaf3}'..='\u{aaf4}', '\u{aaf6}'..='\u{aaf6}', '\u{ab5b}'..='\u{ab5f}', + '\u{ab69}'..='\u{ab6b}', '\u{abe5}'..='\u{abe5}', '\u{abe8}'..='\u{abe8}', + '\u{abed}'..='\u{abed}', '\u{fb1e}'..='\u{fb1e}', '\u{fbb2}'..='\u{fbc2}', + '\u{fe00}'..='\u{fe0f}', '\u{fe13}'..='\u{fe13}', '\u{fe20}'..='\u{fe2f}', + '\u{fe52}'..='\u{fe52}', '\u{fe55}'..='\u{fe55}', '\u{feff}'..='\u{feff}', + '\u{ff07}'..='\u{ff07}', '\u{ff0e}'..='\u{ff0e}', '\u{ff1a}'..='\u{ff1a}', + '\u{ff3e}'..='\u{ff3e}', '\u{ff40}'..='\u{ff40}', '\u{ff70}'..='\u{ff70}', + '\u{ff9e}'..='\u{ff9f}', '\u{ffe3}'..='\u{ffe3}', '\u{fff9}'..='\u{fffb}', + '\u{101fd}'..='\u{101fd}', '\u{102e0}'..='\u{102e0}', '\u{10376}'..='\u{1037a}', + '\u{10780}'..='\u{10785}', '\u{10787}'..='\u{107b0}', '\u{107b2}'..='\u{107ba}', + '\u{10a01}'..='\u{10a03}', '\u{10a05}'..='\u{10a06}', '\u{10a0c}'..='\u{10a0f}', + '\u{10a38}'..='\u{10a3a}', '\u{10a3f}'..='\u{10a3f}', '\u{10ae5}'..='\u{10ae6}', + '\u{10d24}'..='\u{10d27}', '\u{10d4e}'..='\u{10d4e}', '\u{10d69}'..='\u{10d6d}', + '\u{10d6f}'..='\u{10d6f}', '\u{10eab}'..='\u{10eac}', '\u{10ec5}'..='\u{10ec5}', + '\u{10efa}'..='\u{10eff}', '\u{10f46}'..='\u{10f50}', '\u{10f82}'..='\u{10f85}', + '\u{11001}'..='\u{11001}', '\u{11038}'..='\u{11046}', '\u{11070}'..='\u{11070}', + '\u{11073}'..='\u{11074}', '\u{1107f}'..='\u{11081}', '\u{110b3}'..='\u{110b6}', + '\u{110b9}'..='\u{110ba}', '\u{110bd}'..='\u{110bd}', '\u{110c2}'..='\u{110c2}', + '\u{110cd}'..='\u{110cd}', '\u{11100}'..='\u{11102}', '\u{11127}'..='\u{1112b}', + '\u{1112d}'..='\u{11134}', '\u{11173}'..='\u{11173}', '\u{11180}'..='\u{11181}', + '\u{111b6}'..='\u{111be}', '\u{111c9}'..='\u{111cc}', '\u{111cf}'..='\u{111cf}', + '\u{1122f}'..='\u{11231}', '\u{11234}'..='\u{11234}', '\u{11236}'..='\u{11237}', + '\u{1123e}'..='\u{1123e}', '\u{11241}'..='\u{11241}', '\u{112df}'..='\u{112df}', + '\u{112e3}'..='\u{112ea}', '\u{11300}'..='\u{11301}', '\u{1133b}'..='\u{1133c}', + '\u{11340}'..='\u{11340}', '\u{11366}'..='\u{1136c}', '\u{11370}'..='\u{11374}', + '\u{113bb}'..='\u{113c0}', '\u{113ce}'..='\u{113ce}', '\u{113d0}'..='\u{113d0}', + '\u{113d2}'..='\u{113d2}', '\u{113e1}'..='\u{113e2}', '\u{11438}'..='\u{1143f}', + '\u{11442}'..='\u{11444}', '\u{11446}'..='\u{11446}', '\u{1145e}'..='\u{1145e}', + '\u{114b3}'..='\u{114b8}', '\u{114ba}'..='\u{114ba}', '\u{114bf}'..='\u{114c0}', + '\u{114c2}'..='\u{114c3}', '\u{115b2}'..='\u{115b5}', '\u{115bc}'..='\u{115bd}', + '\u{115bf}'..='\u{115c0}', '\u{115dc}'..='\u{115dd}', '\u{11633}'..='\u{1163a}', + '\u{1163d}'..='\u{1163d}', '\u{1163f}'..='\u{11640}', '\u{116ab}'..='\u{116ab}', + '\u{116ad}'..='\u{116ad}', '\u{116b0}'..='\u{116b5}', '\u{116b7}'..='\u{116b7}', + '\u{1171d}'..='\u{1171d}', '\u{1171f}'..='\u{1171f}', '\u{11722}'..='\u{11725}', + '\u{11727}'..='\u{1172b}', '\u{1182f}'..='\u{11837}', '\u{11839}'..='\u{1183a}', + '\u{1193b}'..='\u{1193c}', '\u{1193e}'..='\u{1193e}', '\u{11943}'..='\u{11943}', + '\u{119d4}'..='\u{119d7}', '\u{119da}'..='\u{119db}', '\u{119e0}'..='\u{119e0}', + '\u{11a01}'..='\u{11a0a}', '\u{11a33}'..='\u{11a38}', '\u{11a3b}'..='\u{11a3e}', + '\u{11a47}'..='\u{11a47}', '\u{11a51}'..='\u{11a56}', '\u{11a59}'..='\u{11a5b}', + '\u{11a8a}'..='\u{11a96}', '\u{11a98}'..='\u{11a99}', '\u{11b60}'..='\u{11b60}', + '\u{11b62}'..='\u{11b64}', '\u{11b66}'..='\u{11b66}', '\u{11c30}'..='\u{11c36}', + '\u{11c38}'..='\u{11c3d}', '\u{11c3f}'..='\u{11c3f}', '\u{11c92}'..='\u{11ca7}', + '\u{11caa}'..='\u{11cb0}', '\u{11cb2}'..='\u{11cb3}', '\u{11cb5}'..='\u{11cb6}', + '\u{11d31}'..='\u{11d36}', '\u{11d3a}'..='\u{11d3a}', '\u{11d3c}'..='\u{11d3d}', + '\u{11d3f}'..='\u{11d45}', '\u{11d47}'..='\u{11d47}', '\u{11d90}'..='\u{11d91}', + '\u{11d95}'..='\u{11d95}', '\u{11d97}'..='\u{11d97}', '\u{11dd9}'..='\u{11dd9}', + '\u{11ef3}'..='\u{11ef4}', '\u{11f00}'..='\u{11f01}', '\u{11f36}'..='\u{11f3a}', + '\u{11f40}'..='\u{11f40}', '\u{11f42}'..='\u{11f42}', '\u{11f5a}'..='\u{11f5a}', + '\u{13430}'..='\u{13440}', '\u{13447}'..='\u{13455}', '\u{1611e}'..='\u{16129}', + '\u{1612d}'..='\u{1612f}', '\u{16af0}'..='\u{16af4}', '\u{16b30}'..='\u{16b36}', + '\u{16b40}'..='\u{16b43}', '\u{16d40}'..='\u{16d42}', '\u{16d6b}'..='\u{16d6c}', + '\u{16f4f}'..='\u{16f4f}', '\u{16f8f}'..='\u{16f9f}', '\u{16fe0}'..='\u{16fe1}', + '\u{16fe3}'..='\u{16fe4}', '\u{16ff2}'..='\u{16ff3}', '\u{1aff0}'..='\u{1aff3}', + '\u{1aff5}'..='\u{1affb}', '\u{1affd}'..='\u{1affe}', '\u{1bc9d}'..='\u{1bc9e}', + '\u{1bca0}'..='\u{1bca3}', '\u{1cf00}'..='\u{1cf2d}', '\u{1cf30}'..='\u{1cf46}', + '\u{1d167}'..='\u{1d169}', '\u{1d173}'..='\u{1d182}', '\u{1d185}'..='\u{1d18b}', + '\u{1d1aa}'..='\u{1d1ad}', '\u{1d242}'..='\u{1d244}', '\u{1da00}'..='\u{1da36}', + '\u{1da3b}'..='\u{1da6c}', '\u{1da75}'..='\u{1da75}', '\u{1da84}'..='\u{1da84}', + '\u{1da9b}'..='\u{1da9f}', '\u{1daa1}'..='\u{1daaf}', '\u{1e000}'..='\u{1e006}', + '\u{1e008}'..='\u{1e018}', '\u{1e01b}'..='\u{1e021}', '\u{1e023}'..='\u{1e024}', + '\u{1e026}'..='\u{1e02a}', '\u{1e030}'..='\u{1e06d}', '\u{1e08f}'..='\u{1e08f}', + '\u{1e130}'..='\u{1e13d}', '\u{1e2ae}'..='\u{1e2ae}', '\u{1e2ec}'..='\u{1e2ef}', + '\u{1e4eb}'..='\u{1e4ef}', '\u{1e5ee}'..='\u{1e5ef}', '\u{1e6e3}'..='\u{1e6e3}', + '\u{1e6e6}'..='\u{1e6e6}', '\u{1e6ee}'..='\u{1e6ef}', '\u{1e6f5}'..='\u{1e6f5}', + '\u{1e6ff}'..='\u{1e6ff}', '\u{1e8d0}'..='\u{1e8d6}', '\u{1e944}'..='\u{1e94b}', + '\u{1f3fb}'..='\u{1f3ff}', '\u{e0001}'..='\u{e0001}', '\u{e0020}'..='\u{e007f}', + '\u{e0100}'..='\u{e01ef}', +]; + +#[rustfmt::skip] +pub(super) static CASED: &[RangeInclusive; 156] = &[ + '\u{aa}'..='\u{aa}', '\u{b5}'..='\u{b5}', '\u{ba}'..='\u{ba}', '\u{c0}'..='\u{d6}', + '\u{d8}'..='\u{f6}', '\u{f8}'..='\u{1ba}', '\u{1bc}'..='\u{1bf}', '\u{1c4}'..='\u{293}', + '\u{296}'..='\u{2b8}', '\u{2c0}'..='\u{2c1}', '\u{2e0}'..='\u{2e4}', '\u{345}'..='\u{345}', + '\u{370}'..='\u{373}', '\u{376}'..='\u{377}', '\u{37a}'..='\u{37d}', '\u{37f}'..='\u{37f}', + '\u{386}'..='\u{386}', '\u{388}'..='\u{38a}', '\u{38c}'..='\u{38c}', '\u{38e}'..='\u{3a1}', + '\u{3a3}'..='\u{3f5}', '\u{3f7}'..='\u{481}', '\u{48a}'..='\u{52f}', '\u{531}'..='\u{556}', + '\u{560}'..='\u{588}', '\u{10a0}'..='\u{10c5}', '\u{10c7}'..='\u{10c7}', + '\u{10cd}'..='\u{10cd}', '\u{10d0}'..='\u{10fa}', '\u{10fc}'..='\u{10ff}', + '\u{13a0}'..='\u{13f5}', '\u{13f8}'..='\u{13fd}', '\u{1c80}'..='\u{1c8a}', + '\u{1c90}'..='\u{1cba}', '\u{1cbd}'..='\u{1cbf}', '\u{1d00}'..='\u{1dbf}', + '\u{1e00}'..='\u{1f15}', '\u{1f18}'..='\u{1f1d}', '\u{1f20}'..='\u{1f45}', + '\u{1f48}'..='\u{1f4d}', '\u{1f50}'..='\u{1f57}', '\u{1f59}'..='\u{1f59}', + '\u{1f5b}'..='\u{1f5b}', '\u{1f5d}'..='\u{1f5d}', '\u{1f5f}'..='\u{1f7d}', + '\u{1f80}'..='\u{1fb4}', '\u{1fb6}'..='\u{1fbc}', '\u{1fbe}'..='\u{1fbe}', + '\u{1fc2}'..='\u{1fc4}', '\u{1fc6}'..='\u{1fcc}', '\u{1fd0}'..='\u{1fd3}', + '\u{1fd6}'..='\u{1fdb}', '\u{1fe0}'..='\u{1fec}', '\u{1ff2}'..='\u{1ff4}', + '\u{1ff6}'..='\u{1ffc}', '\u{2071}'..='\u{2071}', '\u{207f}'..='\u{207f}', + '\u{2090}'..='\u{209c}', '\u{2102}'..='\u{2102}', '\u{2107}'..='\u{2107}', + '\u{210a}'..='\u{2113}', '\u{2115}'..='\u{2115}', '\u{2119}'..='\u{211d}', + '\u{2124}'..='\u{2124}', '\u{2126}'..='\u{2126}', '\u{2128}'..='\u{2128}', + '\u{212a}'..='\u{212d}', '\u{212f}'..='\u{2134}', '\u{2139}'..='\u{2139}', + '\u{213c}'..='\u{213f}', '\u{2145}'..='\u{2149}', '\u{214e}'..='\u{214e}', + '\u{2160}'..='\u{217f}', '\u{2183}'..='\u{2184}', '\u{24b6}'..='\u{24e9}', + '\u{2c00}'..='\u{2ce4}', '\u{2ceb}'..='\u{2cee}', '\u{2cf2}'..='\u{2cf3}', + '\u{2d00}'..='\u{2d25}', '\u{2d27}'..='\u{2d27}', '\u{2d2d}'..='\u{2d2d}', + '\u{a640}'..='\u{a66d}', '\u{a680}'..='\u{a69d}', '\u{a722}'..='\u{a787}', + '\u{a78b}'..='\u{a78e}', '\u{a790}'..='\u{a7dc}', '\u{a7f1}'..='\u{a7f6}', + '\u{a7f8}'..='\u{a7fa}', '\u{ab30}'..='\u{ab5a}', '\u{ab5c}'..='\u{ab69}', + '\u{ab70}'..='\u{abbf}', '\u{fb00}'..='\u{fb06}', '\u{fb13}'..='\u{fb17}', + '\u{ff21}'..='\u{ff3a}', '\u{ff41}'..='\u{ff5a}', '\u{10400}'..='\u{1044f}', + '\u{104b0}'..='\u{104d3}', '\u{104d8}'..='\u{104fb}', '\u{10570}'..='\u{1057a}', + '\u{1057c}'..='\u{1058a}', '\u{1058c}'..='\u{10592}', '\u{10594}'..='\u{10595}', + '\u{10597}'..='\u{105a1}', '\u{105a3}'..='\u{105b1}', '\u{105b3}'..='\u{105b9}', + '\u{105bb}'..='\u{105bc}', '\u{10780}'..='\u{10780}', '\u{10783}'..='\u{10785}', + '\u{10787}'..='\u{107b0}', '\u{107b2}'..='\u{107ba}', '\u{10c80}'..='\u{10cb2}', + '\u{10cc0}'..='\u{10cf2}', '\u{10d50}'..='\u{10d65}', '\u{10d70}'..='\u{10d85}', + '\u{118a0}'..='\u{118df}', '\u{16e40}'..='\u{16e7f}', '\u{16ea0}'..='\u{16eb8}', + '\u{16ebb}'..='\u{16ed3}', '\u{1d400}'..='\u{1d454}', '\u{1d456}'..='\u{1d49c}', + '\u{1d49e}'..='\u{1d49f}', '\u{1d4a2}'..='\u{1d4a2}', '\u{1d4a5}'..='\u{1d4a6}', + '\u{1d4a9}'..='\u{1d4ac}', '\u{1d4ae}'..='\u{1d4b9}', '\u{1d4bb}'..='\u{1d4bb}', + '\u{1d4bd}'..='\u{1d4c3}', '\u{1d4c5}'..='\u{1d505}', '\u{1d507}'..='\u{1d50a}', + '\u{1d50d}'..='\u{1d514}', '\u{1d516}'..='\u{1d51c}', '\u{1d51e}'..='\u{1d539}', + '\u{1d53b}'..='\u{1d53e}', '\u{1d540}'..='\u{1d544}', '\u{1d546}'..='\u{1d546}', + '\u{1d54a}'..='\u{1d550}', '\u{1d552}'..='\u{1d6a5}', '\u{1d6a8}'..='\u{1d6c0}', + '\u{1d6c2}'..='\u{1d6da}', '\u{1d6dc}'..='\u{1d6fa}', '\u{1d6fc}'..='\u{1d714}', + '\u{1d716}'..='\u{1d734}', '\u{1d736}'..='\u{1d74e}', '\u{1d750}'..='\u{1d76e}', + '\u{1d770}'..='\u{1d788}', '\u{1d78a}'..='\u{1d7a8}', '\u{1d7aa}'..='\u{1d7c2}', + '\u{1d7c4}'..='\u{1d7cb}', '\u{1df00}'..='\u{1df09}', '\u{1df0b}'..='\u{1df1e}', + '\u{1df25}'..='\u{1df2a}', '\u{1e030}'..='\u{1e06d}', '\u{1e900}'..='\u{1e943}', + '\u{1f130}'..='\u{1f149}', '\u{1f150}'..='\u{1f169}', '\u{1f170}'..='\u{1f189}', +]; + +#[rustfmt::skip] +pub(super) static GRAPHEME_EXTEND: &[RangeInclusive; 383] = &[ + '\u{300}'..='\u{36f}', '\u{483}'..='\u{489}', '\u{591}'..='\u{5bd}', '\u{5bf}'..='\u{5bf}', + '\u{5c1}'..='\u{5c2}', '\u{5c4}'..='\u{5c5}', '\u{5c7}'..='\u{5c7}', '\u{610}'..='\u{61a}', + '\u{64b}'..='\u{65f}', '\u{670}'..='\u{670}', '\u{6d6}'..='\u{6dc}', '\u{6df}'..='\u{6e4}', + '\u{6e7}'..='\u{6e8}', '\u{6ea}'..='\u{6ed}', '\u{711}'..='\u{711}', '\u{730}'..='\u{74a}', + '\u{7a6}'..='\u{7b0}', '\u{7eb}'..='\u{7f3}', '\u{7fd}'..='\u{7fd}', '\u{816}'..='\u{819}', + '\u{81b}'..='\u{823}', '\u{825}'..='\u{827}', '\u{829}'..='\u{82d}', '\u{859}'..='\u{85b}', + '\u{897}'..='\u{89f}', '\u{8ca}'..='\u{8e1}', '\u{8e3}'..='\u{902}', '\u{93a}'..='\u{93a}', + '\u{93c}'..='\u{93c}', '\u{941}'..='\u{948}', '\u{94d}'..='\u{94d}', '\u{951}'..='\u{957}', + '\u{962}'..='\u{963}', '\u{981}'..='\u{981}', '\u{9bc}'..='\u{9bc}', '\u{9be}'..='\u{9be}', + '\u{9c1}'..='\u{9c4}', '\u{9cd}'..='\u{9cd}', '\u{9d7}'..='\u{9d7}', '\u{9e2}'..='\u{9e3}', + '\u{9fe}'..='\u{9fe}', '\u{a01}'..='\u{a02}', '\u{a3c}'..='\u{a3c}', '\u{a41}'..='\u{a42}', + '\u{a47}'..='\u{a48}', '\u{a4b}'..='\u{a4d}', '\u{a51}'..='\u{a51}', '\u{a70}'..='\u{a71}', + '\u{a75}'..='\u{a75}', '\u{a81}'..='\u{a82}', '\u{abc}'..='\u{abc}', '\u{ac1}'..='\u{ac5}', + '\u{ac7}'..='\u{ac8}', '\u{acd}'..='\u{acd}', '\u{ae2}'..='\u{ae3}', '\u{afa}'..='\u{aff}', + '\u{b01}'..='\u{b01}', '\u{b3c}'..='\u{b3c}', '\u{b3e}'..='\u{b3f}', '\u{b41}'..='\u{b44}', + '\u{b4d}'..='\u{b4d}', '\u{b55}'..='\u{b57}', '\u{b62}'..='\u{b63}', '\u{b82}'..='\u{b82}', + '\u{bbe}'..='\u{bbe}', '\u{bc0}'..='\u{bc0}', '\u{bcd}'..='\u{bcd}', '\u{bd7}'..='\u{bd7}', + '\u{c00}'..='\u{c00}', '\u{c04}'..='\u{c04}', '\u{c3c}'..='\u{c3c}', '\u{c3e}'..='\u{c40}', + '\u{c46}'..='\u{c48}', '\u{c4a}'..='\u{c4d}', '\u{c55}'..='\u{c56}', '\u{c62}'..='\u{c63}', + '\u{c81}'..='\u{c81}', '\u{cbc}'..='\u{cbc}', '\u{cbf}'..='\u{cc0}', '\u{cc2}'..='\u{cc2}', + '\u{cc6}'..='\u{cc8}', '\u{cca}'..='\u{ccd}', '\u{cd5}'..='\u{cd6}', '\u{ce2}'..='\u{ce3}', + '\u{d00}'..='\u{d01}', '\u{d3b}'..='\u{d3c}', '\u{d3e}'..='\u{d3e}', '\u{d41}'..='\u{d44}', + '\u{d4d}'..='\u{d4d}', '\u{d57}'..='\u{d57}', '\u{d62}'..='\u{d63}', '\u{d81}'..='\u{d81}', + '\u{dca}'..='\u{dca}', '\u{dcf}'..='\u{dcf}', '\u{dd2}'..='\u{dd4}', '\u{dd6}'..='\u{dd6}', + '\u{ddf}'..='\u{ddf}', '\u{e31}'..='\u{e31}', '\u{e34}'..='\u{e3a}', '\u{e47}'..='\u{e4e}', + '\u{eb1}'..='\u{eb1}', '\u{eb4}'..='\u{ebc}', '\u{ec8}'..='\u{ece}', '\u{f18}'..='\u{f19}', + '\u{f35}'..='\u{f35}', '\u{f37}'..='\u{f37}', '\u{f39}'..='\u{f39}', '\u{f71}'..='\u{f7e}', + '\u{f80}'..='\u{f84}', '\u{f86}'..='\u{f87}', '\u{f8d}'..='\u{f97}', '\u{f99}'..='\u{fbc}', + '\u{fc6}'..='\u{fc6}', '\u{102d}'..='\u{1030}', '\u{1032}'..='\u{1037}', + '\u{1039}'..='\u{103a}', '\u{103d}'..='\u{103e}', '\u{1058}'..='\u{1059}', + '\u{105e}'..='\u{1060}', '\u{1071}'..='\u{1074}', '\u{1082}'..='\u{1082}', + '\u{1085}'..='\u{1086}', '\u{108d}'..='\u{108d}', '\u{109d}'..='\u{109d}', + '\u{135d}'..='\u{135f}', '\u{1712}'..='\u{1715}', '\u{1732}'..='\u{1734}', + '\u{1752}'..='\u{1753}', '\u{1772}'..='\u{1773}', '\u{17b4}'..='\u{17b5}', + '\u{17b7}'..='\u{17bd}', '\u{17c6}'..='\u{17c6}', '\u{17c9}'..='\u{17d3}', + '\u{17dd}'..='\u{17dd}', '\u{180b}'..='\u{180d}', '\u{180f}'..='\u{180f}', + '\u{1885}'..='\u{1886}', '\u{18a9}'..='\u{18a9}', '\u{1920}'..='\u{1922}', + '\u{1927}'..='\u{1928}', '\u{1932}'..='\u{1932}', '\u{1939}'..='\u{193b}', + '\u{1a17}'..='\u{1a18}', '\u{1a1b}'..='\u{1a1b}', '\u{1a56}'..='\u{1a56}', + '\u{1a58}'..='\u{1a5e}', '\u{1a60}'..='\u{1a60}', '\u{1a62}'..='\u{1a62}', + '\u{1a65}'..='\u{1a6c}', '\u{1a73}'..='\u{1a7c}', '\u{1a7f}'..='\u{1a7f}', + '\u{1ab0}'..='\u{1add}', '\u{1ae0}'..='\u{1aeb}', '\u{1b00}'..='\u{1b03}', + '\u{1b34}'..='\u{1b3d}', '\u{1b42}'..='\u{1b44}', '\u{1b6b}'..='\u{1b73}', + '\u{1b80}'..='\u{1b81}', '\u{1ba2}'..='\u{1ba5}', '\u{1ba8}'..='\u{1bad}', + '\u{1be6}'..='\u{1be6}', '\u{1be8}'..='\u{1be9}', '\u{1bed}'..='\u{1bed}', + '\u{1bef}'..='\u{1bf3}', '\u{1c2c}'..='\u{1c33}', '\u{1c36}'..='\u{1c37}', + '\u{1cd0}'..='\u{1cd2}', '\u{1cd4}'..='\u{1ce0}', '\u{1ce2}'..='\u{1ce8}', + '\u{1ced}'..='\u{1ced}', '\u{1cf4}'..='\u{1cf4}', '\u{1cf8}'..='\u{1cf9}', + '\u{1dc0}'..='\u{1dff}', '\u{200c}'..='\u{200c}', '\u{20d0}'..='\u{20f0}', + '\u{2cef}'..='\u{2cf1}', '\u{2d7f}'..='\u{2d7f}', '\u{2de0}'..='\u{2dff}', + '\u{302a}'..='\u{302f}', '\u{3099}'..='\u{309a}', '\u{a66f}'..='\u{a672}', + '\u{a674}'..='\u{a67d}', '\u{a69e}'..='\u{a69f}', '\u{a6f0}'..='\u{a6f1}', + '\u{a802}'..='\u{a802}', '\u{a806}'..='\u{a806}', '\u{a80b}'..='\u{a80b}', + '\u{a825}'..='\u{a826}', '\u{a82c}'..='\u{a82c}', '\u{a8c4}'..='\u{a8c5}', + '\u{a8e0}'..='\u{a8f1}', '\u{a8ff}'..='\u{a8ff}', '\u{a926}'..='\u{a92d}', + '\u{a947}'..='\u{a951}', '\u{a953}'..='\u{a953}', '\u{a980}'..='\u{a982}', + '\u{a9b3}'..='\u{a9b3}', '\u{a9b6}'..='\u{a9b9}', '\u{a9bc}'..='\u{a9bd}', + '\u{a9c0}'..='\u{a9c0}', '\u{a9e5}'..='\u{a9e5}', '\u{aa29}'..='\u{aa2e}', + '\u{aa31}'..='\u{aa32}', '\u{aa35}'..='\u{aa36}', '\u{aa43}'..='\u{aa43}', + '\u{aa4c}'..='\u{aa4c}', '\u{aa7c}'..='\u{aa7c}', '\u{aab0}'..='\u{aab0}', + '\u{aab2}'..='\u{aab4}', '\u{aab7}'..='\u{aab8}', '\u{aabe}'..='\u{aabf}', + '\u{aac1}'..='\u{aac1}', '\u{aaec}'..='\u{aaed}', '\u{aaf6}'..='\u{aaf6}', + '\u{abe5}'..='\u{abe5}', '\u{abe8}'..='\u{abe8}', '\u{abed}'..='\u{abed}', + '\u{fb1e}'..='\u{fb1e}', '\u{fe00}'..='\u{fe0f}', '\u{fe20}'..='\u{fe2f}', + '\u{ff9e}'..='\u{ff9f}', '\u{101fd}'..='\u{101fd}', '\u{102e0}'..='\u{102e0}', + '\u{10376}'..='\u{1037a}', '\u{10a01}'..='\u{10a03}', '\u{10a05}'..='\u{10a06}', + '\u{10a0c}'..='\u{10a0f}', '\u{10a38}'..='\u{10a3a}', '\u{10a3f}'..='\u{10a3f}', + '\u{10ae5}'..='\u{10ae6}', '\u{10d24}'..='\u{10d27}', '\u{10d69}'..='\u{10d6d}', + '\u{10eab}'..='\u{10eac}', '\u{10efa}'..='\u{10eff}', '\u{10f46}'..='\u{10f50}', + '\u{10f82}'..='\u{10f85}', '\u{11001}'..='\u{11001}', '\u{11038}'..='\u{11046}', + '\u{11070}'..='\u{11070}', '\u{11073}'..='\u{11074}', '\u{1107f}'..='\u{11081}', + '\u{110b3}'..='\u{110b6}', '\u{110b9}'..='\u{110ba}', '\u{110c2}'..='\u{110c2}', + '\u{11100}'..='\u{11102}', '\u{11127}'..='\u{1112b}', '\u{1112d}'..='\u{11134}', + '\u{11173}'..='\u{11173}', '\u{11180}'..='\u{11181}', '\u{111b6}'..='\u{111be}', + '\u{111c0}'..='\u{111c0}', '\u{111c9}'..='\u{111cc}', '\u{111cf}'..='\u{111cf}', + '\u{1122f}'..='\u{11231}', '\u{11234}'..='\u{11237}', '\u{1123e}'..='\u{1123e}', + '\u{11241}'..='\u{11241}', '\u{112df}'..='\u{112df}', '\u{112e3}'..='\u{112ea}', + '\u{11300}'..='\u{11301}', '\u{1133b}'..='\u{1133c}', '\u{1133e}'..='\u{1133e}', + '\u{11340}'..='\u{11340}', '\u{1134d}'..='\u{1134d}', '\u{11357}'..='\u{11357}', + '\u{11366}'..='\u{1136c}', '\u{11370}'..='\u{11374}', '\u{113b8}'..='\u{113b8}', + '\u{113bb}'..='\u{113c0}', '\u{113c2}'..='\u{113c2}', '\u{113c5}'..='\u{113c5}', + '\u{113c7}'..='\u{113c9}', '\u{113ce}'..='\u{113d0}', '\u{113d2}'..='\u{113d2}', + '\u{113e1}'..='\u{113e2}', '\u{11438}'..='\u{1143f}', '\u{11442}'..='\u{11444}', + '\u{11446}'..='\u{11446}', '\u{1145e}'..='\u{1145e}', '\u{114b0}'..='\u{114b0}', + '\u{114b3}'..='\u{114b8}', '\u{114ba}'..='\u{114ba}', '\u{114bd}'..='\u{114bd}', + '\u{114bf}'..='\u{114c0}', '\u{114c2}'..='\u{114c3}', '\u{115af}'..='\u{115af}', + '\u{115b2}'..='\u{115b5}', '\u{115bc}'..='\u{115bd}', '\u{115bf}'..='\u{115c0}', + '\u{115dc}'..='\u{115dd}', '\u{11633}'..='\u{1163a}', '\u{1163d}'..='\u{1163d}', + '\u{1163f}'..='\u{11640}', '\u{116ab}'..='\u{116ab}', '\u{116ad}'..='\u{116ad}', + '\u{116b0}'..='\u{116b7}', '\u{1171d}'..='\u{1171d}', '\u{1171f}'..='\u{1171f}', + '\u{11722}'..='\u{11725}', '\u{11727}'..='\u{1172b}', '\u{1182f}'..='\u{11837}', + '\u{11839}'..='\u{1183a}', '\u{11930}'..='\u{11930}', '\u{1193b}'..='\u{1193e}', + '\u{11943}'..='\u{11943}', '\u{119d4}'..='\u{119d7}', '\u{119da}'..='\u{119db}', + '\u{119e0}'..='\u{119e0}', '\u{11a01}'..='\u{11a0a}', '\u{11a33}'..='\u{11a38}', + '\u{11a3b}'..='\u{11a3e}', '\u{11a47}'..='\u{11a47}', '\u{11a51}'..='\u{11a56}', + '\u{11a59}'..='\u{11a5b}', '\u{11a8a}'..='\u{11a96}', '\u{11a98}'..='\u{11a99}', + '\u{11b60}'..='\u{11b60}', '\u{11b62}'..='\u{11b64}', '\u{11b66}'..='\u{11b66}', + '\u{11c30}'..='\u{11c36}', '\u{11c38}'..='\u{11c3d}', '\u{11c3f}'..='\u{11c3f}', + '\u{11c92}'..='\u{11ca7}', '\u{11caa}'..='\u{11cb0}', '\u{11cb2}'..='\u{11cb3}', + '\u{11cb5}'..='\u{11cb6}', '\u{11d31}'..='\u{11d36}', '\u{11d3a}'..='\u{11d3a}', + '\u{11d3c}'..='\u{11d3d}', '\u{11d3f}'..='\u{11d45}', '\u{11d47}'..='\u{11d47}', + '\u{11d90}'..='\u{11d91}', '\u{11d95}'..='\u{11d95}', '\u{11d97}'..='\u{11d97}', + '\u{11ef3}'..='\u{11ef4}', '\u{11f00}'..='\u{11f01}', '\u{11f36}'..='\u{11f3a}', + '\u{11f40}'..='\u{11f42}', '\u{11f5a}'..='\u{11f5a}', '\u{13440}'..='\u{13440}', + '\u{13447}'..='\u{13455}', '\u{1611e}'..='\u{16129}', '\u{1612d}'..='\u{1612f}', + '\u{16af0}'..='\u{16af4}', '\u{16b30}'..='\u{16b36}', '\u{16f4f}'..='\u{16f4f}', + '\u{16f8f}'..='\u{16f92}', '\u{16fe4}'..='\u{16fe4}', '\u{16ff0}'..='\u{16ff1}', + '\u{1bc9d}'..='\u{1bc9e}', '\u{1cf00}'..='\u{1cf2d}', '\u{1cf30}'..='\u{1cf46}', + '\u{1d165}'..='\u{1d169}', '\u{1d16d}'..='\u{1d172}', '\u{1d17b}'..='\u{1d182}', + '\u{1d185}'..='\u{1d18b}', '\u{1d1aa}'..='\u{1d1ad}', '\u{1d242}'..='\u{1d244}', + '\u{1da00}'..='\u{1da36}', '\u{1da3b}'..='\u{1da6c}', '\u{1da75}'..='\u{1da75}', + '\u{1da84}'..='\u{1da84}', '\u{1da9b}'..='\u{1da9f}', '\u{1daa1}'..='\u{1daaf}', + '\u{1e000}'..='\u{1e006}', '\u{1e008}'..='\u{1e018}', '\u{1e01b}'..='\u{1e021}', + '\u{1e023}'..='\u{1e024}', '\u{1e026}'..='\u{1e02a}', '\u{1e08f}'..='\u{1e08f}', + '\u{1e130}'..='\u{1e136}', '\u{1e2ae}'..='\u{1e2ae}', '\u{1e2ec}'..='\u{1e2ef}', + '\u{1e4ec}'..='\u{1e4ef}', '\u{1e5ee}'..='\u{1e5ef}', '\u{1e6e3}'..='\u{1e6e3}', + '\u{1e6e6}'..='\u{1e6e6}', '\u{1e6ee}'..='\u{1e6ef}', '\u{1e6f5}'..='\u{1e6f5}', + '\u{1e8d0}'..='\u{1e8d6}', '\u{1e944}'..='\u{1e94a}', '\u{e0020}'..='\u{e007f}', + '\u{e0100}'..='\u{e01ef}', +]; + +#[rustfmt::skip] +pub(super) static LOWERCASE: &[RangeInclusive; 676] = &[ + '\u{aa}'..='\u{aa}', '\u{b5}'..='\u{b5}', '\u{ba}'..='\u{ba}', '\u{df}'..='\u{f6}', + '\u{f8}'..='\u{ff}', '\u{101}'..='\u{101}', '\u{103}'..='\u{103}', '\u{105}'..='\u{105}', + '\u{107}'..='\u{107}', '\u{109}'..='\u{109}', '\u{10b}'..='\u{10b}', '\u{10d}'..='\u{10d}', + '\u{10f}'..='\u{10f}', '\u{111}'..='\u{111}', '\u{113}'..='\u{113}', '\u{115}'..='\u{115}', + '\u{117}'..='\u{117}', '\u{119}'..='\u{119}', '\u{11b}'..='\u{11b}', '\u{11d}'..='\u{11d}', + '\u{11f}'..='\u{11f}', '\u{121}'..='\u{121}', '\u{123}'..='\u{123}', '\u{125}'..='\u{125}', + '\u{127}'..='\u{127}', '\u{129}'..='\u{129}', '\u{12b}'..='\u{12b}', '\u{12d}'..='\u{12d}', + '\u{12f}'..='\u{12f}', '\u{131}'..='\u{131}', '\u{133}'..='\u{133}', '\u{135}'..='\u{135}', + '\u{137}'..='\u{138}', '\u{13a}'..='\u{13a}', '\u{13c}'..='\u{13c}', '\u{13e}'..='\u{13e}', + '\u{140}'..='\u{140}', '\u{142}'..='\u{142}', '\u{144}'..='\u{144}', '\u{146}'..='\u{146}', + '\u{148}'..='\u{149}', '\u{14b}'..='\u{14b}', '\u{14d}'..='\u{14d}', '\u{14f}'..='\u{14f}', + '\u{151}'..='\u{151}', '\u{153}'..='\u{153}', '\u{155}'..='\u{155}', '\u{157}'..='\u{157}', + '\u{159}'..='\u{159}', '\u{15b}'..='\u{15b}', '\u{15d}'..='\u{15d}', '\u{15f}'..='\u{15f}', + '\u{161}'..='\u{161}', '\u{163}'..='\u{163}', '\u{165}'..='\u{165}', '\u{167}'..='\u{167}', + '\u{169}'..='\u{169}', '\u{16b}'..='\u{16b}', '\u{16d}'..='\u{16d}', '\u{16f}'..='\u{16f}', + '\u{171}'..='\u{171}', '\u{173}'..='\u{173}', '\u{175}'..='\u{175}', '\u{177}'..='\u{177}', + '\u{17a}'..='\u{17a}', '\u{17c}'..='\u{17c}', '\u{17e}'..='\u{180}', '\u{183}'..='\u{183}', + '\u{185}'..='\u{185}', '\u{188}'..='\u{188}', '\u{18c}'..='\u{18d}', '\u{192}'..='\u{192}', + '\u{195}'..='\u{195}', '\u{199}'..='\u{19b}', '\u{19e}'..='\u{19e}', '\u{1a1}'..='\u{1a1}', + '\u{1a3}'..='\u{1a3}', '\u{1a5}'..='\u{1a5}', '\u{1a8}'..='\u{1a8}', '\u{1aa}'..='\u{1ab}', + '\u{1ad}'..='\u{1ad}', '\u{1b0}'..='\u{1b0}', '\u{1b4}'..='\u{1b4}', '\u{1b6}'..='\u{1b6}', + '\u{1b9}'..='\u{1ba}', '\u{1bd}'..='\u{1bf}', '\u{1c6}'..='\u{1c6}', '\u{1c9}'..='\u{1c9}', + '\u{1cc}'..='\u{1cc}', '\u{1ce}'..='\u{1ce}', '\u{1d0}'..='\u{1d0}', '\u{1d2}'..='\u{1d2}', + '\u{1d4}'..='\u{1d4}', '\u{1d6}'..='\u{1d6}', '\u{1d8}'..='\u{1d8}', '\u{1da}'..='\u{1da}', + '\u{1dc}'..='\u{1dd}', '\u{1df}'..='\u{1df}', '\u{1e1}'..='\u{1e1}', '\u{1e3}'..='\u{1e3}', + '\u{1e5}'..='\u{1e5}', '\u{1e7}'..='\u{1e7}', '\u{1e9}'..='\u{1e9}', '\u{1eb}'..='\u{1eb}', + '\u{1ed}'..='\u{1ed}', '\u{1ef}'..='\u{1f0}', '\u{1f3}'..='\u{1f3}', '\u{1f5}'..='\u{1f5}', + '\u{1f9}'..='\u{1f9}', '\u{1fb}'..='\u{1fb}', '\u{1fd}'..='\u{1fd}', '\u{1ff}'..='\u{1ff}', + '\u{201}'..='\u{201}', '\u{203}'..='\u{203}', '\u{205}'..='\u{205}', '\u{207}'..='\u{207}', + '\u{209}'..='\u{209}', '\u{20b}'..='\u{20b}', '\u{20d}'..='\u{20d}', '\u{20f}'..='\u{20f}', + '\u{211}'..='\u{211}', '\u{213}'..='\u{213}', '\u{215}'..='\u{215}', '\u{217}'..='\u{217}', + '\u{219}'..='\u{219}', '\u{21b}'..='\u{21b}', '\u{21d}'..='\u{21d}', '\u{21f}'..='\u{21f}', + '\u{221}'..='\u{221}', '\u{223}'..='\u{223}', '\u{225}'..='\u{225}', '\u{227}'..='\u{227}', + '\u{229}'..='\u{229}', '\u{22b}'..='\u{22b}', '\u{22d}'..='\u{22d}', '\u{22f}'..='\u{22f}', + '\u{231}'..='\u{231}', '\u{233}'..='\u{239}', '\u{23c}'..='\u{23c}', '\u{23f}'..='\u{240}', + '\u{242}'..='\u{242}', '\u{247}'..='\u{247}', '\u{249}'..='\u{249}', '\u{24b}'..='\u{24b}', + '\u{24d}'..='\u{24d}', '\u{24f}'..='\u{293}', '\u{296}'..='\u{2b8}', '\u{2c0}'..='\u{2c1}', + '\u{2e0}'..='\u{2e4}', '\u{345}'..='\u{345}', '\u{371}'..='\u{371}', '\u{373}'..='\u{373}', + '\u{377}'..='\u{377}', '\u{37a}'..='\u{37d}', '\u{390}'..='\u{390}', '\u{3ac}'..='\u{3ce}', + '\u{3d0}'..='\u{3d1}', '\u{3d5}'..='\u{3d7}', '\u{3d9}'..='\u{3d9}', '\u{3db}'..='\u{3db}', + '\u{3dd}'..='\u{3dd}', '\u{3df}'..='\u{3df}', '\u{3e1}'..='\u{3e1}', '\u{3e3}'..='\u{3e3}', + '\u{3e5}'..='\u{3e5}', '\u{3e7}'..='\u{3e7}', '\u{3e9}'..='\u{3e9}', '\u{3eb}'..='\u{3eb}', + '\u{3ed}'..='\u{3ed}', '\u{3ef}'..='\u{3f3}', '\u{3f5}'..='\u{3f5}', '\u{3f8}'..='\u{3f8}', + '\u{3fb}'..='\u{3fc}', '\u{430}'..='\u{45f}', '\u{461}'..='\u{461}', '\u{463}'..='\u{463}', + '\u{465}'..='\u{465}', '\u{467}'..='\u{467}', '\u{469}'..='\u{469}', '\u{46b}'..='\u{46b}', + '\u{46d}'..='\u{46d}', '\u{46f}'..='\u{46f}', '\u{471}'..='\u{471}', '\u{473}'..='\u{473}', + '\u{475}'..='\u{475}', '\u{477}'..='\u{477}', '\u{479}'..='\u{479}', '\u{47b}'..='\u{47b}', + '\u{47d}'..='\u{47d}', '\u{47f}'..='\u{47f}', '\u{481}'..='\u{481}', '\u{48b}'..='\u{48b}', + '\u{48d}'..='\u{48d}', '\u{48f}'..='\u{48f}', '\u{491}'..='\u{491}', '\u{493}'..='\u{493}', + '\u{495}'..='\u{495}', '\u{497}'..='\u{497}', '\u{499}'..='\u{499}', '\u{49b}'..='\u{49b}', + '\u{49d}'..='\u{49d}', '\u{49f}'..='\u{49f}', '\u{4a1}'..='\u{4a1}', '\u{4a3}'..='\u{4a3}', + '\u{4a5}'..='\u{4a5}', '\u{4a7}'..='\u{4a7}', '\u{4a9}'..='\u{4a9}', '\u{4ab}'..='\u{4ab}', + '\u{4ad}'..='\u{4ad}', '\u{4af}'..='\u{4af}', '\u{4b1}'..='\u{4b1}', '\u{4b3}'..='\u{4b3}', + '\u{4b5}'..='\u{4b5}', '\u{4b7}'..='\u{4b7}', '\u{4b9}'..='\u{4b9}', '\u{4bb}'..='\u{4bb}', + '\u{4bd}'..='\u{4bd}', '\u{4bf}'..='\u{4bf}', '\u{4c2}'..='\u{4c2}', '\u{4c4}'..='\u{4c4}', + '\u{4c6}'..='\u{4c6}', '\u{4c8}'..='\u{4c8}', '\u{4ca}'..='\u{4ca}', '\u{4cc}'..='\u{4cc}', + '\u{4ce}'..='\u{4cf}', '\u{4d1}'..='\u{4d1}', '\u{4d3}'..='\u{4d3}', '\u{4d5}'..='\u{4d5}', + '\u{4d7}'..='\u{4d7}', '\u{4d9}'..='\u{4d9}', '\u{4db}'..='\u{4db}', '\u{4dd}'..='\u{4dd}', + '\u{4df}'..='\u{4df}', '\u{4e1}'..='\u{4e1}', '\u{4e3}'..='\u{4e3}', '\u{4e5}'..='\u{4e5}', + '\u{4e7}'..='\u{4e7}', '\u{4e9}'..='\u{4e9}', '\u{4eb}'..='\u{4eb}', '\u{4ed}'..='\u{4ed}', + '\u{4ef}'..='\u{4ef}', '\u{4f1}'..='\u{4f1}', '\u{4f3}'..='\u{4f3}', '\u{4f5}'..='\u{4f5}', + '\u{4f7}'..='\u{4f7}', '\u{4f9}'..='\u{4f9}', '\u{4fb}'..='\u{4fb}', '\u{4fd}'..='\u{4fd}', + '\u{4ff}'..='\u{4ff}', '\u{501}'..='\u{501}', '\u{503}'..='\u{503}', '\u{505}'..='\u{505}', + '\u{507}'..='\u{507}', '\u{509}'..='\u{509}', '\u{50b}'..='\u{50b}', '\u{50d}'..='\u{50d}', + '\u{50f}'..='\u{50f}', '\u{511}'..='\u{511}', '\u{513}'..='\u{513}', '\u{515}'..='\u{515}', + '\u{517}'..='\u{517}', '\u{519}'..='\u{519}', '\u{51b}'..='\u{51b}', '\u{51d}'..='\u{51d}', + '\u{51f}'..='\u{51f}', '\u{521}'..='\u{521}', '\u{523}'..='\u{523}', '\u{525}'..='\u{525}', + '\u{527}'..='\u{527}', '\u{529}'..='\u{529}', '\u{52b}'..='\u{52b}', '\u{52d}'..='\u{52d}', + '\u{52f}'..='\u{52f}', '\u{560}'..='\u{588}', '\u{10d0}'..='\u{10fa}', + '\u{10fc}'..='\u{10ff}', '\u{13f8}'..='\u{13fd}', '\u{1c80}'..='\u{1c88}', + '\u{1c8a}'..='\u{1c8a}', '\u{1d00}'..='\u{1dbf}', '\u{1e01}'..='\u{1e01}', + '\u{1e03}'..='\u{1e03}', '\u{1e05}'..='\u{1e05}', '\u{1e07}'..='\u{1e07}', + '\u{1e09}'..='\u{1e09}', '\u{1e0b}'..='\u{1e0b}', '\u{1e0d}'..='\u{1e0d}', + '\u{1e0f}'..='\u{1e0f}', '\u{1e11}'..='\u{1e11}', '\u{1e13}'..='\u{1e13}', + '\u{1e15}'..='\u{1e15}', '\u{1e17}'..='\u{1e17}', '\u{1e19}'..='\u{1e19}', + '\u{1e1b}'..='\u{1e1b}', '\u{1e1d}'..='\u{1e1d}', '\u{1e1f}'..='\u{1e1f}', + '\u{1e21}'..='\u{1e21}', '\u{1e23}'..='\u{1e23}', '\u{1e25}'..='\u{1e25}', + '\u{1e27}'..='\u{1e27}', '\u{1e29}'..='\u{1e29}', '\u{1e2b}'..='\u{1e2b}', + '\u{1e2d}'..='\u{1e2d}', '\u{1e2f}'..='\u{1e2f}', '\u{1e31}'..='\u{1e31}', + '\u{1e33}'..='\u{1e33}', '\u{1e35}'..='\u{1e35}', '\u{1e37}'..='\u{1e37}', + '\u{1e39}'..='\u{1e39}', '\u{1e3b}'..='\u{1e3b}', '\u{1e3d}'..='\u{1e3d}', + '\u{1e3f}'..='\u{1e3f}', '\u{1e41}'..='\u{1e41}', '\u{1e43}'..='\u{1e43}', + '\u{1e45}'..='\u{1e45}', '\u{1e47}'..='\u{1e47}', '\u{1e49}'..='\u{1e49}', + '\u{1e4b}'..='\u{1e4b}', '\u{1e4d}'..='\u{1e4d}', '\u{1e4f}'..='\u{1e4f}', + '\u{1e51}'..='\u{1e51}', '\u{1e53}'..='\u{1e53}', '\u{1e55}'..='\u{1e55}', + '\u{1e57}'..='\u{1e57}', '\u{1e59}'..='\u{1e59}', '\u{1e5b}'..='\u{1e5b}', + '\u{1e5d}'..='\u{1e5d}', '\u{1e5f}'..='\u{1e5f}', '\u{1e61}'..='\u{1e61}', + '\u{1e63}'..='\u{1e63}', '\u{1e65}'..='\u{1e65}', '\u{1e67}'..='\u{1e67}', + '\u{1e69}'..='\u{1e69}', '\u{1e6b}'..='\u{1e6b}', '\u{1e6d}'..='\u{1e6d}', + '\u{1e6f}'..='\u{1e6f}', '\u{1e71}'..='\u{1e71}', '\u{1e73}'..='\u{1e73}', + '\u{1e75}'..='\u{1e75}', '\u{1e77}'..='\u{1e77}', '\u{1e79}'..='\u{1e79}', + '\u{1e7b}'..='\u{1e7b}', '\u{1e7d}'..='\u{1e7d}', '\u{1e7f}'..='\u{1e7f}', + '\u{1e81}'..='\u{1e81}', '\u{1e83}'..='\u{1e83}', '\u{1e85}'..='\u{1e85}', + '\u{1e87}'..='\u{1e87}', '\u{1e89}'..='\u{1e89}', '\u{1e8b}'..='\u{1e8b}', + '\u{1e8d}'..='\u{1e8d}', '\u{1e8f}'..='\u{1e8f}', '\u{1e91}'..='\u{1e91}', + '\u{1e93}'..='\u{1e93}', '\u{1e95}'..='\u{1e9d}', '\u{1e9f}'..='\u{1e9f}', + '\u{1ea1}'..='\u{1ea1}', '\u{1ea3}'..='\u{1ea3}', '\u{1ea5}'..='\u{1ea5}', + '\u{1ea7}'..='\u{1ea7}', '\u{1ea9}'..='\u{1ea9}', '\u{1eab}'..='\u{1eab}', + '\u{1ead}'..='\u{1ead}', '\u{1eaf}'..='\u{1eaf}', '\u{1eb1}'..='\u{1eb1}', + '\u{1eb3}'..='\u{1eb3}', '\u{1eb5}'..='\u{1eb5}', '\u{1eb7}'..='\u{1eb7}', + '\u{1eb9}'..='\u{1eb9}', '\u{1ebb}'..='\u{1ebb}', '\u{1ebd}'..='\u{1ebd}', + '\u{1ebf}'..='\u{1ebf}', '\u{1ec1}'..='\u{1ec1}', '\u{1ec3}'..='\u{1ec3}', + '\u{1ec5}'..='\u{1ec5}', '\u{1ec7}'..='\u{1ec7}', '\u{1ec9}'..='\u{1ec9}', + '\u{1ecb}'..='\u{1ecb}', '\u{1ecd}'..='\u{1ecd}', '\u{1ecf}'..='\u{1ecf}', + '\u{1ed1}'..='\u{1ed1}', '\u{1ed3}'..='\u{1ed3}', '\u{1ed5}'..='\u{1ed5}', + '\u{1ed7}'..='\u{1ed7}', '\u{1ed9}'..='\u{1ed9}', '\u{1edb}'..='\u{1edb}', + '\u{1edd}'..='\u{1edd}', '\u{1edf}'..='\u{1edf}', '\u{1ee1}'..='\u{1ee1}', + '\u{1ee3}'..='\u{1ee3}', '\u{1ee5}'..='\u{1ee5}', '\u{1ee7}'..='\u{1ee7}', + '\u{1ee9}'..='\u{1ee9}', '\u{1eeb}'..='\u{1eeb}', '\u{1eed}'..='\u{1eed}', + '\u{1eef}'..='\u{1eef}', '\u{1ef1}'..='\u{1ef1}', '\u{1ef3}'..='\u{1ef3}', + '\u{1ef5}'..='\u{1ef5}', '\u{1ef7}'..='\u{1ef7}', '\u{1ef9}'..='\u{1ef9}', + '\u{1efb}'..='\u{1efb}', '\u{1efd}'..='\u{1efd}', '\u{1eff}'..='\u{1f07}', + '\u{1f10}'..='\u{1f15}', '\u{1f20}'..='\u{1f27}', '\u{1f30}'..='\u{1f37}', + '\u{1f40}'..='\u{1f45}', '\u{1f50}'..='\u{1f57}', '\u{1f60}'..='\u{1f67}', + '\u{1f70}'..='\u{1f7d}', '\u{1f80}'..='\u{1f87}', '\u{1f90}'..='\u{1f97}', + '\u{1fa0}'..='\u{1fa7}', '\u{1fb0}'..='\u{1fb4}', '\u{1fb6}'..='\u{1fb7}', + '\u{1fbe}'..='\u{1fbe}', '\u{1fc2}'..='\u{1fc4}', '\u{1fc6}'..='\u{1fc7}', + '\u{1fd0}'..='\u{1fd3}', '\u{1fd6}'..='\u{1fd7}', '\u{1fe0}'..='\u{1fe7}', + '\u{1ff2}'..='\u{1ff4}', '\u{1ff6}'..='\u{1ff7}', '\u{2071}'..='\u{2071}', + '\u{207f}'..='\u{207f}', '\u{2090}'..='\u{209c}', '\u{210a}'..='\u{210a}', + '\u{210e}'..='\u{210f}', '\u{2113}'..='\u{2113}', '\u{212f}'..='\u{212f}', + '\u{2134}'..='\u{2134}', '\u{2139}'..='\u{2139}', '\u{213c}'..='\u{213d}', + '\u{2146}'..='\u{2149}', '\u{214e}'..='\u{214e}', '\u{2170}'..='\u{217f}', + '\u{2184}'..='\u{2184}', '\u{24d0}'..='\u{24e9}', '\u{2c30}'..='\u{2c5f}', + '\u{2c61}'..='\u{2c61}', '\u{2c65}'..='\u{2c66}', '\u{2c68}'..='\u{2c68}', + '\u{2c6a}'..='\u{2c6a}', '\u{2c6c}'..='\u{2c6c}', '\u{2c71}'..='\u{2c71}', + '\u{2c73}'..='\u{2c74}', '\u{2c76}'..='\u{2c7d}', '\u{2c81}'..='\u{2c81}', + '\u{2c83}'..='\u{2c83}', '\u{2c85}'..='\u{2c85}', '\u{2c87}'..='\u{2c87}', + '\u{2c89}'..='\u{2c89}', '\u{2c8b}'..='\u{2c8b}', '\u{2c8d}'..='\u{2c8d}', + '\u{2c8f}'..='\u{2c8f}', '\u{2c91}'..='\u{2c91}', '\u{2c93}'..='\u{2c93}', + '\u{2c95}'..='\u{2c95}', '\u{2c97}'..='\u{2c97}', '\u{2c99}'..='\u{2c99}', + '\u{2c9b}'..='\u{2c9b}', '\u{2c9d}'..='\u{2c9d}', '\u{2c9f}'..='\u{2c9f}', + '\u{2ca1}'..='\u{2ca1}', '\u{2ca3}'..='\u{2ca3}', '\u{2ca5}'..='\u{2ca5}', + '\u{2ca7}'..='\u{2ca7}', '\u{2ca9}'..='\u{2ca9}', '\u{2cab}'..='\u{2cab}', + '\u{2cad}'..='\u{2cad}', '\u{2caf}'..='\u{2caf}', '\u{2cb1}'..='\u{2cb1}', + '\u{2cb3}'..='\u{2cb3}', '\u{2cb5}'..='\u{2cb5}', '\u{2cb7}'..='\u{2cb7}', + '\u{2cb9}'..='\u{2cb9}', '\u{2cbb}'..='\u{2cbb}', '\u{2cbd}'..='\u{2cbd}', + '\u{2cbf}'..='\u{2cbf}', '\u{2cc1}'..='\u{2cc1}', '\u{2cc3}'..='\u{2cc3}', + '\u{2cc5}'..='\u{2cc5}', '\u{2cc7}'..='\u{2cc7}', '\u{2cc9}'..='\u{2cc9}', + '\u{2ccb}'..='\u{2ccb}', '\u{2ccd}'..='\u{2ccd}', '\u{2ccf}'..='\u{2ccf}', + '\u{2cd1}'..='\u{2cd1}', '\u{2cd3}'..='\u{2cd3}', '\u{2cd5}'..='\u{2cd5}', + '\u{2cd7}'..='\u{2cd7}', '\u{2cd9}'..='\u{2cd9}', '\u{2cdb}'..='\u{2cdb}', + '\u{2cdd}'..='\u{2cdd}', '\u{2cdf}'..='\u{2cdf}', '\u{2ce1}'..='\u{2ce1}', + '\u{2ce3}'..='\u{2ce4}', '\u{2cec}'..='\u{2cec}', '\u{2cee}'..='\u{2cee}', + '\u{2cf3}'..='\u{2cf3}', '\u{2d00}'..='\u{2d25}', '\u{2d27}'..='\u{2d27}', + '\u{2d2d}'..='\u{2d2d}', '\u{a641}'..='\u{a641}', '\u{a643}'..='\u{a643}', + '\u{a645}'..='\u{a645}', '\u{a647}'..='\u{a647}', '\u{a649}'..='\u{a649}', + '\u{a64b}'..='\u{a64b}', '\u{a64d}'..='\u{a64d}', '\u{a64f}'..='\u{a64f}', + '\u{a651}'..='\u{a651}', '\u{a653}'..='\u{a653}', '\u{a655}'..='\u{a655}', + '\u{a657}'..='\u{a657}', '\u{a659}'..='\u{a659}', '\u{a65b}'..='\u{a65b}', + '\u{a65d}'..='\u{a65d}', '\u{a65f}'..='\u{a65f}', '\u{a661}'..='\u{a661}', + '\u{a663}'..='\u{a663}', '\u{a665}'..='\u{a665}', '\u{a667}'..='\u{a667}', + '\u{a669}'..='\u{a669}', '\u{a66b}'..='\u{a66b}', '\u{a66d}'..='\u{a66d}', + '\u{a681}'..='\u{a681}', '\u{a683}'..='\u{a683}', '\u{a685}'..='\u{a685}', + '\u{a687}'..='\u{a687}', '\u{a689}'..='\u{a689}', '\u{a68b}'..='\u{a68b}', + '\u{a68d}'..='\u{a68d}', '\u{a68f}'..='\u{a68f}', '\u{a691}'..='\u{a691}', + '\u{a693}'..='\u{a693}', '\u{a695}'..='\u{a695}', '\u{a697}'..='\u{a697}', + '\u{a699}'..='\u{a699}', '\u{a69b}'..='\u{a69d}', '\u{a723}'..='\u{a723}', + '\u{a725}'..='\u{a725}', '\u{a727}'..='\u{a727}', '\u{a729}'..='\u{a729}', + '\u{a72b}'..='\u{a72b}', '\u{a72d}'..='\u{a72d}', '\u{a72f}'..='\u{a731}', + '\u{a733}'..='\u{a733}', '\u{a735}'..='\u{a735}', '\u{a737}'..='\u{a737}', + '\u{a739}'..='\u{a739}', '\u{a73b}'..='\u{a73b}', '\u{a73d}'..='\u{a73d}', + '\u{a73f}'..='\u{a73f}', '\u{a741}'..='\u{a741}', '\u{a743}'..='\u{a743}', + '\u{a745}'..='\u{a745}', '\u{a747}'..='\u{a747}', '\u{a749}'..='\u{a749}', + '\u{a74b}'..='\u{a74b}', '\u{a74d}'..='\u{a74d}', '\u{a74f}'..='\u{a74f}', + '\u{a751}'..='\u{a751}', '\u{a753}'..='\u{a753}', '\u{a755}'..='\u{a755}', + '\u{a757}'..='\u{a757}', '\u{a759}'..='\u{a759}', '\u{a75b}'..='\u{a75b}', + '\u{a75d}'..='\u{a75d}', '\u{a75f}'..='\u{a75f}', '\u{a761}'..='\u{a761}', + '\u{a763}'..='\u{a763}', '\u{a765}'..='\u{a765}', '\u{a767}'..='\u{a767}', + '\u{a769}'..='\u{a769}', '\u{a76b}'..='\u{a76b}', '\u{a76d}'..='\u{a76d}', + '\u{a76f}'..='\u{a778}', '\u{a77a}'..='\u{a77a}', '\u{a77c}'..='\u{a77c}', + '\u{a77f}'..='\u{a77f}', '\u{a781}'..='\u{a781}', '\u{a783}'..='\u{a783}', + '\u{a785}'..='\u{a785}', '\u{a787}'..='\u{a787}', '\u{a78c}'..='\u{a78c}', + '\u{a78e}'..='\u{a78e}', '\u{a791}'..='\u{a791}', '\u{a793}'..='\u{a795}', + '\u{a797}'..='\u{a797}', '\u{a799}'..='\u{a799}', '\u{a79b}'..='\u{a79b}', + '\u{a79d}'..='\u{a79d}', '\u{a79f}'..='\u{a79f}', '\u{a7a1}'..='\u{a7a1}', + '\u{a7a3}'..='\u{a7a3}', '\u{a7a5}'..='\u{a7a5}', '\u{a7a7}'..='\u{a7a7}', + '\u{a7a9}'..='\u{a7a9}', '\u{a7af}'..='\u{a7af}', '\u{a7b5}'..='\u{a7b5}', + '\u{a7b7}'..='\u{a7b7}', '\u{a7b9}'..='\u{a7b9}', '\u{a7bb}'..='\u{a7bb}', + '\u{a7bd}'..='\u{a7bd}', '\u{a7bf}'..='\u{a7bf}', '\u{a7c1}'..='\u{a7c1}', + '\u{a7c3}'..='\u{a7c3}', '\u{a7c8}'..='\u{a7c8}', '\u{a7ca}'..='\u{a7ca}', + '\u{a7cd}'..='\u{a7cd}', '\u{a7cf}'..='\u{a7cf}', '\u{a7d1}'..='\u{a7d1}', + '\u{a7d3}'..='\u{a7d3}', '\u{a7d5}'..='\u{a7d5}', '\u{a7d7}'..='\u{a7d7}', + '\u{a7d9}'..='\u{a7d9}', '\u{a7db}'..='\u{a7db}', '\u{a7f1}'..='\u{a7f4}', + '\u{a7f6}'..='\u{a7f6}', '\u{a7f8}'..='\u{a7fa}', '\u{ab30}'..='\u{ab5a}', + '\u{ab5c}'..='\u{ab69}', '\u{ab70}'..='\u{abbf}', '\u{fb00}'..='\u{fb06}', + '\u{fb13}'..='\u{fb17}', '\u{ff41}'..='\u{ff5a}', '\u{10428}'..='\u{1044f}', + '\u{104d8}'..='\u{104fb}', '\u{10597}'..='\u{105a1}', '\u{105a3}'..='\u{105b1}', + '\u{105b3}'..='\u{105b9}', '\u{105bb}'..='\u{105bc}', '\u{10780}'..='\u{10780}', + '\u{10783}'..='\u{10785}', '\u{10787}'..='\u{107b0}', '\u{107b2}'..='\u{107ba}', + '\u{10cc0}'..='\u{10cf2}', '\u{10d70}'..='\u{10d85}', '\u{118c0}'..='\u{118df}', + '\u{16e60}'..='\u{16e7f}', '\u{16ebb}'..='\u{16ed3}', '\u{1d41a}'..='\u{1d433}', + '\u{1d44e}'..='\u{1d454}', '\u{1d456}'..='\u{1d467}', '\u{1d482}'..='\u{1d49b}', + '\u{1d4b6}'..='\u{1d4b9}', '\u{1d4bb}'..='\u{1d4bb}', '\u{1d4bd}'..='\u{1d4c3}', + '\u{1d4c5}'..='\u{1d4cf}', '\u{1d4ea}'..='\u{1d503}', '\u{1d51e}'..='\u{1d537}', + '\u{1d552}'..='\u{1d56b}', '\u{1d586}'..='\u{1d59f}', '\u{1d5ba}'..='\u{1d5d3}', + '\u{1d5ee}'..='\u{1d607}', '\u{1d622}'..='\u{1d63b}', '\u{1d656}'..='\u{1d66f}', + '\u{1d68a}'..='\u{1d6a5}', '\u{1d6c2}'..='\u{1d6da}', '\u{1d6dc}'..='\u{1d6e1}', + '\u{1d6fc}'..='\u{1d714}', '\u{1d716}'..='\u{1d71b}', '\u{1d736}'..='\u{1d74e}', + '\u{1d750}'..='\u{1d755}', '\u{1d770}'..='\u{1d788}', '\u{1d78a}'..='\u{1d78f}', + '\u{1d7aa}'..='\u{1d7c2}', '\u{1d7c4}'..='\u{1d7c9}', '\u{1d7cb}'..='\u{1d7cb}', + '\u{1df00}'..='\u{1df09}', '\u{1df0b}'..='\u{1df1e}', '\u{1df25}'..='\u{1df2a}', + '\u{1e030}'..='\u{1e06d}', '\u{1e922}'..='\u{1e943}', +]; + +#[rustfmt::skip] +pub(super) static N: &[RangeInclusive; 145] = &[ + '\u{b2}'..='\u{b3}', '\u{b9}'..='\u{b9}', '\u{bc}'..='\u{be}', '\u{660}'..='\u{669}', + '\u{6f0}'..='\u{6f9}', '\u{7c0}'..='\u{7c9}', '\u{966}'..='\u{96f}', '\u{9e6}'..='\u{9ef}', + '\u{9f4}'..='\u{9f9}', '\u{a66}'..='\u{a6f}', '\u{ae6}'..='\u{aef}', '\u{b66}'..='\u{b6f}', + '\u{b72}'..='\u{b77}', '\u{be6}'..='\u{bf2}', '\u{c66}'..='\u{c6f}', '\u{c78}'..='\u{c7e}', + '\u{ce6}'..='\u{cef}', '\u{d58}'..='\u{d5e}', '\u{d66}'..='\u{d78}', '\u{de6}'..='\u{def}', + '\u{e50}'..='\u{e59}', '\u{ed0}'..='\u{ed9}', '\u{f20}'..='\u{f33}', + '\u{1040}'..='\u{1049}', '\u{1090}'..='\u{1099}', '\u{1369}'..='\u{137c}', + '\u{16ee}'..='\u{16f0}', '\u{17e0}'..='\u{17e9}', '\u{17f0}'..='\u{17f9}', + '\u{1810}'..='\u{1819}', '\u{1946}'..='\u{194f}', '\u{19d0}'..='\u{19da}', + '\u{1a80}'..='\u{1a89}', '\u{1a90}'..='\u{1a99}', '\u{1b50}'..='\u{1b59}', + '\u{1bb0}'..='\u{1bb9}', '\u{1c40}'..='\u{1c49}', '\u{1c50}'..='\u{1c59}', + '\u{2070}'..='\u{2070}', '\u{2074}'..='\u{2079}', '\u{2080}'..='\u{2089}', + '\u{2150}'..='\u{2182}', '\u{2185}'..='\u{2189}', '\u{2460}'..='\u{249b}', + '\u{24ea}'..='\u{24ff}', '\u{2776}'..='\u{2793}', '\u{2cfd}'..='\u{2cfd}', + '\u{3007}'..='\u{3007}', '\u{3021}'..='\u{3029}', '\u{3038}'..='\u{303a}', + '\u{3192}'..='\u{3195}', '\u{3220}'..='\u{3229}', '\u{3248}'..='\u{324f}', + '\u{3251}'..='\u{325f}', '\u{3280}'..='\u{3289}', '\u{32b1}'..='\u{32bf}', + '\u{a620}'..='\u{a629}', '\u{a6e6}'..='\u{a6ef}', '\u{a830}'..='\u{a835}', + '\u{a8d0}'..='\u{a8d9}', '\u{a900}'..='\u{a909}', '\u{a9d0}'..='\u{a9d9}', + '\u{a9f0}'..='\u{a9f9}', '\u{aa50}'..='\u{aa59}', '\u{abf0}'..='\u{abf9}', + '\u{ff10}'..='\u{ff19}', '\u{10107}'..='\u{10133}', '\u{10140}'..='\u{10178}', + '\u{1018a}'..='\u{1018b}', '\u{102e1}'..='\u{102fb}', '\u{10320}'..='\u{10323}', + '\u{10341}'..='\u{10341}', '\u{1034a}'..='\u{1034a}', '\u{103d1}'..='\u{103d5}', + '\u{104a0}'..='\u{104a9}', '\u{10858}'..='\u{1085f}', '\u{10879}'..='\u{1087f}', + '\u{108a7}'..='\u{108af}', '\u{108fb}'..='\u{108ff}', '\u{10916}'..='\u{1091b}', + '\u{109bc}'..='\u{109bd}', '\u{109c0}'..='\u{109cf}', '\u{109d2}'..='\u{109ff}', + '\u{10a40}'..='\u{10a48}', '\u{10a7d}'..='\u{10a7e}', '\u{10a9d}'..='\u{10a9f}', + '\u{10aeb}'..='\u{10aef}', '\u{10b58}'..='\u{10b5f}', '\u{10b78}'..='\u{10b7f}', + '\u{10ba9}'..='\u{10baf}', '\u{10cfa}'..='\u{10cff}', '\u{10d30}'..='\u{10d39}', + '\u{10d40}'..='\u{10d49}', '\u{10e60}'..='\u{10e7e}', '\u{10f1d}'..='\u{10f26}', + '\u{10f51}'..='\u{10f54}', '\u{10fc5}'..='\u{10fcb}', '\u{11052}'..='\u{1106f}', + '\u{110f0}'..='\u{110f9}', '\u{11136}'..='\u{1113f}', '\u{111d0}'..='\u{111d9}', + '\u{111e1}'..='\u{111f4}', '\u{112f0}'..='\u{112f9}', '\u{11450}'..='\u{11459}', + '\u{114d0}'..='\u{114d9}', '\u{11650}'..='\u{11659}', '\u{116c0}'..='\u{116c9}', + '\u{116d0}'..='\u{116e3}', '\u{11730}'..='\u{1173b}', '\u{118e0}'..='\u{118f2}', + '\u{11950}'..='\u{11959}', '\u{11bf0}'..='\u{11bf9}', '\u{11c50}'..='\u{11c6c}', + '\u{11d50}'..='\u{11d59}', '\u{11da0}'..='\u{11da9}', '\u{11de0}'..='\u{11de9}', + '\u{11f50}'..='\u{11f59}', '\u{11fc0}'..='\u{11fd4}', '\u{12400}'..='\u{1246e}', + '\u{16130}'..='\u{16139}', '\u{16a60}'..='\u{16a69}', '\u{16ac0}'..='\u{16ac9}', + '\u{16b50}'..='\u{16b59}', '\u{16b5b}'..='\u{16b61}', '\u{16d70}'..='\u{16d79}', + '\u{16e80}'..='\u{16e96}', '\u{16ff4}'..='\u{16ff6}', '\u{1ccf0}'..='\u{1ccf9}', + '\u{1d2c0}'..='\u{1d2d3}', '\u{1d2e0}'..='\u{1d2f3}', '\u{1d360}'..='\u{1d378}', + '\u{1d7ce}'..='\u{1d7ff}', '\u{1e140}'..='\u{1e149}', '\u{1e2f0}'..='\u{1e2f9}', + '\u{1e4f0}'..='\u{1e4f9}', '\u{1e5f1}'..='\u{1e5fa}', '\u{1e8c7}'..='\u{1e8cf}', + '\u{1e950}'..='\u{1e959}', '\u{1ec71}'..='\u{1ecab}', '\u{1ecad}'..='\u{1ecaf}', + '\u{1ecb1}'..='\u{1ecb4}', '\u{1ed01}'..='\u{1ed2d}', '\u{1ed2f}'..='\u{1ed3d}', + '\u{1f100}'..='\u{1f10c}', '\u{1fbf0}'..='\u{1fbf9}', +]; + +#[rustfmt::skip] +pub(super) static UPPERCASE: &[RangeInclusive; 659] = &[ + '\u{c0}'..='\u{d6}', '\u{d8}'..='\u{de}', '\u{100}'..='\u{100}', '\u{102}'..='\u{102}', + '\u{104}'..='\u{104}', '\u{106}'..='\u{106}', '\u{108}'..='\u{108}', '\u{10a}'..='\u{10a}', + '\u{10c}'..='\u{10c}', '\u{10e}'..='\u{10e}', '\u{110}'..='\u{110}', '\u{112}'..='\u{112}', + '\u{114}'..='\u{114}', '\u{116}'..='\u{116}', '\u{118}'..='\u{118}', '\u{11a}'..='\u{11a}', + '\u{11c}'..='\u{11c}', '\u{11e}'..='\u{11e}', '\u{120}'..='\u{120}', '\u{122}'..='\u{122}', + '\u{124}'..='\u{124}', '\u{126}'..='\u{126}', '\u{128}'..='\u{128}', '\u{12a}'..='\u{12a}', + '\u{12c}'..='\u{12c}', '\u{12e}'..='\u{12e}', '\u{130}'..='\u{130}', '\u{132}'..='\u{132}', + '\u{134}'..='\u{134}', '\u{136}'..='\u{136}', '\u{139}'..='\u{139}', '\u{13b}'..='\u{13b}', + '\u{13d}'..='\u{13d}', '\u{13f}'..='\u{13f}', '\u{141}'..='\u{141}', '\u{143}'..='\u{143}', + '\u{145}'..='\u{145}', '\u{147}'..='\u{147}', '\u{14a}'..='\u{14a}', '\u{14c}'..='\u{14c}', + '\u{14e}'..='\u{14e}', '\u{150}'..='\u{150}', '\u{152}'..='\u{152}', '\u{154}'..='\u{154}', + '\u{156}'..='\u{156}', '\u{158}'..='\u{158}', '\u{15a}'..='\u{15a}', '\u{15c}'..='\u{15c}', + '\u{15e}'..='\u{15e}', '\u{160}'..='\u{160}', '\u{162}'..='\u{162}', '\u{164}'..='\u{164}', + '\u{166}'..='\u{166}', '\u{168}'..='\u{168}', '\u{16a}'..='\u{16a}', '\u{16c}'..='\u{16c}', + '\u{16e}'..='\u{16e}', '\u{170}'..='\u{170}', '\u{172}'..='\u{172}', '\u{174}'..='\u{174}', + '\u{176}'..='\u{176}', '\u{178}'..='\u{179}', '\u{17b}'..='\u{17b}', '\u{17d}'..='\u{17d}', + '\u{181}'..='\u{182}', '\u{184}'..='\u{184}', '\u{186}'..='\u{187}', '\u{189}'..='\u{18b}', + '\u{18e}'..='\u{191}', '\u{193}'..='\u{194}', '\u{196}'..='\u{198}', '\u{19c}'..='\u{19d}', + '\u{19f}'..='\u{1a0}', '\u{1a2}'..='\u{1a2}', '\u{1a4}'..='\u{1a4}', '\u{1a6}'..='\u{1a7}', + '\u{1a9}'..='\u{1a9}', '\u{1ac}'..='\u{1ac}', '\u{1ae}'..='\u{1af}', '\u{1b1}'..='\u{1b3}', + '\u{1b5}'..='\u{1b5}', '\u{1b7}'..='\u{1b8}', '\u{1bc}'..='\u{1bc}', '\u{1c4}'..='\u{1c4}', + '\u{1c7}'..='\u{1c7}', '\u{1ca}'..='\u{1ca}', '\u{1cd}'..='\u{1cd}', '\u{1cf}'..='\u{1cf}', + '\u{1d1}'..='\u{1d1}', '\u{1d3}'..='\u{1d3}', '\u{1d5}'..='\u{1d5}', '\u{1d7}'..='\u{1d7}', + '\u{1d9}'..='\u{1d9}', '\u{1db}'..='\u{1db}', '\u{1de}'..='\u{1de}', '\u{1e0}'..='\u{1e0}', + '\u{1e2}'..='\u{1e2}', '\u{1e4}'..='\u{1e4}', '\u{1e6}'..='\u{1e6}', '\u{1e8}'..='\u{1e8}', + '\u{1ea}'..='\u{1ea}', '\u{1ec}'..='\u{1ec}', '\u{1ee}'..='\u{1ee}', '\u{1f1}'..='\u{1f1}', + '\u{1f4}'..='\u{1f4}', '\u{1f6}'..='\u{1f8}', '\u{1fa}'..='\u{1fa}', '\u{1fc}'..='\u{1fc}', + '\u{1fe}'..='\u{1fe}', '\u{200}'..='\u{200}', '\u{202}'..='\u{202}', '\u{204}'..='\u{204}', + '\u{206}'..='\u{206}', '\u{208}'..='\u{208}', '\u{20a}'..='\u{20a}', '\u{20c}'..='\u{20c}', + '\u{20e}'..='\u{20e}', '\u{210}'..='\u{210}', '\u{212}'..='\u{212}', '\u{214}'..='\u{214}', + '\u{216}'..='\u{216}', '\u{218}'..='\u{218}', '\u{21a}'..='\u{21a}', '\u{21c}'..='\u{21c}', + '\u{21e}'..='\u{21e}', '\u{220}'..='\u{220}', '\u{222}'..='\u{222}', '\u{224}'..='\u{224}', + '\u{226}'..='\u{226}', '\u{228}'..='\u{228}', '\u{22a}'..='\u{22a}', '\u{22c}'..='\u{22c}', + '\u{22e}'..='\u{22e}', '\u{230}'..='\u{230}', '\u{232}'..='\u{232}', '\u{23a}'..='\u{23b}', + '\u{23d}'..='\u{23e}', '\u{241}'..='\u{241}', '\u{243}'..='\u{246}', '\u{248}'..='\u{248}', + '\u{24a}'..='\u{24a}', '\u{24c}'..='\u{24c}', '\u{24e}'..='\u{24e}', '\u{370}'..='\u{370}', + '\u{372}'..='\u{372}', '\u{376}'..='\u{376}', '\u{37f}'..='\u{37f}', '\u{386}'..='\u{386}', + '\u{388}'..='\u{38a}', '\u{38c}'..='\u{38c}', '\u{38e}'..='\u{38f}', '\u{391}'..='\u{3a1}', + '\u{3a3}'..='\u{3ab}', '\u{3cf}'..='\u{3cf}', '\u{3d2}'..='\u{3d4}', '\u{3d8}'..='\u{3d8}', + '\u{3da}'..='\u{3da}', '\u{3dc}'..='\u{3dc}', '\u{3de}'..='\u{3de}', '\u{3e0}'..='\u{3e0}', + '\u{3e2}'..='\u{3e2}', '\u{3e4}'..='\u{3e4}', '\u{3e6}'..='\u{3e6}', '\u{3e8}'..='\u{3e8}', + '\u{3ea}'..='\u{3ea}', '\u{3ec}'..='\u{3ec}', '\u{3ee}'..='\u{3ee}', '\u{3f4}'..='\u{3f4}', + '\u{3f7}'..='\u{3f7}', '\u{3f9}'..='\u{3fa}', '\u{3fd}'..='\u{42f}', '\u{460}'..='\u{460}', + '\u{462}'..='\u{462}', '\u{464}'..='\u{464}', '\u{466}'..='\u{466}', '\u{468}'..='\u{468}', + '\u{46a}'..='\u{46a}', '\u{46c}'..='\u{46c}', '\u{46e}'..='\u{46e}', '\u{470}'..='\u{470}', + '\u{472}'..='\u{472}', '\u{474}'..='\u{474}', '\u{476}'..='\u{476}', '\u{478}'..='\u{478}', + '\u{47a}'..='\u{47a}', '\u{47c}'..='\u{47c}', '\u{47e}'..='\u{47e}', '\u{480}'..='\u{480}', + '\u{48a}'..='\u{48a}', '\u{48c}'..='\u{48c}', '\u{48e}'..='\u{48e}', '\u{490}'..='\u{490}', + '\u{492}'..='\u{492}', '\u{494}'..='\u{494}', '\u{496}'..='\u{496}', '\u{498}'..='\u{498}', + '\u{49a}'..='\u{49a}', '\u{49c}'..='\u{49c}', '\u{49e}'..='\u{49e}', '\u{4a0}'..='\u{4a0}', + '\u{4a2}'..='\u{4a2}', '\u{4a4}'..='\u{4a4}', '\u{4a6}'..='\u{4a6}', '\u{4a8}'..='\u{4a8}', + '\u{4aa}'..='\u{4aa}', '\u{4ac}'..='\u{4ac}', '\u{4ae}'..='\u{4ae}', '\u{4b0}'..='\u{4b0}', + '\u{4b2}'..='\u{4b2}', '\u{4b4}'..='\u{4b4}', '\u{4b6}'..='\u{4b6}', '\u{4b8}'..='\u{4b8}', + '\u{4ba}'..='\u{4ba}', '\u{4bc}'..='\u{4bc}', '\u{4be}'..='\u{4be}', '\u{4c0}'..='\u{4c1}', + '\u{4c3}'..='\u{4c3}', '\u{4c5}'..='\u{4c5}', '\u{4c7}'..='\u{4c7}', '\u{4c9}'..='\u{4c9}', + '\u{4cb}'..='\u{4cb}', '\u{4cd}'..='\u{4cd}', '\u{4d0}'..='\u{4d0}', '\u{4d2}'..='\u{4d2}', + '\u{4d4}'..='\u{4d4}', '\u{4d6}'..='\u{4d6}', '\u{4d8}'..='\u{4d8}', '\u{4da}'..='\u{4da}', + '\u{4dc}'..='\u{4dc}', '\u{4de}'..='\u{4de}', '\u{4e0}'..='\u{4e0}', '\u{4e2}'..='\u{4e2}', + '\u{4e4}'..='\u{4e4}', '\u{4e6}'..='\u{4e6}', '\u{4e8}'..='\u{4e8}', '\u{4ea}'..='\u{4ea}', + '\u{4ec}'..='\u{4ec}', '\u{4ee}'..='\u{4ee}', '\u{4f0}'..='\u{4f0}', '\u{4f2}'..='\u{4f2}', + '\u{4f4}'..='\u{4f4}', '\u{4f6}'..='\u{4f6}', '\u{4f8}'..='\u{4f8}', '\u{4fa}'..='\u{4fa}', + '\u{4fc}'..='\u{4fc}', '\u{4fe}'..='\u{4fe}', '\u{500}'..='\u{500}', '\u{502}'..='\u{502}', + '\u{504}'..='\u{504}', '\u{506}'..='\u{506}', '\u{508}'..='\u{508}', '\u{50a}'..='\u{50a}', + '\u{50c}'..='\u{50c}', '\u{50e}'..='\u{50e}', '\u{510}'..='\u{510}', '\u{512}'..='\u{512}', + '\u{514}'..='\u{514}', '\u{516}'..='\u{516}', '\u{518}'..='\u{518}', '\u{51a}'..='\u{51a}', + '\u{51c}'..='\u{51c}', '\u{51e}'..='\u{51e}', '\u{520}'..='\u{520}', '\u{522}'..='\u{522}', + '\u{524}'..='\u{524}', '\u{526}'..='\u{526}', '\u{528}'..='\u{528}', '\u{52a}'..='\u{52a}', + '\u{52c}'..='\u{52c}', '\u{52e}'..='\u{52e}', '\u{531}'..='\u{556}', + '\u{10a0}'..='\u{10c5}', '\u{10c7}'..='\u{10c7}', '\u{10cd}'..='\u{10cd}', + '\u{13a0}'..='\u{13f5}', '\u{1c89}'..='\u{1c89}', '\u{1c90}'..='\u{1cba}', + '\u{1cbd}'..='\u{1cbf}', '\u{1e00}'..='\u{1e00}', '\u{1e02}'..='\u{1e02}', + '\u{1e04}'..='\u{1e04}', '\u{1e06}'..='\u{1e06}', '\u{1e08}'..='\u{1e08}', + '\u{1e0a}'..='\u{1e0a}', '\u{1e0c}'..='\u{1e0c}', '\u{1e0e}'..='\u{1e0e}', + '\u{1e10}'..='\u{1e10}', '\u{1e12}'..='\u{1e12}', '\u{1e14}'..='\u{1e14}', + '\u{1e16}'..='\u{1e16}', '\u{1e18}'..='\u{1e18}', '\u{1e1a}'..='\u{1e1a}', + '\u{1e1c}'..='\u{1e1c}', '\u{1e1e}'..='\u{1e1e}', '\u{1e20}'..='\u{1e20}', + '\u{1e22}'..='\u{1e22}', '\u{1e24}'..='\u{1e24}', '\u{1e26}'..='\u{1e26}', + '\u{1e28}'..='\u{1e28}', '\u{1e2a}'..='\u{1e2a}', '\u{1e2c}'..='\u{1e2c}', + '\u{1e2e}'..='\u{1e2e}', '\u{1e30}'..='\u{1e30}', '\u{1e32}'..='\u{1e32}', + '\u{1e34}'..='\u{1e34}', '\u{1e36}'..='\u{1e36}', '\u{1e38}'..='\u{1e38}', + '\u{1e3a}'..='\u{1e3a}', '\u{1e3c}'..='\u{1e3c}', '\u{1e3e}'..='\u{1e3e}', + '\u{1e40}'..='\u{1e40}', '\u{1e42}'..='\u{1e42}', '\u{1e44}'..='\u{1e44}', + '\u{1e46}'..='\u{1e46}', '\u{1e48}'..='\u{1e48}', '\u{1e4a}'..='\u{1e4a}', + '\u{1e4c}'..='\u{1e4c}', '\u{1e4e}'..='\u{1e4e}', '\u{1e50}'..='\u{1e50}', + '\u{1e52}'..='\u{1e52}', '\u{1e54}'..='\u{1e54}', '\u{1e56}'..='\u{1e56}', + '\u{1e58}'..='\u{1e58}', '\u{1e5a}'..='\u{1e5a}', '\u{1e5c}'..='\u{1e5c}', + '\u{1e5e}'..='\u{1e5e}', '\u{1e60}'..='\u{1e60}', '\u{1e62}'..='\u{1e62}', + '\u{1e64}'..='\u{1e64}', '\u{1e66}'..='\u{1e66}', '\u{1e68}'..='\u{1e68}', + '\u{1e6a}'..='\u{1e6a}', '\u{1e6c}'..='\u{1e6c}', '\u{1e6e}'..='\u{1e6e}', + '\u{1e70}'..='\u{1e70}', '\u{1e72}'..='\u{1e72}', '\u{1e74}'..='\u{1e74}', + '\u{1e76}'..='\u{1e76}', '\u{1e78}'..='\u{1e78}', '\u{1e7a}'..='\u{1e7a}', + '\u{1e7c}'..='\u{1e7c}', '\u{1e7e}'..='\u{1e7e}', '\u{1e80}'..='\u{1e80}', + '\u{1e82}'..='\u{1e82}', '\u{1e84}'..='\u{1e84}', '\u{1e86}'..='\u{1e86}', + '\u{1e88}'..='\u{1e88}', '\u{1e8a}'..='\u{1e8a}', '\u{1e8c}'..='\u{1e8c}', + '\u{1e8e}'..='\u{1e8e}', '\u{1e90}'..='\u{1e90}', '\u{1e92}'..='\u{1e92}', + '\u{1e94}'..='\u{1e94}', '\u{1e9e}'..='\u{1e9e}', '\u{1ea0}'..='\u{1ea0}', + '\u{1ea2}'..='\u{1ea2}', '\u{1ea4}'..='\u{1ea4}', '\u{1ea6}'..='\u{1ea6}', + '\u{1ea8}'..='\u{1ea8}', '\u{1eaa}'..='\u{1eaa}', '\u{1eac}'..='\u{1eac}', + '\u{1eae}'..='\u{1eae}', '\u{1eb0}'..='\u{1eb0}', '\u{1eb2}'..='\u{1eb2}', + '\u{1eb4}'..='\u{1eb4}', '\u{1eb6}'..='\u{1eb6}', '\u{1eb8}'..='\u{1eb8}', + '\u{1eba}'..='\u{1eba}', '\u{1ebc}'..='\u{1ebc}', '\u{1ebe}'..='\u{1ebe}', + '\u{1ec0}'..='\u{1ec0}', '\u{1ec2}'..='\u{1ec2}', '\u{1ec4}'..='\u{1ec4}', + '\u{1ec6}'..='\u{1ec6}', '\u{1ec8}'..='\u{1ec8}', '\u{1eca}'..='\u{1eca}', + '\u{1ecc}'..='\u{1ecc}', '\u{1ece}'..='\u{1ece}', '\u{1ed0}'..='\u{1ed0}', + '\u{1ed2}'..='\u{1ed2}', '\u{1ed4}'..='\u{1ed4}', '\u{1ed6}'..='\u{1ed6}', + '\u{1ed8}'..='\u{1ed8}', '\u{1eda}'..='\u{1eda}', '\u{1edc}'..='\u{1edc}', + '\u{1ede}'..='\u{1ede}', '\u{1ee0}'..='\u{1ee0}', '\u{1ee2}'..='\u{1ee2}', + '\u{1ee4}'..='\u{1ee4}', '\u{1ee6}'..='\u{1ee6}', '\u{1ee8}'..='\u{1ee8}', + '\u{1eea}'..='\u{1eea}', '\u{1eec}'..='\u{1eec}', '\u{1eee}'..='\u{1eee}', + '\u{1ef0}'..='\u{1ef0}', '\u{1ef2}'..='\u{1ef2}', '\u{1ef4}'..='\u{1ef4}', + '\u{1ef6}'..='\u{1ef6}', '\u{1ef8}'..='\u{1ef8}', '\u{1efa}'..='\u{1efa}', + '\u{1efc}'..='\u{1efc}', '\u{1efe}'..='\u{1efe}', '\u{1f08}'..='\u{1f0f}', + '\u{1f18}'..='\u{1f1d}', '\u{1f28}'..='\u{1f2f}', '\u{1f38}'..='\u{1f3f}', + '\u{1f48}'..='\u{1f4d}', '\u{1f59}'..='\u{1f59}', '\u{1f5b}'..='\u{1f5b}', + '\u{1f5d}'..='\u{1f5d}', '\u{1f5f}'..='\u{1f5f}', '\u{1f68}'..='\u{1f6f}', + '\u{1fb8}'..='\u{1fbb}', '\u{1fc8}'..='\u{1fcb}', '\u{1fd8}'..='\u{1fdb}', + '\u{1fe8}'..='\u{1fec}', '\u{1ff8}'..='\u{1ffb}', '\u{2102}'..='\u{2102}', + '\u{2107}'..='\u{2107}', '\u{210b}'..='\u{210d}', '\u{2110}'..='\u{2112}', + '\u{2115}'..='\u{2115}', '\u{2119}'..='\u{211d}', '\u{2124}'..='\u{2124}', + '\u{2126}'..='\u{2126}', '\u{2128}'..='\u{2128}', '\u{212a}'..='\u{212d}', + '\u{2130}'..='\u{2133}', '\u{213e}'..='\u{213f}', '\u{2145}'..='\u{2145}', + '\u{2160}'..='\u{216f}', '\u{2183}'..='\u{2183}', '\u{24b6}'..='\u{24cf}', + '\u{2c00}'..='\u{2c2f}', '\u{2c60}'..='\u{2c60}', '\u{2c62}'..='\u{2c64}', + '\u{2c67}'..='\u{2c67}', '\u{2c69}'..='\u{2c69}', '\u{2c6b}'..='\u{2c6b}', + '\u{2c6d}'..='\u{2c70}', '\u{2c72}'..='\u{2c72}', '\u{2c75}'..='\u{2c75}', + '\u{2c7e}'..='\u{2c80}', '\u{2c82}'..='\u{2c82}', '\u{2c84}'..='\u{2c84}', + '\u{2c86}'..='\u{2c86}', '\u{2c88}'..='\u{2c88}', '\u{2c8a}'..='\u{2c8a}', + '\u{2c8c}'..='\u{2c8c}', '\u{2c8e}'..='\u{2c8e}', '\u{2c90}'..='\u{2c90}', + '\u{2c92}'..='\u{2c92}', '\u{2c94}'..='\u{2c94}', '\u{2c96}'..='\u{2c96}', + '\u{2c98}'..='\u{2c98}', '\u{2c9a}'..='\u{2c9a}', '\u{2c9c}'..='\u{2c9c}', + '\u{2c9e}'..='\u{2c9e}', '\u{2ca0}'..='\u{2ca0}', '\u{2ca2}'..='\u{2ca2}', + '\u{2ca4}'..='\u{2ca4}', '\u{2ca6}'..='\u{2ca6}', '\u{2ca8}'..='\u{2ca8}', + '\u{2caa}'..='\u{2caa}', '\u{2cac}'..='\u{2cac}', '\u{2cae}'..='\u{2cae}', + '\u{2cb0}'..='\u{2cb0}', '\u{2cb2}'..='\u{2cb2}', '\u{2cb4}'..='\u{2cb4}', + '\u{2cb6}'..='\u{2cb6}', '\u{2cb8}'..='\u{2cb8}', '\u{2cba}'..='\u{2cba}', + '\u{2cbc}'..='\u{2cbc}', '\u{2cbe}'..='\u{2cbe}', '\u{2cc0}'..='\u{2cc0}', + '\u{2cc2}'..='\u{2cc2}', '\u{2cc4}'..='\u{2cc4}', '\u{2cc6}'..='\u{2cc6}', + '\u{2cc8}'..='\u{2cc8}', '\u{2cca}'..='\u{2cca}', '\u{2ccc}'..='\u{2ccc}', + '\u{2cce}'..='\u{2cce}', '\u{2cd0}'..='\u{2cd0}', '\u{2cd2}'..='\u{2cd2}', + '\u{2cd4}'..='\u{2cd4}', '\u{2cd6}'..='\u{2cd6}', '\u{2cd8}'..='\u{2cd8}', + '\u{2cda}'..='\u{2cda}', '\u{2cdc}'..='\u{2cdc}', '\u{2cde}'..='\u{2cde}', + '\u{2ce0}'..='\u{2ce0}', '\u{2ce2}'..='\u{2ce2}', '\u{2ceb}'..='\u{2ceb}', + '\u{2ced}'..='\u{2ced}', '\u{2cf2}'..='\u{2cf2}', '\u{a640}'..='\u{a640}', + '\u{a642}'..='\u{a642}', '\u{a644}'..='\u{a644}', '\u{a646}'..='\u{a646}', + '\u{a648}'..='\u{a648}', '\u{a64a}'..='\u{a64a}', '\u{a64c}'..='\u{a64c}', + '\u{a64e}'..='\u{a64e}', '\u{a650}'..='\u{a650}', '\u{a652}'..='\u{a652}', + '\u{a654}'..='\u{a654}', '\u{a656}'..='\u{a656}', '\u{a658}'..='\u{a658}', + '\u{a65a}'..='\u{a65a}', '\u{a65c}'..='\u{a65c}', '\u{a65e}'..='\u{a65e}', + '\u{a660}'..='\u{a660}', '\u{a662}'..='\u{a662}', '\u{a664}'..='\u{a664}', + '\u{a666}'..='\u{a666}', '\u{a668}'..='\u{a668}', '\u{a66a}'..='\u{a66a}', + '\u{a66c}'..='\u{a66c}', '\u{a680}'..='\u{a680}', '\u{a682}'..='\u{a682}', + '\u{a684}'..='\u{a684}', '\u{a686}'..='\u{a686}', '\u{a688}'..='\u{a688}', + '\u{a68a}'..='\u{a68a}', '\u{a68c}'..='\u{a68c}', '\u{a68e}'..='\u{a68e}', + '\u{a690}'..='\u{a690}', '\u{a692}'..='\u{a692}', '\u{a694}'..='\u{a694}', + '\u{a696}'..='\u{a696}', '\u{a698}'..='\u{a698}', '\u{a69a}'..='\u{a69a}', + '\u{a722}'..='\u{a722}', '\u{a724}'..='\u{a724}', '\u{a726}'..='\u{a726}', + '\u{a728}'..='\u{a728}', '\u{a72a}'..='\u{a72a}', '\u{a72c}'..='\u{a72c}', + '\u{a72e}'..='\u{a72e}', '\u{a732}'..='\u{a732}', '\u{a734}'..='\u{a734}', + '\u{a736}'..='\u{a736}', '\u{a738}'..='\u{a738}', '\u{a73a}'..='\u{a73a}', + '\u{a73c}'..='\u{a73c}', '\u{a73e}'..='\u{a73e}', '\u{a740}'..='\u{a740}', + '\u{a742}'..='\u{a742}', '\u{a744}'..='\u{a744}', '\u{a746}'..='\u{a746}', + '\u{a748}'..='\u{a748}', '\u{a74a}'..='\u{a74a}', '\u{a74c}'..='\u{a74c}', + '\u{a74e}'..='\u{a74e}', '\u{a750}'..='\u{a750}', '\u{a752}'..='\u{a752}', + '\u{a754}'..='\u{a754}', '\u{a756}'..='\u{a756}', '\u{a758}'..='\u{a758}', + '\u{a75a}'..='\u{a75a}', '\u{a75c}'..='\u{a75c}', '\u{a75e}'..='\u{a75e}', + '\u{a760}'..='\u{a760}', '\u{a762}'..='\u{a762}', '\u{a764}'..='\u{a764}', + '\u{a766}'..='\u{a766}', '\u{a768}'..='\u{a768}', '\u{a76a}'..='\u{a76a}', + '\u{a76c}'..='\u{a76c}', '\u{a76e}'..='\u{a76e}', '\u{a779}'..='\u{a779}', + '\u{a77b}'..='\u{a77b}', '\u{a77d}'..='\u{a77e}', '\u{a780}'..='\u{a780}', + '\u{a782}'..='\u{a782}', '\u{a784}'..='\u{a784}', '\u{a786}'..='\u{a786}', + '\u{a78b}'..='\u{a78b}', '\u{a78d}'..='\u{a78d}', '\u{a790}'..='\u{a790}', + '\u{a792}'..='\u{a792}', '\u{a796}'..='\u{a796}', '\u{a798}'..='\u{a798}', + '\u{a79a}'..='\u{a79a}', '\u{a79c}'..='\u{a79c}', '\u{a79e}'..='\u{a79e}', + '\u{a7a0}'..='\u{a7a0}', '\u{a7a2}'..='\u{a7a2}', '\u{a7a4}'..='\u{a7a4}', + '\u{a7a6}'..='\u{a7a6}', '\u{a7a8}'..='\u{a7a8}', '\u{a7aa}'..='\u{a7ae}', + '\u{a7b0}'..='\u{a7b4}', '\u{a7b6}'..='\u{a7b6}', '\u{a7b8}'..='\u{a7b8}', + '\u{a7ba}'..='\u{a7ba}', '\u{a7bc}'..='\u{a7bc}', '\u{a7be}'..='\u{a7be}', + '\u{a7c0}'..='\u{a7c0}', '\u{a7c2}'..='\u{a7c2}', '\u{a7c4}'..='\u{a7c7}', + '\u{a7c9}'..='\u{a7c9}', '\u{a7cb}'..='\u{a7cc}', '\u{a7ce}'..='\u{a7ce}', + '\u{a7d0}'..='\u{a7d0}', '\u{a7d2}'..='\u{a7d2}', '\u{a7d4}'..='\u{a7d4}', + '\u{a7d6}'..='\u{a7d6}', '\u{a7d8}'..='\u{a7d8}', '\u{a7da}'..='\u{a7da}', + '\u{a7dc}'..='\u{a7dc}', '\u{a7f5}'..='\u{a7f5}', '\u{ff21}'..='\u{ff3a}', + '\u{10400}'..='\u{10427}', '\u{104b0}'..='\u{104d3}', '\u{10570}'..='\u{1057a}', + '\u{1057c}'..='\u{1058a}', '\u{1058c}'..='\u{10592}', '\u{10594}'..='\u{10595}', + '\u{10c80}'..='\u{10cb2}', '\u{10d50}'..='\u{10d65}', '\u{118a0}'..='\u{118bf}', + '\u{16e40}'..='\u{16e5f}', '\u{16ea0}'..='\u{16eb8}', '\u{1d400}'..='\u{1d419}', + '\u{1d434}'..='\u{1d44d}', '\u{1d468}'..='\u{1d481}', '\u{1d49c}'..='\u{1d49c}', + '\u{1d49e}'..='\u{1d49f}', '\u{1d4a2}'..='\u{1d4a2}', '\u{1d4a5}'..='\u{1d4a6}', + '\u{1d4a9}'..='\u{1d4ac}', '\u{1d4ae}'..='\u{1d4b5}', '\u{1d4d0}'..='\u{1d4e9}', + '\u{1d504}'..='\u{1d505}', '\u{1d507}'..='\u{1d50a}', '\u{1d50d}'..='\u{1d514}', + '\u{1d516}'..='\u{1d51c}', '\u{1d538}'..='\u{1d539}', '\u{1d53b}'..='\u{1d53e}', + '\u{1d540}'..='\u{1d544}', '\u{1d546}'..='\u{1d546}', '\u{1d54a}'..='\u{1d550}', + '\u{1d56c}'..='\u{1d585}', '\u{1d5a0}'..='\u{1d5b9}', '\u{1d5d4}'..='\u{1d5ed}', + '\u{1d608}'..='\u{1d621}', '\u{1d63c}'..='\u{1d655}', '\u{1d670}'..='\u{1d689}', + '\u{1d6a8}'..='\u{1d6c0}', '\u{1d6e2}'..='\u{1d6fa}', '\u{1d71c}'..='\u{1d734}', + '\u{1d756}'..='\u{1d76e}', '\u{1d790}'..='\u{1d7a8}', '\u{1d7ca}'..='\u{1d7ca}', + '\u{1e900}'..='\u{1e921}', '\u{1f130}'..='\u{1f149}', '\u{1f150}'..='\u{1f169}', + '\u{1f170}'..='\u{1f189}', +]; + +#[rustfmt::skip] +pub(super) static WHITE_SPACE: &[RangeInclusive; 8] = &[ + '\u{85}'..='\u{85}', '\u{a0}'..='\u{a0}', '\u{1680}'..='\u{1680}', '\u{2000}'..='\u{200a}', + '\u{2028}'..='\u{2029}', '\u{202f}'..='\u{202f}', '\u{205f}'..='\u{205f}', + '\u{3000}'..='\u{3000}', +]; + +#[rustfmt::skip] +pub(super) static TO_LOWER: &[(char, [char; 3]); 1462] = &[ + ('\u{c0}', ['\u{e0}', '\u{0}', '\u{0}']), ('\u{c1}', ['\u{e1}', '\u{0}', '\u{0}']), + ('\u{c2}', ['\u{e2}', '\u{0}', '\u{0}']), ('\u{c3}', ['\u{e3}', '\u{0}', '\u{0}']), + ('\u{c4}', ['\u{e4}', '\u{0}', '\u{0}']), ('\u{c5}', ['\u{e5}', '\u{0}', '\u{0}']), + ('\u{c6}', ['\u{e6}', '\u{0}', '\u{0}']), ('\u{c7}', ['\u{e7}', '\u{0}', '\u{0}']), + ('\u{c8}', ['\u{e8}', '\u{0}', '\u{0}']), ('\u{c9}', ['\u{e9}', '\u{0}', '\u{0}']), + ('\u{ca}', ['\u{ea}', '\u{0}', '\u{0}']), ('\u{cb}', ['\u{eb}', '\u{0}', '\u{0}']), + ('\u{cc}', ['\u{ec}', '\u{0}', '\u{0}']), ('\u{cd}', ['\u{ed}', '\u{0}', '\u{0}']), + ('\u{ce}', ['\u{ee}', '\u{0}', '\u{0}']), ('\u{cf}', ['\u{ef}', '\u{0}', '\u{0}']), + ('\u{d0}', ['\u{f0}', '\u{0}', '\u{0}']), ('\u{d1}', ['\u{f1}', '\u{0}', '\u{0}']), + ('\u{d2}', ['\u{f2}', '\u{0}', '\u{0}']), ('\u{d3}', ['\u{f3}', '\u{0}', '\u{0}']), + ('\u{d4}', ['\u{f4}', '\u{0}', '\u{0}']), ('\u{d5}', ['\u{f5}', '\u{0}', '\u{0}']), + ('\u{d6}', ['\u{f6}', '\u{0}', '\u{0}']), ('\u{d8}', ['\u{f8}', '\u{0}', '\u{0}']), + ('\u{d9}', ['\u{f9}', '\u{0}', '\u{0}']), ('\u{da}', ['\u{fa}', '\u{0}', '\u{0}']), + ('\u{db}', ['\u{fb}', '\u{0}', '\u{0}']), ('\u{dc}', ['\u{fc}', '\u{0}', '\u{0}']), + ('\u{dd}', ['\u{fd}', '\u{0}', '\u{0}']), ('\u{de}', ['\u{fe}', '\u{0}', '\u{0}']), + ('\u{100}', ['\u{101}', '\u{0}', '\u{0}']), ('\u{102}', ['\u{103}', '\u{0}', '\u{0}']), + ('\u{104}', ['\u{105}', '\u{0}', '\u{0}']), ('\u{106}', ['\u{107}', '\u{0}', '\u{0}']), + ('\u{108}', ['\u{109}', '\u{0}', '\u{0}']), ('\u{10a}', ['\u{10b}', '\u{0}', '\u{0}']), + ('\u{10c}', ['\u{10d}', '\u{0}', '\u{0}']), ('\u{10e}', ['\u{10f}', '\u{0}', '\u{0}']), + ('\u{110}', ['\u{111}', '\u{0}', '\u{0}']), ('\u{112}', ['\u{113}', '\u{0}', '\u{0}']), + ('\u{114}', ['\u{115}', '\u{0}', '\u{0}']), ('\u{116}', ['\u{117}', '\u{0}', '\u{0}']), + ('\u{118}', ['\u{119}', '\u{0}', '\u{0}']), ('\u{11a}', ['\u{11b}', '\u{0}', '\u{0}']), + ('\u{11c}', ['\u{11d}', '\u{0}', '\u{0}']), ('\u{11e}', ['\u{11f}', '\u{0}', '\u{0}']), + ('\u{120}', ['\u{121}', '\u{0}', '\u{0}']), ('\u{122}', ['\u{123}', '\u{0}', '\u{0}']), + ('\u{124}', ['\u{125}', '\u{0}', '\u{0}']), ('\u{126}', ['\u{127}', '\u{0}', '\u{0}']), + ('\u{128}', ['\u{129}', '\u{0}', '\u{0}']), ('\u{12a}', ['\u{12b}', '\u{0}', '\u{0}']), + ('\u{12c}', ['\u{12d}', '\u{0}', '\u{0}']), ('\u{12e}', ['\u{12f}', '\u{0}', '\u{0}']), + ('\u{130}', ['i', '\u{307}', '\u{0}']), ('\u{132}', ['\u{133}', '\u{0}', '\u{0}']), + ('\u{134}', ['\u{135}', '\u{0}', '\u{0}']), ('\u{136}', ['\u{137}', '\u{0}', '\u{0}']), + ('\u{139}', ['\u{13a}', '\u{0}', '\u{0}']), ('\u{13b}', ['\u{13c}', '\u{0}', '\u{0}']), + ('\u{13d}', ['\u{13e}', '\u{0}', '\u{0}']), ('\u{13f}', ['\u{140}', '\u{0}', '\u{0}']), + ('\u{141}', ['\u{142}', '\u{0}', '\u{0}']), ('\u{143}', ['\u{144}', '\u{0}', '\u{0}']), + ('\u{145}', ['\u{146}', '\u{0}', '\u{0}']), ('\u{147}', ['\u{148}', '\u{0}', '\u{0}']), + ('\u{14a}', ['\u{14b}', '\u{0}', '\u{0}']), ('\u{14c}', ['\u{14d}', '\u{0}', '\u{0}']), + ('\u{14e}', ['\u{14f}', '\u{0}', '\u{0}']), ('\u{150}', ['\u{151}', '\u{0}', '\u{0}']), + ('\u{152}', ['\u{153}', '\u{0}', '\u{0}']), ('\u{154}', ['\u{155}', '\u{0}', '\u{0}']), + ('\u{156}', ['\u{157}', '\u{0}', '\u{0}']), ('\u{158}', ['\u{159}', '\u{0}', '\u{0}']), + ('\u{15a}', ['\u{15b}', '\u{0}', '\u{0}']), ('\u{15c}', ['\u{15d}', '\u{0}', '\u{0}']), + ('\u{15e}', ['\u{15f}', '\u{0}', '\u{0}']), ('\u{160}', ['\u{161}', '\u{0}', '\u{0}']), + ('\u{162}', ['\u{163}', '\u{0}', '\u{0}']), ('\u{164}', ['\u{165}', '\u{0}', '\u{0}']), + ('\u{166}', ['\u{167}', '\u{0}', '\u{0}']), ('\u{168}', ['\u{169}', '\u{0}', '\u{0}']), + ('\u{16a}', ['\u{16b}', '\u{0}', '\u{0}']), ('\u{16c}', ['\u{16d}', '\u{0}', '\u{0}']), + ('\u{16e}', ['\u{16f}', '\u{0}', '\u{0}']), ('\u{170}', ['\u{171}', '\u{0}', '\u{0}']), + ('\u{172}', ['\u{173}', '\u{0}', '\u{0}']), ('\u{174}', ['\u{175}', '\u{0}', '\u{0}']), + ('\u{176}', ['\u{177}', '\u{0}', '\u{0}']), ('\u{178}', ['\u{ff}', '\u{0}', '\u{0}']), + ('\u{179}', ['\u{17a}', '\u{0}', '\u{0}']), ('\u{17b}', ['\u{17c}', '\u{0}', '\u{0}']), + ('\u{17d}', ['\u{17e}', '\u{0}', '\u{0}']), ('\u{181}', ['\u{253}', '\u{0}', '\u{0}']), + ('\u{182}', ['\u{183}', '\u{0}', '\u{0}']), ('\u{184}', ['\u{185}', '\u{0}', '\u{0}']), + ('\u{186}', ['\u{254}', '\u{0}', '\u{0}']), ('\u{187}', ['\u{188}', '\u{0}', '\u{0}']), + ('\u{189}', ['\u{256}', '\u{0}', '\u{0}']), ('\u{18a}', ['\u{257}', '\u{0}', '\u{0}']), + ('\u{18b}', ['\u{18c}', '\u{0}', '\u{0}']), ('\u{18e}', ['\u{1dd}', '\u{0}', '\u{0}']), + ('\u{18f}', ['\u{259}', '\u{0}', '\u{0}']), ('\u{190}', ['\u{25b}', '\u{0}', '\u{0}']), + ('\u{191}', ['\u{192}', '\u{0}', '\u{0}']), ('\u{193}', ['\u{260}', '\u{0}', '\u{0}']), + ('\u{194}', ['\u{263}', '\u{0}', '\u{0}']), ('\u{196}', ['\u{269}', '\u{0}', '\u{0}']), + ('\u{197}', ['\u{268}', '\u{0}', '\u{0}']), ('\u{198}', ['\u{199}', '\u{0}', '\u{0}']), + ('\u{19c}', ['\u{26f}', '\u{0}', '\u{0}']), ('\u{19d}', ['\u{272}', '\u{0}', '\u{0}']), + ('\u{19f}', ['\u{275}', '\u{0}', '\u{0}']), ('\u{1a0}', ['\u{1a1}', '\u{0}', '\u{0}']), + ('\u{1a2}', ['\u{1a3}', '\u{0}', '\u{0}']), ('\u{1a4}', ['\u{1a5}', '\u{0}', '\u{0}']), + ('\u{1a6}', ['\u{280}', '\u{0}', '\u{0}']), ('\u{1a7}', ['\u{1a8}', '\u{0}', '\u{0}']), + ('\u{1a9}', ['\u{283}', '\u{0}', '\u{0}']), ('\u{1ac}', ['\u{1ad}', '\u{0}', '\u{0}']), + ('\u{1ae}', ['\u{288}', '\u{0}', '\u{0}']), ('\u{1af}', ['\u{1b0}', '\u{0}', '\u{0}']), + ('\u{1b1}', ['\u{28a}', '\u{0}', '\u{0}']), ('\u{1b2}', ['\u{28b}', '\u{0}', '\u{0}']), + ('\u{1b3}', ['\u{1b4}', '\u{0}', '\u{0}']), ('\u{1b5}', ['\u{1b6}', '\u{0}', '\u{0}']), + ('\u{1b7}', ['\u{292}', '\u{0}', '\u{0}']), ('\u{1b8}', ['\u{1b9}', '\u{0}', '\u{0}']), + ('\u{1bc}', ['\u{1bd}', '\u{0}', '\u{0}']), ('\u{1c4}', ['\u{1c6}', '\u{0}', '\u{0}']), + ('\u{1c5}', ['\u{1c6}', '\u{0}', '\u{0}']), ('\u{1c7}', ['\u{1c9}', '\u{0}', '\u{0}']), + ('\u{1c8}', ['\u{1c9}', '\u{0}', '\u{0}']), ('\u{1ca}', ['\u{1cc}', '\u{0}', '\u{0}']), + ('\u{1cb}', ['\u{1cc}', '\u{0}', '\u{0}']), ('\u{1cd}', ['\u{1ce}', '\u{0}', '\u{0}']), + ('\u{1cf}', ['\u{1d0}', '\u{0}', '\u{0}']), ('\u{1d1}', ['\u{1d2}', '\u{0}', '\u{0}']), + ('\u{1d3}', ['\u{1d4}', '\u{0}', '\u{0}']), ('\u{1d5}', ['\u{1d6}', '\u{0}', '\u{0}']), + ('\u{1d7}', ['\u{1d8}', '\u{0}', '\u{0}']), ('\u{1d9}', ['\u{1da}', '\u{0}', '\u{0}']), + ('\u{1db}', ['\u{1dc}', '\u{0}', '\u{0}']), ('\u{1de}', ['\u{1df}', '\u{0}', '\u{0}']), + ('\u{1e0}', ['\u{1e1}', '\u{0}', '\u{0}']), ('\u{1e2}', ['\u{1e3}', '\u{0}', '\u{0}']), + ('\u{1e4}', ['\u{1e5}', '\u{0}', '\u{0}']), ('\u{1e6}', ['\u{1e7}', '\u{0}', '\u{0}']), + ('\u{1e8}', ['\u{1e9}', '\u{0}', '\u{0}']), ('\u{1ea}', ['\u{1eb}', '\u{0}', '\u{0}']), + ('\u{1ec}', ['\u{1ed}', '\u{0}', '\u{0}']), ('\u{1ee}', ['\u{1ef}', '\u{0}', '\u{0}']), + ('\u{1f1}', ['\u{1f3}', '\u{0}', '\u{0}']), ('\u{1f2}', ['\u{1f3}', '\u{0}', '\u{0}']), + ('\u{1f4}', ['\u{1f5}', '\u{0}', '\u{0}']), ('\u{1f6}', ['\u{195}', '\u{0}', '\u{0}']), + ('\u{1f7}', ['\u{1bf}', '\u{0}', '\u{0}']), ('\u{1f8}', ['\u{1f9}', '\u{0}', '\u{0}']), + ('\u{1fa}', ['\u{1fb}', '\u{0}', '\u{0}']), ('\u{1fc}', ['\u{1fd}', '\u{0}', '\u{0}']), + ('\u{1fe}', ['\u{1ff}', '\u{0}', '\u{0}']), ('\u{200}', ['\u{201}', '\u{0}', '\u{0}']), + ('\u{202}', ['\u{203}', '\u{0}', '\u{0}']), ('\u{204}', ['\u{205}', '\u{0}', '\u{0}']), + ('\u{206}', ['\u{207}', '\u{0}', '\u{0}']), ('\u{208}', ['\u{209}', '\u{0}', '\u{0}']), + ('\u{20a}', ['\u{20b}', '\u{0}', '\u{0}']), ('\u{20c}', ['\u{20d}', '\u{0}', '\u{0}']), + ('\u{20e}', ['\u{20f}', '\u{0}', '\u{0}']), ('\u{210}', ['\u{211}', '\u{0}', '\u{0}']), + ('\u{212}', ['\u{213}', '\u{0}', '\u{0}']), ('\u{214}', ['\u{215}', '\u{0}', '\u{0}']), + ('\u{216}', ['\u{217}', '\u{0}', '\u{0}']), ('\u{218}', ['\u{219}', '\u{0}', '\u{0}']), + ('\u{21a}', ['\u{21b}', '\u{0}', '\u{0}']), ('\u{21c}', ['\u{21d}', '\u{0}', '\u{0}']), + ('\u{21e}', ['\u{21f}', '\u{0}', '\u{0}']), ('\u{220}', ['\u{19e}', '\u{0}', '\u{0}']), + ('\u{222}', ['\u{223}', '\u{0}', '\u{0}']), ('\u{224}', ['\u{225}', '\u{0}', '\u{0}']), + ('\u{226}', ['\u{227}', '\u{0}', '\u{0}']), ('\u{228}', ['\u{229}', '\u{0}', '\u{0}']), + ('\u{22a}', ['\u{22b}', '\u{0}', '\u{0}']), ('\u{22c}', ['\u{22d}', '\u{0}', '\u{0}']), + ('\u{22e}', ['\u{22f}', '\u{0}', '\u{0}']), ('\u{230}', ['\u{231}', '\u{0}', '\u{0}']), + ('\u{232}', ['\u{233}', '\u{0}', '\u{0}']), ('\u{23a}', ['\u{2c65}', '\u{0}', '\u{0}']), + ('\u{23b}', ['\u{23c}', '\u{0}', '\u{0}']), ('\u{23d}', ['\u{19a}', '\u{0}', '\u{0}']), + ('\u{23e}', ['\u{2c66}', '\u{0}', '\u{0}']), ('\u{241}', ['\u{242}', '\u{0}', '\u{0}']), + ('\u{243}', ['\u{180}', '\u{0}', '\u{0}']), ('\u{244}', ['\u{289}', '\u{0}', '\u{0}']), + ('\u{245}', ['\u{28c}', '\u{0}', '\u{0}']), ('\u{246}', ['\u{247}', '\u{0}', '\u{0}']), + ('\u{248}', ['\u{249}', '\u{0}', '\u{0}']), ('\u{24a}', ['\u{24b}', '\u{0}', '\u{0}']), + ('\u{24c}', ['\u{24d}', '\u{0}', '\u{0}']), ('\u{24e}', ['\u{24f}', '\u{0}', '\u{0}']), + ('\u{370}', ['\u{371}', '\u{0}', '\u{0}']), ('\u{372}', ['\u{373}', '\u{0}', '\u{0}']), + ('\u{376}', ['\u{377}', '\u{0}', '\u{0}']), ('\u{37f}', ['\u{3f3}', '\u{0}', '\u{0}']), + ('\u{386}', ['\u{3ac}', '\u{0}', '\u{0}']), ('\u{388}', ['\u{3ad}', '\u{0}', '\u{0}']), + ('\u{389}', ['\u{3ae}', '\u{0}', '\u{0}']), ('\u{38a}', ['\u{3af}', '\u{0}', '\u{0}']), + ('\u{38c}', ['\u{3cc}', '\u{0}', '\u{0}']), ('\u{38e}', ['\u{3cd}', '\u{0}', '\u{0}']), + ('\u{38f}', ['\u{3ce}', '\u{0}', '\u{0}']), ('\u{391}', ['\u{3b1}', '\u{0}', '\u{0}']), + ('\u{392}', ['\u{3b2}', '\u{0}', '\u{0}']), ('\u{393}', ['\u{3b3}', '\u{0}', '\u{0}']), + ('\u{394}', ['\u{3b4}', '\u{0}', '\u{0}']), ('\u{395}', ['\u{3b5}', '\u{0}', '\u{0}']), + ('\u{396}', ['\u{3b6}', '\u{0}', '\u{0}']), ('\u{397}', ['\u{3b7}', '\u{0}', '\u{0}']), + ('\u{398}', ['\u{3b8}', '\u{0}', '\u{0}']), ('\u{399}', ['\u{3b9}', '\u{0}', '\u{0}']), + ('\u{39a}', ['\u{3ba}', '\u{0}', '\u{0}']), ('\u{39b}', ['\u{3bb}', '\u{0}', '\u{0}']), + ('\u{39c}', ['\u{3bc}', '\u{0}', '\u{0}']), ('\u{39d}', ['\u{3bd}', '\u{0}', '\u{0}']), + ('\u{39e}', ['\u{3be}', '\u{0}', '\u{0}']), ('\u{39f}', ['\u{3bf}', '\u{0}', '\u{0}']), + ('\u{3a0}', ['\u{3c0}', '\u{0}', '\u{0}']), ('\u{3a1}', ['\u{3c1}', '\u{0}', '\u{0}']), + ('\u{3a3}', ['\u{3c3}', '\u{0}', '\u{0}']), ('\u{3a4}', ['\u{3c4}', '\u{0}', '\u{0}']), + ('\u{3a5}', ['\u{3c5}', '\u{0}', '\u{0}']), ('\u{3a6}', ['\u{3c6}', '\u{0}', '\u{0}']), + ('\u{3a7}', ['\u{3c7}', '\u{0}', '\u{0}']), ('\u{3a8}', ['\u{3c8}', '\u{0}', '\u{0}']), + ('\u{3a9}', ['\u{3c9}', '\u{0}', '\u{0}']), ('\u{3aa}', ['\u{3ca}', '\u{0}', '\u{0}']), + ('\u{3ab}', ['\u{3cb}', '\u{0}', '\u{0}']), ('\u{3cf}', ['\u{3d7}', '\u{0}', '\u{0}']), + ('\u{3d8}', ['\u{3d9}', '\u{0}', '\u{0}']), ('\u{3da}', ['\u{3db}', '\u{0}', '\u{0}']), + ('\u{3dc}', ['\u{3dd}', '\u{0}', '\u{0}']), ('\u{3de}', ['\u{3df}', '\u{0}', '\u{0}']), + ('\u{3e0}', ['\u{3e1}', '\u{0}', '\u{0}']), ('\u{3e2}', ['\u{3e3}', '\u{0}', '\u{0}']), + ('\u{3e4}', ['\u{3e5}', '\u{0}', '\u{0}']), ('\u{3e6}', ['\u{3e7}', '\u{0}', '\u{0}']), + ('\u{3e8}', ['\u{3e9}', '\u{0}', '\u{0}']), ('\u{3ea}', ['\u{3eb}', '\u{0}', '\u{0}']), + ('\u{3ec}', ['\u{3ed}', '\u{0}', '\u{0}']), ('\u{3ee}', ['\u{3ef}', '\u{0}', '\u{0}']), + ('\u{3f4}', ['\u{3b8}', '\u{0}', '\u{0}']), ('\u{3f7}', ['\u{3f8}', '\u{0}', '\u{0}']), + ('\u{3f9}', ['\u{3f2}', '\u{0}', '\u{0}']), ('\u{3fa}', ['\u{3fb}', '\u{0}', '\u{0}']), + ('\u{3fd}', ['\u{37b}', '\u{0}', '\u{0}']), ('\u{3fe}', ['\u{37c}', '\u{0}', '\u{0}']), + ('\u{3ff}', ['\u{37d}', '\u{0}', '\u{0}']), ('\u{400}', ['\u{450}', '\u{0}', '\u{0}']), + ('\u{401}', ['\u{451}', '\u{0}', '\u{0}']), ('\u{402}', ['\u{452}', '\u{0}', '\u{0}']), + ('\u{403}', ['\u{453}', '\u{0}', '\u{0}']), ('\u{404}', ['\u{454}', '\u{0}', '\u{0}']), + ('\u{405}', ['\u{455}', '\u{0}', '\u{0}']), ('\u{406}', ['\u{456}', '\u{0}', '\u{0}']), + ('\u{407}', ['\u{457}', '\u{0}', '\u{0}']), ('\u{408}', ['\u{458}', '\u{0}', '\u{0}']), + ('\u{409}', ['\u{459}', '\u{0}', '\u{0}']), ('\u{40a}', ['\u{45a}', '\u{0}', '\u{0}']), + ('\u{40b}', ['\u{45b}', '\u{0}', '\u{0}']), ('\u{40c}', ['\u{45c}', '\u{0}', '\u{0}']), + ('\u{40d}', ['\u{45d}', '\u{0}', '\u{0}']), ('\u{40e}', ['\u{45e}', '\u{0}', '\u{0}']), + ('\u{40f}', ['\u{45f}', '\u{0}', '\u{0}']), ('\u{410}', ['\u{430}', '\u{0}', '\u{0}']), + ('\u{411}', ['\u{431}', '\u{0}', '\u{0}']), ('\u{412}', ['\u{432}', '\u{0}', '\u{0}']), + ('\u{413}', ['\u{433}', '\u{0}', '\u{0}']), ('\u{414}', ['\u{434}', '\u{0}', '\u{0}']), + ('\u{415}', ['\u{435}', '\u{0}', '\u{0}']), ('\u{416}', ['\u{436}', '\u{0}', '\u{0}']), + ('\u{417}', ['\u{437}', '\u{0}', '\u{0}']), ('\u{418}', ['\u{438}', '\u{0}', '\u{0}']), + ('\u{419}', ['\u{439}', '\u{0}', '\u{0}']), ('\u{41a}', ['\u{43a}', '\u{0}', '\u{0}']), + ('\u{41b}', ['\u{43b}', '\u{0}', '\u{0}']), ('\u{41c}', ['\u{43c}', '\u{0}', '\u{0}']), + ('\u{41d}', ['\u{43d}', '\u{0}', '\u{0}']), ('\u{41e}', ['\u{43e}', '\u{0}', '\u{0}']), + ('\u{41f}', ['\u{43f}', '\u{0}', '\u{0}']), ('\u{420}', ['\u{440}', '\u{0}', '\u{0}']), + ('\u{421}', ['\u{441}', '\u{0}', '\u{0}']), ('\u{422}', ['\u{442}', '\u{0}', '\u{0}']), + ('\u{423}', ['\u{443}', '\u{0}', '\u{0}']), ('\u{424}', ['\u{444}', '\u{0}', '\u{0}']), + ('\u{425}', ['\u{445}', '\u{0}', '\u{0}']), ('\u{426}', ['\u{446}', '\u{0}', '\u{0}']), + ('\u{427}', ['\u{447}', '\u{0}', '\u{0}']), ('\u{428}', ['\u{448}', '\u{0}', '\u{0}']), + ('\u{429}', ['\u{449}', '\u{0}', '\u{0}']), ('\u{42a}', ['\u{44a}', '\u{0}', '\u{0}']), + ('\u{42b}', ['\u{44b}', '\u{0}', '\u{0}']), ('\u{42c}', ['\u{44c}', '\u{0}', '\u{0}']), + ('\u{42d}', ['\u{44d}', '\u{0}', '\u{0}']), ('\u{42e}', ['\u{44e}', '\u{0}', '\u{0}']), + ('\u{42f}', ['\u{44f}', '\u{0}', '\u{0}']), ('\u{460}', ['\u{461}', '\u{0}', '\u{0}']), + ('\u{462}', ['\u{463}', '\u{0}', '\u{0}']), ('\u{464}', ['\u{465}', '\u{0}', '\u{0}']), + ('\u{466}', ['\u{467}', '\u{0}', '\u{0}']), ('\u{468}', ['\u{469}', '\u{0}', '\u{0}']), + ('\u{46a}', ['\u{46b}', '\u{0}', '\u{0}']), ('\u{46c}', ['\u{46d}', '\u{0}', '\u{0}']), + ('\u{46e}', ['\u{46f}', '\u{0}', '\u{0}']), ('\u{470}', ['\u{471}', '\u{0}', '\u{0}']), + ('\u{472}', ['\u{473}', '\u{0}', '\u{0}']), ('\u{474}', ['\u{475}', '\u{0}', '\u{0}']), + ('\u{476}', ['\u{477}', '\u{0}', '\u{0}']), ('\u{478}', ['\u{479}', '\u{0}', '\u{0}']), + ('\u{47a}', ['\u{47b}', '\u{0}', '\u{0}']), ('\u{47c}', ['\u{47d}', '\u{0}', '\u{0}']), + ('\u{47e}', ['\u{47f}', '\u{0}', '\u{0}']), ('\u{480}', ['\u{481}', '\u{0}', '\u{0}']), + ('\u{48a}', ['\u{48b}', '\u{0}', '\u{0}']), ('\u{48c}', ['\u{48d}', '\u{0}', '\u{0}']), + ('\u{48e}', ['\u{48f}', '\u{0}', '\u{0}']), ('\u{490}', ['\u{491}', '\u{0}', '\u{0}']), + ('\u{492}', ['\u{493}', '\u{0}', '\u{0}']), ('\u{494}', ['\u{495}', '\u{0}', '\u{0}']), + ('\u{496}', ['\u{497}', '\u{0}', '\u{0}']), ('\u{498}', ['\u{499}', '\u{0}', '\u{0}']), + ('\u{49a}', ['\u{49b}', '\u{0}', '\u{0}']), ('\u{49c}', ['\u{49d}', '\u{0}', '\u{0}']), + ('\u{49e}', ['\u{49f}', '\u{0}', '\u{0}']), ('\u{4a0}', ['\u{4a1}', '\u{0}', '\u{0}']), + ('\u{4a2}', ['\u{4a3}', '\u{0}', '\u{0}']), ('\u{4a4}', ['\u{4a5}', '\u{0}', '\u{0}']), + ('\u{4a6}', ['\u{4a7}', '\u{0}', '\u{0}']), ('\u{4a8}', ['\u{4a9}', '\u{0}', '\u{0}']), + ('\u{4aa}', ['\u{4ab}', '\u{0}', '\u{0}']), ('\u{4ac}', ['\u{4ad}', '\u{0}', '\u{0}']), + ('\u{4ae}', ['\u{4af}', '\u{0}', '\u{0}']), ('\u{4b0}', ['\u{4b1}', '\u{0}', '\u{0}']), + ('\u{4b2}', ['\u{4b3}', '\u{0}', '\u{0}']), ('\u{4b4}', ['\u{4b5}', '\u{0}', '\u{0}']), + ('\u{4b6}', ['\u{4b7}', '\u{0}', '\u{0}']), ('\u{4b8}', ['\u{4b9}', '\u{0}', '\u{0}']), + ('\u{4ba}', ['\u{4bb}', '\u{0}', '\u{0}']), ('\u{4bc}', ['\u{4bd}', '\u{0}', '\u{0}']), + ('\u{4be}', ['\u{4bf}', '\u{0}', '\u{0}']), ('\u{4c0}', ['\u{4cf}', '\u{0}', '\u{0}']), + ('\u{4c1}', ['\u{4c2}', '\u{0}', '\u{0}']), ('\u{4c3}', ['\u{4c4}', '\u{0}', '\u{0}']), + ('\u{4c5}', ['\u{4c6}', '\u{0}', '\u{0}']), ('\u{4c7}', ['\u{4c8}', '\u{0}', '\u{0}']), + ('\u{4c9}', ['\u{4ca}', '\u{0}', '\u{0}']), ('\u{4cb}', ['\u{4cc}', '\u{0}', '\u{0}']), + ('\u{4cd}', ['\u{4ce}', '\u{0}', '\u{0}']), ('\u{4d0}', ['\u{4d1}', '\u{0}', '\u{0}']), + ('\u{4d2}', ['\u{4d3}', '\u{0}', '\u{0}']), ('\u{4d4}', ['\u{4d5}', '\u{0}', '\u{0}']), + ('\u{4d6}', ['\u{4d7}', '\u{0}', '\u{0}']), ('\u{4d8}', ['\u{4d9}', '\u{0}', '\u{0}']), + ('\u{4da}', ['\u{4db}', '\u{0}', '\u{0}']), ('\u{4dc}', ['\u{4dd}', '\u{0}', '\u{0}']), + ('\u{4de}', ['\u{4df}', '\u{0}', '\u{0}']), ('\u{4e0}', ['\u{4e1}', '\u{0}', '\u{0}']), + ('\u{4e2}', ['\u{4e3}', '\u{0}', '\u{0}']), ('\u{4e4}', ['\u{4e5}', '\u{0}', '\u{0}']), + ('\u{4e6}', ['\u{4e7}', '\u{0}', '\u{0}']), ('\u{4e8}', ['\u{4e9}', '\u{0}', '\u{0}']), + ('\u{4ea}', ['\u{4eb}', '\u{0}', '\u{0}']), ('\u{4ec}', ['\u{4ed}', '\u{0}', '\u{0}']), + ('\u{4ee}', ['\u{4ef}', '\u{0}', '\u{0}']), ('\u{4f0}', ['\u{4f1}', '\u{0}', '\u{0}']), + ('\u{4f2}', ['\u{4f3}', '\u{0}', '\u{0}']), ('\u{4f4}', ['\u{4f5}', '\u{0}', '\u{0}']), + ('\u{4f6}', ['\u{4f7}', '\u{0}', '\u{0}']), ('\u{4f8}', ['\u{4f9}', '\u{0}', '\u{0}']), + ('\u{4fa}', ['\u{4fb}', '\u{0}', '\u{0}']), ('\u{4fc}', ['\u{4fd}', '\u{0}', '\u{0}']), + ('\u{4fe}', ['\u{4ff}', '\u{0}', '\u{0}']), ('\u{500}', ['\u{501}', '\u{0}', '\u{0}']), + ('\u{502}', ['\u{503}', '\u{0}', '\u{0}']), ('\u{504}', ['\u{505}', '\u{0}', '\u{0}']), + ('\u{506}', ['\u{507}', '\u{0}', '\u{0}']), ('\u{508}', ['\u{509}', '\u{0}', '\u{0}']), + ('\u{50a}', ['\u{50b}', '\u{0}', '\u{0}']), ('\u{50c}', ['\u{50d}', '\u{0}', '\u{0}']), + ('\u{50e}', ['\u{50f}', '\u{0}', '\u{0}']), ('\u{510}', ['\u{511}', '\u{0}', '\u{0}']), + ('\u{512}', ['\u{513}', '\u{0}', '\u{0}']), ('\u{514}', ['\u{515}', '\u{0}', '\u{0}']), + ('\u{516}', ['\u{517}', '\u{0}', '\u{0}']), ('\u{518}', ['\u{519}', '\u{0}', '\u{0}']), + ('\u{51a}', ['\u{51b}', '\u{0}', '\u{0}']), ('\u{51c}', ['\u{51d}', '\u{0}', '\u{0}']), + ('\u{51e}', ['\u{51f}', '\u{0}', '\u{0}']), ('\u{520}', ['\u{521}', '\u{0}', '\u{0}']), + ('\u{522}', ['\u{523}', '\u{0}', '\u{0}']), ('\u{524}', ['\u{525}', '\u{0}', '\u{0}']), + ('\u{526}', ['\u{527}', '\u{0}', '\u{0}']), ('\u{528}', ['\u{529}', '\u{0}', '\u{0}']), + ('\u{52a}', ['\u{52b}', '\u{0}', '\u{0}']), ('\u{52c}', ['\u{52d}', '\u{0}', '\u{0}']), + ('\u{52e}', ['\u{52f}', '\u{0}', '\u{0}']), ('\u{531}', ['\u{561}', '\u{0}', '\u{0}']), + ('\u{532}', ['\u{562}', '\u{0}', '\u{0}']), ('\u{533}', ['\u{563}', '\u{0}', '\u{0}']), + ('\u{534}', ['\u{564}', '\u{0}', '\u{0}']), ('\u{535}', ['\u{565}', '\u{0}', '\u{0}']), + ('\u{536}', ['\u{566}', '\u{0}', '\u{0}']), ('\u{537}', ['\u{567}', '\u{0}', '\u{0}']), + ('\u{538}', ['\u{568}', '\u{0}', '\u{0}']), ('\u{539}', ['\u{569}', '\u{0}', '\u{0}']), + ('\u{53a}', ['\u{56a}', '\u{0}', '\u{0}']), ('\u{53b}', ['\u{56b}', '\u{0}', '\u{0}']), + ('\u{53c}', ['\u{56c}', '\u{0}', '\u{0}']), ('\u{53d}', ['\u{56d}', '\u{0}', '\u{0}']), + ('\u{53e}', ['\u{56e}', '\u{0}', '\u{0}']), ('\u{53f}', ['\u{56f}', '\u{0}', '\u{0}']), + ('\u{540}', ['\u{570}', '\u{0}', '\u{0}']), ('\u{541}', ['\u{571}', '\u{0}', '\u{0}']), + ('\u{542}', ['\u{572}', '\u{0}', '\u{0}']), ('\u{543}', ['\u{573}', '\u{0}', '\u{0}']), + ('\u{544}', ['\u{574}', '\u{0}', '\u{0}']), ('\u{545}', ['\u{575}', '\u{0}', '\u{0}']), + ('\u{546}', ['\u{576}', '\u{0}', '\u{0}']), ('\u{547}', ['\u{577}', '\u{0}', '\u{0}']), + ('\u{548}', ['\u{578}', '\u{0}', '\u{0}']), ('\u{549}', ['\u{579}', '\u{0}', '\u{0}']), + ('\u{54a}', ['\u{57a}', '\u{0}', '\u{0}']), ('\u{54b}', ['\u{57b}', '\u{0}', '\u{0}']), + ('\u{54c}', ['\u{57c}', '\u{0}', '\u{0}']), ('\u{54d}', ['\u{57d}', '\u{0}', '\u{0}']), + ('\u{54e}', ['\u{57e}', '\u{0}', '\u{0}']), ('\u{54f}', ['\u{57f}', '\u{0}', '\u{0}']), + ('\u{550}', ['\u{580}', '\u{0}', '\u{0}']), ('\u{551}', ['\u{581}', '\u{0}', '\u{0}']), + ('\u{552}', ['\u{582}', '\u{0}', '\u{0}']), ('\u{553}', ['\u{583}', '\u{0}', '\u{0}']), + ('\u{554}', ['\u{584}', '\u{0}', '\u{0}']), ('\u{555}', ['\u{585}', '\u{0}', '\u{0}']), + ('\u{556}', ['\u{586}', '\u{0}', '\u{0}']), ('\u{10a0}', ['\u{2d00}', '\u{0}', '\u{0}']), + ('\u{10a1}', ['\u{2d01}', '\u{0}', '\u{0}']), ('\u{10a2}', ['\u{2d02}', '\u{0}', '\u{0}']), + ('\u{10a3}', ['\u{2d03}', '\u{0}', '\u{0}']), ('\u{10a4}', ['\u{2d04}', '\u{0}', '\u{0}']), + ('\u{10a5}', ['\u{2d05}', '\u{0}', '\u{0}']), ('\u{10a6}', ['\u{2d06}', '\u{0}', '\u{0}']), + ('\u{10a7}', ['\u{2d07}', '\u{0}', '\u{0}']), ('\u{10a8}', ['\u{2d08}', '\u{0}', '\u{0}']), + ('\u{10a9}', ['\u{2d09}', '\u{0}', '\u{0}']), ('\u{10aa}', ['\u{2d0a}', '\u{0}', '\u{0}']), + ('\u{10ab}', ['\u{2d0b}', '\u{0}', '\u{0}']), ('\u{10ac}', ['\u{2d0c}', '\u{0}', '\u{0}']), + ('\u{10ad}', ['\u{2d0d}', '\u{0}', '\u{0}']), ('\u{10ae}', ['\u{2d0e}', '\u{0}', '\u{0}']), + ('\u{10af}', ['\u{2d0f}', '\u{0}', '\u{0}']), ('\u{10b0}', ['\u{2d10}', '\u{0}', '\u{0}']), + ('\u{10b1}', ['\u{2d11}', '\u{0}', '\u{0}']), ('\u{10b2}', ['\u{2d12}', '\u{0}', '\u{0}']), + ('\u{10b3}', ['\u{2d13}', '\u{0}', '\u{0}']), ('\u{10b4}', ['\u{2d14}', '\u{0}', '\u{0}']), + ('\u{10b5}', ['\u{2d15}', '\u{0}', '\u{0}']), ('\u{10b6}', ['\u{2d16}', '\u{0}', '\u{0}']), + ('\u{10b7}', ['\u{2d17}', '\u{0}', '\u{0}']), ('\u{10b8}', ['\u{2d18}', '\u{0}', '\u{0}']), + ('\u{10b9}', ['\u{2d19}', '\u{0}', '\u{0}']), ('\u{10ba}', ['\u{2d1a}', '\u{0}', '\u{0}']), + ('\u{10bb}', ['\u{2d1b}', '\u{0}', '\u{0}']), ('\u{10bc}', ['\u{2d1c}', '\u{0}', '\u{0}']), + ('\u{10bd}', ['\u{2d1d}', '\u{0}', '\u{0}']), ('\u{10be}', ['\u{2d1e}', '\u{0}', '\u{0}']), + ('\u{10bf}', ['\u{2d1f}', '\u{0}', '\u{0}']), ('\u{10c0}', ['\u{2d20}', '\u{0}', '\u{0}']), + ('\u{10c1}', ['\u{2d21}', '\u{0}', '\u{0}']), ('\u{10c2}', ['\u{2d22}', '\u{0}', '\u{0}']), + ('\u{10c3}', ['\u{2d23}', '\u{0}', '\u{0}']), ('\u{10c4}', ['\u{2d24}', '\u{0}', '\u{0}']), + ('\u{10c5}', ['\u{2d25}', '\u{0}', '\u{0}']), ('\u{10c7}', ['\u{2d27}', '\u{0}', '\u{0}']), + ('\u{10cd}', ['\u{2d2d}', '\u{0}', '\u{0}']), ('\u{13a0}', ['\u{ab70}', '\u{0}', '\u{0}']), + ('\u{13a1}', ['\u{ab71}', '\u{0}', '\u{0}']), ('\u{13a2}', ['\u{ab72}', '\u{0}', '\u{0}']), + ('\u{13a3}', ['\u{ab73}', '\u{0}', '\u{0}']), ('\u{13a4}', ['\u{ab74}', '\u{0}', '\u{0}']), + ('\u{13a5}', ['\u{ab75}', '\u{0}', '\u{0}']), ('\u{13a6}', ['\u{ab76}', '\u{0}', '\u{0}']), + ('\u{13a7}', ['\u{ab77}', '\u{0}', '\u{0}']), ('\u{13a8}', ['\u{ab78}', '\u{0}', '\u{0}']), + ('\u{13a9}', ['\u{ab79}', '\u{0}', '\u{0}']), ('\u{13aa}', ['\u{ab7a}', '\u{0}', '\u{0}']), + ('\u{13ab}', ['\u{ab7b}', '\u{0}', '\u{0}']), ('\u{13ac}', ['\u{ab7c}', '\u{0}', '\u{0}']), + ('\u{13ad}', ['\u{ab7d}', '\u{0}', '\u{0}']), ('\u{13ae}', ['\u{ab7e}', '\u{0}', '\u{0}']), + ('\u{13af}', ['\u{ab7f}', '\u{0}', '\u{0}']), ('\u{13b0}', ['\u{ab80}', '\u{0}', '\u{0}']), + ('\u{13b1}', ['\u{ab81}', '\u{0}', '\u{0}']), ('\u{13b2}', ['\u{ab82}', '\u{0}', '\u{0}']), + ('\u{13b3}', ['\u{ab83}', '\u{0}', '\u{0}']), ('\u{13b4}', ['\u{ab84}', '\u{0}', '\u{0}']), + ('\u{13b5}', ['\u{ab85}', '\u{0}', '\u{0}']), ('\u{13b6}', ['\u{ab86}', '\u{0}', '\u{0}']), + ('\u{13b7}', ['\u{ab87}', '\u{0}', '\u{0}']), ('\u{13b8}', ['\u{ab88}', '\u{0}', '\u{0}']), + ('\u{13b9}', ['\u{ab89}', '\u{0}', '\u{0}']), ('\u{13ba}', ['\u{ab8a}', '\u{0}', '\u{0}']), + ('\u{13bb}', ['\u{ab8b}', '\u{0}', '\u{0}']), ('\u{13bc}', ['\u{ab8c}', '\u{0}', '\u{0}']), + ('\u{13bd}', ['\u{ab8d}', '\u{0}', '\u{0}']), ('\u{13be}', ['\u{ab8e}', '\u{0}', '\u{0}']), + ('\u{13bf}', ['\u{ab8f}', '\u{0}', '\u{0}']), ('\u{13c0}', ['\u{ab90}', '\u{0}', '\u{0}']), + ('\u{13c1}', ['\u{ab91}', '\u{0}', '\u{0}']), ('\u{13c2}', ['\u{ab92}', '\u{0}', '\u{0}']), + ('\u{13c3}', ['\u{ab93}', '\u{0}', '\u{0}']), ('\u{13c4}', ['\u{ab94}', '\u{0}', '\u{0}']), + ('\u{13c5}', ['\u{ab95}', '\u{0}', '\u{0}']), ('\u{13c6}', ['\u{ab96}', '\u{0}', '\u{0}']), + ('\u{13c7}', ['\u{ab97}', '\u{0}', '\u{0}']), ('\u{13c8}', ['\u{ab98}', '\u{0}', '\u{0}']), + ('\u{13c9}', ['\u{ab99}', '\u{0}', '\u{0}']), ('\u{13ca}', ['\u{ab9a}', '\u{0}', '\u{0}']), + ('\u{13cb}', ['\u{ab9b}', '\u{0}', '\u{0}']), ('\u{13cc}', ['\u{ab9c}', '\u{0}', '\u{0}']), + ('\u{13cd}', ['\u{ab9d}', '\u{0}', '\u{0}']), ('\u{13ce}', ['\u{ab9e}', '\u{0}', '\u{0}']), + ('\u{13cf}', ['\u{ab9f}', '\u{0}', '\u{0}']), ('\u{13d0}', ['\u{aba0}', '\u{0}', '\u{0}']), + ('\u{13d1}', ['\u{aba1}', '\u{0}', '\u{0}']), ('\u{13d2}', ['\u{aba2}', '\u{0}', '\u{0}']), + ('\u{13d3}', ['\u{aba3}', '\u{0}', '\u{0}']), ('\u{13d4}', ['\u{aba4}', '\u{0}', '\u{0}']), + ('\u{13d5}', ['\u{aba5}', '\u{0}', '\u{0}']), ('\u{13d6}', ['\u{aba6}', '\u{0}', '\u{0}']), + ('\u{13d7}', ['\u{aba7}', '\u{0}', '\u{0}']), ('\u{13d8}', ['\u{aba8}', '\u{0}', '\u{0}']), + ('\u{13d9}', ['\u{aba9}', '\u{0}', '\u{0}']), ('\u{13da}', ['\u{abaa}', '\u{0}', '\u{0}']), + ('\u{13db}', ['\u{abab}', '\u{0}', '\u{0}']), ('\u{13dc}', ['\u{abac}', '\u{0}', '\u{0}']), + ('\u{13dd}', ['\u{abad}', '\u{0}', '\u{0}']), ('\u{13de}', ['\u{abae}', '\u{0}', '\u{0}']), + ('\u{13df}', ['\u{abaf}', '\u{0}', '\u{0}']), ('\u{13e0}', ['\u{abb0}', '\u{0}', '\u{0}']), + ('\u{13e1}', ['\u{abb1}', '\u{0}', '\u{0}']), ('\u{13e2}', ['\u{abb2}', '\u{0}', '\u{0}']), + ('\u{13e3}', ['\u{abb3}', '\u{0}', '\u{0}']), ('\u{13e4}', ['\u{abb4}', '\u{0}', '\u{0}']), + ('\u{13e5}', ['\u{abb5}', '\u{0}', '\u{0}']), ('\u{13e6}', ['\u{abb6}', '\u{0}', '\u{0}']), + ('\u{13e7}', ['\u{abb7}', '\u{0}', '\u{0}']), ('\u{13e8}', ['\u{abb8}', '\u{0}', '\u{0}']), + ('\u{13e9}', ['\u{abb9}', '\u{0}', '\u{0}']), ('\u{13ea}', ['\u{abba}', '\u{0}', '\u{0}']), + ('\u{13eb}', ['\u{abbb}', '\u{0}', '\u{0}']), ('\u{13ec}', ['\u{abbc}', '\u{0}', '\u{0}']), + ('\u{13ed}', ['\u{abbd}', '\u{0}', '\u{0}']), ('\u{13ee}', ['\u{abbe}', '\u{0}', '\u{0}']), + ('\u{13ef}', ['\u{abbf}', '\u{0}', '\u{0}']), ('\u{13f0}', ['\u{13f8}', '\u{0}', '\u{0}']), + ('\u{13f1}', ['\u{13f9}', '\u{0}', '\u{0}']), ('\u{13f2}', ['\u{13fa}', '\u{0}', '\u{0}']), + ('\u{13f3}', ['\u{13fb}', '\u{0}', '\u{0}']), ('\u{13f4}', ['\u{13fc}', '\u{0}', '\u{0}']), + ('\u{13f5}', ['\u{13fd}', '\u{0}', '\u{0}']), ('\u{1c89}', ['\u{1c8a}', '\u{0}', '\u{0}']), + ('\u{1c90}', ['\u{10d0}', '\u{0}', '\u{0}']), ('\u{1c91}', ['\u{10d1}', '\u{0}', '\u{0}']), + ('\u{1c92}', ['\u{10d2}', '\u{0}', '\u{0}']), ('\u{1c93}', ['\u{10d3}', '\u{0}', '\u{0}']), + ('\u{1c94}', ['\u{10d4}', '\u{0}', '\u{0}']), ('\u{1c95}', ['\u{10d5}', '\u{0}', '\u{0}']), + ('\u{1c96}', ['\u{10d6}', '\u{0}', '\u{0}']), ('\u{1c97}', ['\u{10d7}', '\u{0}', '\u{0}']), + ('\u{1c98}', ['\u{10d8}', '\u{0}', '\u{0}']), ('\u{1c99}', ['\u{10d9}', '\u{0}', '\u{0}']), + ('\u{1c9a}', ['\u{10da}', '\u{0}', '\u{0}']), ('\u{1c9b}', ['\u{10db}', '\u{0}', '\u{0}']), + ('\u{1c9c}', ['\u{10dc}', '\u{0}', '\u{0}']), ('\u{1c9d}', ['\u{10dd}', '\u{0}', '\u{0}']), + ('\u{1c9e}', ['\u{10de}', '\u{0}', '\u{0}']), ('\u{1c9f}', ['\u{10df}', '\u{0}', '\u{0}']), + ('\u{1ca0}', ['\u{10e0}', '\u{0}', '\u{0}']), ('\u{1ca1}', ['\u{10e1}', '\u{0}', '\u{0}']), + ('\u{1ca2}', ['\u{10e2}', '\u{0}', '\u{0}']), ('\u{1ca3}', ['\u{10e3}', '\u{0}', '\u{0}']), + ('\u{1ca4}', ['\u{10e4}', '\u{0}', '\u{0}']), ('\u{1ca5}', ['\u{10e5}', '\u{0}', '\u{0}']), + ('\u{1ca6}', ['\u{10e6}', '\u{0}', '\u{0}']), ('\u{1ca7}', ['\u{10e7}', '\u{0}', '\u{0}']), + ('\u{1ca8}', ['\u{10e8}', '\u{0}', '\u{0}']), ('\u{1ca9}', ['\u{10e9}', '\u{0}', '\u{0}']), + ('\u{1caa}', ['\u{10ea}', '\u{0}', '\u{0}']), ('\u{1cab}', ['\u{10eb}', '\u{0}', '\u{0}']), + ('\u{1cac}', ['\u{10ec}', '\u{0}', '\u{0}']), ('\u{1cad}', ['\u{10ed}', '\u{0}', '\u{0}']), + ('\u{1cae}', ['\u{10ee}', '\u{0}', '\u{0}']), ('\u{1caf}', ['\u{10ef}', '\u{0}', '\u{0}']), + ('\u{1cb0}', ['\u{10f0}', '\u{0}', '\u{0}']), ('\u{1cb1}', ['\u{10f1}', '\u{0}', '\u{0}']), + ('\u{1cb2}', ['\u{10f2}', '\u{0}', '\u{0}']), ('\u{1cb3}', ['\u{10f3}', '\u{0}', '\u{0}']), + ('\u{1cb4}', ['\u{10f4}', '\u{0}', '\u{0}']), ('\u{1cb5}', ['\u{10f5}', '\u{0}', '\u{0}']), + ('\u{1cb6}', ['\u{10f6}', '\u{0}', '\u{0}']), ('\u{1cb7}', ['\u{10f7}', '\u{0}', '\u{0}']), + ('\u{1cb8}', ['\u{10f8}', '\u{0}', '\u{0}']), ('\u{1cb9}', ['\u{10f9}', '\u{0}', '\u{0}']), + ('\u{1cba}', ['\u{10fa}', '\u{0}', '\u{0}']), ('\u{1cbd}', ['\u{10fd}', '\u{0}', '\u{0}']), + ('\u{1cbe}', ['\u{10fe}', '\u{0}', '\u{0}']), ('\u{1cbf}', ['\u{10ff}', '\u{0}', '\u{0}']), + ('\u{1e00}', ['\u{1e01}', '\u{0}', '\u{0}']), ('\u{1e02}', ['\u{1e03}', '\u{0}', '\u{0}']), + ('\u{1e04}', ['\u{1e05}', '\u{0}', '\u{0}']), ('\u{1e06}', ['\u{1e07}', '\u{0}', '\u{0}']), + ('\u{1e08}', ['\u{1e09}', '\u{0}', '\u{0}']), ('\u{1e0a}', ['\u{1e0b}', '\u{0}', '\u{0}']), + ('\u{1e0c}', ['\u{1e0d}', '\u{0}', '\u{0}']), ('\u{1e0e}', ['\u{1e0f}', '\u{0}', '\u{0}']), + ('\u{1e10}', ['\u{1e11}', '\u{0}', '\u{0}']), ('\u{1e12}', ['\u{1e13}', '\u{0}', '\u{0}']), + ('\u{1e14}', ['\u{1e15}', '\u{0}', '\u{0}']), ('\u{1e16}', ['\u{1e17}', '\u{0}', '\u{0}']), + ('\u{1e18}', ['\u{1e19}', '\u{0}', '\u{0}']), ('\u{1e1a}', ['\u{1e1b}', '\u{0}', '\u{0}']), + ('\u{1e1c}', ['\u{1e1d}', '\u{0}', '\u{0}']), ('\u{1e1e}', ['\u{1e1f}', '\u{0}', '\u{0}']), + ('\u{1e20}', ['\u{1e21}', '\u{0}', '\u{0}']), ('\u{1e22}', ['\u{1e23}', '\u{0}', '\u{0}']), + ('\u{1e24}', ['\u{1e25}', '\u{0}', '\u{0}']), ('\u{1e26}', ['\u{1e27}', '\u{0}', '\u{0}']), + ('\u{1e28}', ['\u{1e29}', '\u{0}', '\u{0}']), ('\u{1e2a}', ['\u{1e2b}', '\u{0}', '\u{0}']), + ('\u{1e2c}', ['\u{1e2d}', '\u{0}', '\u{0}']), ('\u{1e2e}', ['\u{1e2f}', '\u{0}', '\u{0}']), + ('\u{1e30}', ['\u{1e31}', '\u{0}', '\u{0}']), ('\u{1e32}', ['\u{1e33}', '\u{0}', '\u{0}']), + ('\u{1e34}', ['\u{1e35}', '\u{0}', '\u{0}']), ('\u{1e36}', ['\u{1e37}', '\u{0}', '\u{0}']), + ('\u{1e38}', ['\u{1e39}', '\u{0}', '\u{0}']), ('\u{1e3a}', ['\u{1e3b}', '\u{0}', '\u{0}']), + ('\u{1e3c}', ['\u{1e3d}', '\u{0}', '\u{0}']), ('\u{1e3e}', ['\u{1e3f}', '\u{0}', '\u{0}']), + ('\u{1e40}', ['\u{1e41}', '\u{0}', '\u{0}']), ('\u{1e42}', ['\u{1e43}', '\u{0}', '\u{0}']), + ('\u{1e44}', ['\u{1e45}', '\u{0}', '\u{0}']), ('\u{1e46}', ['\u{1e47}', '\u{0}', '\u{0}']), + ('\u{1e48}', ['\u{1e49}', '\u{0}', '\u{0}']), ('\u{1e4a}', ['\u{1e4b}', '\u{0}', '\u{0}']), + ('\u{1e4c}', ['\u{1e4d}', '\u{0}', '\u{0}']), ('\u{1e4e}', ['\u{1e4f}', '\u{0}', '\u{0}']), + ('\u{1e50}', ['\u{1e51}', '\u{0}', '\u{0}']), ('\u{1e52}', ['\u{1e53}', '\u{0}', '\u{0}']), + ('\u{1e54}', ['\u{1e55}', '\u{0}', '\u{0}']), ('\u{1e56}', ['\u{1e57}', '\u{0}', '\u{0}']), + ('\u{1e58}', ['\u{1e59}', '\u{0}', '\u{0}']), ('\u{1e5a}', ['\u{1e5b}', '\u{0}', '\u{0}']), + ('\u{1e5c}', ['\u{1e5d}', '\u{0}', '\u{0}']), ('\u{1e5e}', ['\u{1e5f}', '\u{0}', '\u{0}']), + ('\u{1e60}', ['\u{1e61}', '\u{0}', '\u{0}']), ('\u{1e62}', ['\u{1e63}', '\u{0}', '\u{0}']), + ('\u{1e64}', ['\u{1e65}', '\u{0}', '\u{0}']), ('\u{1e66}', ['\u{1e67}', '\u{0}', '\u{0}']), + ('\u{1e68}', ['\u{1e69}', '\u{0}', '\u{0}']), ('\u{1e6a}', ['\u{1e6b}', '\u{0}', '\u{0}']), + ('\u{1e6c}', ['\u{1e6d}', '\u{0}', '\u{0}']), ('\u{1e6e}', ['\u{1e6f}', '\u{0}', '\u{0}']), + ('\u{1e70}', ['\u{1e71}', '\u{0}', '\u{0}']), ('\u{1e72}', ['\u{1e73}', '\u{0}', '\u{0}']), + ('\u{1e74}', ['\u{1e75}', '\u{0}', '\u{0}']), ('\u{1e76}', ['\u{1e77}', '\u{0}', '\u{0}']), + ('\u{1e78}', ['\u{1e79}', '\u{0}', '\u{0}']), ('\u{1e7a}', ['\u{1e7b}', '\u{0}', '\u{0}']), + ('\u{1e7c}', ['\u{1e7d}', '\u{0}', '\u{0}']), ('\u{1e7e}', ['\u{1e7f}', '\u{0}', '\u{0}']), + ('\u{1e80}', ['\u{1e81}', '\u{0}', '\u{0}']), ('\u{1e82}', ['\u{1e83}', '\u{0}', '\u{0}']), + ('\u{1e84}', ['\u{1e85}', '\u{0}', '\u{0}']), ('\u{1e86}', ['\u{1e87}', '\u{0}', '\u{0}']), + ('\u{1e88}', ['\u{1e89}', '\u{0}', '\u{0}']), ('\u{1e8a}', ['\u{1e8b}', '\u{0}', '\u{0}']), + ('\u{1e8c}', ['\u{1e8d}', '\u{0}', '\u{0}']), ('\u{1e8e}', ['\u{1e8f}', '\u{0}', '\u{0}']), + ('\u{1e90}', ['\u{1e91}', '\u{0}', '\u{0}']), ('\u{1e92}', ['\u{1e93}', '\u{0}', '\u{0}']), + ('\u{1e94}', ['\u{1e95}', '\u{0}', '\u{0}']), ('\u{1e9e}', ['\u{df}', '\u{0}', '\u{0}']), + ('\u{1ea0}', ['\u{1ea1}', '\u{0}', '\u{0}']), ('\u{1ea2}', ['\u{1ea3}', '\u{0}', '\u{0}']), + ('\u{1ea4}', ['\u{1ea5}', '\u{0}', '\u{0}']), ('\u{1ea6}', ['\u{1ea7}', '\u{0}', '\u{0}']), + ('\u{1ea8}', ['\u{1ea9}', '\u{0}', '\u{0}']), ('\u{1eaa}', ['\u{1eab}', '\u{0}', '\u{0}']), + ('\u{1eac}', ['\u{1ead}', '\u{0}', '\u{0}']), ('\u{1eae}', ['\u{1eaf}', '\u{0}', '\u{0}']), + ('\u{1eb0}', ['\u{1eb1}', '\u{0}', '\u{0}']), ('\u{1eb2}', ['\u{1eb3}', '\u{0}', '\u{0}']), + ('\u{1eb4}', ['\u{1eb5}', '\u{0}', '\u{0}']), ('\u{1eb6}', ['\u{1eb7}', '\u{0}', '\u{0}']), + ('\u{1eb8}', ['\u{1eb9}', '\u{0}', '\u{0}']), ('\u{1eba}', ['\u{1ebb}', '\u{0}', '\u{0}']), + ('\u{1ebc}', ['\u{1ebd}', '\u{0}', '\u{0}']), ('\u{1ebe}', ['\u{1ebf}', '\u{0}', '\u{0}']), + ('\u{1ec0}', ['\u{1ec1}', '\u{0}', '\u{0}']), ('\u{1ec2}', ['\u{1ec3}', '\u{0}', '\u{0}']), + ('\u{1ec4}', ['\u{1ec5}', '\u{0}', '\u{0}']), ('\u{1ec6}', ['\u{1ec7}', '\u{0}', '\u{0}']), + ('\u{1ec8}', ['\u{1ec9}', '\u{0}', '\u{0}']), ('\u{1eca}', ['\u{1ecb}', '\u{0}', '\u{0}']), + ('\u{1ecc}', ['\u{1ecd}', '\u{0}', '\u{0}']), ('\u{1ece}', ['\u{1ecf}', '\u{0}', '\u{0}']), + ('\u{1ed0}', ['\u{1ed1}', '\u{0}', '\u{0}']), ('\u{1ed2}', ['\u{1ed3}', '\u{0}', '\u{0}']), + ('\u{1ed4}', ['\u{1ed5}', '\u{0}', '\u{0}']), ('\u{1ed6}', ['\u{1ed7}', '\u{0}', '\u{0}']), + ('\u{1ed8}', ['\u{1ed9}', '\u{0}', '\u{0}']), ('\u{1eda}', ['\u{1edb}', '\u{0}', '\u{0}']), + ('\u{1edc}', ['\u{1edd}', '\u{0}', '\u{0}']), ('\u{1ede}', ['\u{1edf}', '\u{0}', '\u{0}']), + ('\u{1ee0}', ['\u{1ee1}', '\u{0}', '\u{0}']), ('\u{1ee2}', ['\u{1ee3}', '\u{0}', '\u{0}']), + ('\u{1ee4}', ['\u{1ee5}', '\u{0}', '\u{0}']), ('\u{1ee6}', ['\u{1ee7}', '\u{0}', '\u{0}']), + ('\u{1ee8}', ['\u{1ee9}', '\u{0}', '\u{0}']), ('\u{1eea}', ['\u{1eeb}', '\u{0}', '\u{0}']), + ('\u{1eec}', ['\u{1eed}', '\u{0}', '\u{0}']), ('\u{1eee}', ['\u{1eef}', '\u{0}', '\u{0}']), + ('\u{1ef0}', ['\u{1ef1}', '\u{0}', '\u{0}']), ('\u{1ef2}', ['\u{1ef3}', '\u{0}', '\u{0}']), + ('\u{1ef4}', ['\u{1ef5}', '\u{0}', '\u{0}']), ('\u{1ef6}', ['\u{1ef7}', '\u{0}', '\u{0}']), + ('\u{1ef8}', ['\u{1ef9}', '\u{0}', '\u{0}']), ('\u{1efa}', ['\u{1efb}', '\u{0}', '\u{0}']), + ('\u{1efc}', ['\u{1efd}', '\u{0}', '\u{0}']), ('\u{1efe}', ['\u{1eff}', '\u{0}', '\u{0}']), + ('\u{1f08}', ['\u{1f00}', '\u{0}', '\u{0}']), ('\u{1f09}', ['\u{1f01}', '\u{0}', '\u{0}']), + ('\u{1f0a}', ['\u{1f02}', '\u{0}', '\u{0}']), ('\u{1f0b}', ['\u{1f03}', '\u{0}', '\u{0}']), + ('\u{1f0c}', ['\u{1f04}', '\u{0}', '\u{0}']), ('\u{1f0d}', ['\u{1f05}', '\u{0}', '\u{0}']), + ('\u{1f0e}', ['\u{1f06}', '\u{0}', '\u{0}']), ('\u{1f0f}', ['\u{1f07}', '\u{0}', '\u{0}']), + ('\u{1f18}', ['\u{1f10}', '\u{0}', '\u{0}']), ('\u{1f19}', ['\u{1f11}', '\u{0}', '\u{0}']), + ('\u{1f1a}', ['\u{1f12}', '\u{0}', '\u{0}']), ('\u{1f1b}', ['\u{1f13}', '\u{0}', '\u{0}']), + ('\u{1f1c}', ['\u{1f14}', '\u{0}', '\u{0}']), ('\u{1f1d}', ['\u{1f15}', '\u{0}', '\u{0}']), + ('\u{1f28}', ['\u{1f20}', '\u{0}', '\u{0}']), ('\u{1f29}', ['\u{1f21}', '\u{0}', '\u{0}']), + ('\u{1f2a}', ['\u{1f22}', '\u{0}', '\u{0}']), ('\u{1f2b}', ['\u{1f23}', '\u{0}', '\u{0}']), + ('\u{1f2c}', ['\u{1f24}', '\u{0}', '\u{0}']), ('\u{1f2d}', ['\u{1f25}', '\u{0}', '\u{0}']), + ('\u{1f2e}', ['\u{1f26}', '\u{0}', '\u{0}']), ('\u{1f2f}', ['\u{1f27}', '\u{0}', '\u{0}']), + ('\u{1f38}', ['\u{1f30}', '\u{0}', '\u{0}']), ('\u{1f39}', ['\u{1f31}', '\u{0}', '\u{0}']), + ('\u{1f3a}', ['\u{1f32}', '\u{0}', '\u{0}']), ('\u{1f3b}', ['\u{1f33}', '\u{0}', '\u{0}']), + ('\u{1f3c}', ['\u{1f34}', '\u{0}', '\u{0}']), ('\u{1f3d}', ['\u{1f35}', '\u{0}', '\u{0}']), + ('\u{1f3e}', ['\u{1f36}', '\u{0}', '\u{0}']), ('\u{1f3f}', ['\u{1f37}', '\u{0}', '\u{0}']), + ('\u{1f48}', ['\u{1f40}', '\u{0}', '\u{0}']), ('\u{1f49}', ['\u{1f41}', '\u{0}', '\u{0}']), + ('\u{1f4a}', ['\u{1f42}', '\u{0}', '\u{0}']), ('\u{1f4b}', ['\u{1f43}', '\u{0}', '\u{0}']), + ('\u{1f4c}', ['\u{1f44}', '\u{0}', '\u{0}']), ('\u{1f4d}', ['\u{1f45}', '\u{0}', '\u{0}']), + ('\u{1f59}', ['\u{1f51}', '\u{0}', '\u{0}']), ('\u{1f5b}', ['\u{1f53}', '\u{0}', '\u{0}']), + ('\u{1f5d}', ['\u{1f55}', '\u{0}', '\u{0}']), ('\u{1f5f}', ['\u{1f57}', '\u{0}', '\u{0}']), + ('\u{1f68}', ['\u{1f60}', '\u{0}', '\u{0}']), ('\u{1f69}', ['\u{1f61}', '\u{0}', '\u{0}']), + ('\u{1f6a}', ['\u{1f62}', '\u{0}', '\u{0}']), ('\u{1f6b}', ['\u{1f63}', '\u{0}', '\u{0}']), + ('\u{1f6c}', ['\u{1f64}', '\u{0}', '\u{0}']), ('\u{1f6d}', ['\u{1f65}', '\u{0}', '\u{0}']), + ('\u{1f6e}', ['\u{1f66}', '\u{0}', '\u{0}']), ('\u{1f6f}', ['\u{1f67}', '\u{0}', '\u{0}']), + ('\u{1f88}', ['\u{1f80}', '\u{0}', '\u{0}']), ('\u{1f89}', ['\u{1f81}', '\u{0}', '\u{0}']), + ('\u{1f8a}', ['\u{1f82}', '\u{0}', '\u{0}']), ('\u{1f8b}', ['\u{1f83}', '\u{0}', '\u{0}']), + ('\u{1f8c}', ['\u{1f84}', '\u{0}', '\u{0}']), ('\u{1f8d}', ['\u{1f85}', '\u{0}', '\u{0}']), + ('\u{1f8e}', ['\u{1f86}', '\u{0}', '\u{0}']), ('\u{1f8f}', ['\u{1f87}', '\u{0}', '\u{0}']), + ('\u{1f98}', ['\u{1f90}', '\u{0}', '\u{0}']), ('\u{1f99}', ['\u{1f91}', '\u{0}', '\u{0}']), + ('\u{1f9a}', ['\u{1f92}', '\u{0}', '\u{0}']), ('\u{1f9b}', ['\u{1f93}', '\u{0}', '\u{0}']), + ('\u{1f9c}', ['\u{1f94}', '\u{0}', '\u{0}']), ('\u{1f9d}', ['\u{1f95}', '\u{0}', '\u{0}']), + ('\u{1f9e}', ['\u{1f96}', '\u{0}', '\u{0}']), ('\u{1f9f}', ['\u{1f97}', '\u{0}', '\u{0}']), + ('\u{1fa8}', ['\u{1fa0}', '\u{0}', '\u{0}']), ('\u{1fa9}', ['\u{1fa1}', '\u{0}', '\u{0}']), + ('\u{1faa}', ['\u{1fa2}', '\u{0}', '\u{0}']), ('\u{1fab}', ['\u{1fa3}', '\u{0}', '\u{0}']), + ('\u{1fac}', ['\u{1fa4}', '\u{0}', '\u{0}']), ('\u{1fad}', ['\u{1fa5}', '\u{0}', '\u{0}']), + ('\u{1fae}', ['\u{1fa6}', '\u{0}', '\u{0}']), ('\u{1faf}', ['\u{1fa7}', '\u{0}', '\u{0}']), + ('\u{1fb8}', ['\u{1fb0}', '\u{0}', '\u{0}']), ('\u{1fb9}', ['\u{1fb1}', '\u{0}', '\u{0}']), + ('\u{1fba}', ['\u{1f70}', '\u{0}', '\u{0}']), ('\u{1fbb}', ['\u{1f71}', '\u{0}', '\u{0}']), + ('\u{1fbc}', ['\u{1fb3}', '\u{0}', '\u{0}']), ('\u{1fc8}', ['\u{1f72}', '\u{0}', '\u{0}']), + ('\u{1fc9}', ['\u{1f73}', '\u{0}', '\u{0}']), ('\u{1fca}', ['\u{1f74}', '\u{0}', '\u{0}']), + ('\u{1fcb}', ['\u{1f75}', '\u{0}', '\u{0}']), ('\u{1fcc}', ['\u{1fc3}', '\u{0}', '\u{0}']), + ('\u{1fd8}', ['\u{1fd0}', '\u{0}', '\u{0}']), ('\u{1fd9}', ['\u{1fd1}', '\u{0}', '\u{0}']), + ('\u{1fda}', ['\u{1f76}', '\u{0}', '\u{0}']), ('\u{1fdb}', ['\u{1f77}', '\u{0}', '\u{0}']), + ('\u{1fe8}', ['\u{1fe0}', '\u{0}', '\u{0}']), ('\u{1fe9}', ['\u{1fe1}', '\u{0}', '\u{0}']), + ('\u{1fea}', ['\u{1f7a}', '\u{0}', '\u{0}']), ('\u{1feb}', ['\u{1f7b}', '\u{0}', '\u{0}']), + ('\u{1fec}', ['\u{1fe5}', '\u{0}', '\u{0}']), ('\u{1ff8}', ['\u{1f78}', '\u{0}', '\u{0}']), + ('\u{1ff9}', ['\u{1f79}', '\u{0}', '\u{0}']), ('\u{1ffa}', ['\u{1f7c}', '\u{0}', '\u{0}']), + ('\u{1ffb}', ['\u{1f7d}', '\u{0}', '\u{0}']), ('\u{1ffc}', ['\u{1ff3}', '\u{0}', '\u{0}']), + ('\u{2126}', ['\u{3c9}', '\u{0}', '\u{0}']), ('\u{212a}', ['k', '\u{0}', '\u{0}']), + ('\u{212b}', ['\u{e5}', '\u{0}', '\u{0}']), ('\u{2132}', ['\u{214e}', '\u{0}', '\u{0}']), + ('\u{2160}', ['\u{2170}', '\u{0}', '\u{0}']), ('\u{2161}', ['\u{2171}', '\u{0}', '\u{0}']), + ('\u{2162}', ['\u{2172}', '\u{0}', '\u{0}']), ('\u{2163}', ['\u{2173}', '\u{0}', '\u{0}']), + ('\u{2164}', ['\u{2174}', '\u{0}', '\u{0}']), ('\u{2165}', ['\u{2175}', '\u{0}', '\u{0}']), + ('\u{2166}', ['\u{2176}', '\u{0}', '\u{0}']), ('\u{2167}', ['\u{2177}', '\u{0}', '\u{0}']), + ('\u{2168}', ['\u{2178}', '\u{0}', '\u{0}']), ('\u{2169}', ['\u{2179}', '\u{0}', '\u{0}']), + ('\u{216a}', ['\u{217a}', '\u{0}', '\u{0}']), ('\u{216b}', ['\u{217b}', '\u{0}', '\u{0}']), + ('\u{216c}', ['\u{217c}', '\u{0}', '\u{0}']), ('\u{216d}', ['\u{217d}', '\u{0}', '\u{0}']), + ('\u{216e}', ['\u{217e}', '\u{0}', '\u{0}']), ('\u{216f}', ['\u{217f}', '\u{0}', '\u{0}']), + ('\u{2183}', ['\u{2184}', '\u{0}', '\u{0}']), ('\u{24b6}', ['\u{24d0}', '\u{0}', '\u{0}']), + ('\u{24b7}', ['\u{24d1}', '\u{0}', '\u{0}']), ('\u{24b8}', ['\u{24d2}', '\u{0}', '\u{0}']), + ('\u{24b9}', ['\u{24d3}', '\u{0}', '\u{0}']), ('\u{24ba}', ['\u{24d4}', '\u{0}', '\u{0}']), + ('\u{24bb}', ['\u{24d5}', '\u{0}', '\u{0}']), ('\u{24bc}', ['\u{24d6}', '\u{0}', '\u{0}']), + ('\u{24bd}', ['\u{24d7}', '\u{0}', '\u{0}']), ('\u{24be}', ['\u{24d8}', '\u{0}', '\u{0}']), + ('\u{24bf}', ['\u{24d9}', '\u{0}', '\u{0}']), ('\u{24c0}', ['\u{24da}', '\u{0}', '\u{0}']), + ('\u{24c1}', ['\u{24db}', '\u{0}', '\u{0}']), ('\u{24c2}', ['\u{24dc}', '\u{0}', '\u{0}']), + ('\u{24c3}', ['\u{24dd}', '\u{0}', '\u{0}']), ('\u{24c4}', ['\u{24de}', '\u{0}', '\u{0}']), + ('\u{24c5}', ['\u{24df}', '\u{0}', '\u{0}']), ('\u{24c6}', ['\u{24e0}', '\u{0}', '\u{0}']), + ('\u{24c7}', ['\u{24e1}', '\u{0}', '\u{0}']), ('\u{24c8}', ['\u{24e2}', '\u{0}', '\u{0}']), + ('\u{24c9}', ['\u{24e3}', '\u{0}', '\u{0}']), ('\u{24ca}', ['\u{24e4}', '\u{0}', '\u{0}']), + ('\u{24cb}', ['\u{24e5}', '\u{0}', '\u{0}']), ('\u{24cc}', ['\u{24e6}', '\u{0}', '\u{0}']), + ('\u{24cd}', ['\u{24e7}', '\u{0}', '\u{0}']), ('\u{24ce}', ['\u{24e8}', '\u{0}', '\u{0}']), + ('\u{24cf}', ['\u{24e9}', '\u{0}', '\u{0}']), ('\u{2c00}', ['\u{2c30}', '\u{0}', '\u{0}']), + ('\u{2c01}', ['\u{2c31}', '\u{0}', '\u{0}']), ('\u{2c02}', ['\u{2c32}', '\u{0}', '\u{0}']), + ('\u{2c03}', ['\u{2c33}', '\u{0}', '\u{0}']), ('\u{2c04}', ['\u{2c34}', '\u{0}', '\u{0}']), + ('\u{2c05}', ['\u{2c35}', '\u{0}', '\u{0}']), ('\u{2c06}', ['\u{2c36}', '\u{0}', '\u{0}']), + ('\u{2c07}', ['\u{2c37}', '\u{0}', '\u{0}']), ('\u{2c08}', ['\u{2c38}', '\u{0}', '\u{0}']), + ('\u{2c09}', ['\u{2c39}', '\u{0}', '\u{0}']), ('\u{2c0a}', ['\u{2c3a}', '\u{0}', '\u{0}']), + ('\u{2c0b}', ['\u{2c3b}', '\u{0}', '\u{0}']), ('\u{2c0c}', ['\u{2c3c}', '\u{0}', '\u{0}']), + ('\u{2c0d}', ['\u{2c3d}', '\u{0}', '\u{0}']), ('\u{2c0e}', ['\u{2c3e}', '\u{0}', '\u{0}']), + ('\u{2c0f}', ['\u{2c3f}', '\u{0}', '\u{0}']), ('\u{2c10}', ['\u{2c40}', '\u{0}', '\u{0}']), + ('\u{2c11}', ['\u{2c41}', '\u{0}', '\u{0}']), ('\u{2c12}', ['\u{2c42}', '\u{0}', '\u{0}']), + ('\u{2c13}', ['\u{2c43}', '\u{0}', '\u{0}']), ('\u{2c14}', ['\u{2c44}', '\u{0}', '\u{0}']), + ('\u{2c15}', ['\u{2c45}', '\u{0}', '\u{0}']), ('\u{2c16}', ['\u{2c46}', '\u{0}', '\u{0}']), + ('\u{2c17}', ['\u{2c47}', '\u{0}', '\u{0}']), ('\u{2c18}', ['\u{2c48}', '\u{0}', '\u{0}']), + ('\u{2c19}', ['\u{2c49}', '\u{0}', '\u{0}']), ('\u{2c1a}', ['\u{2c4a}', '\u{0}', '\u{0}']), + ('\u{2c1b}', ['\u{2c4b}', '\u{0}', '\u{0}']), ('\u{2c1c}', ['\u{2c4c}', '\u{0}', '\u{0}']), + ('\u{2c1d}', ['\u{2c4d}', '\u{0}', '\u{0}']), ('\u{2c1e}', ['\u{2c4e}', '\u{0}', '\u{0}']), + ('\u{2c1f}', ['\u{2c4f}', '\u{0}', '\u{0}']), ('\u{2c20}', ['\u{2c50}', '\u{0}', '\u{0}']), + ('\u{2c21}', ['\u{2c51}', '\u{0}', '\u{0}']), ('\u{2c22}', ['\u{2c52}', '\u{0}', '\u{0}']), + ('\u{2c23}', ['\u{2c53}', '\u{0}', '\u{0}']), ('\u{2c24}', ['\u{2c54}', '\u{0}', '\u{0}']), + ('\u{2c25}', ['\u{2c55}', '\u{0}', '\u{0}']), ('\u{2c26}', ['\u{2c56}', '\u{0}', '\u{0}']), + ('\u{2c27}', ['\u{2c57}', '\u{0}', '\u{0}']), ('\u{2c28}', ['\u{2c58}', '\u{0}', '\u{0}']), + ('\u{2c29}', ['\u{2c59}', '\u{0}', '\u{0}']), ('\u{2c2a}', ['\u{2c5a}', '\u{0}', '\u{0}']), + ('\u{2c2b}', ['\u{2c5b}', '\u{0}', '\u{0}']), ('\u{2c2c}', ['\u{2c5c}', '\u{0}', '\u{0}']), + ('\u{2c2d}', ['\u{2c5d}', '\u{0}', '\u{0}']), ('\u{2c2e}', ['\u{2c5e}', '\u{0}', '\u{0}']), + ('\u{2c2f}', ['\u{2c5f}', '\u{0}', '\u{0}']), ('\u{2c60}', ['\u{2c61}', '\u{0}', '\u{0}']), + ('\u{2c62}', ['\u{26b}', '\u{0}', '\u{0}']), ('\u{2c63}', ['\u{1d7d}', '\u{0}', '\u{0}']), + ('\u{2c64}', ['\u{27d}', '\u{0}', '\u{0}']), ('\u{2c67}', ['\u{2c68}', '\u{0}', '\u{0}']), + ('\u{2c69}', ['\u{2c6a}', '\u{0}', '\u{0}']), ('\u{2c6b}', ['\u{2c6c}', '\u{0}', '\u{0}']), + ('\u{2c6d}', ['\u{251}', '\u{0}', '\u{0}']), ('\u{2c6e}', ['\u{271}', '\u{0}', '\u{0}']), + ('\u{2c6f}', ['\u{250}', '\u{0}', '\u{0}']), ('\u{2c70}', ['\u{252}', '\u{0}', '\u{0}']), + ('\u{2c72}', ['\u{2c73}', '\u{0}', '\u{0}']), ('\u{2c75}', ['\u{2c76}', '\u{0}', '\u{0}']), + ('\u{2c7e}', ['\u{23f}', '\u{0}', '\u{0}']), ('\u{2c7f}', ['\u{240}', '\u{0}', '\u{0}']), + ('\u{2c80}', ['\u{2c81}', '\u{0}', '\u{0}']), ('\u{2c82}', ['\u{2c83}', '\u{0}', '\u{0}']), + ('\u{2c84}', ['\u{2c85}', '\u{0}', '\u{0}']), ('\u{2c86}', ['\u{2c87}', '\u{0}', '\u{0}']), + ('\u{2c88}', ['\u{2c89}', '\u{0}', '\u{0}']), ('\u{2c8a}', ['\u{2c8b}', '\u{0}', '\u{0}']), + ('\u{2c8c}', ['\u{2c8d}', '\u{0}', '\u{0}']), ('\u{2c8e}', ['\u{2c8f}', '\u{0}', '\u{0}']), + ('\u{2c90}', ['\u{2c91}', '\u{0}', '\u{0}']), ('\u{2c92}', ['\u{2c93}', '\u{0}', '\u{0}']), + ('\u{2c94}', ['\u{2c95}', '\u{0}', '\u{0}']), ('\u{2c96}', ['\u{2c97}', '\u{0}', '\u{0}']), + ('\u{2c98}', ['\u{2c99}', '\u{0}', '\u{0}']), ('\u{2c9a}', ['\u{2c9b}', '\u{0}', '\u{0}']), + ('\u{2c9c}', ['\u{2c9d}', '\u{0}', '\u{0}']), ('\u{2c9e}', ['\u{2c9f}', '\u{0}', '\u{0}']), + ('\u{2ca0}', ['\u{2ca1}', '\u{0}', '\u{0}']), ('\u{2ca2}', ['\u{2ca3}', '\u{0}', '\u{0}']), + ('\u{2ca4}', ['\u{2ca5}', '\u{0}', '\u{0}']), ('\u{2ca6}', ['\u{2ca7}', '\u{0}', '\u{0}']), + ('\u{2ca8}', ['\u{2ca9}', '\u{0}', '\u{0}']), ('\u{2caa}', ['\u{2cab}', '\u{0}', '\u{0}']), + ('\u{2cac}', ['\u{2cad}', '\u{0}', '\u{0}']), ('\u{2cae}', ['\u{2caf}', '\u{0}', '\u{0}']), + ('\u{2cb0}', ['\u{2cb1}', '\u{0}', '\u{0}']), ('\u{2cb2}', ['\u{2cb3}', '\u{0}', '\u{0}']), + ('\u{2cb4}', ['\u{2cb5}', '\u{0}', '\u{0}']), ('\u{2cb6}', ['\u{2cb7}', '\u{0}', '\u{0}']), + ('\u{2cb8}', ['\u{2cb9}', '\u{0}', '\u{0}']), ('\u{2cba}', ['\u{2cbb}', '\u{0}', '\u{0}']), + ('\u{2cbc}', ['\u{2cbd}', '\u{0}', '\u{0}']), ('\u{2cbe}', ['\u{2cbf}', '\u{0}', '\u{0}']), + ('\u{2cc0}', ['\u{2cc1}', '\u{0}', '\u{0}']), ('\u{2cc2}', ['\u{2cc3}', '\u{0}', '\u{0}']), + ('\u{2cc4}', ['\u{2cc5}', '\u{0}', '\u{0}']), ('\u{2cc6}', ['\u{2cc7}', '\u{0}', '\u{0}']), + ('\u{2cc8}', ['\u{2cc9}', '\u{0}', '\u{0}']), ('\u{2cca}', ['\u{2ccb}', '\u{0}', '\u{0}']), + ('\u{2ccc}', ['\u{2ccd}', '\u{0}', '\u{0}']), ('\u{2cce}', ['\u{2ccf}', '\u{0}', '\u{0}']), + ('\u{2cd0}', ['\u{2cd1}', '\u{0}', '\u{0}']), ('\u{2cd2}', ['\u{2cd3}', '\u{0}', '\u{0}']), + ('\u{2cd4}', ['\u{2cd5}', '\u{0}', '\u{0}']), ('\u{2cd6}', ['\u{2cd7}', '\u{0}', '\u{0}']), + ('\u{2cd8}', ['\u{2cd9}', '\u{0}', '\u{0}']), ('\u{2cda}', ['\u{2cdb}', '\u{0}', '\u{0}']), + ('\u{2cdc}', ['\u{2cdd}', '\u{0}', '\u{0}']), ('\u{2cde}', ['\u{2cdf}', '\u{0}', '\u{0}']), + ('\u{2ce0}', ['\u{2ce1}', '\u{0}', '\u{0}']), ('\u{2ce2}', ['\u{2ce3}', '\u{0}', '\u{0}']), + ('\u{2ceb}', ['\u{2cec}', '\u{0}', '\u{0}']), ('\u{2ced}', ['\u{2cee}', '\u{0}', '\u{0}']), + ('\u{2cf2}', ['\u{2cf3}', '\u{0}', '\u{0}']), ('\u{a640}', ['\u{a641}', '\u{0}', '\u{0}']), + ('\u{a642}', ['\u{a643}', '\u{0}', '\u{0}']), ('\u{a644}', ['\u{a645}', '\u{0}', '\u{0}']), + ('\u{a646}', ['\u{a647}', '\u{0}', '\u{0}']), ('\u{a648}', ['\u{a649}', '\u{0}', '\u{0}']), + ('\u{a64a}', ['\u{a64b}', '\u{0}', '\u{0}']), ('\u{a64c}', ['\u{a64d}', '\u{0}', '\u{0}']), + ('\u{a64e}', ['\u{a64f}', '\u{0}', '\u{0}']), ('\u{a650}', ['\u{a651}', '\u{0}', '\u{0}']), + ('\u{a652}', ['\u{a653}', '\u{0}', '\u{0}']), ('\u{a654}', ['\u{a655}', '\u{0}', '\u{0}']), + ('\u{a656}', ['\u{a657}', '\u{0}', '\u{0}']), ('\u{a658}', ['\u{a659}', '\u{0}', '\u{0}']), + ('\u{a65a}', ['\u{a65b}', '\u{0}', '\u{0}']), ('\u{a65c}', ['\u{a65d}', '\u{0}', '\u{0}']), + ('\u{a65e}', ['\u{a65f}', '\u{0}', '\u{0}']), ('\u{a660}', ['\u{a661}', '\u{0}', '\u{0}']), + ('\u{a662}', ['\u{a663}', '\u{0}', '\u{0}']), ('\u{a664}', ['\u{a665}', '\u{0}', '\u{0}']), + ('\u{a666}', ['\u{a667}', '\u{0}', '\u{0}']), ('\u{a668}', ['\u{a669}', '\u{0}', '\u{0}']), + ('\u{a66a}', ['\u{a66b}', '\u{0}', '\u{0}']), ('\u{a66c}', ['\u{a66d}', '\u{0}', '\u{0}']), + ('\u{a680}', ['\u{a681}', '\u{0}', '\u{0}']), ('\u{a682}', ['\u{a683}', '\u{0}', '\u{0}']), + ('\u{a684}', ['\u{a685}', '\u{0}', '\u{0}']), ('\u{a686}', ['\u{a687}', '\u{0}', '\u{0}']), + ('\u{a688}', ['\u{a689}', '\u{0}', '\u{0}']), ('\u{a68a}', ['\u{a68b}', '\u{0}', '\u{0}']), + ('\u{a68c}', ['\u{a68d}', '\u{0}', '\u{0}']), ('\u{a68e}', ['\u{a68f}', '\u{0}', '\u{0}']), + ('\u{a690}', ['\u{a691}', '\u{0}', '\u{0}']), ('\u{a692}', ['\u{a693}', '\u{0}', '\u{0}']), + ('\u{a694}', ['\u{a695}', '\u{0}', '\u{0}']), ('\u{a696}', ['\u{a697}', '\u{0}', '\u{0}']), + ('\u{a698}', ['\u{a699}', '\u{0}', '\u{0}']), ('\u{a69a}', ['\u{a69b}', '\u{0}', '\u{0}']), + ('\u{a722}', ['\u{a723}', '\u{0}', '\u{0}']), ('\u{a724}', ['\u{a725}', '\u{0}', '\u{0}']), + ('\u{a726}', ['\u{a727}', '\u{0}', '\u{0}']), ('\u{a728}', ['\u{a729}', '\u{0}', '\u{0}']), + ('\u{a72a}', ['\u{a72b}', '\u{0}', '\u{0}']), ('\u{a72c}', ['\u{a72d}', '\u{0}', '\u{0}']), + ('\u{a72e}', ['\u{a72f}', '\u{0}', '\u{0}']), ('\u{a732}', ['\u{a733}', '\u{0}', '\u{0}']), + ('\u{a734}', ['\u{a735}', '\u{0}', '\u{0}']), ('\u{a736}', ['\u{a737}', '\u{0}', '\u{0}']), + ('\u{a738}', ['\u{a739}', '\u{0}', '\u{0}']), ('\u{a73a}', ['\u{a73b}', '\u{0}', '\u{0}']), + ('\u{a73c}', ['\u{a73d}', '\u{0}', '\u{0}']), ('\u{a73e}', ['\u{a73f}', '\u{0}', '\u{0}']), + ('\u{a740}', ['\u{a741}', '\u{0}', '\u{0}']), ('\u{a742}', ['\u{a743}', '\u{0}', '\u{0}']), + ('\u{a744}', ['\u{a745}', '\u{0}', '\u{0}']), ('\u{a746}', ['\u{a747}', '\u{0}', '\u{0}']), + ('\u{a748}', ['\u{a749}', '\u{0}', '\u{0}']), ('\u{a74a}', ['\u{a74b}', '\u{0}', '\u{0}']), + ('\u{a74c}', ['\u{a74d}', '\u{0}', '\u{0}']), ('\u{a74e}', ['\u{a74f}', '\u{0}', '\u{0}']), + ('\u{a750}', ['\u{a751}', '\u{0}', '\u{0}']), ('\u{a752}', ['\u{a753}', '\u{0}', '\u{0}']), + ('\u{a754}', ['\u{a755}', '\u{0}', '\u{0}']), ('\u{a756}', ['\u{a757}', '\u{0}', '\u{0}']), + ('\u{a758}', ['\u{a759}', '\u{0}', '\u{0}']), ('\u{a75a}', ['\u{a75b}', '\u{0}', '\u{0}']), + ('\u{a75c}', ['\u{a75d}', '\u{0}', '\u{0}']), ('\u{a75e}', ['\u{a75f}', '\u{0}', '\u{0}']), + ('\u{a760}', ['\u{a761}', '\u{0}', '\u{0}']), ('\u{a762}', ['\u{a763}', '\u{0}', '\u{0}']), + ('\u{a764}', ['\u{a765}', '\u{0}', '\u{0}']), ('\u{a766}', ['\u{a767}', '\u{0}', '\u{0}']), + ('\u{a768}', ['\u{a769}', '\u{0}', '\u{0}']), ('\u{a76a}', ['\u{a76b}', '\u{0}', '\u{0}']), + ('\u{a76c}', ['\u{a76d}', '\u{0}', '\u{0}']), ('\u{a76e}', ['\u{a76f}', '\u{0}', '\u{0}']), + ('\u{a779}', ['\u{a77a}', '\u{0}', '\u{0}']), ('\u{a77b}', ['\u{a77c}', '\u{0}', '\u{0}']), + ('\u{a77d}', ['\u{1d79}', '\u{0}', '\u{0}']), ('\u{a77e}', ['\u{a77f}', '\u{0}', '\u{0}']), + ('\u{a780}', ['\u{a781}', '\u{0}', '\u{0}']), ('\u{a782}', ['\u{a783}', '\u{0}', '\u{0}']), + ('\u{a784}', ['\u{a785}', '\u{0}', '\u{0}']), ('\u{a786}', ['\u{a787}', '\u{0}', '\u{0}']), + ('\u{a78b}', ['\u{a78c}', '\u{0}', '\u{0}']), ('\u{a78d}', ['\u{265}', '\u{0}', '\u{0}']), + ('\u{a790}', ['\u{a791}', '\u{0}', '\u{0}']), ('\u{a792}', ['\u{a793}', '\u{0}', '\u{0}']), + ('\u{a796}', ['\u{a797}', '\u{0}', '\u{0}']), ('\u{a798}', ['\u{a799}', '\u{0}', '\u{0}']), + ('\u{a79a}', ['\u{a79b}', '\u{0}', '\u{0}']), ('\u{a79c}', ['\u{a79d}', '\u{0}', '\u{0}']), + ('\u{a79e}', ['\u{a79f}', '\u{0}', '\u{0}']), ('\u{a7a0}', ['\u{a7a1}', '\u{0}', '\u{0}']), + ('\u{a7a2}', ['\u{a7a3}', '\u{0}', '\u{0}']), ('\u{a7a4}', ['\u{a7a5}', '\u{0}', '\u{0}']), + ('\u{a7a6}', ['\u{a7a7}', '\u{0}', '\u{0}']), ('\u{a7a8}', ['\u{a7a9}', '\u{0}', '\u{0}']), + ('\u{a7aa}', ['\u{266}', '\u{0}', '\u{0}']), ('\u{a7ab}', ['\u{25c}', '\u{0}', '\u{0}']), + ('\u{a7ac}', ['\u{261}', '\u{0}', '\u{0}']), ('\u{a7ad}', ['\u{26c}', '\u{0}', '\u{0}']), + ('\u{a7ae}', ['\u{26a}', '\u{0}', '\u{0}']), ('\u{a7b0}', ['\u{29e}', '\u{0}', '\u{0}']), + ('\u{a7b1}', ['\u{287}', '\u{0}', '\u{0}']), ('\u{a7b2}', ['\u{29d}', '\u{0}', '\u{0}']), + ('\u{a7b3}', ['\u{ab53}', '\u{0}', '\u{0}']), ('\u{a7b4}', ['\u{a7b5}', '\u{0}', '\u{0}']), + ('\u{a7b6}', ['\u{a7b7}', '\u{0}', '\u{0}']), ('\u{a7b8}', ['\u{a7b9}', '\u{0}', '\u{0}']), + ('\u{a7ba}', ['\u{a7bb}', '\u{0}', '\u{0}']), ('\u{a7bc}', ['\u{a7bd}', '\u{0}', '\u{0}']), + ('\u{a7be}', ['\u{a7bf}', '\u{0}', '\u{0}']), ('\u{a7c0}', ['\u{a7c1}', '\u{0}', '\u{0}']), + ('\u{a7c2}', ['\u{a7c3}', '\u{0}', '\u{0}']), ('\u{a7c4}', ['\u{a794}', '\u{0}', '\u{0}']), + ('\u{a7c5}', ['\u{282}', '\u{0}', '\u{0}']), ('\u{a7c6}', ['\u{1d8e}', '\u{0}', '\u{0}']), + ('\u{a7c7}', ['\u{a7c8}', '\u{0}', '\u{0}']), ('\u{a7c9}', ['\u{a7ca}', '\u{0}', '\u{0}']), + ('\u{a7cb}', ['\u{264}', '\u{0}', '\u{0}']), ('\u{a7cc}', ['\u{a7cd}', '\u{0}', '\u{0}']), + ('\u{a7ce}', ['\u{a7cf}', '\u{0}', '\u{0}']), ('\u{a7d0}', ['\u{a7d1}', '\u{0}', '\u{0}']), + ('\u{a7d2}', ['\u{a7d3}', '\u{0}', '\u{0}']), ('\u{a7d4}', ['\u{a7d5}', '\u{0}', '\u{0}']), + ('\u{a7d6}', ['\u{a7d7}', '\u{0}', '\u{0}']), ('\u{a7d8}', ['\u{a7d9}', '\u{0}', '\u{0}']), + ('\u{a7da}', ['\u{a7db}', '\u{0}', '\u{0}']), ('\u{a7dc}', ['\u{19b}', '\u{0}', '\u{0}']), + ('\u{a7f5}', ['\u{a7f6}', '\u{0}', '\u{0}']), ('\u{ff21}', ['\u{ff41}', '\u{0}', '\u{0}']), + ('\u{ff22}', ['\u{ff42}', '\u{0}', '\u{0}']), ('\u{ff23}', ['\u{ff43}', '\u{0}', '\u{0}']), + ('\u{ff24}', ['\u{ff44}', '\u{0}', '\u{0}']), ('\u{ff25}', ['\u{ff45}', '\u{0}', '\u{0}']), + ('\u{ff26}', ['\u{ff46}', '\u{0}', '\u{0}']), ('\u{ff27}', ['\u{ff47}', '\u{0}', '\u{0}']), + ('\u{ff28}', ['\u{ff48}', '\u{0}', '\u{0}']), ('\u{ff29}', ['\u{ff49}', '\u{0}', '\u{0}']), + ('\u{ff2a}', ['\u{ff4a}', '\u{0}', '\u{0}']), ('\u{ff2b}', ['\u{ff4b}', '\u{0}', '\u{0}']), + ('\u{ff2c}', ['\u{ff4c}', '\u{0}', '\u{0}']), ('\u{ff2d}', ['\u{ff4d}', '\u{0}', '\u{0}']), + ('\u{ff2e}', ['\u{ff4e}', '\u{0}', '\u{0}']), ('\u{ff2f}', ['\u{ff4f}', '\u{0}', '\u{0}']), + ('\u{ff30}', ['\u{ff50}', '\u{0}', '\u{0}']), ('\u{ff31}', ['\u{ff51}', '\u{0}', '\u{0}']), + ('\u{ff32}', ['\u{ff52}', '\u{0}', '\u{0}']), ('\u{ff33}', ['\u{ff53}', '\u{0}', '\u{0}']), + ('\u{ff34}', ['\u{ff54}', '\u{0}', '\u{0}']), ('\u{ff35}', ['\u{ff55}', '\u{0}', '\u{0}']), + ('\u{ff36}', ['\u{ff56}', '\u{0}', '\u{0}']), ('\u{ff37}', ['\u{ff57}', '\u{0}', '\u{0}']), + ('\u{ff38}', ['\u{ff58}', '\u{0}', '\u{0}']), ('\u{ff39}', ['\u{ff59}', '\u{0}', '\u{0}']), + ('\u{ff3a}', ['\u{ff5a}', '\u{0}', '\u{0}']), + ('\u{10400}', ['\u{10428}', '\u{0}', '\u{0}']), + ('\u{10401}', ['\u{10429}', '\u{0}', '\u{0}']), + ('\u{10402}', ['\u{1042a}', '\u{0}', '\u{0}']), + ('\u{10403}', ['\u{1042b}', '\u{0}', '\u{0}']), + ('\u{10404}', ['\u{1042c}', '\u{0}', '\u{0}']), + ('\u{10405}', ['\u{1042d}', '\u{0}', '\u{0}']), + ('\u{10406}', ['\u{1042e}', '\u{0}', '\u{0}']), + ('\u{10407}', ['\u{1042f}', '\u{0}', '\u{0}']), + ('\u{10408}', ['\u{10430}', '\u{0}', '\u{0}']), + ('\u{10409}', ['\u{10431}', '\u{0}', '\u{0}']), + ('\u{1040a}', ['\u{10432}', '\u{0}', '\u{0}']), + ('\u{1040b}', ['\u{10433}', '\u{0}', '\u{0}']), + ('\u{1040c}', ['\u{10434}', '\u{0}', '\u{0}']), + ('\u{1040d}', ['\u{10435}', '\u{0}', '\u{0}']), + ('\u{1040e}', ['\u{10436}', '\u{0}', '\u{0}']), + ('\u{1040f}', ['\u{10437}', '\u{0}', '\u{0}']), + ('\u{10410}', ['\u{10438}', '\u{0}', '\u{0}']), + ('\u{10411}', ['\u{10439}', '\u{0}', '\u{0}']), + ('\u{10412}', ['\u{1043a}', '\u{0}', '\u{0}']), + ('\u{10413}', ['\u{1043b}', '\u{0}', '\u{0}']), + ('\u{10414}', ['\u{1043c}', '\u{0}', '\u{0}']), + ('\u{10415}', ['\u{1043d}', '\u{0}', '\u{0}']), + ('\u{10416}', ['\u{1043e}', '\u{0}', '\u{0}']), + ('\u{10417}', ['\u{1043f}', '\u{0}', '\u{0}']), + ('\u{10418}', ['\u{10440}', '\u{0}', '\u{0}']), + ('\u{10419}', ['\u{10441}', '\u{0}', '\u{0}']), + ('\u{1041a}', ['\u{10442}', '\u{0}', '\u{0}']), + ('\u{1041b}', ['\u{10443}', '\u{0}', '\u{0}']), + ('\u{1041c}', ['\u{10444}', '\u{0}', '\u{0}']), + ('\u{1041d}', ['\u{10445}', '\u{0}', '\u{0}']), + ('\u{1041e}', ['\u{10446}', '\u{0}', '\u{0}']), + ('\u{1041f}', ['\u{10447}', '\u{0}', '\u{0}']), + ('\u{10420}', ['\u{10448}', '\u{0}', '\u{0}']), + ('\u{10421}', ['\u{10449}', '\u{0}', '\u{0}']), + ('\u{10422}', ['\u{1044a}', '\u{0}', '\u{0}']), + ('\u{10423}', ['\u{1044b}', '\u{0}', '\u{0}']), + ('\u{10424}', ['\u{1044c}', '\u{0}', '\u{0}']), + ('\u{10425}', ['\u{1044d}', '\u{0}', '\u{0}']), + ('\u{10426}', ['\u{1044e}', '\u{0}', '\u{0}']), + ('\u{10427}', ['\u{1044f}', '\u{0}', '\u{0}']), + ('\u{104b0}', ['\u{104d8}', '\u{0}', '\u{0}']), + ('\u{104b1}', ['\u{104d9}', '\u{0}', '\u{0}']), + ('\u{104b2}', ['\u{104da}', '\u{0}', '\u{0}']), + ('\u{104b3}', ['\u{104db}', '\u{0}', '\u{0}']), + ('\u{104b4}', ['\u{104dc}', '\u{0}', '\u{0}']), + ('\u{104b5}', ['\u{104dd}', '\u{0}', '\u{0}']), + ('\u{104b6}', ['\u{104de}', '\u{0}', '\u{0}']), + ('\u{104b7}', ['\u{104df}', '\u{0}', '\u{0}']), + ('\u{104b8}', ['\u{104e0}', '\u{0}', '\u{0}']), + ('\u{104b9}', ['\u{104e1}', '\u{0}', '\u{0}']), + ('\u{104ba}', ['\u{104e2}', '\u{0}', '\u{0}']), + ('\u{104bb}', ['\u{104e3}', '\u{0}', '\u{0}']), + ('\u{104bc}', ['\u{104e4}', '\u{0}', '\u{0}']), + ('\u{104bd}', ['\u{104e5}', '\u{0}', '\u{0}']), + ('\u{104be}', ['\u{104e6}', '\u{0}', '\u{0}']), + ('\u{104bf}', ['\u{104e7}', '\u{0}', '\u{0}']), + ('\u{104c0}', ['\u{104e8}', '\u{0}', '\u{0}']), + ('\u{104c1}', ['\u{104e9}', '\u{0}', '\u{0}']), + ('\u{104c2}', ['\u{104ea}', '\u{0}', '\u{0}']), + ('\u{104c3}', ['\u{104eb}', '\u{0}', '\u{0}']), + ('\u{104c4}', ['\u{104ec}', '\u{0}', '\u{0}']), + ('\u{104c5}', ['\u{104ed}', '\u{0}', '\u{0}']), + ('\u{104c6}', ['\u{104ee}', '\u{0}', '\u{0}']), + ('\u{104c7}', ['\u{104ef}', '\u{0}', '\u{0}']), + ('\u{104c8}', ['\u{104f0}', '\u{0}', '\u{0}']), + ('\u{104c9}', ['\u{104f1}', '\u{0}', '\u{0}']), + ('\u{104ca}', ['\u{104f2}', '\u{0}', '\u{0}']), + ('\u{104cb}', ['\u{104f3}', '\u{0}', '\u{0}']), + ('\u{104cc}', ['\u{104f4}', '\u{0}', '\u{0}']), + ('\u{104cd}', ['\u{104f5}', '\u{0}', '\u{0}']), + ('\u{104ce}', ['\u{104f6}', '\u{0}', '\u{0}']), + ('\u{104cf}', ['\u{104f7}', '\u{0}', '\u{0}']), + ('\u{104d0}', ['\u{104f8}', '\u{0}', '\u{0}']), + ('\u{104d1}', ['\u{104f9}', '\u{0}', '\u{0}']), + ('\u{104d2}', ['\u{104fa}', '\u{0}', '\u{0}']), + ('\u{104d3}', ['\u{104fb}', '\u{0}', '\u{0}']), + ('\u{10570}', ['\u{10597}', '\u{0}', '\u{0}']), + ('\u{10571}', ['\u{10598}', '\u{0}', '\u{0}']), + ('\u{10572}', ['\u{10599}', '\u{0}', '\u{0}']), + ('\u{10573}', ['\u{1059a}', '\u{0}', '\u{0}']), + ('\u{10574}', ['\u{1059b}', '\u{0}', '\u{0}']), + ('\u{10575}', ['\u{1059c}', '\u{0}', '\u{0}']), + ('\u{10576}', ['\u{1059d}', '\u{0}', '\u{0}']), + ('\u{10577}', ['\u{1059e}', '\u{0}', '\u{0}']), + ('\u{10578}', ['\u{1059f}', '\u{0}', '\u{0}']), + ('\u{10579}', ['\u{105a0}', '\u{0}', '\u{0}']), + ('\u{1057a}', ['\u{105a1}', '\u{0}', '\u{0}']), + ('\u{1057c}', ['\u{105a3}', '\u{0}', '\u{0}']), + ('\u{1057d}', ['\u{105a4}', '\u{0}', '\u{0}']), + ('\u{1057e}', ['\u{105a5}', '\u{0}', '\u{0}']), + ('\u{1057f}', ['\u{105a6}', '\u{0}', '\u{0}']), + ('\u{10580}', ['\u{105a7}', '\u{0}', '\u{0}']), + ('\u{10581}', ['\u{105a8}', '\u{0}', '\u{0}']), + ('\u{10582}', ['\u{105a9}', '\u{0}', '\u{0}']), + ('\u{10583}', ['\u{105aa}', '\u{0}', '\u{0}']), + ('\u{10584}', ['\u{105ab}', '\u{0}', '\u{0}']), + ('\u{10585}', ['\u{105ac}', '\u{0}', '\u{0}']), + ('\u{10586}', ['\u{105ad}', '\u{0}', '\u{0}']), + ('\u{10587}', ['\u{105ae}', '\u{0}', '\u{0}']), + ('\u{10588}', ['\u{105af}', '\u{0}', '\u{0}']), + ('\u{10589}', ['\u{105b0}', '\u{0}', '\u{0}']), + ('\u{1058a}', ['\u{105b1}', '\u{0}', '\u{0}']), + ('\u{1058c}', ['\u{105b3}', '\u{0}', '\u{0}']), + ('\u{1058d}', ['\u{105b4}', '\u{0}', '\u{0}']), + ('\u{1058e}', ['\u{105b5}', '\u{0}', '\u{0}']), + ('\u{1058f}', ['\u{105b6}', '\u{0}', '\u{0}']), + ('\u{10590}', ['\u{105b7}', '\u{0}', '\u{0}']), + ('\u{10591}', ['\u{105b8}', '\u{0}', '\u{0}']), + ('\u{10592}', ['\u{105b9}', '\u{0}', '\u{0}']), + ('\u{10594}', ['\u{105bb}', '\u{0}', '\u{0}']), + ('\u{10595}', ['\u{105bc}', '\u{0}', '\u{0}']), + ('\u{10c80}', ['\u{10cc0}', '\u{0}', '\u{0}']), + ('\u{10c81}', ['\u{10cc1}', '\u{0}', '\u{0}']), + ('\u{10c82}', ['\u{10cc2}', '\u{0}', '\u{0}']), + ('\u{10c83}', ['\u{10cc3}', '\u{0}', '\u{0}']), + ('\u{10c84}', ['\u{10cc4}', '\u{0}', '\u{0}']), + ('\u{10c85}', ['\u{10cc5}', '\u{0}', '\u{0}']), + ('\u{10c86}', ['\u{10cc6}', '\u{0}', '\u{0}']), + ('\u{10c87}', ['\u{10cc7}', '\u{0}', '\u{0}']), + ('\u{10c88}', ['\u{10cc8}', '\u{0}', '\u{0}']), + ('\u{10c89}', ['\u{10cc9}', '\u{0}', '\u{0}']), + ('\u{10c8a}', ['\u{10cca}', '\u{0}', '\u{0}']), + ('\u{10c8b}', ['\u{10ccb}', '\u{0}', '\u{0}']), + ('\u{10c8c}', ['\u{10ccc}', '\u{0}', '\u{0}']), + ('\u{10c8d}', ['\u{10ccd}', '\u{0}', '\u{0}']), + ('\u{10c8e}', ['\u{10cce}', '\u{0}', '\u{0}']), + ('\u{10c8f}', ['\u{10ccf}', '\u{0}', '\u{0}']), + ('\u{10c90}', ['\u{10cd0}', '\u{0}', '\u{0}']), + ('\u{10c91}', ['\u{10cd1}', '\u{0}', '\u{0}']), + ('\u{10c92}', ['\u{10cd2}', '\u{0}', '\u{0}']), + ('\u{10c93}', ['\u{10cd3}', '\u{0}', '\u{0}']), + ('\u{10c94}', ['\u{10cd4}', '\u{0}', '\u{0}']), + ('\u{10c95}', ['\u{10cd5}', '\u{0}', '\u{0}']), + ('\u{10c96}', ['\u{10cd6}', '\u{0}', '\u{0}']), + ('\u{10c97}', ['\u{10cd7}', '\u{0}', '\u{0}']), + ('\u{10c98}', ['\u{10cd8}', '\u{0}', '\u{0}']), + ('\u{10c99}', ['\u{10cd9}', '\u{0}', '\u{0}']), + ('\u{10c9a}', ['\u{10cda}', '\u{0}', '\u{0}']), + ('\u{10c9b}', ['\u{10cdb}', '\u{0}', '\u{0}']), + ('\u{10c9c}', ['\u{10cdc}', '\u{0}', '\u{0}']), + ('\u{10c9d}', ['\u{10cdd}', '\u{0}', '\u{0}']), + ('\u{10c9e}', ['\u{10cde}', '\u{0}', '\u{0}']), + ('\u{10c9f}', ['\u{10cdf}', '\u{0}', '\u{0}']), + ('\u{10ca0}', ['\u{10ce0}', '\u{0}', '\u{0}']), + ('\u{10ca1}', ['\u{10ce1}', '\u{0}', '\u{0}']), + ('\u{10ca2}', ['\u{10ce2}', '\u{0}', '\u{0}']), + ('\u{10ca3}', ['\u{10ce3}', '\u{0}', '\u{0}']), + ('\u{10ca4}', ['\u{10ce4}', '\u{0}', '\u{0}']), + ('\u{10ca5}', ['\u{10ce5}', '\u{0}', '\u{0}']), + ('\u{10ca6}', ['\u{10ce6}', '\u{0}', '\u{0}']), + ('\u{10ca7}', ['\u{10ce7}', '\u{0}', '\u{0}']), + ('\u{10ca8}', ['\u{10ce8}', '\u{0}', '\u{0}']), + ('\u{10ca9}', ['\u{10ce9}', '\u{0}', '\u{0}']), + ('\u{10caa}', ['\u{10cea}', '\u{0}', '\u{0}']), + ('\u{10cab}', ['\u{10ceb}', '\u{0}', '\u{0}']), + ('\u{10cac}', ['\u{10cec}', '\u{0}', '\u{0}']), + ('\u{10cad}', ['\u{10ced}', '\u{0}', '\u{0}']), + ('\u{10cae}', ['\u{10cee}', '\u{0}', '\u{0}']), + ('\u{10caf}', ['\u{10cef}', '\u{0}', '\u{0}']), + ('\u{10cb0}', ['\u{10cf0}', '\u{0}', '\u{0}']), + ('\u{10cb1}', ['\u{10cf1}', '\u{0}', '\u{0}']), + ('\u{10cb2}', ['\u{10cf2}', '\u{0}', '\u{0}']), + ('\u{10d50}', ['\u{10d70}', '\u{0}', '\u{0}']), + ('\u{10d51}', ['\u{10d71}', '\u{0}', '\u{0}']), + ('\u{10d52}', ['\u{10d72}', '\u{0}', '\u{0}']), + ('\u{10d53}', ['\u{10d73}', '\u{0}', '\u{0}']), + ('\u{10d54}', ['\u{10d74}', '\u{0}', '\u{0}']), + ('\u{10d55}', ['\u{10d75}', '\u{0}', '\u{0}']), + ('\u{10d56}', ['\u{10d76}', '\u{0}', '\u{0}']), + ('\u{10d57}', ['\u{10d77}', '\u{0}', '\u{0}']), + ('\u{10d58}', ['\u{10d78}', '\u{0}', '\u{0}']), + ('\u{10d59}', ['\u{10d79}', '\u{0}', '\u{0}']), + ('\u{10d5a}', ['\u{10d7a}', '\u{0}', '\u{0}']), + ('\u{10d5b}', ['\u{10d7b}', '\u{0}', '\u{0}']), + ('\u{10d5c}', ['\u{10d7c}', '\u{0}', '\u{0}']), + ('\u{10d5d}', ['\u{10d7d}', '\u{0}', '\u{0}']), + ('\u{10d5e}', ['\u{10d7e}', '\u{0}', '\u{0}']), + ('\u{10d5f}', ['\u{10d7f}', '\u{0}', '\u{0}']), + ('\u{10d60}', ['\u{10d80}', '\u{0}', '\u{0}']), + ('\u{10d61}', ['\u{10d81}', '\u{0}', '\u{0}']), + ('\u{10d62}', ['\u{10d82}', '\u{0}', '\u{0}']), + ('\u{10d63}', ['\u{10d83}', '\u{0}', '\u{0}']), + ('\u{10d64}', ['\u{10d84}', '\u{0}', '\u{0}']), + ('\u{10d65}', ['\u{10d85}', '\u{0}', '\u{0}']), + ('\u{118a0}', ['\u{118c0}', '\u{0}', '\u{0}']), + ('\u{118a1}', ['\u{118c1}', '\u{0}', '\u{0}']), + ('\u{118a2}', ['\u{118c2}', '\u{0}', '\u{0}']), + ('\u{118a3}', ['\u{118c3}', '\u{0}', '\u{0}']), + ('\u{118a4}', ['\u{118c4}', '\u{0}', '\u{0}']), + ('\u{118a5}', ['\u{118c5}', '\u{0}', '\u{0}']), + ('\u{118a6}', ['\u{118c6}', '\u{0}', '\u{0}']), + ('\u{118a7}', ['\u{118c7}', '\u{0}', '\u{0}']), + ('\u{118a8}', ['\u{118c8}', '\u{0}', '\u{0}']), + ('\u{118a9}', ['\u{118c9}', '\u{0}', '\u{0}']), + ('\u{118aa}', ['\u{118ca}', '\u{0}', '\u{0}']), + ('\u{118ab}', ['\u{118cb}', '\u{0}', '\u{0}']), + ('\u{118ac}', ['\u{118cc}', '\u{0}', '\u{0}']), + ('\u{118ad}', ['\u{118cd}', '\u{0}', '\u{0}']), + ('\u{118ae}', ['\u{118ce}', '\u{0}', '\u{0}']), + ('\u{118af}', ['\u{118cf}', '\u{0}', '\u{0}']), + ('\u{118b0}', ['\u{118d0}', '\u{0}', '\u{0}']), + ('\u{118b1}', ['\u{118d1}', '\u{0}', '\u{0}']), + ('\u{118b2}', ['\u{118d2}', '\u{0}', '\u{0}']), + ('\u{118b3}', ['\u{118d3}', '\u{0}', '\u{0}']), + ('\u{118b4}', ['\u{118d4}', '\u{0}', '\u{0}']), + ('\u{118b5}', ['\u{118d5}', '\u{0}', '\u{0}']), + ('\u{118b6}', ['\u{118d6}', '\u{0}', '\u{0}']), + ('\u{118b7}', ['\u{118d7}', '\u{0}', '\u{0}']), + ('\u{118b8}', ['\u{118d8}', '\u{0}', '\u{0}']), + ('\u{118b9}', ['\u{118d9}', '\u{0}', '\u{0}']), + ('\u{118ba}', ['\u{118da}', '\u{0}', '\u{0}']), + ('\u{118bb}', ['\u{118db}', '\u{0}', '\u{0}']), + ('\u{118bc}', ['\u{118dc}', '\u{0}', '\u{0}']), + ('\u{118bd}', ['\u{118dd}', '\u{0}', '\u{0}']), + ('\u{118be}', ['\u{118de}', '\u{0}', '\u{0}']), + ('\u{118bf}', ['\u{118df}', '\u{0}', '\u{0}']), + ('\u{16e40}', ['\u{16e60}', '\u{0}', '\u{0}']), + ('\u{16e41}', ['\u{16e61}', '\u{0}', '\u{0}']), + ('\u{16e42}', ['\u{16e62}', '\u{0}', '\u{0}']), + ('\u{16e43}', ['\u{16e63}', '\u{0}', '\u{0}']), + ('\u{16e44}', ['\u{16e64}', '\u{0}', '\u{0}']), + ('\u{16e45}', ['\u{16e65}', '\u{0}', '\u{0}']), + ('\u{16e46}', ['\u{16e66}', '\u{0}', '\u{0}']), + ('\u{16e47}', ['\u{16e67}', '\u{0}', '\u{0}']), + ('\u{16e48}', ['\u{16e68}', '\u{0}', '\u{0}']), + ('\u{16e49}', ['\u{16e69}', '\u{0}', '\u{0}']), + ('\u{16e4a}', ['\u{16e6a}', '\u{0}', '\u{0}']), + ('\u{16e4b}', ['\u{16e6b}', '\u{0}', '\u{0}']), + ('\u{16e4c}', ['\u{16e6c}', '\u{0}', '\u{0}']), + ('\u{16e4d}', ['\u{16e6d}', '\u{0}', '\u{0}']), + ('\u{16e4e}', ['\u{16e6e}', '\u{0}', '\u{0}']), + ('\u{16e4f}', ['\u{16e6f}', '\u{0}', '\u{0}']), + ('\u{16e50}', ['\u{16e70}', '\u{0}', '\u{0}']), + ('\u{16e51}', ['\u{16e71}', '\u{0}', '\u{0}']), + ('\u{16e52}', ['\u{16e72}', '\u{0}', '\u{0}']), + ('\u{16e53}', ['\u{16e73}', '\u{0}', '\u{0}']), + ('\u{16e54}', ['\u{16e74}', '\u{0}', '\u{0}']), + ('\u{16e55}', ['\u{16e75}', '\u{0}', '\u{0}']), + ('\u{16e56}', ['\u{16e76}', '\u{0}', '\u{0}']), + ('\u{16e57}', ['\u{16e77}', '\u{0}', '\u{0}']), + ('\u{16e58}', ['\u{16e78}', '\u{0}', '\u{0}']), + ('\u{16e59}', ['\u{16e79}', '\u{0}', '\u{0}']), + ('\u{16e5a}', ['\u{16e7a}', '\u{0}', '\u{0}']), + ('\u{16e5b}', ['\u{16e7b}', '\u{0}', '\u{0}']), + ('\u{16e5c}', ['\u{16e7c}', '\u{0}', '\u{0}']), + ('\u{16e5d}', ['\u{16e7d}', '\u{0}', '\u{0}']), + ('\u{16e5e}', ['\u{16e7e}', '\u{0}', '\u{0}']), + ('\u{16e5f}', ['\u{16e7f}', '\u{0}', '\u{0}']), + ('\u{16ea0}', ['\u{16ebb}', '\u{0}', '\u{0}']), + ('\u{16ea1}', ['\u{16ebc}', '\u{0}', '\u{0}']), + ('\u{16ea2}', ['\u{16ebd}', '\u{0}', '\u{0}']), + ('\u{16ea3}', ['\u{16ebe}', '\u{0}', '\u{0}']), + ('\u{16ea4}', ['\u{16ebf}', '\u{0}', '\u{0}']), + ('\u{16ea5}', ['\u{16ec0}', '\u{0}', '\u{0}']), + ('\u{16ea6}', ['\u{16ec1}', '\u{0}', '\u{0}']), + ('\u{16ea7}', ['\u{16ec2}', '\u{0}', '\u{0}']), + ('\u{16ea8}', ['\u{16ec3}', '\u{0}', '\u{0}']), + ('\u{16ea9}', ['\u{16ec4}', '\u{0}', '\u{0}']), + ('\u{16eaa}', ['\u{16ec5}', '\u{0}', '\u{0}']), + ('\u{16eab}', ['\u{16ec6}', '\u{0}', '\u{0}']), + ('\u{16eac}', ['\u{16ec7}', '\u{0}', '\u{0}']), + ('\u{16ead}', ['\u{16ec8}', '\u{0}', '\u{0}']), + ('\u{16eae}', ['\u{16ec9}', '\u{0}', '\u{0}']), + ('\u{16eaf}', ['\u{16eca}', '\u{0}', '\u{0}']), + ('\u{16eb0}', ['\u{16ecb}', '\u{0}', '\u{0}']), + ('\u{16eb1}', ['\u{16ecc}', '\u{0}', '\u{0}']), + ('\u{16eb2}', ['\u{16ecd}', '\u{0}', '\u{0}']), + ('\u{16eb3}', ['\u{16ece}', '\u{0}', '\u{0}']), + ('\u{16eb4}', ['\u{16ecf}', '\u{0}', '\u{0}']), + ('\u{16eb5}', ['\u{16ed0}', '\u{0}', '\u{0}']), + ('\u{16eb6}', ['\u{16ed1}', '\u{0}', '\u{0}']), + ('\u{16eb7}', ['\u{16ed2}', '\u{0}', '\u{0}']), + ('\u{16eb8}', ['\u{16ed3}', '\u{0}', '\u{0}']), + ('\u{1e900}', ['\u{1e922}', '\u{0}', '\u{0}']), + ('\u{1e901}', ['\u{1e923}', '\u{0}', '\u{0}']), + ('\u{1e902}', ['\u{1e924}', '\u{0}', '\u{0}']), + ('\u{1e903}', ['\u{1e925}', '\u{0}', '\u{0}']), + ('\u{1e904}', ['\u{1e926}', '\u{0}', '\u{0}']), + ('\u{1e905}', ['\u{1e927}', '\u{0}', '\u{0}']), + ('\u{1e906}', ['\u{1e928}', '\u{0}', '\u{0}']), + ('\u{1e907}', ['\u{1e929}', '\u{0}', '\u{0}']), + ('\u{1e908}', ['\u{1e92a}', '\u{0}', '\u{0}']), + ('\u{1e909}', ['\u{1e92b}', '\u{0}', '\u{0}']), + ('\u{1e90a}', ['\u{1e92c}', '\u{0}', '\u{0}']), + ('\u{1e90b}', ['\u{1e92d}', '\u{0}', '\u{0}']), + ('\u{1e90c}', ['\u{1e92e}', '\u{0}', '\u{0}']), + ('\u{1e90d}', ['\u{1e92f}', '\u{0}', '\u{0}']), + ('\u{1e90e}', ['\u{1e930}', '\u{0}', '\u{0}']), + ('\u{1e90f}', ['\u{1e931}', '\u{0}', '\u{0}']), + ('\u{1e910}', ['\u{1e932}', '\u{0}', '\u{0}']), + ('\u{1e911}', ['\u{1e933}', '\u{0}', '\u{0}']), + ('\u{1e912}', ['\u{1e934}', '\u{0}', '\u{0}']), + ('\u{1e913}', ['\u{1e935}', '\u{0}', '\u{0}']), + ('\u{1e914}', ['\u{1e936}', '\u{0}', '\u{0}']), + ('\u{1e915}', ['\u{1e937}', '\u{0}', '\u{0}']), + ('\u{1e916}', ['\u{1e938}', '\u{0}', '\u{0}']), + ('\u{1e917}', ['\u{1e939}', '\u{0}', '\u{0}']), + ('\u{1e918}', ['\u{1e93a}', '\u{0}', '\u{0}']), + ('\u{1e919}', ['\u{1e93b}', '\u{0}', '\u{0}']), + ('\u{1e91a}', ['\u{1e93c}', '\u{0}', '\u{0}']), + ('\u{1e91b}', ['\u{1e93d}', '\u{0}', '\u{0}']), + ('\u{1e91c}', ['\u{1e93e}', '\u{0}', '\u{0}']), + ('\u{1e91d}', ['\u{1e93f}', '\u{0}', '\u{0}']), + ('\u{1e91e}', ['\u{1e940}', '\u{0}', '\u{0}']), + ('\u{1e91f}', ['\u{1e941}', '\u{0}', '\u{0}']), + ('\u{1e920}', ['\u{1e942}', '\u{0}', '\u{0}']), + ('\u{1e921}', ['\u{1e943}', '\u{0}', '\u{0}']), +]; + +#[rustfmt::skip] +pub(super) static TO_UPPER: &[(char, [char; 3]); 1554] = &[ + ('\u{b5}', ['\u{39c}', '\u{0}', '\u{0}']), ('\u{df}', ['S', 'S', '\u{0}']), + ('\u{e0}', ['\u{c0}', '\u{0}', '\u{0}']), ('\u{e1}', ['\u{c1}', '\u{0}', '\u{0}']), + ('\u{e2}', ['\u{c2}', '\u{0}', '\u{0}']), ('\u{e3}', ['\u{c3}', '\u{0}', '\u{0}']), + ('\u{e4}', ['\u{c4}', '\u{0}', '\u{0}']), ('\u{e5}', ['\u{c5}', '\u{0}', '\u{0}']), + ('\u{e6}', ['\u{c6}', '\u{0}', '\u{0}']), ('\u{e7}', ['\u{c7}', '\u{0}', '\u{0}']), + ('\u{e8}', ['\u{c8}', '\u{0}', '\u{0}']), ('\u{e9}', ['\u{c9}', '\u{0}', '\u{0}']), + ('\u{ea}', ['\u{ca}', '\u{0}', '\u{0}']), ('\u{eb}', ['\u{cb}', '\u{0}', '\u{0}']), + ('\u{ec}', ['\u{cc}', '\u{0}', '\u{0}']), ('\u{ed}', ['\u{cd}', '\u{0}', '\u{0}']), + ('\u{ee}', ['\u{ce}', '\u{0}', '\u{0}']), ('\u{ef}', ['\u{cf}', '\u{0}', '\u{0}']), + ('\u{f0}', ['\u{d0}', '\u{0}', '\u{0}']), ('\u{f1}', ['\u{d1}', '\u{0}', '\u{0}']), + ('\u{f2}', ['\u{d2}', '\u{0}', '\u{0}']), ('\u{f3}', ['\u{d3}', '\u{0}', '\u{0}']), + ('\u{f4}', ['\u{d4}', '\u{0}', '\u{0}']), ('\u{f5}', ['\u{d5}', '\u{0}', '\u{0}']), + ('\u{f6}', ['\u{d6}', '\u{0}', '\u{0}']), ('\u{f8}', ['\u{d8}', '\u{0}', '\u{0}']), + ('\u{f9}', ['\u{d9}', '\u{0}', '\u{0}']), ('\u{fa}', ['\u{da}', '\u{0}', '\u{0}']), + ('\u{fb}', ['\u{db}', '\u{0}', '\u{0}']), ('\u{fc}', ['\u{dc}', '\u{0}', '\u{0}']), + ('\u{fd}', ['\u{dd}', '\u{0}', '\u{0}']), ('\u{fe}', ['\u{de}', '\u{0}', '\u{0}']), + ('\u{ff}', ['\u{178}', '\u{0}', '\u{0}']), ('\u{101}', ['\u{100}', '\u{0}', '\u{0}']), + ('\u{103}', ['\u{102}', '\u{0}', '\u{0}']), ('\u{105}', ['\u{104}', '\u{0}', '\u{0}']), + ('\u{107}', ['\u{106}', '\u{0}', '\u{0}']), ('\u{109}', ['\u{108}', '\u{0}', '\u{0}']), + ('\u{10b}', ['\u{10a}', '\u{0}', '\u{0}']), ('\u{10d}', ['\u{10c}', '\u{0}', '\u{0}']), + ('\u{10f}', ['\u{10e}', '\u{0}', '\u{0}']), ('\u{111}', ['\u{110}', '\u{0}', '\u{0}']), + ('\u{113}', ['\u{112}', '\u{0}', '\u{0}']), ('\u{115}', ['\u{114}', '\u{0}', '\u{0}']), + ('\u{117}', ['\u{116}', '\u{0}', '\u{0}']), ('\u{119}', ['\u{118}', '\u{0}', '\u{0}']), + ('\u{11b}', ['\u{11a}', '\u{0}', '\u{0}']), ('\u{11d}', ['\u{11c}', '\u{0}', '\u{0}']), + ('\u{11f}', ['\u{11e}', '\u{0}', '\u{0}']), ('\u{121}', ['\u{120}', '\u{0}', '\u{0}']), + ('\u{123}', ['\u{122}', '\u{0}', '\u{0}']), ('\u{125}', ['\u{124}', '\u{0}', '\u{0}']), + ('\u{127}', ['\u{126}', '\u{0}', '\u{0}']), ('\u{129}', ['\u{128}', '\u{0}', '\u{0}']), + ('\u{12b}', ['\u{12a}', '\u{0}', '\u{0}']), ('\u{12d}', ['\u{12c}', '\u{0}', '\u{0}']), + ('\u{12f}', ['\u{12e}', '\u{0}', '\u{0}']), ('\u{131}', ['I', '\u{0}', '\u{0}']), + ('\u{133}', ['\u{132}', '\u{0}', '\u{0}']), ('\u{135}', ['\u{134}', '\u{0}', '\u{0}']), + ('\u{137}', ['\u{136}', '\u{0}', '\u{0}']), ('\u{13a}', ['\u{139}', '\u{0}', '\u{0}']), + ('\u{13c}', ['\u{13b}', '\u{0}', '\u{0}']), ('\u{13e}', ['\u{13d}', '\u{0}', '\u{0}']), + ('\u{140}', ['\u{13f}', '\u{0}', '\u{0}']), ('\u{142}', ['\u{141}', '\u{0}', '\u{0}']), + ('\u{144}', ['\u{143}', '\u{0}', '\u{0}']), ('\u{146}', ['\u{145}', '\u{0}', '\u{0}']), + ('\u{148}', ['\u{147}', '\u{0}', '\u{0}']), ('\u{149}', ['\u{2bc}', 'N', '\u{0}']), + ('\u{14b}', ['\u{14a}', '\u{0}', '\u{0}']), ('\u{14d}', ['\u{14c}', '\u{0}', '\u{0}']), + ('\u{14f}', ['\u{14e}', '\u{0}', '\u{0}']), ('\u{151}', ['\u{150}', '\u{0}', '\u{0}']), + ('\u{153}', ['\u{152}', '\u{0}', '\u{0}']), ('\u{155}', ['\u{154}', '\u{0}', '\u{0}']), + ('\u{157}', ['\u{156}', '\u{0}', '\u{0}']), ('\u{159}', ['\u{158}', '\u{0}', '\u{0}']), + ('\u{15b}', ['\u{15a}', '\u{0}', '\u{0}']), ('\u{15d}', ['\u{15c}', '\u{0}', '\u{0}']), + ('\u{15f}', ['\u{15e}', '\u{0}', '\u{0}']), ('\u{161}', ['\u{160}', '\u{0}', '\u{0}']), + ('\u{163}', ['\u{162}', '\u{0}', '\u{0}']), ('\u{165}', ['\u{164}', '\u{0}', '\u{0}']), + ('\u{167}', ['\u{166}', '\u{0}', '\u{0}']), ('\u{169}', ['\u{168}', '\u{0}', '\u{0}']), + ('\u{16b}', ['\u{16a}', '\u{0}', '\u{0}']), ('\u{16d}', ['\u{16c}', '\u{0}', '\u{0}']), + ('\u{16f}', ['\u{16e}', '\u{0}', '\u{0}']), ('\u{171}', ['\u{170}', '\u{0}', '\u{0}']), + ('\u{173}', ['\u{172}', '\u{0}', '\u{0}']), ('\u{175}', ['\u{174}', '\u{0}', '\u{0}']), + ('\u{177}', ['\u{176}', '\u{0}', '\u{0}']), ('\u{17a}', ['\u{179}', '\u{0}', '\u{0}']), + ('\u{17c}', ['\u{17b}', '\u{0}', '\u{0}']), ('\u{17e}', ['\u{17d}', '\u{0}', '\u{0}']), + ('\u{17f}', ['S', '\u{0}', '\u{0}']), ('\u{180}', ['\u{243}', '\u{0}', '\u{0}']), + ('\u{183}', ['\u{182}', '\u{0}', '\u{0}']), ('\u{185}', ['\u{184}', '\u{0}', '\u{0}']), + ('\u{188}', ['\u{187}', '\u{0}', '\u{0}']), ('\u{18c}', ['\u{18b}', '\u{0}', '\u{0}']), + ('\u{192}', ['\u{191}', '\u{0}', '\u{0}']), ('\u{195}', ['\u{1f6}', '\u{0}', '\u{0}']), + ('\u{199}', ['\u{198}', '\u{0}', '\u{0}']), ('\u{19a}', ['\u{23d}', '\u{0}', '\u{0}']), + ('\u{19b}', ['\u{a7dc}', '\u{0}', '\u{0}']), ('\u{19e}', ['\u{220}', '\u{0}', '\u{0}']), + ('\u{1a1}', ['\u{1a0}', '\u{0}', '\u{0}']), ('\u{1a3}', ['\u{1a2}', '\u{0}', '\u{0}']), + ('\u{1a5}', ['\u{1a4}', '\u{0}', '\u{0}']), ('\u{1a8}', ['\u{1a7}', '\u{0}', '\u{0}']), + ('\u{1ad}', ['\u{1ac}', '\u{0}', '\u{0}']), ('\u{1b0}', ['\u{1af}', '\u{0}', '\u{0}']), + ('\u{1b4}', ['\u{1b3}', '\u{0}', '\u{0}']), ('\u{1b6}', ['\u{1b5}', '\u{0}', '\u{0}']), + ('\u{1b9}', ['\u{1b8}', '\u{0}', '\u{0}']), ('\u{1bd}', ['\u{1bc}', '\u{0}', '\u{0}']), + ('\u{1bf}', ['\u{1f7}', '\u{0}', '\u{0}']), ('\u{1c5}', ['\u{1c4}', '\u{0}', '\u{0}']), + ('\u{1c6}', ['\u{1c4}', '\u{0}', '\u{0}']), ('\u{1c8}', ['\u{1c7}', '\u{0}', '\u{0}']), + ('\u{1c9}', ['\u{1c7}', '\u{0}', '\u{0}']), ('\u{1cb}', ['\u{1ca}', '\u{0}', '\u{0}']), + ('\u{1cc}', ['\u{1ca}', '\u{0}', '\u{0}']), ('\u{1ce}', ['\u{1cd}', '\u{0}', '\u{0}']), + ('\u{1d0}', ['\u{1cf}', '\u{0}', '\u{0}']), ('\u{1d2}', ['\u{1d1}', '\u{0}', '\u{0}']), + ('\u{1d4}', ['\u{1d3}', '\u{0}', '\u{0}']), ('\u{1d6}', ['\u{1d5}', '\u{0}', '\u{0}']), + ('\u{1d8}', ['\u{1d7}', '\u{0}', '\u{0}']), ('\u{1da}', ['\u{1d9}', '\u{0}', '\u{0}']), + ('\u{1dc}', ['\u{1db}', '\u{0}', '\u{0}']), ('\u{1dd}', ['\u{18e}', '\u{0}', '\u{0}']), + ('\u{1df}', ['\u{1de}', '\u{0}', '\u{0}']), ('\u{1e1}', ['\u{1e0}', '\u{0}', '\u{0}']), + ('\u{1e3}', ['\u{1e2}', '\u{0}', '\u{0}']), ('\u{1e5}', ['\u{1e4}', '\u{0}', '\u{0}']), + ('\u{1e7}', ['\u{1e6}', '\u{0}', '\u{0}']), ('\u{1e9}', ['\u{1e8}', '\u{0}', '\u{0}']), + ('\u{1eb}', ['\u{1ea}', '\u{0}', '\u{0}']), ('\u{1ed}', ['\u{1ec}', '\u{0}', '\u{0}']), + ('\u{1ef}', ['\u{1ee}', '\u{0}', '\u{0}']), ('\u{1f0}', ['J', '\u{30c}', '\u{0}']), + ('\u{1f2}', ['\u{1f1}', '\u{0}', '\u{0}']), ('\u{1f3}', ['\u{1f1}', '\u{0}', '\u{0}']), + ('\u{1f5}', ['\u{1f4}', '\u{0}', '\u{0}']), ('\u{1f9}', ['\u{1f8}', '\u{0}', '\u{0}']), + ('\u{1fb}', ['\u{1fa}', '\u{0}', '\u{0}']), ('\u{1fd}', ['\u{1fc}', '\u{0}', '\u{0}']), + ('\u{1ff}', ['\u{1fe}', '\u{0}', '\u{0}']), ('\u{201}', ['\u{200}', '\u{0}', '\u{0}']), + ('\u{203}', ['\u{202}', '\u{0}', '\u{0}']), ('\u{205}', ['\u{204}', '\u{0}', '\u{0}']), + ('\u{207}', ['\u{206}', '\u{0}', '\u{0}']), ('\u{209}', ['\u{208}', '\u{0}', '\u{0}']), + ('\u{20b}', ['\u{20a}', '\u{0}', '\u{0}']), ('\u{20d}', ['\u{20c}', '\u{0}', '\u{0}']), + ('\u{20f}', ['\u{20e}', '\u{0}', '\u{0}']), ('\u{211}', ['\u{210}', '\u{0}', '\u{0}']), + ('\u{213}', ['\u{212}', '\u{0}', '\u{0}']), ('\u{215}', ['\u{214}', '\u{0}', '\u{0}']), + ('\u{217}', ['\u{216}', '\u{0}', '\u{0}']), ('\u{219}', ['\u{218}', '\u{0}', '\u{0}']), + ('\u{21b}', ['\u{21a}', '\u{0}', '\u{0}']), ('\u{21d}', ['\u{21c}', '\u{0}', '\u{0}']), + ('\u{21f}', ['\u{21e}', '\u{0}', '\u{0}']), ('\u{223}', ['\u{222}', '\u{0}', '\u{0}']), + ('\u{225}', ['\u{224}', '\u{0}', '\u{0}']), ('\u{227}', ['\u{226}', '\u{0}', '\u{0}']), + ('\u{229}', ['\u{228}', '\u{0}', '\u{0}']), ('\u{22b}', ['\u{22a}', '\u{0}', '\u{0}']), + ('\u{22d}', ['\u{22c}', '\u{0}', '\u{0}']), ('\u{22f}', ['\u{22e}', '\u{0}', '\u{0}']), + ('\u{231}', ['\u{230}', '\u{0}', '\u{0}']), ('\u{233}', ['\u{232}', '\u{0}', '\u{0}']), + ('\u{23c}', ['\u{23b}', '\u{0}', '\u{0}']), ('\u{23f}', ['\u{2c7e}', '\u{0}', '\u{0}']), + ('\u{240}', ['\u{2c7f}', '\u{0}', '\u{0}']), ('\u{242}', ['\u{241}', '\u{0}', '\u{0}']), + ('\u{247}', ['\u{246}', '\u{0}', '\u{0}']), ('\u{249}', ['\u{248}', '\u{0}', '\u{0}']), + ('\u{24b}', ['\u{24a}', '\u{0}', '\u{0}']), ('\u{24d}', ['\u{24c}', '\u{0}', '\u{0}']), + ('\u{24f}', ['\u{24e}', '\u{0}', '\u{0}']), ('\u{250}', ['\u{2c6f}', '\u{0}', '\u{0}']), + ('\u{251}', ['\u{2c6d}', '\u{0}', '\u{0}']), ('\u{252}', ['\u{2c70}', '\u{0}', '\u{0}']), + ('\u{253}', ['\u{181}', '\u{0}', '\u{0}']), ('\u{254}', ['\u{186}', '\u{0}', '\u{0}']), + ('\u{256}', ['\u{189}', '\u{0}', '\u{0}']), ('\u{257}', ['\u{18a}', '\u{0}', '\u{0}']), + ('\u{259}', ['\u{18f}', '\u{0}', '\u{0}']), ('\u{25b}', ['\u{190}', '\u{0}', '\u{0}']), + ('\u{25c}', ['\u{a7ab}', '\u{0}', '\u{0}']), ('\u{260}', ['\u{193}', '\u{0}', '\u{0}']), + ('\u{261}', ['\u{a7ac}', '\u{0}', '\u{0}']), ('\u{263}', ['\u{194}', '\u{0}', '\u{0}']), + ('\u{264}', ['\u{a7cb}', '\u{0}', '\u{0}']), ('\u{265}', ['\u{a78d}', '\u{0}', '\u{0}']), + ('\u{266}', ['\u{a7aa}', '\u{0}', '\u{0}']), ('\u{268}', ['\u{197}', '\u{0}', '\u{0}']), + ('\u{269}', ['\u{196}', '\u{0}', '\u{0}']), ('\u{26a}', ['\u{a7ae}', '\u{0}', '\u{0}']), + ('\u{26b}', ['\u{2c62}', '\u{0}', '\u{0}']), ('\u{26c}', ['\u{a7ad}', '\u{0}', '\u{0}']), + ('\u{26f}', ['\u{19c}', '\u{0}', '\u{0}']), ('\u{271}', ['\u{2c6e}', '\u{0}', '\u{0}']), + ('\u{272}', ['\u{19d}', '\u{0}', '\u{0}']), ('\u{275}', ['\u{19f}', '\u{0}', '\u{0}']), + ('\u{27d}', ['\u{2c64}', '\u{0}', '\u{0}']), ('\u{280}', ['\u{1a6}', '\u{0}', '\u{0}']), + ('\u{282}', ['\u{a7c5}', '\u{0}', '\u{0}']), ('\u{283}', ['\u{1a9}', '\u{0}', '\u{0}']), + ('\u{287}', ['\u{a7b1}', '\u{0}', '\u{0}']), ('\u{288}', ['\u{1ae}', '\u{0}', '\u{0}']), + ('\u{289}', ['\u{244}', '\u{0}', '\u{0}']), ('\u{28a}', ['\u{1b1}', '\u{0}', '\u{0}']), + ('\u{28b}', ['\u{1b2}', '\u{0}', '\u{0}']), ('\u{28c}', ['\u{245}', '\u{0}', '\u{0}']), + ('\u{292}', ['\u{1b7}', '\u{0}', '\u{0}']), ('\u{29d}', ['\u{a7b2}', '\u{0}', '\u{0}']), + ('\u{29e}', ['\u{a7b0}', '\u{0}', '\u{0}']), ('\u{345}', ['\u{399}', '\u{0}', '\u{0}']), + ('\u{371}', ['\u{370}', '\u{0}', '\u{0}']), ('\u{373}', ['\u{372}', '\u{0}', '\u{0}']), + ('\u{377}', ['\u{376}', '\u{0}', '\u{0}']), ('\u{37b}', ['\u{3fd}', '\u{0}', '\u{0}']), + ('\u{37c}', ['\u{3fe}', '\u{0}', '\u{0}']), ('\u{37d}', ['\u{3ff}', '\u{0}', '\u{0}']), + ('\u{390}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{3ac}', ['\u{386}', '\u{0}', '\u{0}']), + ('\u{3ad}', ['\u{388}', '\u{0}', '\u{0}']), ('\u{3ae}', ['\u{389}', '\u{0}', '\u{0}']), + ('\u{3af}', ['\u{38a}', '\u{0}', '\u{0}']), ('\u{3b0}', ['\u{3a5}', '\u{308}', '\u{301}']), + ('\u{3b1}', ['\u{391}', '\u{0}', '\u{0}']), ('\u{3b2}', ['\u{392}', '\u{0}', '\u{0}']), + ('\u{3b3}', ['\u{393}', '\u{0}', '\u{0}']), ('\u{3b4}', ['\u{394}', '\u{0}', '\u{0}']), + ('\u{3b5}', ['\u{395}', '\u{0}', '\u{0}']), ('\u{3b6}', ['\u{396}', '\u{0}', '\u{0}']), + ('\u{3b7}', ['\u{397}', '\u{0}', '\u{0}']), ('\u{3b8}', ['\u{398}', '\u{0}', '\u{0}']), + ('\u{3b9}', ['\u{399}', '\u{0}', '\u{0}']), ('\u{3ba}', ['\u{39a}', '\u{0}', '\u{0}']), + ('\u{3bb}', ['\u{39b}', '\u{0}', '\u{0}']), ('\u{3bc}', ['\u{39c}', '\u{0}', '\u{0}']), + ('\u{3bd}', ['\u{39d}', '\u{0}', '\u{0}']), ('\u{3be}', ['\u{39e}', '\u{0}', '\u{0}']), + ('\u{3bf}', ['\u{39f}', '\u{0}', '\u{0}']), ('\u{3c0}', ['\u{3a0}', '\u{0}', '\u{0}']), + ('\u{3c1}', ['\u{3a1}', '\u{0}', '\u{0}']), ('\u{3c2}', ['\u{3a3}', '\u{0}', '\u{0}']), + ('\u{3c3}', ['\u{3a3}', '\u{0}', '\u{0}']), ('\u{3c4}', ['\u{3a4}', '\u{0}', '\u{0}']), + ('\u{3c5}', ['\u{3a5}', '\u{0}', '\u{0}']), ('\u{3c6}', ['\u{3a6}', '\u{0}', '\u{0}']), + ('\u{3c7}', ['\u{3a7}', '\u{0}', '\u{0}']), ('\u{3c8}', ['\u{3a8}', '\u{0}', '\u{0}']), + ('\u{3c9}', ['\u{3a9}', '\u{0}', '\u{0}']), ('\u{3ca}', ['\u{3aa}', '\u{0}', '\u{0}']), + ('\u{3cb}', ['\u{3ab}', '\u{0}', '\u{0}']), ('\u{3cc}', ['\u{38c}', '\u{0}', '\u{0}']), + ('\u{3cd}', ['\u{38e}', '\u{0}', '\u{0}']), ('\u{3ce}', ['\u{38f}', '\u{0}', '\u{0}']), + ('\u{3d0}', ['\u{392}', '\u{0}', '\u{0}']), ('\u{3d1}', ['\u{398}', '\u{0}', '\u{0}']), + ('\u{3d5}', ['\u{3a6}', '\u{0}', '\u{0}']), ('\u{3d6}', ['\u{3a0}', '\u{0}', '\u{0}']), + ('\u{3d7}', ['\u{3cf}', '\u{0}', '\u{0}']), ('\u{3d9}', ['\u{3d8}', '\u{0}', '\u{0}']), + ('\u{3db}', ['\u{3da}', '\u{0}', '\u{0}']), ('\u{3dd}', ['\u{3dc}', '\u{0}', '\u{0}']), + ('\u{3df}', ['\u{3de}', '\u{0}', '\u{0}']), ('\u{3e1}', ['\u{3e0}', '\u{0}', '\u{0}']), + ('\u{3e3}', ['\u{3e2}', '\u{0}', '\u{0}']), ('\u{3e5}', ['\u{3e4}', '\u{0}', '\u{0}']), + ('\u{3e7}', ['\u{3e6}', '\u{0}', '\u{0}']), ('\u{3e9}', ['\u{3e8}', '\u{0}', '\u{0}']), + ('\u{3eb}', ['\u{3ea}', '\u{0}', '\u{0}']), ('\u{3ed}', ['\u{3ec}', '\u{0}', '\u{0}']), + ('\u{3ef}', ['\u{3ee}', '\u{0}', '\u{0}']), ('\u{3f0}', ['\u{39a}', '\u{0}', '\u{0}']), + ('\u{3f1}', ['\u{3a1}', '\u{0}', '\u{0}']), ('\u{3f2}', ['\u{3f9}', '\u{0}', '\u{0}']), + ('\u{3f3}', ['\u{37f}', '\u{0}', '\u{0}']), ('\u{3f5}', ['\u{395}', '\u{0}', '\u{0}']), + ('\u{3f8}', ['\u{3f7}', '\u{0}', '\u{0}']), ('\u{3fb}', ['\u{3fa}', '\u{0}', '\u{0}']), + ('\u{430}', ['\u{410}', '\u{0}', '\u{0}']), ('\u{431}', ['\u{411}', '\u{0}', '\u{0}']), + ('\u{432}', ['\u{412}', '\u{0}', '\u{0}']), ('\u{433}', ['\u{413}', '\u{0}', '\u{0}']), + ('\u{434}', ['\u{414}', '\u{0}', '\u{0}']), ('\u{435}', ['\u{415}', '\u{0}', '\u{0}']), + ('\u{436}', ['\u{416}', '\u{0}', '\u{0}']), ('\u{437}', ['\u{417}', '\u{0}', '\u{0}']), + ('\u{438}', ['\u{418}', '\u{0}', '\u{0}']), ('\u{439}', ['\u{419}', '\u{0}', '\u{0}']), + ('\u{43a}', ['\u{41a}', '\u{0}', '\u{0}']), ('\u{43b}', ['\u{41b}', '\u{0}', '\u{0}']), + ('\u{43c}', ['\u{41c}', '\u{0}', '\u{0}']), ('\u{43d}', ['\u{41d}', '\u{0}', '\u{0}']), + ('\u{43e}', ['\u{41e}', '\u{0}', '\u{0}']), ('\u{43f}', ['\u{41f}', '\u{0}', '\u{0}']), + ('\u{440}', ['\u{420}', '\u{0}', '\u{0}']), ('\u{441}', ['\u{421}', '\u{0}', '\u{0}']), + ('\u{442}', ['\u{422}', '\u{0}', '\u{0}']), ('\u{443}', ['\u{423}', '\u{0}', '\u{0}']), + ('\u{444}', ['\u{424}', '\u{0}', '\u{0}']), ('\u{445}', ['\u{425}', '\u{0}', '\u{0}']), + ('\u{446}', ['\u{426}', '\u{0}', '\u{0}']), ('\u{447}', ['\u{427}', '\u{0}', '\u{0}']), + ('\u{448}', ['\u{428}', '\u{0}', '\u{0}']), ('\u{449}', ['\u{429}', '\u{0}', '\u{0}']), + ('\u{44a}', ['\u{42a}', '\u{0}', '\u{0}']), ('\u{44b}', ['\u{42b}', '\u{0}', '\u{0}']), + ('\u{44c}', ['\u{42c}', '\u{0}', '\u{0}']), ('\u{44d}', ['\u{42d}', '\u{0}', '\u{0}']), + ('\u{44e}', ['\u{42e}', '\u{0}', '\u{0}']), ('\u{44f}', ['\u{42f}', '\u{0}', '\u{0}']), + ('\u{450}', ['\u{400}', '\u{0}', '\u{0}']), ('\u{451}', ['\u{401}', '\u{0}', '\u{0}']), + ('\u{452}', ['\u{402}', '\u{0}', '\u{0}']), ('\u{453}', ['\u{403}', '\u{0}', '\u{0}']), + ('\u{454}', ['\u{404}', '\u{0}', '\u{0}']), ('\u{455}', ['\u{405}', '\u{0}', '\u{0}']), + ('\u{456}', ['\u{406}', '\u{0}', '\u{0}']), ('\u{457}', ['\u{407}', '\u{0}', '\u{0}']), + ('\u{458}', ['\u{408}', '\u{0}', '\u{0}']), ('\u{459}', ['\u{409}', '\u{0}', '\u{0}']), + ('\u{45a}', ['\u{40a}', '\u{0}', '\u{0}']), ('\u{45b}', ['\u{40b}', '\u{0}', '\u{0}']), + ('\u{45c}', ['\u{40c}', '\u{0}', '\u{0}']), ('\u{45d}', ['\u{40d}', '\u{0}', '\u{0}']), + ('\u{45e}', ['\u{40e}', '\u{0}', '\u{0}']), ('\u{45f}', ['\u{40f}', '\u{0}', '\u{0}']), + ('\u{461}', ['\u{460}', '\u{0}', '\u{0}']), ('\u{463}', ['\u{462}', '\u{0}', '\u{0}']), + ('\u{465}', ['\u{464}', '\u{0}', '\u{0}']), ('\u{467}', ['\u{466}', '\u{0}', '\u{0}']), + ('\u{469}', ['\u{468}', '\u{0}', '\u{0}']), ('\u{46b}', ['\u{46a}', '\u{0}', '\u{0}']), + ('\u{46d}', ['\u{46c}', '\u{0}', '\u{0}']), ('\u{46f}', ['\u{46e}', '\u{0}', '\u{0}']), + ('\u{471}', ['\u{470}', '\u{0}', '\u{0}']), ('\u{473}', ['\u{472}', '\u{0}', '\u{0}']), + ('\u{475}', ['\u{474}', '\u{0}', '\u{0}']), ('\u{477}', ['\u{476}', '\u{0}', '\u{0}']), + ('\u{479}', ['\u{478}', '\u{0}', '\u{0}']), ('\u{47b}', ['\u{47a}', '\u{0}', '\u{0}']), + ('\u{47d}', ['\u{47c}', '\u{0}', '\u{0}']), ('\u{47f}', ['\u{47e}', '\u{0}', '\u{0}']), + ('\u{481}', ['\u{480}', '\u{0}', '\u{0}']), ('\u{48b}', ['\u{48a}', '\u{0}', '\u{0}']), + ('\u{48d}', ['\u{48c}', '\u{0}', '\u{0}']), ('\u{48f}', ['\u{48e}', '\u{0}', '\u{0}']), + ('\u{491}', ['\u{490}', '\u{0}', '\u{0}']), ('\u{493}', ['\u{492}', '\u{0}', '\u{0}']), + ('\u{495}', ['\u{494}', '\u{0}', '\u{0}']), ('\u{497}', ['\u{496}', '\u{0}', '\u{0}']), + ('\u{499}', ['\u{498}', '\u{0}', '\u{0}']), ('\u{49b}', ['\u{49a}', '\u{0}', '\u{0}']), + ('\u{49d}', ['\u{49c}', '\u{0}', '\u{0}']), ('\u{49f}', ['\u{49e}', '\u{0}', '\u{0}']), + ('\u{4a1}', ['\u{4a0}', '\u{0}', '\u{0}']), ('\u{4a3}', ['\u{4a2}', '\u{0}', '\u{0}']), + ('\u{4a5}', ['\u{4a4}', '\u{0}', '\u{0}']), ('\u{4a7}', ['\u{4a6}', '\u{0}', '\u{0}']), + ('\u{4a9}', ['\u{4a8}', '\u{0}', '\u{0}']), ('\u{4ab}', ['\u{4aa}', '\u{0}', '\u{0}']), + ('\u{4ad}', ['\u{4ac}', '\u{0}', '\u{0}']), ('\u{4af}', ['\u{4ae}', '\u{0}', '\u{0}']), + ('\u{4b1}', ['\u{4b0}', '\u{0}', '\u{0}']), ('\u{4b3}', ['\u{4b2}', '\u{0}', '\u{0}']), + ('\u{4b5}', ['\u{4b4}', '\u{0}', '\u{0}']), ('\u{4b7}', ['\u{4b6}', '\u{0}', '\u{0}']), + ('\u{4b9}', ['\u{4b8}', '\u{0}', '\u{0}']), ('\u{4bb}', ['\u{4ba}', '\u{0}', '\u{0}']), + ('\u{4bd}', ['\u{4bc}', '\u{0}', '\u{0}']), ('\u{4bf}', ['\u{4be}', '\u{0}', '\u{0}']), + ('\u{4c2}', ['\u{4c1}', '\u{0}', '\u{0}']), ('\u{4c4}', ['\u{4c3}', '\u{0}', '\u{0}']), + ('\u{4c6}', ['\u{4c5}', '\u{0}', '\u{0}']), ('\u{4c8}', ['\u{4c7}', '\u{0}', '\u{0}']), + ('\u{4ca}', ['\u{4c9}', '\u{0}', '\u{0}']), ('\u{4cc}', ['\u{4cb}', '\u{0}', '\u{0}']), + ('\u{4ce}', ['\u{4cd}', '\u{0}', '\u{0}']), ('\u{4cf}', ['\u{4c0}', '\u{0}', '\u{0}']), + ('\u{4d1}', ['\u{4d0}', '\u{0}', '\u{0}']), ('\u{4d3}', ['\u{4d2}', '\u{0}', '\u{0}']), + ('\u{4d5}', ['\u{4d4}', '\u{0}', '\u{0}']), ('\u{4d7}', ['\u{4d6}', '\u{0}', '\u{0}']), + ('\u{4d9}', ['\u{4d8}', '\u{0}', '\u{0}']), ('\u{4db}', ['\u{4da}', '\u{0}', '\u{0}']), + ('\u{4dd}', ['\u{4dc}', '\u{0}', '\u{0}']), ('\u{4df}', ['\u{4de}', '\u{0}', '\u{0}']), + ('\u{4e1}', ['\u{4e0}', '\u{0}', '\u{0}']), ('\u{4e3}', ['\u{4e2}', '\u{0}', '\u{0}']), + ('\u{4e5}', ['\u{4e4}', '\u{0}', '\u{0}']), ('\u{4e7}', ['\u{4e6}', '\u{0}', '\u{0}']), + ('\u{4e9}', ['\u{4e8}', '\u{0}', '\u{0}']), ('\u{4eb}', ['\u{4ea}', '\u{0}', '\u{0}']), + ('\u{4ed}', ['\u{4ec}', '\u{0}', '\u{0}']), ('\u{4ef}', ['\u{4ee}', '\u{0}', '\u{0}']), + ('\u{4f1}', ['\u{4f0}', '\u{0}', '\u{0}']), ('\u{4f3}', ['\u{4f2}', '\u{0}', '\u{0}']), + ('\u{4f5}', ['\u{4f4}', '\u{0}', '\u{0}']), ('\u{4f7}', ['\u{4f6}', '\u{0}', '\u{0}']), + ('\u{4f9}', ['\u{4f8}', '\u{0}', '\u{0}']), ('\u{4fb}', ['\u{4fa}', '\u{0}', '\u{0}']), + ('\u{4fd}', ['\u{4fc}', '\u{0}', '\u{0}']), ('\u{4ff}', ['\u{4fe}', '\u{0}', '\u{0}']), + ('\u{501}', ['\u{500}', '\u{0}', '\u{0}']), ('\u{503}', ['\u{502}', '\u{0}', '\u{0}']), + ('\u{505}', ['\u{504}', '\u{0}', '\u{0}']), ('\u{507}', ['\u{506}', '\u{0}', '\u{0}']), + ('\u{509}', ['\u{508}', '\u{0}', '\u{0}']), ('\u{50b}', ['\u{50a}', '\u{0}', '\u{0}']), + ('\u{50d}', ['\u{50c}', '\u{0}', '\u{0}']), ('\u{50f}', ['\u{50e}', '\u{0}', '\u{0}']), + ('\u{511}', ['\u{510}', '\u{0}', '\u{0}']), ('\u{513}', ['\u{512}', '\u{0}', '\u{0}']), + ('\u{515}', ['\u{514}', '\u{0}', '\u{0}']), ('\u{517}', ['\u{516}', '\u{0}', '\u{0}']), + ('\u{519}', ['\u{518}', '\u{0}', '\u{0}']), ('\u{51b}', ['\u{51a}', '\u{0}', '\u{0}']), + ('\u{51d}', ['\u{51c}', '\u{0}', '\u{0}']), ('\u{51f}', ['\u{51e}', '\u{0}', '\u{0}']), + ('\u{521}', ['\u{520}', '\u{0}', '\u{0}']), ('\u{523}', ['\u{522}', '\u{0}', '\u{0}']), + ('\u{525}', ['\u{524}', '\u{0}', '\u{0}']), ('\u{527}', ['\u{526}', '\u{0}', '\u{0}']), + ('\u{529}', ['\u{528}', '\u{0}', '\u{0}']), ('\u{52b}', ['\u{52a}', '\u{0}', '\u{0}']), + ('\u{52d}', ['\u{52c}', '\u{0}', '\u{0}']), ('\u{52f}', ['\u{52e}', '\u{0}', '\u{0}']), + ('\u{561}', ['\u{531}', '\u{0}', '\u{0}']), ('\u{562}', ['\u{532}', '\u{0}', '\u{0}']), + ('\u{563}', ['\u{533}', '\u{0}', '\u{0}']), ('\u{564}', ['\u{534}', '\u{0}', '\u{0}']), + ('\u{565}', ['\u{535}', '\u{0}', '\u{0}']), ('\u{566}', ['\u{536}', '\u{0}', '\u{0}']), + ('\u{567}', ['\u{537}', '\u{0}', '\u{0}']), ('\u{568}', ['\u{538}', '\u{0}', '\u{0}']), + ('\u{569}', ['\u{539}', '\u{0}', '\u{0}']), ('\u{56a}', ['\u{53a}', '\u{0}', '\u{0}']), + ('\u{56b}', ['\u{53b}', '\u{0}', '\u{0}']), ('\u{56c}', ['\u{53c}', '\u{0}', '\u{0}']), + ('\u{56d}', ['\u{53d}', '\u{0}', '\u{0}']), ('\u{56e}', ['\u{53e}', '\u{0}', '\u{0}']), + ('\u{56f}', ['\u{53f}', '\u{0}', '\u{0}']), ('\u{570}', ['\u{540}', '\u{0}', '\u{0}']), + ('\u{571}', ['\u{541}', '\u{0}', '\u{0}']), ('\u{572}', ['\u{542}', '\u{0}', '\u{0}']), + ('\u{573}', ['\u{543}', '\u{0}', '\u{0}']), ('\u{574}', ['\u{544}', '\u{0}', '\u{0}']), + ('\u{575}', ['\u{545}', '\u{0}', '\u{0}']), ('\u{576}', ['\u{546}', '\u{0}', '\u{0}']), + ('\u{577}', ['\u{547}', '\u{0}', '\u{0}']), ('\u{578}', ['\u{548}', '\u{0}', '\u{0}']), + ('\u{579}', ['\u{549}', '\u{0}', '\u{0}']), ('\u{57a}', ['\u{54a}', '\u{0}', '\u{0}']), + ('\u{57b}', ['\u{54b}', '\u{0}', '\u{0}']), ('\u{57c}', ['\u{54c}', '\u{0}', '\u{0}']), + ('\u{57d}', ['\u{54d}', '\u{0}', '\u{0}']), ('\u{57e}', ['\u{54e}', '\u{0}', '\u{0}']), + ('\u{57f}', ['\u{54f}', '\u{0}', '\u{0}']), ('\u{580}', ['\u{550}', '\u{0}', '\u{0}']), + ('\u{581}', ['\u{551}', '\u{0}', '\u{0}']), ('\u{582}', ['\u{552}', '\u{0}', '\u{0}']), + ('\u{583}', ['\u{553}', '\u{0}', '\u{0}']), ('\u{584}', ['\u{554}', '\u{0}', '\u{0}']), + ('\u{585}', ['\u{555}', '\u{0}', '\u{0}']), ('\u{586}', ['\u{556}', '\u{0}', '\u{0}']), + ('\u{587}', ['\u{535}', '\u{552}', '\u{0}']), ('\u{10d0}', ['\u{1c90}', '\u{0}', '\u{0}']), + ('\u{10d1}', ['\u{1c91}', '\u{0}', '\u{0}']), ('\u{10d2}', ['\u{1c92}', '\u{0}', '\u{0}']), + ('\u{10d3}', ['\u{1c93}', '\u{0}', '\u{0}']), ('\u{10d4}', ['\u{1c94}', '\u{0}', '\u{0}']), + ('\u{10d5}', ['\u{1c95}', '\u{0}', '\u{0}']), ('\u{10d6}', ['\u{1c96}', '\u{0}', '\u{0}']), + ('\u{10d7}', ['\u{1c97}', '\u{0}', '\u{0}']), ('\u{10d8}', ['\u{1c98}', '\u{0}', '\u{0}']), + ('\u{10d9}', ['\u{1c99}', '\u{0}', '\u{0}']), ('\u{10da}', ['\u{1c9a}', '\u{0}', '\u{0}']), + ('\u{10db}', ['\u{1c9b}', '\u{0}', '\u{0}']), ('\u{10dc}', ['\u{1c9c}', '\u{0}', '\u{0}']), + ('\u{10dd}', ['\u{1c9d}', '\u{0}', '\u{0}']), ('\u{10de}', ['\u{1c9e}', '\u{0}', '\u{0}']), + ('\u{10df}', ['\u{1c9f}', '\u{0}', '\u{0}']), ('\u{10e0}', ['\u{1ca0}', '\u{0}', '\u{0}']), + ('\u{10e1}', ['\u{1ca1}', '\u{0}', '\u{0}']), ('\u{10e2}', ['\u{1ca2}', '\u{0}', '\u{0}']), + ('\u{10e3}', ['\u{1ca3}', '\u{0}', '\u{0}']), ('\u{10e4}', ['\u{1ca4}', '\u{0}', '\u{0}']), + ('\u{10e5}', ['\u{1ca5}', '\u{0}', '\u{0}']), ('\u{10e6}', ['\u{1ca6}', '\u{0}', '\u{0}']), + ('\u{10e7}', ['\u{1ca7}', '\u{0}', '\u{0}']), ('\u{10e8}', ['\u{1ca8}', '\u{0}', '\u{0}']), + ('\u{10e9}', ['\u{1ca9}', '\u{0}', '\u{0}']), ('\u{10ea}', ['\u{1caa}', '\u{0}', '\u{0}']), + ('\u{10eb}', ['\u{1cab}', '\u{0}', '\u{0}']), ('\u{10ec}', ['\u{1cac}', '\u{0}', '\u{0}']), + ('\u{10ed}', ['\u{1cad}', '\u{0}', '\u{0}']), ('\u{10ee}', ['\u{1cae}', '\u{0}', '\u{0}']), + ('\u{10ef}', ['\u{1caf}', '\u{0}', '\u{0}']), ('\u{10f0}', ['\u{1cb0}', '\u{0}', '\u{0}']), + ('\u{10f1}', ['\u{1cb1}', '\u{0}', '\u{0}']), ('\u{10f2}', ['\u{1cb2}', '\u{0}', '\u{0}']), + ('\u{10f3}', ['\u{1cb3}', '\u{0}', '\u{0}']), ('\u{10f4}', ['\u{1cb4}', '\u{0}', '\u{0}']), + ('\u{10f5}', ['\u{1cb5}', '\u{0}', '\u{0}']), ('\u{10f6}', ['\u{1cb6}', '\u{0}', '\u{0}']), + ('\u{10f7}', ['\u{1cb7}', '\u{0}', '\u{0}']), ('\u{10f8}', ['\u{1cb8}', '\u{0}', '\u{0}']), + ('\u{10f9}', ['\u{1cb9}', '\u{0}', '\u{0}']), ('\u{10fa}', ['\u{1cba}', '\u{0}', '\u{0}']), + ('\u{10fd}', ['\u{1cbd}', '\u{0}', '\u{0}']), ('\u{10fe}', ['\u{1cbe}', '\u{0}', '\u{0}']), + ('\u{10ff}', ['\u{1cbf}', '\u{0}', '\u{0}']), ('\u{13f8}', ['\u{13f0}', '\u{0}', '\u{0}']), + ('\u{13f9}', ['\u{13f1}', '\u{0}', '\u{0}']), ('\u{13fa}', ['\u{13f2}', '\u{0}', '\u{0}']), + ('\u{13fb}', ['\u{13f3}', '\u{0}', '\u{0}']), ('\u{13fc}', ['\u{13f4}', '\u{0}', '\u{0}']), + ('\u{13fd}', ['\u{13f5}', '\u{0}', '\u{0}']), ('\u{1c80}', ['\u{412}', '\u{0}', '\u{0}']), + ('\u{1c81}', ['\u{414}', '\u{0}', '\u{0}']), ('\u{1c82}', ['\u{41e}', '\u{0}', '\u{0}']), + ('\u{1c83}', ['\u{421}', '\u{0}', '\u{0}']), ('\u{1c84}', ['\u{422}', '\u{0}', '\u{0}']), + ('\u{1c85}', ['\u{422}', '\u{0}', '\u{0}']), ('\u{1c86}', ['\u{42a}', '\u{0}', '\u{0}']), + ('\u{1c87}', ['\u{462}', '\u{0}', '\u{0}']), ('\u{1c88}', ['\u{a64a}', '\u{0}', '\u{0}']), + ('\u{1c8a}', ['\u{1c89}', '\u{0}', '\u{0}']), ('\u{1d79}', ['\u{a77d}', '\u{0}', '\u{0}']), + ('\u{1d7d}', ['\u{2c63}', '\u{0}', '\u{0}']), ('\u{1d8e}', ['\u{a7c6}', '\u{0}', '\u{0}']), + ('\u{1e01}', ['\u{1e00}', '\u{0}', '\u{0}']), ('\u{1e03}', ['\u{1e02}', '\u{0}', '\u{0}']), + ('\u{1e05}', ['\u{1e04}', '\u{0}', '\u{0}']), ('\u{1e07}', ['\u{1e06}', '\u{0}', '\u{0}']), + ('\u{1e09}', ['\u{1e08}', '\u{0}', '\u{0}']), ('\u{1e0b}', ['\u{1e0a}', '\u{0}', '\u{0}']), + ('\u{1e0d}', ['\u{1e0c}', '\u{0}', '\u{0}']), ('\u{1e0f}', ['\u{1e0e}', '\u{0}', '\u{0}']), + ('\u{1e11}', ['\u{1e10}', '\u{0}', '\u{0}']), ('\u{1e13}', ['\u{1e12}', '\u{0}', '\u{0}']), + ('\u{1e15}', ['\u{1e14}', '\u{0}', '\u{0}']), ('\u{1e17}', ['\u{1e16}', '\u{0}', '\u{0}']), + ('\u{1e19}', ['\u{1e18}', '\u{0}', '\u{0}']), ('\u{1e1b}', ['\u{1e1a}', '\u{0}', '\u{0}']), + ('\u{1e1d}', ['\u{1e1c}', '\u{0}', '\u{0}']), ('\u{1e1f}', ['\u{1e1e}', '\u{0}', '\u{0}']), + ('\u{1e21}', ['\u{1e20}', '\u{0}', '\u{0}']), ('\u{1e23}', ['\u{1e22}', '\u{0}', '\u{0}']), + ('\u{1e25}', ['\u{1e24}', '\u{0}', '\u{0}']), ('\u{1e27}', ['\u{1e26}', '\u{0}', '\u{0}']), + ('\u{1e29}', ['\u{1e28}', '\u{0}', '\u{0}']), ('\u{1e2b}', ['\u{1e2a}', '\u{0}', '\u{0}']), + ('\u{1e2d}', ['\u{1e2c}', '\u{0}', '\u{0}']), ('\u{1e2f}', ['\u{1e2e}', '\u{0}', '\u{0}']), + ('\u{1e31}', ['\u{1e30}', '\u{0}', '\u{0}']), ('\u{1e33}', ['\u{1e32}', '\u{0}', '\u{0}']), + ('\u{1e35}', ['\u{1e34}', '\u{0}', '\u{0}']), ('\u{1e37}', ['\u{1e36}', '\u{0}', '\u{0}']), + ('\u{1e39}', ['\u{1e38}', '\u{0}', '\u{0}']), ('\u{1e3b}', ['\u{1e3a}', '\u{0}', '\u{0}']), + ('\u{1e3d}', ['\u{1e3c}', '\u{0}', '\u{0}']), ('\u{1e3f}', ['\u{1e3e}', '\u{0}', '\u{0}']), + ('\u{1e41}', ['\u{1e40}', '\u{0}', '\u{0}']), ('\u{1e43}', ['\u{1e42}', '\u{0}', '\u{0}']), + ('\u{1e45}', ['\u{1e44}', '\u{0}', '\u{0}']), ('\u{1e47}', ['\u{1e46}', '\u{0}', '\u{0}']), + ('\u{1e49}', ['\u{1e48}', '\u{0}', '\u{0}']), ('\u{1e4b}', ['\u{1e4a}', '\u{0}', '\u{0}']), + ('\u{1e4d}', ['\u{1e4c}', '\u{0}', '\u{0}']), ('\u{1e4f}', ['\u{1e4e}', '\u{0}', '\u{0}']), + ('\u{1e51}', ['\u{1e50}', '\u{0}', '\u{0}']), ('\u{1e53}', ['\u{1e52}', '\u{0}', '\u{0}']), + ('\u{1e55}', ['\u{1e54}', '\u{0}', '\u{0}']), ('\u{1e57}', ['\u{1e56}', '\u{0}', '\u{0}']), + ('\u{1e59}', ['\u{1e58}', '\u{0}', '\u{0}']), ('\u{1e5b}', ['\u{1e5a}', '\u{0}', '\u{0}']), + ('\u{1e5d}', ['\u{1e5c}', '\u{0}', '\u{0}']), ('\u{1e5f}', ['\u{1e5e}', '\u{0}', '\u{0}']), + ('\u{1e61}', ['\u{1e60}', '\u{0}', '\u{0}']), ('\u{1e63}', ['\u{1e62}', '\u{0}', '\u{0}']), + ('\u{1e65}', ['\u{1e64}', '\u{0}', '\u{0}']), ('\u{1e67}', ['\u{1e66}', '\u{0}', '\u{0}']), + ('\u{1e69}', ['\u{1e68}', '\u{0}', '\u{0}']), ('\u{1e6b}', ['\u{1e6a}', '\u{0}', '\u{0}']), + ('\u{1e6d}', ['\u{1e6c}', '\u{0}', '\u{0}']), ('\u{1e6f}', ['\u{1e6e}', '\u{0}', '\u{0}']), + ('\u{1e71}', ['\u{1e70}', '\u{0}', '\u{0}']), ('\u{1e73}', ['\u{1e72}', '\u{0}', '\u{0}']), + ('\u{1e75}', ['\u{1e74}', '\u{0}', '\u{0}']), ('\u{1e77}', ['\u{1e76}', '\u{0}', '\u{0}']), + ('\u{1e79}', ['\u{1e78}', '\u{0}', '\u{0}']), ('\u{1e7b}', ['\u{1e7a}', '\u{0}', '\u{0}']), + ('\u{1e7d}', ['\u{1e7c}', '\u{0}', '\u{0}']), ('\u{1e7f}', ['\u{1e7e}', '\u{0}', '\u{0}']), + ('\u{1e81}', ['\u{1e80}', '\u{0}', '\u{0}']), ('\u{1e83}', ['\u{1e82}', '\u{0}', '\u{0}']), + ('\u{1e85}', ['\u{1e84}', '\u{0}', '\u{0}']), ('\u{1e87}', ['\u{1e86}', '\u{0}', '\u{0}']), + ('\u{1e89}', ['\u{1e88}', '\u{0}', '\u{0}']), ('\u{1e8b}', ['\u{1e8a}', '\u{0}', '\u{0}']), + ('\u{1e8d}', ['\u{1e8c}', '\u{0}', '\u{0}']), ('\u{1e8f}', ['\u{1e8e}', '\u{0}', '\u{0}']), + ('\u{1e91}', ['\u{1e90}', '\u{0}', '\u{0}']), ('\u{1e93}', ['\u{1e92}', '\u{0}', '\u{0}']), + ('\u{1e95}', ['\u{1e94}', '\u{0}', '\u{0}']), ('\u{1e96}', ['H', '\u{331}', '\u{0}']), + ('\u{1e97}', ['T', '\u{308}', '\u{0}']), ('\u{1e98}', ['W', '\u{30a}', '\u{0}']), + ('\u{1e99}', ['Y', '\u{30a}', '\u{0}']), ('\u{1e9a}', ['A', '\u{2be}', '\u{0}']), + ('\u{1e9b}', ['\u{1e60}', '\u{0}', '\u{0}']), ('\u{1ea1}', ['\u{1ea0}', '\u{0}', '\u{0}']), + ('\u{1ea3}', ['\u{1ea2}', '\u{0}', '\u{0}']), ('\u{1ea5}', ['\u{1ea4}', '\u{0}', '\u{0}']), + ('\u{1ea7}', ['\u{1ea6}', '\u{0}', '\u{0}']), ('\u{1ea9}', ['\u{1ea8}', '\u{0}', '\u{0}']), + ('\u{1eab}', ['\u{1eaa}', '\u{0}', '\u{0}']), ('\u{1ead}', ['\u{1eac}', '\u{0}', '\u{0}']), + ('\u{1eaf}', ['\u{1eae}', '\u{0}', '\u{0}']), ('\u{1eb1}', ['\u{1eb0}', '\u{0}', '\u{0}']), + ('\u{1eb3}', ['\u{1eb2}', '\u{0}', '\u{0}']), ('\u{1eb5}', ['\u{1eb4}', '\u{0}', '\u{0}']), + ('\u{1eb7}', ['\u{1eb6}', '\u{0}', '\u{0}']), ('\u{1eb9}', ['\u{1eb8}', '\u{0}', '\u{0}']), + ('\u{1ebb}', ['\u{1eba}', '\u{0}', '\u{0}']), ('\u{1ebd}', ['\u{1ebc}', '\u{0}', '\u{0}']), + ('\u{1ebf}', ['\u{1ebe}', '\u{0}', '\u{0}']), ('\u{1ec1}', ['\u{1ec0}', '\u{0}', '\u{0}']), + ('\u{1ec3}', ['\u{1ec2}', '\u{0}', '\u{0}']), ('\u{1ec5}', ['\u{1ec4}', '\u{0}', '\u{0}']), + ('\u{1ec7}', ['\u{1ec6}', '\u{0}', '\u{0}']), ('\u{1ec9}', ['\u{1ec8}', '\u{0}', '\u{0}']), + ('\u{1ecb}', ['\u{1eca}', '\u{0}', '\u{0}']), ('\u{1ecd}', ['\u{1ecc}', '\u{0}', '\u{0}']), + ('\u{1ecf}', ['\u{1ece}', '\u{0}', '\u{0}']), ('\u{1ed1}', ['\u{1ed0}', '\u{0}', '\u{0}']), + ('\u{1ed3}', ['\u{1ed2}', '\u{0}', '\u{0}']), ('\u{1ed5}', ['\u{1ed4}', '\u{0}', '\u{0}']), + ('\u{1ed7}', ['\u{1ed6}', '\u{0}', '\u{0}']), ('\u{1ed9}', ['\u{1ed8}', '\u{0}', '\u{0}']), + ('\u{1edb}', ['\u{1eda}', '\u{0}', '\u{0}']), ('\u{1edd}', ['\u{1edc}', '\u{0}', '\u{0}']), + ('\u{1edf}', ['\u{1ede}', '\u{0}', '\u{0}']), ('\u{1ee1}', ['\u{1ee0}', '\u{0}', '\u{0}']), + ('\u{1ee3}', ['\u{1ee2}', '\u{0}', '\u{0}']), ('\u{1ee5}', ['\u{1ee4}', '\u{0}', '\u{0}']), + ('\u{1ee7}', ['\u{1ee6}', '\u{0}', '\u{0}']), ('\u{1ee9}', ['\u{1ee8}', '\u{0}', '\u{0}']), + ('\u{1eeb}', ['\u{1eea}', '\u{0}', '\u{0}']), ('\u{1eed}', ['\u{1eec}', '\u{0}', '\u{0}']), + ('\u{1eef}', ['\u{1eee}', '\u{0}', '\u{0}']), ('\u{1ef1}', ['\u{1ef0}', '\u{0}', '\u{0}']), + ('\u{1ef3}', ['\u{1ef2}', '\u{0}', '\u{0}']), ('\u{1ef5}', ['\u{1ef4}', '\u{0}', '\u{0}']), + ('\u{1ef7}', ['\u{1ef6}', '\u{0}', '\u{0}']), ('\u{1ef9}', ['\u{1ef8}', '\u{0}', '\u{0}']), + ('\u{1efb}', ['\u{1efa}', '\u{0}', '\u{0}']), ('\u{1efd}', ['\u{1efc}', '\u{0}', '\u{0}']), + ('\u{1eff}', ['\u{1efe}', '\u{0}', '\u{0}']), ('\u{1f00}', ['\u{1f08}', '\u{0}', '\u{0}']), + ('\u{1f01}', ['\u{1f09}', '\u{0}', '\u{0}']), ('\u{1f02}', ['\u{1f0a}', '\u{0}', '\u{0}']), + ('\u{1f03}', ['\u{1f0b}', '\u{0}', '\u{0}']), ('\u{1f04}', ['\u{1f0c}', '\u{0}', '\u{0}']), + ('\u{1f05}', ['\u{1f0d}', '\u{0}', '\u{0}']), ('\u{1f06}', ['\u{1f0e}', '\u{0}', '\u{0}']), + ('\u{1f07}', ['\u{1f0f}', '\u{0}', '\u{0}']), ('\u{1f10}', ['\u{1f18}', '\u{0}', '\u{0}']), + ('\u{1f11}', ['\u{1f19}', '\u{0}', '\u{0}']), ('\u{1f12}', ['\u{1f1a}', '\u{0}', '\u{0}']), + ('\u{1f13}', ['\u{1f1b}', '\u{0}', '\u{0}']), ('\u{1f14}', ['\u{1f1c}', '\u{0}', '\u{0}']), + ('\u{1f15}', ['\u{1f1d}', '\u{0}', '\u{0}']), ('\u{1f20}', ['\u{1f28}', '\u{0}', '\u{0}']), + ('\u{1f21}', ['\u{1f29}', '\u{0}', '\u{0}']), ('\u{1f22}', ['\u{1f2a}', '\u{0}', '\u{0}']), + ('\u{1f23}', ['\u{1f2b}', '\u{0}', '\u{0}']), ('\u{1f24}', ['\u{1f2c}', '\u{0}', '\u{0}']), + ('\u{1f25}', ['\u{1f2d}', '\u{0}', '\u{0}']), ('\u{1f26}', ['\u{1f2e}', '\u{0}', '\u{0}']), + ('\u{1f27}', ['\u{1f2f}', '\u{0}', '\u{0}']), ('\u{1f30}', ['\u{1f38}', '\u{0}', '\u{0}']), + ('\u{1f31}', ['\u{1f39}', '\u{0}', '\u{0}']), ('\u{1f32}', ['\u{1f3a}', '\u{0}', '\u{0}']), + ('\u{1f33}', ['\u{1f3b}', '\u{0}', '\u{0}']), ('\u{1f34}', ['\u{1f3c}', '\u{0}', '\u{0}']), + ('\u{1f35}', ['\u{1f3d}', '\u{0}', '\u{0}']), ('\u{1f36}', ['\u{1f3e}', '\u{0}', '\u{0}']), + ('\u{1f37}', ['\u{1f3f}', '\u{0}', '\u{0}']), ('\u{1f40}', ['\u{1f48}', '\u{0}', '\u{0}']), + ('\u{1f41}', ['\u{1f49}', '\u{0}', '\u{0}']), ('\u{1f42}', ['\u{1f4a}', '\u{0}', '\u{0}']), + ('\u{1f43}', ['\u{1f4b}', '\u{0}', '\u{0}']), ('\u{1f44}', ['\u{1f4c}', '\u{0}', '\u{0}']), + ('\u{1f45}', ['\u{1f4d}', '\u{0}', '\u{0}']), ('\u{1f50}', ['\u{3a5}', '\u{313}', '\u{0}']), + ('\u{1f51}', ['\u{1f59}', '\u{0}', '\u{0}']), + ('\u{1f52}', ['\u{3a5}', '\u{313}', '\u{300}']), + ('\u{1f53}', ['\u{1f5b}', '\u{0}', '\u{0}']), + ('\u{1f54}', ['\u{3a5}', '\u{313}', '\u{301}']), + ('\u{1f55}', ['\u{1f5d}', '\u{0}', '\u{0}']), + ('\u{1f56}', ['\u{3a5}', '\u{313}', '\u{342}']), + ('\u{1f57}', ['\u{1f5f}', '\u{0}', '\u{0}']), ('\u{1f60}', ['\u{1f68}', '\u{0}', '\u{0}']), + ('\u{1f61}', ['\u{1f69}', '\u{0}', '\u{0}']), ('\u{1f62}', ['\u{1f6a}', '\u{0}', '\u{0}']), + ('\u{1f63}', ['\u{1f6b}', '\u{0}', '\u{0}']), ('\u{1f64}', ['\u{1f6c}', '\u{0}', '\u{0}']), + ('\u{1f65}', ['\u{1f6d}', '\u{0}', '\u{0}']), ('\u{1f66}', ['\u{1f6e}', '\u{0}', '\u{0}']), + ('\u{1f67}', ['\u{1f6f}', '\u{0}', '\u{0}']), ('\u{1f70}', ['\u{1fba}', '\u{0}', '\u{0}']), + ('\u{1f71}', ['\u{1fbb}', '\u{0}', '\u{0}']), ('\u{1f72}', ['\u{1fc8}', '\u{0}', '\u{0}']), + ('\u{1f73}', ['\u{1fc9}', '\u{0}', '\u{0}']), ('\u{1f74}', ['\u{1fca}', '\u{0}', '\u{0}']), + ('\u{1f75}', ['\u{1fcb}', '\u{0}', '\u{0}']), ('\u{1f76}', ['\u{1fda}', '\u{0}', '\u{0}']), + ('\u{1f77}', ['\u{1fdb}', '\u{0}', '\u{0}']), ('\u{1f78}', ['\u{1ff8}', '\u{0}', '\u{0}']), + ('\u{1f79}', ['\u{1ff9}', '\u{0}', '\u{0}']), ('\u{1f7a}', ['\u{1fea}', '\u{0}', '\u{0}']), + ('\u{1f7b}', ['\u{1feb}', '\u{0}', '\u{0}']), ('\u{1f7c}', ['\u{1ffa}', '\u{0}', '\u{0}']), + ('\u{1f7d}', ['\u{1ffb}', '\u{0}', '\u{0}']), + ('\u{1f80}', ['\u{1f08}', '\u{399}', '\u{0}']), + ('\u{1f81}', ['\u{1f09}', '\u{399}', '\u{0}']), + ('\u{1f82}', ['\u{1f0a}', '\u{399}', '\u{0}']), + ('\u{1f83}', ['\u{1f0b}', '\u{399}', '\u{0}']), + ('\u{1f84}', ['\u{1f0c}', '\u{399}', '\u{0}']), + ('\u{1f85}', ['\u{1f0d}', '\u{399}', '\u{0}']), + ('\u{1f86}', ['\u{1f0e}', '\u{399}', '\u{0}']), + ('\u{1f87}', ['\u{1f0f}', '\u{399}', '\u{0}']), + ('\u{1f88}', ['\u{1f08}', '\u{399}', '\u{0}']), + ('\u{1f89}', ['\u{1f09}', '\u{399}', '\u{0}']), + ('\u{1f8a}', ['\u{1f0a}', '\u{399}', '\u{0}']), + ('\u{1f8b}', ['\u{1f0b}', '\u{399}', '\u{0}']), + ('\u{1f8c}', ['\u{1f0c}', '\u{399}', '\u{0}']), + ('\u{1f8d}', ['\u{1f0d}', '\u{399}', '\u{0}']), + ('\u{1f8e}', ['\u{1f0e}', '\u{399}', '\u{0}']), + ('\u{1f8f}', ['\u{1f0f}', '\u{399}', '\u{0}']), + ('\u{1f90}', ['\u{1f28}', '\u{399}', '\u{0}']), + ('\u{1f91}', ['\u{1f29}', '\u{399}', '\u{0}']), + ('\u{1f92}', ['\u{1f2a}', '\u{399}', '\u{0}']), + ('\u{1f93}', ['\u{1f2b}', '\u{399}', '\u{0}']), + ('\u{1f94}', ['\u{1f2c}', '\u{399}', '\u{0}']), + ('\u{1f95}', ['\u{1f2d}', '\u{399}', '\u{0}']), + ('\u{1f96}', ['\u{1f2e}', '\u{399}', '\u{0}']), + ('\u{1f97}', ['\u{1f2f}', '\u{399}', '\u{0}']), + ('\u{1f98}', ['\u{1f28}', '\u{399}', '\u{0}']), + ('\u{1f99}', ['\u{1f29}', '\u{399}', '\u{0}']), + ('\u{1f9a}', ['\u{1f2a}', '\u{399}', '\u{0}']), + ('\u{1f9b}', ['\u{1f2b}', '\u{399}', '\u{0}']), + ('\u{1f9c}', ['\u{1f2c}', '\u{399}', '\u{0}']), + ('\u{1f9d}', ['\u{1f2d}', '\u{399}', '\u{0}']), + ('\u{1f9e}', ['\u{1f2e}', '\u{399}', '\u{0}']), + ('\u{1f9f}', ['\u{1f2f}', '\u{399}', '\u{0}']), + ('\u{1fa0}', ['\u{1f68}', '\u{399}', '\u{0}']), + ('\u{1fa1}', ['\u{1f69}', '\u{399}', '\u{0}']), + ('\u{1fa2}', ['\u{1f6a}', '\u{399}', '\u{0}']), + ('\u{1fa3}', ['\u{1f6b}', '\u{399}', '\u{0}']), + ('\u{1fa4}', ['\u{1f6c}', '\u{399}', '\u{0}']), + ('\u{1fa5}', ['\u{1f6d}', '\u{399}', '\u{0}']), + ('\u{1fa6}', ['\u{1f6e}', '\u{399}', '\u{0}']), + ('\u{1fa7}', ['\u{1f6f}', '\u{399}', '\u{0}']), + ('\u{1fa8}', ['\u{1f68}', '\u{399}', '\u{0}']), + ('\u{1fa9}', ['\u{1f69}', '\u{399}', '\u{0}']), + ('\u{1faa}', ['\u{1f6a}', '\u{399}', '\u{0}']), + ('\u{1fab}', ['\u{1f6b}', '\u{399}', '\u{0}']), + ('\u{1fac}', ['\u{1f6c}', '\u{399}', '\u{0}']), + ('\u{1fad}', ['\u{1f6d}', '\u{399}', '\u{0}']), + ('\u{1fae}', ['\u{1f6e}', '\u{399}', '\u{0}']), + ('\u{1faf}', ['\u{1f6f}', '\u{399}', '\u{0}']), + ('\u{1fb0}', ['\u{1fb8}', '\u{0}', '\u{0}']), ('\u{1fb1}', ['\u{1fb9}', '\u{0}', '\u{0}']), + ('\u{1fb2}', ['\u{1fba}', '\u{399}', '\u{0}']), + ('\u{1fb3}', ['\u{391}', '\u{399}', '\u{0}']), + ('\u{1fb4}', ['\u{386}', '\u{399}', '\u{0}']), + ('\u{1fb6}', ['\u{391}', '\u{342}', '\u{0}']), + ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{399}']), + ('\u{1fbc}', ['\u{391}', '\u{399}', '\u{0}']), ('\u{1fbe}', ['\u{399}', '\u{0}', '\u{0}']), + ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\u{0}']), + ('\u{1fc3}', ['\u{397}', '\u{399}', '\u{0}']), + ('\u{1fc4}', ['\u{389}', '\u{399}', '\u{0}']), + ('\u{1fc6}', ['\u{397}', '\u{342}', '\u{0}']), + ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), + ('\u{1fcc}', ['\u{397}', '\u{399}', '\u{0}']), ('\u{1fd0}', ['\u{1fd8}', '\u{0}', '\u{0}']), + ('\u{1fd1}', ['\u{1fd9}', '\u{0}', '\u{0}']), + ('\u{1fd2}', ['\u{399}', '\u{308}', '\u{300}']), + ('\u{1fd3}', ['\u{399}', '\u{308}', '\u{301}']), + ('\u{1fd6}', ['\u{399}', '\u{342}', '\u{0}']), + ('\u{1fd7}', ['\u{399}', '\u{308}', '\u{342}']), + ('\u{1fe0}', ['\u{1fe8}', '\u{0}', '\u{0}']), ('\u{1fe1}', ['\u{1fe9}', '\u{0}', '\u{0}']), + ('\u{1fe2}', ['\u{3a5}', '\u{308}', '\u{300}']), + ('\u{1fe3}', ['\u{3a5}', '\u{308}', '\u{301}']), + ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\u{0}']), ('\u{1fe5}', ['\u{1fec}', '\u{0}', '\u{0}']), + ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\u{0}']), + ('\u{1fe7}', ['\u{3a5}', '\u{308}', '\u{342}']), + ('\u{1ff2}', ['\u{1ffa}', '\u{399}', '\u{0}']), + ('\u{1ff3}', ['\u{3a9}', '\u{399}', '\u{0}']), + ('\u{1ff4}', ['\u{38f}', '\u{399}', '\u{0}']), + ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\u{0}']), + ('\u{1ff7}', ['\u{3a9}', '\u{342}', '\u{399}']), + ('\u{1ffc}', ['\u{3a9}', '\u{399}', '\u{0}']), ('\u{214e}', ['\u{2132}', '\u{0}', '\u{0}']), + ('\u{2170}', ['\u{2160}', '\u{0}', '\u{0}']), ('\u{2171}', ['\u{2161}', '\u{0}', '\u{0}']), + ('\u{2172}', ['\u{2162}', '\u{0}', '\u{0}']), ('\u{2173}', ['\u{2163}', '\u{0}', '\u{0}']), + ('\u{2174}', ['\u{2164}', '\u{0}', '\u{0}']), ('\u{2175}', ['\u{2165}', '\u{0}', '\u{0}']), + ('\u{2176}', ['\u{2166}', '\u{0}', '\u{0}']), ('\u{2177}', ['\u{2167}', '\u{0}', '\u{0}']), + ('\u{2178}', ['\u{2168}', '\u{0}', '\u{0}']), ('\u{2179}', ['\u{2169}', '\u{0}', '\u{0}']), + ('\u{217a}', ['\u{216a}', '\u{0}', '\u{0}']), ('\u{217b}', ['\u{216b}', '\u{0}', '\u{0}']), + ('\u{217c}', ['\u{216c}', '\u{0}', '\u{0}']), ('\u{217d}', ['\u{216d}', '\u{0}', '\u{0}']), + ('\u{217e}', ['\u{216e}', '\u{0}', '\u{0}']), ('\u{217f}', ['\u{216f}', '\u{0}', '\u{0}']), + ('\u{2184}', ['\u{2183}', '\u{0}', '\u{0}']), ('\u{24d0}', ['\u{24b6}', '\u{0}', '\u{0}']), + ('\u{24d1}', ['\u{24b7}', '\u{0}', '\u{0}']), ('\u{24d2}', ['\u{24b8}', '\u{0}', '\u{0}']), + ('\u{24d3}', ['\u{24b9}', '\u{0}', '\u{0}']), ('\u{24d4}', ['\u{24ba}', '\u{0}', '\u{0}']), + ('\u{24d5}', ['\u{24bb}', '\u{0}', '\u{0}']), ('\u{24d6}', ['\u{24bc}', '\u{0}', '\u{0}']), + ('\u{24d7}', ['\u{24bd}', '\u{0}', '\u{0}']), ('\u{24d8}', ['\u{24be}', '\u{0}', '\u{0}']), + ('\u{24d9}', ['\u{24bf}', '\u{0}', '\u{0}']), ('\u{24da}', ['\u{24c0}', '\u{0}', '\u{0}']), + ('\u{24db}', ['\u{24c1}', '\u{0}', '\u{0}']), ('\u{24dc}', ['\u{24c2}', '\u{0}', '\u{0}']), + ('\u{24dd}', ['\u{24c3}', '\u{0}', '\u{0}']), ('\u{24de}', ['\u{24c4}', '\u{0}', '\u{0}']), + ('\u{24df}', ['\u{24c5}', '\u{0}', '\u{0}']), ('\u{24e0}', ['\u{24c6}', '\u{0}', '\u{0}']), + ('\u{24e1}', ['\u{24c7}', '\u{0}', '\u{0}']), ('\u{24e2}', ['\u{24c8}', '\u{0}', '\u{0}']), + ('\u{24e3}', ['\u{24c9}', '\u{0}', '\u{0}']), ('\u{24e4}', ['\u{24ca}', '\u{0}', '\u{0}']), + ('\u{24e5}', ['\u{24cb}', '\u{0}', '\u{0}']), ('\u{24e6}', ['\u{24cc}', '\u{0}', '\u{0}']), + ('\u{24e7}', ['\u{24cd}', '\u{0}', '\u{0}']), ('\u{24e8}', ['\u{24ce}', '\u{0}', '\u{0}']), + ('\u{24e9}', ['\u{24cf}', '\u{0}', '\u{0}']), ('\u{2c30}', ['\u{2c00}', '\u{0}', '\u{0}']), + ('\u{2c31}', ['\u{2c01}', '\u{0}', '\u{0}']), ('\u{2c32}', ['\u{2c02}', '\u{0}', '\u{0}']), + ('\u{2c33}', ['\u{2c03}', '\u{0}', '\u{0}']), ('\u{2c34}', ['\u{2c04}', '\u{0}', '\u{0}']), + ('\u{2c35}', ['\u{2c05}', '\u{0}', '\u{0}']), ('\u{2c36}', ['\u{2c06}', '\u{0}', '\u{0}']), + ('\u{2c37}', ['\u{2c07}', '\u{0}', '\u{0}']), ('\u{2c38}', ['\u{2c08}', '\u{0}', '\u{0}']), + ('\u{2c39}', ['\u{2c09}', '\u{0}', '\u{0}']), ('\u{2c3a}', ['\u{2c0a}', '\u{0}', '\u{0}']), + ('\u{2c3b}', ['\u{2c0b}', '\u{0}', '\u{0}']), ('\u{2c3c}', ['\u{2c0c}', '\u{0}', '\u{0}']), + ('\u{2c3d}', ['\u{2c0d}', '\u{0}', '\u{0}']), ('\u{2c3e}', ['\u{2c0e}', '\u{0}', '\u{0}']), + ('\u{2c3f}', ['\u{2c0f}', '\u{0}', '\u{0}']), ('\u{2c40}', ['\u{2c10}', '\u{0}', '\u{0}']), + ('\u{2c41}', ['\u{2c11}', '\u{0}', '\u{0}']), ('\u{2c42}', ['\u{2c12}', '\u{0}', '\u{0}']), + ('\u{2c43}', ['\u{2c13}', '\u{0}', '\u{0}']), ('\u{2c44}', ['\u{2c14}', '\u{0}', '\u{0}']), + ('\u{2c45}', ['\u{2c15}', '\u{0}', '\u{0}']), ('\u{2c46}', ['\u{2c16}', '\u{0}', '\u{0}']), + ('\u{2c47}', ['\u{2c17}', '\u{0}', '\u{0}']), ('\u{2c48}', ['\u{2c18}', '\u{0}', '\u{0}']), + ('\u{2c49}', ['\u{2c19}', '\u{0}', '\u{0}']), ('\u{2c4a}', ['\u{2c1a}', '\u{0}', '\u{0}']), + ('\u{2c4b}', ['\u{2c1b}', '\u{0}', '\u{0}']), ('\u{2c4c}', ['\u{2c1c}', '\u{0}', '\u{0}']), + ('\u{2c4d}', ['\u{2c1d}', '\u{0}', '\u{0}']), ('\u{2c4e}', ['\u{2c1e}', '\u{0}', '\u{0}']), + ('\u{2c4f}', ['\u{2c1f}', '\u{0}', '\u{0}']), ('\u{2c50}', ['\u{2c20}', '\u{0}', '\u{0}']), + ('\u{2c51}', ['\u{2c21}', '\u{0}', '\u{0}']), ('\u{2c52}', ['\u{2c22}', '\u{0}', '\u{0}']), + ('\u{2c53}', ['\u{2c23}', '\u{0}', '\u{0}']), ('\u{2c54}', ['\u{2c24}', '\u{0}', '\u{0}']), + ('\u{2c55}', ['\u{2c25}', '\u{0}', '\u{0}']), ('\u{2c56}', ['\u{2c26}', '\u{0}', '\u{0}']), + ('\u{2c57}', ['\u{2c27}', '\u{0}', '\u{0}']), ('\u{2c58}', ['\u{2c28}', '\u{0}', '\u{0}']), + ('\u{2c59}', ['\u{2c29}', '\u{0}', '\u{0}']), ('\u{2c5a}', ['\u{2c2a}', '\u{0}', '\u{0}']), + ('\u{2c5b}', ['\u{2c2b}', '\u{0}', '\u{0}']), ('\u{2c5c}', ['\u{2c2c}', '\u{0}', '\u{0}']), + ('\u{2c5d}', ['\u{2c2d}', '\u{0}', '\u{0}']), ('\u{2c5e}', ['\u{2c2e}', '\u{0}', '\u{0}']), + ('\u{2c5f}', ['\u{2c2f}', '\u{0}', '\u{0}']), ('\u{2c61}', ['\u{2c60}', '\u{0}', '\u{0}']), + ('\u{2c65}', ['\u{23a}', '\u{0}', '\u{0}']), ('\u{2c66}', ['\u{23e}', '\u{0}', '\u{0}']), + ('\u{2c68}', ['\u{2c67}', '\u{0}', '\u{0}']), ('\u{2c6a}', ['\u{2c69}', '\u{0}', '\u{0}']), + ('\u{2c6c}', ['\u{2c6b}', '\u{0}', '\u{0}']), ('\u{2c73}', ['\u{2c72}', '\u{0}', '\u{0}']), + ('\u{2c76}', ['\u{2c75}', '\u{0}', '\u{0}']), ('\u{2c81}', ['\u{2c80}', '\u{0}', '\u{0}']), + ('\u{2c83}', ['\u{2c82}', '\u{0}', '\u{0}']), ('\u{2c85}', ['\u{2c84}', '\u{0}', '\u{0}']), + ('\u{2c87}', ['\u{2c86}', '\u{0}', '\u{0}']), ('\u{2c89}', ['\u{2c88}', '\u{0}', '\u{0}']), + ('\u{2c8b}', ['\u{2c8a}', '\u{0}', '\u{0}']), ('\u{2c8d}', ['\u{2c8c}', '\u{0}', '\u{0}']), + ('\u{2c8f}', ['\u{2c8e}', '\u{0}', '\u{0}']), ('\u{2c91}', ['\u{2c90}', '\u{0}', '\u{0}']), + ('\u{2c93}', ['\u{2c92}', '\u{0}', '\u{0}']), ('\u{2c95}', ['\u{2c94}', '\u{0}', '\u{0}']), + ('\u{2c97}', ['\u{2c96}', '\u{0}', '\u{0}']), ('\u{2c99}', ['\u{2c98}', '\u{0}', '\u{0}']), + ('\u{2c9b}', ['\u{2c9a}', '\u{0}', '\u{0}']), ('\u{2c9d}', ['\u{2c9c}', '\u{0}', '\u{0}']), + ('\u{2c9f}', ['\u{2c9e}', '\u{0}', '\u{0}']), ('\u{2ca1}', ['\u{2ca0}', '\u{0}', '\u{0}']), + ('\u{2ca3}', ['\u{2ca2}', '\u{0}', '\u{0}']), ('\u{2ca5}', ['\u{2ca4}', '\u{0}', '\u{0}']), + ('\u{2ca7}', ['\u{2ca6}', '\u{0}', '\u{0}']), ('\u{2ca9}', ['\u{2ca8}', '\u{0}', '\u{0}']), + ('\u{2cab}', ['\u{2caa}', '\u{0}', '\u{0}']), ('\u{2cad}', ['\u{2cac}', '\u{0}', '\u{0}']), + ('\u{2caf}', ['\u{2cae}', '\u{0}', '\u{0}']), ('\u{2cb1}', ['\u{2cb0}', '\u{0}', '\u{0}']), + ('\u{2cb3}', ['\u{2cb2}', '\u{0}', '\u{0}']), ('\u{2cb5}', ['\u{2cb4}', '\u{0}', '\u{0}']), + ('\u{2cb7}', ['\u{2cb6}', '\u{0}', '\u{0}']), ('\u{2cb9}', ['\u{2cb8}', '\u{0}', '\u{0}']), + ('\u{2cbb}', ['\u{2cba}', '\u{0}', '\u{0}']), ('\u{2cbd}', ['\u{2cbc}', '\u{0}', '\u{0}']), + ('\u{2cbf}', ['\u{2cbe}', '\u{0}', '\u{0}']), ('\u{2cc1}', ['\u{2cc0}', '\u{0}', '\u{0}']), + ('\u{2cc3}', ['\u{2cc2}', '\u{0}', '\u{0}']), ('\u{2cc5}', ['\u{2cc4}', '\u{0}', '\u{0}']), + ('\u{2cc7}', ['\u{2cc6}', '\u{0}', '\u{0}']), ('\u{2cc9}', ['\u{2cc8}', '\u{0}', '\u{0}']), + ('\u{2ccb}', ['\u{2cca}', '\u{0}', '\u{0}']), ('\u{2ccd}', ['\u{2ccc}', '\u{0}', '\u{0}']), + ('\u{2ccf}', ['\u{2cce}', '\u{0}', '\u{0}']), ('\u{2cd1}', ['\u{2cd0}', '\u{0}', '\u{0}']), + ('\u{2cd3}', ['\u{2cd2}', '\u{0}', '\u{0}']), ('\u{2cd5}', ['\u{2cd4}', '\u{0}', '\u{0}']), + ('\u{2cd7}', ['\u{2cd6}', '\u{0}', '\u{0}']), ('\u{2cd9}', ['\u{2cd8}', '\u{0}', '\u{0}']), + ('\u{2cdb}', ['\u{2cda}', '\u{0}', '\u{0}']), ('\u{2cdd}', ['\u{2cdc}', '\u{0}', '\u{0}']), + ('\u{2cdf}', ['\u{2cde}', '\u{0}', '\u{0}']), ('\u{2ce1}', ['\u{2ce0}', '\u{0}', '\u{0}']), + ('\u{2ce3}', ['\u{2ce2}', '\u{0}', '\u{0}']), ('\u{2cec}', ['\u{2ceb}', '\u{0}', '\u{0}']), + ('\u{2cee}', ['\u{2ced}', '\u{0}', '\u{0}']), ('\u{2cf3}', ['\u{2cf2}', '\u{0}', '\u{0}']), + ('\u{2d00}', ['\u{10a0}', '\u{0}', '\u{0}']), ('\u{2d01}', ['\u{10a1}', '\u{0}', '\u{0}']), + ('\u{2d02}', ['\u{10a2}', '\u{0}', '\u{0}']), ('\u{2d03}', ['\u{10a3}', '\u{0}', '\u{0}']), + ('\u{2d04}', ['\u{10a4}', '\u{0}', '\u{0}']), ('\u{2d05}', ['\u{10a5}', '\u{0}', '\u{0}']), + ('\u{2d06}', ['\u{10a6}', '\u{0}', '\u{0}']), ('\u{2d07}', ['\u{10a7}', '\u{0}', '\u{0}']), + ('\u{2d08}', ['\u{10a8}', '\u{0}', '\u{0}']), ('\u{2d09}', ['\u{10a9}', '\u{0}', '\u{0}']), + ('\u{2d0a}', ['\u{10aa}', '\u{0}', '\u{0}']), ('\u{2d0b}', ['\u{10ab}', '\u{0}', '\u{0}']), + ('\u{2d0c}', ['\u{10ac}', '\u{0}', '\u{0}']), ('\u{2d0d}', ['\u{10ad}', '\u{0}', '\u{0}']), + ('\u{2d0e}', ['\u{10ae}', '\u{0}', '\u{0}']), ('\u{2d0f}', ['\u{10af}', '\u{0}', '\u{0}']), + ('\u{2d10}', ['\u{10b0}', '\u{0}', '\u{0}']), ('\u{2d11}', ['\u{10b1}', '\u{0}', '\u{0}']), + ('\u{2d12}', ['\u{10b2}', '\u{0}', '\u{0}']), ('\u{2d13}', ['\u{10b3}', '\u{0}', '\u{0}']), + ('\u{2d14}', ['\u{10b4}', '\u{0}', '\u{0}']), ('\u{2d15}', ['\u{10b5}', '\u{0}', '\u{0}']), + ('\u{2d16}', ['\u{10b6}', '\u{0}', '\u{0}']), ('\u{2d17}', ['\u{10b7}', '\u{0}', '\u{0}']), + ('\u{2d18}', ['\u{10b8}', '\u{0}', '\u{0}']), ('\u{2d19}', ['\u{10b9}', '\u{0}', '\u{0}']), + ('\u{2d1a}', ['\u{10ba}', '\u{0}', '\u{0}']), ('\u{2d1b}', ['\u{10bb}', '\u{0}', '\u{0}']), + ('\u{2d1c}', ['\u{10bc}', '\u{0}', '\u{0}']), ('\u{2d1d}', ['\u{10bd}', '\u{0}', '\u{0}']), + ('\u{2d1e}', ['\u{10be}', '\u{0}', '\u{0}']), ('\u{2d1f}', ['\u{10bf}', '\u{0}', '\u{0}']), + ('\u{2d20}', ['\u{10c0}', '\u{0}', '\u{0}']), ('\u{2d21}', ['\u{10c1}', '\u{0}', '\u{0}']), + ('\u{2d22}', ['\u{10c2}', '\u{0}', '\u{0}']), ('\u{2d23}', ['\u{10c3}', '\u{0}', '\u{0}']), + ('\u{2d24}', ['\u{10c4}', '\u{0}', '\u{0}']), ('\u{2d25}', ['\u{10c5}', '\u{0}', '\u{0}']), + ('\u{2d27}', ['\u{10c7}', '\u{0}', '\u{0}']), ('\u{2d2d}', ['\u{10cd}', '\u{0}', '\u{0}']), + ('\u{a641}', ['\u{a640}', '\u{0}', '\u{0}']), ('\u{a643}', ['\u{a642}', '\u{0}', '\u{0}']), + ('\u{a645}', ['\u{a644}', '\u{0}', '\u{0}']), ('\u{a647}', ['\u{a646}', '\u{0}', '\u{0}']), + ('\u{a649}', ['\u{a648}', '\u{0}', '\u{0}']), ('\u{a64b}', ['\u{a64a}', '\u{0}', '\u{0}']), + ('\u{a64d}', ['\u{a64c}', '\u{0}', '\u{0}']), ('\u{a64f}', ['\u{a64e}', '\u{0}', '\u{0}']), + ('\u{a651}', ['\u{a650}', '\u{0}', '\u{0}']), ('\u{a653}', ['\u{a652}', '\u{0}', '\u{0}']), + ('\u{a655}', ['\u{a654}', '\u{0}', '\u{0}']), ('\u{a657}', ['\u{a656}', '\u{0}', '\u{0}']), + ('\u{a659}', ['\u{a658}', '\u{0}', '\u{0}']), ('\u{a65b}', ['\u{a65a}', '\u{0}', '\u{0}']), + ('\u{a65d}', ['\u{a65c}', '\u{0}', '\u{0}']), ('\u{a65f}', ['\u{a65e}', '\u{0}', '\u{0}']), + ('\u{a661}', ['\u{a660}', '\u{0}', '\u{0}']), ('\u{a663}', ['\u{a662}', '\u{0}', '\u{0}']), + ('\u{a665}', ['\u{a664}', '\u{0}', '\u{0}']), ('\u{a667}', ['\u{a666}', '\u{0}', '\u{0}']), + ('\u{a669}', ['\u{a668}', '\u{0}', '\u{0}']), ('\u{a66b}', ['\u{a66a}', '\u{0}', '\u{0}']), + ('\u{a66d}', ['\u{a66c}', '\u{0}', '\u{0}']), ('\u{a681}', ['\u{a680}', '\u{0}', '\u{0}']), + ('\u{a683}', ['\u{a682}', '\u{0}', '\u{0}']), ('\u{a685}', ['\u{a684}', '\u{0}', '\u{0}']), + ('\u{a687}', ['\u{a686}', '\u{0}', '\u{0}']), ('\u{a689}', ['\u{a688}', '\u{0}', '\u{0}']), + ('\u{a68b}', ['\u{a68a}', '\u{0}', '\u{0}']), ('\u{a68d}', ['\u{a68c}', '\u{0}', '\u{0}']), + ('\u{a68f}', ['\u{a68e}', '\u{0}', '\u{0}']), ('\u{a691}', ['\u{a690}', '\u{0}', '\u{0}']), + ('\u{a693}', ['\u{a692}', '\u{0}', '\u{0}']), ('\u{a695}', ['\u{a694}', '\u{0}', '\u{0}']), + ('\u{a697}', ['\u{a696}', '\u{0}', '\u{0}']), ('\u{a699}', ['\u{a698}', '\u{0}', '\u{0}']), + ('\u{a69b}', ['\u{a69a}', '\u{0}', '\u{0}']), ('\u{a723}', ['\u{a722}', '\u{0}', '\u{0}']), + ('\u{a725}', ['\u{a724}', '\u{0}', '\u{0}']), ('\u{a727}', ['\u{a726}', '\u{0}', '\u{0}']), + ('\u{a729}', ['\u{a728}', '\u{0}', '\u{0}']), ('\u{a72b}', ['\u{a72a}', '\u{0}', '\u{0}']), + ('\u{a72d}', ['\u{a72c}', '\u{0}', '\u{0}']), ('\u{a72f}', ['\u{a72e}', '\u{0}', '\u{0}']), + ('\u{a733}', ['\u{a732}', '\u{0}', '\u{0}']), ('\u{a735}', ['\u{a734}', '\u{0}', '\u{0}']), + ('\u{a737}', ['\u{a736}', '\u{0}', '\u{0}']), ('\u{a739}', ['\u{a738}', '\u{0}', '\u{0}']), + ('\u{a73b}', ['\u{a73a}', '\u{0}', '\u{0}']), ('\u{a73d}', ['\u{a73c}', '\u{0}', '\u{0}']), + ('\u{a73f}', ['\u{a73e}', '\u{0}', '\u{0}']), ('\u{a741}', ['\u{a740}', '\u{0}', '\u{0}']), + ('\u{a743}', ['\u{a742}', '\u{0}', '\u{0}']), ('\u{a745}', ['\u{a744}', '\u{0}', '\u{0}']), + ('\u{a747}', ['\u{a746}', '\u{0}', '\u{0}']), ('\u{a749}', ['\u{a748}', '\u{0}', '\u{0}']), + ('\u{a74b}', ['\u{a74a}', '\u{0}', '\u{0}']), ('\u{a74d}', ['\u{a74c}', '\u{0}', '\u{0}']), + ('\u{a74f}', ['\u{a74e}', '\u{0}', '\u{0}']), ('\u{a751}', ['\u{a750}', '\u{0}', '\u{0}']), + ('\u{a753}', ['\u{a752}', '\u{0}', '\u{0}']), ('\u{a755}', ['\u{a754}', '\u{0}', '\u{0}']), + ('\u{a757}', ['\u{a756}', '\u{0}', '\u{0}']), ('\u{a759}', ['\u{a758}', '\u{0}', '\u{0}']), + ('\u{a75b}', ['\u{a75a}', '\u{0}', '\u{0}']), ('\u{a75d}', ['\u{a75c}', '\u{0}', '\u{0}']), + ('\u{a75f}', ['\u{a75e}', '\u{0}', '\u{0}']), ('\u{a761}', ['\u{a760}', '\u{0}', '\u{0}']), + ('\u{a763}', ['\u{a762}', '\u{0}', '\u{0}']), ('\u{a765}', ['\u{a764}', '\u{0}', '\u{0}']), + ('\u{a767}', ['\u{a766}', '\u{0}', '\u{0}']), ('\u{a769}', ['\u{a768}', '\u{0}', '\u{0}']), + ('\u{a76b}', ['\u{a76a}', '\u{0}', '\u{0}']), ('\u{a76d}', ['\u{a76c}', '\u{0}', '\u{0}']), + ('\u{a76f}', ['\u{a76e}', '\u{0}', '\u{0}']), ('\u{a77a}', ['\u{a779}', '\u{0}', '\u{0}']), + ('\u{a77c}', ['\u{a77b}', '\u{0}', '\u{0}']), ('\u{a77f}', ['\u{a77e}', '\u{0}', '\u{0}']), + ('\u{a781}', ['\u{a780}', '\u{0}', '\u{0}']), ('\u{a783}', ['\u{a782}', '\u{0}', '\u{0}']), + ('\u{a785}', ['\u{a784}', '\u{0}', '\u{0}']), ('\u{a787}', ['\u{a786}', '\u{0}', '\u{0}']), + ('\u{a78c}', ['\u{a78b}', '\u{0}', '\u{0}']), ('\u{a791}', ['\u{a790}', '\u{0}', '\u{0}']), + ('\u{a793}', ['\u{a792}', '\u{0}', '\u{0}']), ('\u{a794}', ['\u{a7c4}', '\u{0}', '\u{0}']), + ('\u{a797}', ['\u{a796}', '\u{0}', '\u{0}']), ('\u{a799}', ['\u{a798}', '\u{0}', '\u{0}']), + ('\u{a79b}', ['\u{a79a}', '\u{0}', '\u{0}']), ('\u{a79d}', ['\u{a79c}', '\u{0}', '\u{0}']), + ('\u{a79f}', ['\u{a79e}', '\u{0}', '\u{0}']), ('\u{a7a1}', ['\u{a7a0}', '\u{0}', '\u{0}']), + ('\u{a7a3}', ['\u{a7a2}', '\u{0}', '\u{0}']), ('\u{a7a5}', ['\u{a7a4}', '\u{0}', '\u{0}']), + ('\u{a7a7}', ['\u{a7a6}', '\u{0}', '\u{0}']), ('\u{a7a9}', ['\u{a7a8}', '\u{0}', '\u{0}']), + ('\u{a7b5}', ['\u{a7b4}', '\u{0}', '\u{0}']), ('\u{a7b7}', ['\u{a7b6}', '\u{0}', '\u{0}']), + ('\u{a7b9}', ['\u{a7b8}', '\u{0}', '\u{0}']), ('\u{a7bb}', ['\u{a7ba}', '\u{0}', '\u{0}']), + ('\u{a7bd}', ['\u{a7bc}', '\u{0}', '\u{0}']), ('\u{a7bf}', ['\u{a7be}', '\u{0}', '\u{0}']), + ('\u{a7c1}', ['\u{a7c0}', '\u{0}', '\u{0}']), ('\u{a7c3}', ['\u{a7c2}', '\u{0}', '\u{0}']), + ('\u{a7c8}', ['\u{a7c7}', '\u{0}', '\u{0}']), ('\u{a7ca}', ['\u{a7c9}', '\u{0}', '\u{0}']), + ('\u{a7cd}', ['\u{a7cc}', '\u{0}', '\u{0}']), ('\u{a7cf}', ['\u{a7ce}', '\u{0}', '\u{0}']), + ('\u{a7d1}', ['\u{a7d0}', '\u{0}', '\u{0}']), ('\u{a7d3}', ['\u{a7d2}', '\u{0}', '\u{0}']), + ('\u{a7d5}', ['\u{a7d4}', '\u{0}', '\u{0}']), ('\u{a7d7}', ['\u{a7d6}', '\u{0}', '\u{0}']), + ('\u{a7d9}', ['\u{a7d8}', '\u{0}', '\u{0}']), ('\u{a7db}', ['\u{a7da}', '\u{0}', '\u{0}']), + ('\u{a7f6}', ['\u{a7f5}', '\u{0}', '\u{0}']), ('\u{ab53}', ['\u{a7b3}', '\u{0}', '\u{0}']), + ('\u{ab70}', ['\u{13a0}', '\u{0}', '\u{0}']), ('\u{ab71}', ['\u{13a1}', '\u{0}', '\u{0}']), + ('\u{ab72}', ['\u{13a2}', '\u{0}', '\u{0}']), ('\u{ab73}', ['\u{13a3}', '\u{0}', '\u{0}']), + ('\u{ab74}', ['\u{13a4}', '\u{0}', '\u{0}']), ('\u{ab75}', ['\u{13a5}', '\u{0}', '\u{0}']), + ('\u{ab76}', ['\u{13a6}', '\u{0}', '\u{0}']), ('\u{ab77}', ['\u{13a7}', '\u{0}', '\u{0}']), + ('\u{ab78}', ['\u{13a8}', '\u{0}', '\u{0}']), ('\u{ab79}', ['\u{13a9}', '\u{0}', '\u{0}']), + ('\u{ab7a}', ['\u{13aa}', '\u{0}', '\u{0}']), ('\u{ab7b}', ['\u{13ab}', '\u{0}', '\u{0}']), + ('\u{ab7c}', ['\u{13ac}', '\u{0}', '\u{0}']), ('\u{ab7d}', ['\u{13ad}', '\u{0}', '\u{0}']), + ('\u{ab7e}', ['\u{13ae}', '\u{0}', '\u{0}']), ('\u{ab7f}', ['\u{13af}', '\u{0}', '\u{0}']), + ('\u{ab80}', ['\u{13b0}', '\u{0}', '\u{0}']), ('\u{ab81}', ['\u{13b1}', '\u{0}', '\u{0}']), + ('\u{ab82}', ['\u{13b2}', '\u{0}', '\u{0}']), ('\u{ab83}', ['\u{13b3}', '\u{0}', '\u{0}']), + ('\u{ab84}', ['\u{13b4}', '\u{0}', '\u{0}']), ('\u{ab85}', ['\u{13b5}', '\u{0}', '\u{0}']), + ('\u{ab86}', ['\u{13b6}', '\u{0}', '\u{0}']), ('\u{ab87}', ['\u{13b7}', '\u{0}', '\u{0}']), + ('\u{ab88}', ['\u{13b8}', '\u{0}', '\u{0}']), ('\u{ab89}', ['\u{13b9}', '\u{0}', '\u{0}']), + ('\u{ab8a}', ['\u{13ba}', '\u{0}', '\u{0}']), ('\u{ab8b}', ['\u{13bb}', '\u{0}', '\u{0}']), + ('\u{ab8c}', ['\u{13bc}', '\u{0}', '\u{0}']), ('\u{ab8d}', ['\u{13bd}', '\u{0}', '\u{0}']), + ('\u{ab8e}', ['\u{13be}', '\u{0}', '\u{0}']), ('\u{ab8f}', ['\u{13bf}', '\u{0}', '\u{0}']), + ('\u{ab90}', ['\u{13c0}', '\u{0}', '\u{0}']), ('\u{ab91}', ['\u{13c1}', '\u{0}', '\u{0}']), + ('\u{ab92}', ['\u{13c2}', '\u{0}', '\u{0}']), ('\u{ab93}', ['\u{13c3}', '\u{0}', '\u{0}']), + ('\u{ab94}', ['\u{13c4}', '\u{0}', '\u{0}']), ('\u{ab95}', ['\u{13c5}', '\u{0}', '\u{0}']), + ('\u{ab96}', ['\u{13c6}', '\u{0}', '\u{0}']), ('\u{ab97}', ['\u{13c7}', '\u{0}', '\u{0}']), + ('\u{ab98}', ['\u{13c8}', '\u{0}', '\u{0}']), ('\u{ab99}', ['\u{13c9}', '\u{0}', '\u{0}']), + ('\u{ab9a}', ['\u{13ca}', '\u{0}', '\u{0}']), ('\u{ab9b}', ['\u{13cb}', '\u{0}', '\u{0}']), + ('\u{ab9c}', ['\u{13cc}', '\u{0}', '\u{0}']), ('\u{ab9d}', ['\u{13cd}', '\u{0}', '\u{0}']), + ('\u{ab9e}', ['\u{13ce}', '\u{0}', '\u{0}']), ('\u{ab9f}', ['\u{13cf}', '\u{0}', '\u{0}']), + ('\u{aba0}', ['\u{13d0}', '\u{0}', '\u{0}']), ('\u{aba1}', ['\u{13d1}', '\u{0}', '\u{0}']), + ('\u{aba2}', ['\u{13d2}', '\u{0}', '\u{0}']), ('\u{aba3}', ['\u{13d3}', '\u{0}', '\u{0}']), + ('\u{aba4}', ['\u{13d4}', '\u{0}', '\u{0}']), ('\u{aba5}', ['\u{13d5}', '\u{0}', '\u{0}']), + ('\u{aba6}', ['\u{13d6}', '\u{0}', '\u{0}']), ('\u{aba7}', ['\u{13d7}', '\u{0}', '\u{0}']), + ('\u{aba8}', ['\u{13d8}', '\u{0}', '\u{0}']), ('\u{aba9}', ['\u{13d9}', '\u{0}', '\u{0}']), + ('\u{abaa}', ['\u{13da}', '\u{0}', '\u{0}']), ('\u{abab}', ['\u{13db}', '\u{0}', '\u{0}']), + ('\u{abac}', ['\u{13dc}', '\u{0}', '\u{0}']), ('\u{abad}', ['\u{13dd}', '\u{0}', '\u{0}']), + ('\u{abae}', ['\u{13de}', '\u{0}', '\u{0}']), ('\u{abaf}', ['\u{13df}', '\u{0}', '\u{0}']), + ('\u{abb0}', ['\u{13e0}', '\u{0}', '\u{0}']), ('\u{abb1}', ['\u{13e1}', '\u{0}', '\u{0}']), + ('\u{abb2}', ['\u{13e2}', '\u{0}', '\u{0}']), ('\u{abb3}', ['\u{13e3}', '\u{0}', '\u{0}']), + ('\u{abb4}', ['\u{13e4}', '\u{0}', '\u{0}']), ('\u{abb5}', ['\u{13e5}', '\u{0}', '\u{0}']), + ('\u{abb6}', ['\u{13e6}', '\u{0}', '\u{0}']), ('\u{abb7}', ['\u{13e7}', '\u{0}', '\u{0}']), + ('\u{abb8}', ['\u{13e8}', '\u{0}', '\u{0}']), ('\u{abb9}', ['\u{13e9}', '\u{0}', '\u{0}']), + ('\u{abba}', ['\u{13ea}', '\u{0}', '\u{0}']), ('\u{abbb}', ['\u{13eb}', '\u{0}', '\u{0}']), + ('\u{abbc}', ['\u{13ec}', '\u{0}', '\u{0}']), ('\u{abbd}', ['\u{13ed}', '\u{0}', '\u{0}']), + ('\u{abbe}', ['\u{13ee}', '\u{0}', '\u{0}']), ('\u{abbf}', ['\u{13ef}', '\u{0}', '\u{0}']), + ('\u{fb00}', ['F', 'F', '\u{0}']), ('\u{fb01}', ['F', 'I', '\u{0}']), + ('\u{fb02}', ['F', 'L', '\u{0}']), ('\u{fb03}', ['F', 'F', 'I']), + ('\u{fb04}', ['F', 'F', 'L']), ('\u{fb05}', ['S', 'T', '\u{0}']), + ('\u{fb06}', ['S', 'T', '\u{0}']), ('\u{fb13}', ['\u{544}', '\u{546}', '\u{0}']), + ('\u{fb14}', ['\u{544}', '\u{535}', '\u{0}']), + ('\u{fb15}', ['\u{544}', '\u{53b}', '\u{0}']), + ('\u{fb16}', ['\u{54e}', '\u{546}', '\u{0}']), + ('\u{fb17}', ['\u{544}', '\u{53d}', '\u{0}']), ('\u{ff41}', ['\u{ff21}', '\u{0}', '\u{0}']), + ('\u{ff42}', ['\u{ff22}', '\u{0}', '\u{0}']), ('\u{ff43}', ['\u{ff23}', '\u{0}', '\u{0}']), + ('\u{ff44}', ['\u{ff24}', '\u{0}', '\u{0}']), ('\u{ff45}', ['\u{ff25}', '\u{0}', '\u{0}']), + ('\u{ff46}', ['\u{ff26}', '\u{0}', '\u{0}']), ('\u{ff47}', ['\u{ff27}', '\u{0}', '\u{0}']), + ('\u{ff48}', ['\u{ff28}', '\u{0}', '\u{0}']), ('\u{ff49}', ['\u{ff29}', '\u{0}', '\u{0}']), + ('\u{ff4a}', ['\u{ff2a}', '\u{0}', '\u{0}']), ('\u{ff4b}', ['\u{ff2b}', '\u{0}', '\u{0}']), + ('\u{ff4c}', ['\u{ff2c}', '\u{0}', '\u{0}']), ('\u{ff4d}', ['\u{ff2d}', '\u{0}', '\u{0}']), + ('\u{ff4e}', ['\u{ff2e}', '\u{0}', '\u{0}']), ('\u{ff4f}', ['\u{ff2f}', '\u{0}', '\u{0}']), + ('\u{ff50}', ['\u{ff30}', '\u{0}', '\u{0}']), ('\u{ff51}', ['\u{ff31}', '\u{0}', '\u{0}']), + ('\u{ff52}', ['\u{ff32}', '\u{0}', '\u{0}']), ('\u{ff53}', ['\u{ff33}', '\u{0}', '\u{0}']), + ('\u{ff54}', ['\u{ff34}', '\u{0}', '\u{0}']), ('\u{ff55}', ['\u{ff35}', '\u{0}', '\u{0}']), + ('\u{ff56}', ['\u{ff36}', '\u{0}', '\u{0}']), ('\u{ff57}', ['\u{ff37}', '\u{0}', '\u{0}']), + ('\u{ff58}', ['\u{ff38}', '\u{0}', '\u{0}']), ('\u{ff59}', ['\u{ff39}', '\u{0}', '\u{0}']), + ('\u{ff5a}', ['\u{ff3a}', '\u{0}', '\u{0}']), + ('\u{10428}', ['\u{10400}', '\u{0}', '\u{0}']), + ('\u{10429}', ['\u{10401}', '\u{0}', '\u{0}']), + ('\u{1042a}', ['\u{10402}', '\u{0}', '\u{0}']), + ('\u{1042b}', ['\u{10403}', '\u{0}', '\u{0}']), + ('\u{1042c}', ['\u{10404}', '\u{0}', '\u{0}']), + ('\u{1042d}', ['\u{10405}', '\u{0}', '\u{0}']), + ('\u{1042e}', ['\u{10406}', '\u{0}', '\u{0}']), + ('\u{1042f}', ['\u{10407}', '\u{0}', '\u{0}']), + ('\u{10430}', ['\u{10408}', '\u{0}', '\u{0}']), + ('\u{10431}', ['\u{10409}', '\u{0}', '\u{0}']), + ('\u{10432}', ['\u{1040a}', '\u{0}', '\u{0}']), + ('\u{10433}', ['\u{1040b}', '\u{0}', '\u{0}']), + ('\u{10434}', ['\u{1040c}', '\u{0}', '\u{0}']), + ('\u{10435}', ['\u{1040d}', '\u{0}', '\u{0}']), + ('\u{10436}', ['\u{1040e}', '\u{0}', '\u{0}']), + ('\u{10437}', ['\u{1040f}', '\u{0}', '\u{0}']), + ('\u{10438}', ['\u{10410}', '\u{0}', '\u{0}']), + ('\u{10439}', ['\u{10411}', '\u{0}', '\u{0}']), + ('\u{1043a}', ['\u{10412}', '\u{0}', '\u{0}']), + ('\u{1043b}', ['\u{10413}', '\u{0}', '\u{0}']), + ('\u{1043c}', ['\u{10414}', '\u{0}', '\u{0}']), + ('\u{1043d}', ['\u{10415}', '\u{0}', '\u{0}']), + ('\u{1043e}', ['\u{10416}', '\u{0}', '\u{0}']), + ('\u{1043f}', ['\u{10417}', '\u{0}', '\u{0}']), + ('\u{10440}', ['\u{10418}', '\u{0}', '\u{0}']), + ('\u{10441}', ['\u{10419}', '\u{0}', '\u{0}']), + ('\u{10442}', ['\u{1041a}', '\u{0}', '\u{0}']), + ('\u{10443}', ['\u{1041b}', '\u{0}', '\u{0}']), + ('\u{10444}', ['\u{1041c}', '\u{0}', '\u{0}']), + ('\u{10445}', ['\u{1041d}', '\u{0}', '\u{0}']), + ('\u{10446}', ['\u{1041e}', '\u{0}', '\u{0}']), + ('\u{10447}', ['\u{1041f}', '\u{0}', '\u{0}']), + ('\u{10448}', ['\u{10420}', '\u{0}', '\u{0}']), + ('\u{10449}', ['\u{10421}', '\u{0}', '\u{0}']), + ('\u{1044a}', ['\u{10422}', '\u{0}', '\u{0}']), + ('\u{1044b}', ['\u{10423}', '\u{0}', '\u{0}']), + ('\u{1044c}', ['\u{10424}', '\u{0}', '\u{0}']), + ('\u{1044d}', ['\u{10425}', '\u{0}', '\u{0}']), + ('\u{1044e}', ['\u{10426}', '\u{0}', '\u{0}']), + ('\u{1044f}', ['\u{10427}', '\u{0}', '\u{0}']), + ('\u{104d8}', ['\u{104b0}', '\u{0}', '\u{0}']), + ('\u{104d9}', ['\u{104b1}', '\u{0}', '\u{0}']), + ('\u{104da}', ['\u{104b2}', '\u{0}', '\u{0}']), + ('\u{104db}', ['\u{104b3}', '\u{0}', '\u{0}']), + ('\u{104dc}', ['\u{104b4}', '\u{0}', '\u{0}']), + ('\u{104dd}', ['\u{104b5}', '\u{0}', '\u{0}']), + ('\u{104de}', ['\u{104b6}', '\u{0}', '\u{0}']), + ('\u{104df}', ['\u{104b7}', '\u{0}', '\u{0}']), + ('\u{104e0}', ['\u{104b8}', '\u{0}', '\u{0}']), + ('\u{104e1}', ['\u{104b9}', '\u{0}', '\u{0}']), + ('\u{104e2}', ['\u{104ba}', '\u{0}', '\u{0}']), + ('\u{104e3}', ['\u{104bb}', '\u{0}', '\u{0}']), + ('\u{104e4}', ['\u{104bc}', '\u{0}', '\u{0}']), + ('\u{104e5}', ['\u{104bd}', '\u{0}', '\u{0}']), + ('\u{104e6}', ['\u{104be}', '\u{0}', '\u{0}']), + ('\u{104e7}', ['\u{104bf}', '\u{0}', '\u{0}']), + ('\u{104e8}', ['\u{104c0}', '\u{0}', '\u{0}']), + ('\u{104e9}', ['\u{104c1}', '\u{0}', '\u{0}']), + ('\u{104ea}', ['\u{104c2}', '\u{0}', '\u{0}']), + ('\u{104eb}', ['\u{104c3}', '\u{0}', '\u{0}']), + ('\u{104ec}', ['\u{104c4}', '\u{0}', '\u{0}']), + ('\u{104ed}', ['\u{104c5}', '\u{0}', '\u{0}']), + ('\u{104ee}', ['\u{104c6}', '\u{0}', '\u{0}']), + ('\u{104ef}', ['\u{104c7}', '\u{0}', '\u{0}']), + ('\u{104f0}', ['\u{104c8}', '\u{0}', '\u{0}']), + ('\u{104f1}', ['\u{104c9}', '\u{0}', '\u{0}']), + ('\u{104f2}', ['\u{104ca}', '\u{0}', '\u{0}']), + ('\u{104f3}', ['\u{104cb}', '\u{0}', '\u{0}']), + ('\u{104f4}', ['\u{104cc}', '\u{0}', '\u{0}']), + ('\u{104f5}', ['\u{104cd}', '\u{0}', '\u{0}']), + ('\u{104f6}', ['\u{104ce}', '\u{0}', '\u{0}']), + ('\u{104f7}', ['\u{104cf}', '\u{0}', '\u{0}']), + ('\u{104f8}', ['\u{104d0}', '\u{0}', '\u{0}']), + ('\u{104f9}', ['\u{104d1}', '\u{0}', '\u{0}']), + ('\u{104fa}', ['\u{104d2}', '\u{0}', '\u{0}']), + ('\u{104fb}', ['\u{104d3}', '\u{0}', '\u{0}']), + ('\u{10597}', ['\u{10570}', '\u{0}', '\u{0}']), + ('\u{10598}', ['\u{10571}', '\u{0}', '\u{0}']), + ('\u{10599}', ['\u{10572}', '\u{0}', '\u{0}']), + ('\u{1059a}', ['\u{10573}', '\u{0}', '\u{0}']), + ('\u{1059b}', ['\u{10574}', '\u{0}', '\u{0}']), + ('\u{1059c}', ['\u{10575}', '\u{0}', '\u{0}']), + ('\u{1059d}', ['\u{10576}', '\u{0}', '\u{0}']), + ('\u{1059e}', ['\u{10577}', '\u{0}', '\u{0}']), + ('\u{1059f}', ['\u{10578}', '\u{0}', '\u{0}']), + ('\u{105a0}', ['\u{10579}', '\u{0}', '\u{0}']), + ('\u{105a1}', ['\u{1057a}', '\u{0}', '\u{0}']), + ('\u{105a3}', ['\u{1057c}', '\u{0}', '\u{0}']), + ('\u{105a4}', ['\u{1057d}', '\u{0}', '\u{0}']), + ('\u{105a5}', ['\u{1057e}', '\u{0}', '\u{0}']), + ('\u{105a6}', ['\u{1057f}', '\u{0}', '\u{0}']), + ('\u{105a7}', ['\u{10580}', '\u{0}', '\u{0}']), + ('\u{105a8}', ['\u{10581}', '\u{0}', '\u{0}']), + ('\u{105a9}', ['\u{10582}', '\u{0}', '\u{0}']), + ('\u{105aa}', ['\u{10583}', '\u{0}', '\u{0}']), + ('\u{105ab}', ['\u{10584}', '\u{0}', '\u{0}']), + ('\u{105ac}', ['\u{10585}', '\u{0}', '\u{0}']), + ('\u{105ad}', ['\u{10586}', '\u{0}', '\u{0}']), + ('\u{105ae}', ['\u{10587}', '\u{0}', '\u{0}']), + ('\u{105af}', ['\u{10588}', '\u{0}', '\u{0}']), + ('\u{105b0}', ['\u{10589}', '\u{0}', '\u{0}']), + ('\u{105b1}', ['\u{1058a}', '\u{0}', '\u{0}']), + ('\u{105b3}', ['\u{1058c}', '\u{0}', '\u{0}']), + ('\u{105b4}', ['\u{1058d}', '\u{0}', '\u{0}']), + ('\u{105b5}', ['\u{1058e}', '\u{0}', '\u{0}']), + ('\u{105b6}', ['\u{1058f}', '\u{0}', '\u{0}']), + ('\u{105b7}', ['\u{10590}', '\u{0}', '\u{0}']), + ('\u{105b8}', ['\u{10591}', '\u{0}', '\u{0}']), + ('\u{105b9}', ['\u{10592}', '\u{0}', '\u{0}']), + ('\u{105bb}', ['\u{10594}', '\u{0}', '\u{0}']), + ('\u{105bc}', ['\u{10595}', '\u{0}', '\u{0}']), + ('\u{10cc0}', ['\u{10c80}', '\u{0}', '\u{0}']), + ('\u{10cc1}', ['\u{10c81}', '\u{0}', '\u{0}']), + ('\u{10cc2}', ['\u{10c82}', '\u{0}', '\u{0}']), + ('\u{10cc3}', ['\u{10c83}', '\u{0}', '\u{0}']), + ('\u{10cc4}', ['\u{10c84}', '\u{0}', '\u{0}']), + ('\u{10cc5}', ['\u{10c85}', '\u{0}', '\u{0}']), + ('\u{10cc6}', ['\u{10c86}', '\u{0}', '\u{0}']), + ('\u{10cc7}', ['\u{10c87}', '\u{0}', '\u{0}']), + ('\u{10cc8}', ['\u{10c88}', '\u{0}', '\u{0}']), + ('\u{10cc9}', ['\u{10c89}', '\u{0}', '\u{0}']), + ('\u{10cca}', ['\u{10c8a}', '\u{0}', '\u{0}']), + ('\u{10ccb}', ['\u{10c8b}', '\u{0}', '\u{0}']), + ('\u{10ccc}', ['\u{10c8c}', '\u{0}', '\u{0}']), + ('\u{10ccd}', ['\u{10c8d}', '\u{0}', '\u{0}']), + ('\u{10cce}', ['\u{10c8e}', '\u{0}', '\u{0}']), + ('\u{10ccf}', ['\u{10c8f}', '\u{0}', '\u{0}']), + ('\u{10cd0}', ['\u{10c90}', '\u{0}', '\u{0}']), + ('\u{10cd1}', ['\u{10c91}', '\u{0}', '\u{0}']), + ('\u{10cd2}', ['\u{10c92}', '\u{0}', '\u{0}']), + ('\u{10cd3}', ['\u{10c93}', '\u{0}', '\u{0}']), + ('\u{10cd4}', ['\u{10c94}', '\u{0}', '\u{0}']), + ('\u{10cd5}', ['\u{10c95}', '\u{0}', '\u{0}']), + ('\u{10cd6}', ['\u{10c96}', '\u{0}', '\u{0}']), + ('\u{10cd7}', ['\u{10c97}', '\u{0}', '\u{0}']), + ('\u{10cd8}', ['\u{10c98}', '\u{0}', '\u{0}']), + ('\u{10cd9}', ['\u{10c99}', '\u{0}', '\u{0}']), + ('\u{10cda}', ['\u{10c9a}', '\u{0}', '\u{0}']), + ('\u{10cdb}', ['\u{10c9b}', '\u{0}', '\u{0}']), + ('\u{10cdc}', ['\u{10c9c}', '\u{0}', '\u{0}']), + ('\u{10cdd}', ['\u{10c9d}', '\u{0}', '\u{0}']), + ('\u{10cde}', ['\u{10c9e}', '\u{0}', '\u{0}']), + ('\u{10cdf}', ['\u{10c9f}', '\u{0}', '\u{0}']), + ('\u{10ce0}', ['\u{10ca0}', '\u{0}', '\u{0}']), + ('\u{10ce1}', ['\u{10ca1}', '\u{0}', '\u{0}']), + ('\u{10ce2}', ['\u{10ca2}', '\u{0}', '\u{0}']), + ('\u{10ce3}', ['\u{10ca3}', '\u{0}', '\u{0}']), + ('\u{10ce4}', ['\u{10ca4}', '\u{0}', '\u{0}']), + ('\u{10ce5}', ['\u{10ca5}', '\u{0}', '\u{0}']), + ('\u{10ce6}', ['\u{10ca6}', '\u{0}', '\u{0}']), + ('\u{10ce7}', ['\u{10ca7}', '\u{0}', '\u{0}']), + ('\u{10ce8}', ['\u{10ca8}', '\u{0}', '\u{0}']), + ('\u{10ce9}', ['\u{10ca9}', '\u{0}', '\u{0}']), + ('\u{10cea}', ['\u{10caa}', '\u{0}', '\u{0}']), + ('\u{10ceb}', ['\u{10cab}', '\u{0}', '\u{0}']), + ('\u{10cec}', ['\u{10cac}', '\u{0}', '\u{0}']), + ('\u{10ced}', ['\u{10cad}', '\u{0}', '\u{0}']), + ('\u{10cee}', ['\u{10cae}', '\u{0}', '\u{0}']), + ('\u{10cef}', ['\u{10caf}', '\u{0}', '\u{0}']), + ('\u{10cf0}', ['\u{10cb0}', '\u{0}', '\u{0}']), + ('\u{10cf1}', ['\u{10cb1}', '\u{0}', '\u{0}']), + ('\u{10cf2}', ['\u{10cb2}', '\u{0}', '\u{0}']), + ('\u{10d70}', ['\u{10d50}', '\u{0}', '\u{0}']), + ('\u{10d71}', ['\u{10d51}', '\u{0}', '\u{0}']), + ('\u{10d72}', ['\u{10d52}', '\u{0}', '\u{0}']), + ('\u{10d73}', ['\u{10d53}', '\u{0}', '\u{0}']), + ('\u{10d74}', ['\u{10d54}', '\u{0}', '\u{0}']), + ('\u{10d75}', ['\u{10d55}', '\u{0}', '\u{0}']), + ('\u{10d76}', ['\u{10d56}', '\u{0}', '\u{0}']), + ('\u{10d77}', ['\u{10d57}', '\u{0}', '\u{0}']), + ('\u{10d78}', ['\u{10d58}', '\u{0}', '\u{0}']), + ('\u{10d79}', ['\u{10d59}', '\u{0}', '\u{0}']), + ('\u{10d7a}', ['\u{10d5a}', '\u{0}', '\u{0}']), + ('\u{10d7b}', ['\u{10d5b}', '\u{0}', '\u{0}']), + ('\u{10d7c}', ['\u{10d5c}', '\u{0}', '\u{0}']), + ('\u{10d7d}', ['\u{10d5d}', '\u{0}', '\u{0}']), + ('\u{10d7e}', ['\u{10d5e}', '\u{0}', '\u{0}']), + ('\u{10d7f}', ['\u{10d5f}', '\u{0}', '\u{0}']), + ('\u{10d80}', ['\u{10d60}', '\u{0}', '\u{0}']), + ('\u{10d81}', ['\u{10d61}', '\u{0}', '\u{0}']), + ('\u{10d82}', ['\u{10d62}', '\u{0}', '\u{0}']), + ('\u{10d83}', ['\u{10d63}', '\u{0}', '\u{0}']), + ('\u{10d84}', ['\u{10d64}', '\u{0}', '\u{0}']), + ('\u{10d85}', ['\u{10d65}', '\u{0}', '\u{0}']), + ('\u{118c0}', ['\u{118a0}', '\u{0}', '\u{0}']), + ('\u{118c1}', ['\u{118a1}', '\u{0}', '\u{0}']), + ('\u{118c2}', ['\u{118a2}', '\u{0}', '\u{0}']), + ('\u{118c3}', ['\u{118a3}', '\u{0}', '\u{0}']), + ('\u{118c4}', ['\u{118a4}', '\u{0}', '\u{0}']), + ('\u{118c5}', ['\u{118a5}', '\u{0}', '\u{0}']), + ('\u{118c6}', ['\u{118a6}', '\u{0}', '\u{0}']), + ('\u{118c7}', ['\u{118a7}', '\u{0}', '\u{0}']), + ('\u{118c8}', ['\u{118a8}', '\u{0}', '\u{0}']), + ('\u{118c9}', ['\u{118a9}', '\u{0}', '\u{0}']), + ('\u{118ca}', ['\u{118aa}', '\u{0}', '\u{0}']), + ('\u{118cb}', ['\u{118ab}', '\u{0}', '\u{0}']), + ('\u{118cc}', ['\u{118ac}', '\u{0}', '\u{0}']), + ('\u{118cd}', ['\u{118ad}', '\u{0}', '\u{0}']), + ('\u{118ce}', ['\u{118ae}', '\u{0}', '\u{0}']), + ('\u{118cf}', ['\u{118af}', '\u{0}', '\u{0}']), + ('\u{118d0}', ['\u{118b0}', '\u{0}', '\u{0}']), + ('\u{118d1}', ['\u{118b1}', '\u{0}', '\u{0}']), + ('\u{118d2}', ['\u{118b2}', '\u{0}', '\u{0}']), + ('\u{118d3}', ['\u{118b3}', '\u{0}', '\u{0}']), + ('\u{118d4}', ['\u{118b4}', '\u{0}', '\u{0}']), + ('\u{118d5}', ['\u{118b5}', '\u{0}', '\u{0}']), + ('\u{118d6}', ['\u{118b6}', '\u{0}', '\u{0}']), + ('\u{118d7}', ['\u{118b7}', '\u{0}', '\u{0}']), + ('\u{118d8}', ['\u{118b8}', '\u{0}', '\u{0}']), + ('\u{118d9}', ['\u{118b9}', '\u{0}', '\u{0}']), + ('\u{118da}', ['\u{118ba}', '\u{0}', '\u{0}']), + ('\u{118db}', ['\u{118bb}', '\u{0}', '\u{0}']), + ('\u{118dc}', ['\u{118bc}', '\u{0}', '\u{0}']), + ('\u{118dd}', ['\u{118bd}', '\u{0}', '\u{0}']), + ('\u{118de}', ['\u{118be}', '\u{0}', '\u{0}']), + ('\u{118df}', ['\u{118bf}', '\u{0}', '\u{0}']), + ('\u{16e60}', ['\u{16e40}', '\u{0}', '\u{0}']), + ('\u{16e61}', ['\u{16e41}', '\u{0}', '\u{0}']), + ('\u{16e62}', ['\u{16e42}', '\u{0}', '\u{0}']), + ('\u{16e63}', ['\u{16e43}', '\u{0}', '\u{0}']), + ('\u{16e64}', ['\u{16e44}', '\u{0}', '\u{0}']), + ('\u{16e65}', ['\u{16e45}', '\u{0}', '\u{0}']), + ('\u{16e66}', ['\u{16e46}', '\u{0}', '\u{0}']), + ('\u{16e67}', ['\u{16e47}', '\u{0}', '\u{0}']), + ('\u{16e68}', ['\u{16e48}', '\u{0}', '\u{0}']), + ('\u{16e69}', ['\u{16e49}', '\u{0}', '\u{0}']), + ('\u{16e6a}', ['\u{16e4a}', '\u{0}', '\u{0}']), + ('\u{16e6b}', ['\u{16e4b}', '\u{0}', '\u{0}']), + ('\u{16e6c}', ['\u{16e4c}', '\u{0}', '\u{0}']), + ('\u{16e6d}', ['\u{16e4d}', '\u{0}', '\u{0}']), + ('\u{16e6e}', ['\u{16e4e}', '\u{0}', '\u{0}']), + ('\u{16e6f}', ['\u{16e4f}', '\u{0}', '\u{0}']), + ('\u{16e70}', ['\u{16e50}', '\u{0}', '\u{0}']), + ('\u{16e71}', ['\u{16e51}', '\u{0}', '\u{0}']), + ('\u{16e72}', ['\u{16e52}', '\u{0}', '\u{0}']), + ('\u{16e73}', ['\u{16e53}', '\u{0}', '\u{0}']), + ('\u{16e74}', ['\u{16e54}', '\u{0}', '\u{0}']), + ('\u{16e75}', ['\u{16e55}', '\u{0}', '\u{0}']), + ('\u{16e76}', ['\u{16e56}', '\u{0}', '\u{0}']), + ('\u{16e77}', ['\u{16e57}', '\u{0}', '\u{0}']), + ('\u{16e78}', ['\u{16e58}', '\u{0}', '\u{0}']), + ('\u{16e79}', ['\u{16e59}', '\u{0}', '\u{0}']), + ('\u{16e7a}', ['\u{16e5a}', '\u{0}', '\u{0}']), + ('\u{16e7b}', ['\u{16e5b}', '\u{0}', '\u{0}']), + ('\u{16e7c}', ['\u{16e5c}', '\u{0}', '\u{0}']), + ('\u{16e7d}', ['\u{16e5d}', '\u{0}', '\u{0}']), + ('\u{16e7e}', ['\u{16e5e}', '\u{0}', '\u{0}']), + ('\u{16e7f}', ['\u{16e5f}', '\u{0}', '\u{0}']), + ('\u{16ebb}', ['\u{16ea0}', '\u{0}', '\u{0}']), + ('\u{16ebc}', ['\u{16ea1}', '\u{0}', '\u{0}']), + ('\u{16ebd}', ['\u{16ea2}', '\u{0}', '\u{0}']), + ('\u{16ebe}', ['\u{16ea3}', '\u{0}', '\u{0}']), + ('\u{16ebf}', ['\u{16ea4}', '\u{0}', '\u{0}']), + ('\u{16ec0}', ['\u{16ea5}', '\u{0}', '\u{0}']), + ('\u{16ec1}', ['\u{16ea6}', '\u{0}', '\u{0}']), + ('\u{16ec2}', ['\u{16ea7}', '\u{0}', '\u{0}']), + ('\u{16ec3}', ['\u{16ea8}', '\u{0}', '\u{0}']), + ('\u{16ec4}', ['\u{16ea9}', '\u{0}', '\u{0}']), + ('\u{16ec5}', ['\u{16eaa}', '\u{0}', '\u{0}']), + ('\u{16ec6}', ['\u{16eab}', '\u{0}', '\u{0}']), + ('\u{16ec7}', ['\u{16eac}', '\u{0}', '\u{0}']), + ('\u{16ec8}', ['\u{16ead}', '\u{0}', '\u{0}']), + ('\u{16ec9}', ['\u{16eae}', '\u{0}', '\u{0}']), + ('\u{16eca}', ['\u{16eaf}', '\u{0}', '\u{0}']), + ('\u{16ecb}', ['\u{16eb0}', '\u{0}', '\u{0}']), + ('\u{16ecc}', ['\u{16eb1}', '\u{0}', '\u{0}']), + ('\u{16ecd}', ['\u{16eb2}', '\u{0}', '\u{0}']), + ('\u{16ece}', ['\u{16eb3}', '\u{0}', '\u{0}']), + ('\u{16ecf}', ['\u{16eb4}', '\u{0}', '\u{0}']), + ('\u{16ed0}', ['\u{16eb5}', '\u{0}', '\u{0}']), + ('\u{16ed1}', ['\u{16eb6}', '\u{0}', '\u{0}']), + ('\u{16ed2}', ['\u{16eb7}', '\u{0}', '\u{0}']), + ('\u{16ed3}', ['\u{16eb8}', '\u{0}', '\u{0}']), + ('\u{1e922}', ['\u{1e900}', '\u{0}', '\u{0}']), + ('\u{1e923}', ['\u{1e901}', '\u{0}', '\u{0}']), + ('\u{1e924}', ['\u{1e902}', '\u{0}', '\u{0}']), + ('\u{1e925}', ['\u{1e903}', '\u{0}', '\u{0}']), + ('\u{1e926}', ['\u{1e904}', '\u{0}', '\u{0}']), + ('\u{1e927}', ['\u{1e905}', '\u{0}', '\u{0}']), + ('\u{1e928}', ['\u{1e906}', '\u{0}', '\u{0}']), + ('\u{1e929}', ['\u{1e907}', '\u{0}', '\u{0}']), + ('\u{1e92a}', ['\u{1e908}', '\u{0}', '\u{0}']), + ('\u{1e92b}', ['\u{1e909}', '\u{0}', '\u{0}']), + ('\u{1e92c}', ['\u{1e90a}', '\u{0}', '\u{0}']), + ('\u{1e92d}', ['\u{1e90b}', '\u{0}', '\u{0}']), + ('\u{1e92e}', ['\u{1e90c}', '\u{0}', '\u{0}']), + ('\u{1e92f}', ['\u{1e90d}', '\u{0}', '\u{0}']), + ('\u{1e930}', ['\u{1e90e}', '\u{0}', '\u{0}']), + ('\u{1e931}', ['\u{1e90f}', '\u{0}', '\u{0}']), + ('\u{1e932}', ['\u{1e910}', '\u{0}', '\u{0}']), + ('\u{1e933}', ['\u{1e911}', '\u{0}', '\u{0}']), + ('\u{1e934}', ['\u{1e912}', '\u{0}', '\u{0}']), + ('\u{1e935}', ['\u{1e913}', '\u{0}', '\u{0}']), + ('\u{1e936}', ['\u{1e914}', '\u{0}', '\u{0}']), + ('\u{1e937}', ['\u{1e915}', '\u{0}', '\u{0}']), + ('\u{1e938}', ['\u{1e916}', '\u{0}', '\u{0}']), + ('\u{1e939}', ['\u{1e917}', '\u{0}', '\u{0}']), + ('\u{1e93a}', ['\u{1e918}', '\u{0}', '\u{0}']), + ('\u{1e93b}', ['\u{1e919}', '\u{0}', '\u{0}']), + ('\u{1e93c}', ['\u{1e91a}', '\u{0}', '\u{0}']), + ('\u{1e93d}', ['\u{1e91b}', '\u{0}', '\u{0}']), + ('\u{1e93e}', ['\u{1e91c}', '\u{0}', '\u{0}']), + ('\u{1e93f}', ['\u{1e91d}', '\u{0}', '\u{0}']), + ('\u{1e940}', ['\u{1e91e}', '\u{0}', '\u{0}']), + ('\u{1e941}', ['\u{1e91f}', '\u{0}', '\u{0}']), + ('\u{1e942}', ['\u{1e920}', '\u{0}', '\u{0}']), + ('\u{1e943}', ['\u{1e921}', '\u{0}', '\u{0}']), +]; + +#[rustfmt::skip] +pub(super) static TO_TITLE: &[(char, [char; 3]); 135] = &[ + ('\u{df}', ['S', 's', '\u{0}']), ('\u{1c4}', ['\u{1c5}', '\u{0}', '\u{0}']), + ('\u{1c5}', ['\u{1c5}', '\u{0}', '\u{0}']), ('\u{1c6}', ['\u{1c5}', '\u{0}', '\u{0}']), + ('\u{1c7}', ['\u{1c8}', '\u{0}', '\u{0}']), ('\u{1c8}', ['\u{1c8}', '\u{0}', '\u{0}']), + ('\u{1c9}', ['\u{1c8}', '\u{0}', '\u{0}']), ('\u{1ca}', ['\u{1cb}', '\u{0}', '\u{0}']), + ('\u{1cb}', ['\u{1cb}', '\u{0}', '\u{0}']), ('\u{1cc}', ['\u{1cb}', '\u{0}', '\u{0}']), + ('\u{1f1}', ['\u{1f2}', '\u{0}', '\u{0}']), ('\u{1f2}', ['\u{1f2}', '\u{0}', '\u{0}']), + ('\u{1f3}', ['\u{1f2}', '\u{0}', '\u{0}']), ('\u{587}', ['\u{535}', '\u{582}', '\u{0}']), + ('\u{10d0}', ['\u{10d0}', '\u{0}', '\u{0}']), ('\u{10d1}', ['\u{10d1}', '\u{0}', '\u{0}']), + ('\u{10d2}', ['\u{10d2}', '\u{0}', '\u{0}']), ('\u{10d3}', ['\u{10d3}', '\u{0}', '\u{0}']), + ('\u{10d4}', ['\u{10d4}', '\u{0}', '\u{0}']), ('\u{10d5}', ['\u{10d5}', '\u{0}', '\u{0}']), + ('\u{10d6}', ['\u{10d6}', '\u{0}', '\u{0}']), ('\u{10d7}', ['\u{10d7}', '\u{0}', '\u{0}']), + ('\u{10d8}', ['\u{10d8}', '\u{0}', '\u{0}']), ('\u{10d9}', ['\u{10d9}', '\u{0}', '\u{0}']), + ('\u{10da}', ['\u{10da}', '\u{0}', '\u{0}']), ('\u{10db}', ['\u{10db}', '\u{0}', '\u{0}']), + ('\u{10dc}', ['\u{10dc}', '\u{0}', '\u{0}']), ('\u{10dd}', ['\u{10dd}', '\u{0}', '\u{0}']), + ('\u{10de}', ['\u{10de}', '\u{0}', '\u{0}']), ('\u{10df}', ['\u{10df}', '\u{0}', '\u{0}']), + ('\u{10e0}', ['\u{10e0}', '\u{0}', '\u{0}']), ('\u{10e1}', ['\u{10e1}', '\u{0}', '\u{0}']), + ('\u{10e2}', ['\u{10e2}', '\u{0}', '\u{0}']), ('\u{10e3}', ['\u{10e3}', '\u{0}', '\u{0}']), + ('\u{10e4}', ['\u{10e4}', '\u{0}', '\u{0}']), ('\u{10e5}', ['\u{10e5}', '\u{0}', '\u{0}']), + ('\u{10e6}', ['\u{10e6}', '\u{0}', '\u{0}']), ('\u{10e7}', ['\u{10e7}', '\u{0}', '\u{0}']), + ('\u{10e8}', ['\u{10e8}', '\u{0}', '\u{0}']), ('\u{10e9}', ['\u{10e9}', '\u{0}', '\u{0}']), + ('\u{10ea}', ['\u{10ea}', '\u{0}', '\u{0}']), ('\u{10eb}', ['\u{10eb}', '\u{0}', '\u{0}']), + ('\u{10ec}', ['\u{10ec}', '\u{0}', '\u{0}']), ('\u{10ed}', ['\u{10ed}', '\u{0}', '\u{0}']), + ('\u{10ee}', ['\u{10ee}', '\u{0}', '\u{0}']), ('\u{10ef}', ['\u{10ef}', '\u{0}', '\u{0}']), + ('\u{10f0}', ['\u{10f0}', '\u{0}', '\u{0}']), ('\u{10f1}', ['\u{10f1}', '\u{0}', '\u{0}']), + ('\u{10f2}', ['\u{10f2}', '\u{0}', '\u{0}']), ('\u{10f3}', ['\u{10f3}', '\u{0}', '\u{0}']), + ('\u{10f4}', ['\u{10f4}', '\u{0}', '\u{0}']), ('\u{10f5}', ['\u{10f5}', '\u{0}', '\u{0}']), + ('\u{10f6}', ['\u{10f6}', '\u{0}', '\u{0}']), ('\u{10f7}', ['\u{10f7}', '\u{0}', '\u{0}']), + ('\u{10f8}', ['\u{10f8}', '\u{0}', '\u{0}']), ('\u{10f9}', ['\u{10f9}', '\u{0}', '\u{0}']), + ('\u{10fa}', ['\u{10fa}', '\u{0}', '\u{0}']), ('\u{10fd}', ['\u{10fd}', '\u{0}', '\u{0}']), + ('\u{10fe}', ['\u{10fe}', '\u{0}', '\u{0}']), ('\u{10ff}', ['\u{10ff}', '\u{0}', '\u{0}']), + ('\u{1f80}', ['\u{1f88}', '\u{0}', '\u{0}']), ('\u{1f81}', ['\u{1f89}', '\u{0}', '\u{0}']), + ('\u{1f82}', ['\u{1f8a}', '\u{0}', '\u{0}']), ('\u{1f83}', ['\u{1f8b}', '\u{0}', '\u{0}']), + ('\u{1f84}', ['\u{1f8c}', '\u{0}', '\u{0}']), ('\u{1f85}', ['\u{1f8d}', '\u{0}', '\u{0}']), + ('\u{1f86}', ['\u{1f8e}', '\u{0}', '\u{0}']), ('\u{1f87}', ['\u{1f8f}', '\u{0}', '\u{0}']), + ('\u{1f88}', ['\u{1f88}', '\u{0}', '\u{0}']), ('\u{1f89}', ['\u{1f89}', '\u{0}', '\u{0}']), + ('\u{1f8a}', ['\u{1f8a}', '\u{0}', '\u{0}']), ('\u{1f8b}', ['\u{1f8b}', '\u{0}', '\u{0}']), + ('\u{1f8c}', ['\u{1f8c}', '\u{0}', '\u{0}']), ('\u{1f8d}', ['\u{1f8d}', '\u{0}', '\u{0}']), + ('\u{1f8e}', ['\u{1f8e}', '\u{0}', '\u{0}']), ('\u{1f8f}', ['\u{1f8f}', '\u{0}', '\u{0}']), + ('\u{1f90}', ['\u{1f98}', '\u{0}', '\u{0}']), ('\u{1f91}', ['\u{1f99}', '\u{0}', '\u{0}']), + ('\u{1f92}', ['\u{1f9a}', '\u{0}', '\u{0}']), ('\u{1f93}', ['\u{1f9b}', '\u{0}', '\u{0}']), + ('\u{1f94}', ['\u{1f9c}', '\u{0}', '\u{0}']), ('\u{1f95}', ['\u{1f9d}', '\u{0}', '\u{0}']), + ('\u{1f96}', ['\u{1f9e}', '\u{0}', '\u{0}']), ('\u{1f97}', ['\u{1f9f}', '\u{0}', '\u{0}']), + ('\u{1f98}', ['\u{1f98}', '\u{0}', '\u{0}']), ('\u{1f99}', ['\u{1f99}', '\u{0}', '\u{0}']), + ('\u{1f9a}', ['\u{1f9a}', '\u{0}', '\u{0}']), ('\u{1f9b}', ['\u{1f9b}', '\u{0}', '\u{0}']), + ('\u{1f9c}', ['\u{1f9c}', '\u{0}', '\u{0}']), ('\u{1f9d}', ['\u{1f9d}', '\u{0}', '\u{0}']), + ('\u{1f9e}', ['\u{1f9e}', '\u{0}', '\u{0}']), ('\u{1f9f}', ['\u{1f9f}', '\u{0}', '\u{0}']), + ('\u{1fa0}', ['\u{1fa8}', '\u{0}', '\u{0}']), ('\u{1fa1}', ['\u{1fa9}', '\u{0}', '\u{0}']), + ('\u{1fa2}', ['\u{1faa}', '\u{0}', '\u{0}']), ('\u{1fa3}', ['\u{1fab}', '\u{0}', '\u{0}']), + ('\u{1fa4}', ['\u{1fac}', '\u{0}', '\u{0}']), ('\u{1fa5}', ['\u{1fad}', '\u{0}', '\u{0}']), + ('\u{1fa6}', ['\u{1fae}', '\u{0}', '\u{0}']), ('\u{1fa7}', ['\u{1faf}', '\u{0}', '\u{0}']), + ('\u{1fa8}', ['\u{1fa8}', '\u{0}', '\u{0}']), ('\u{1fa9}', ['\u{1fa9}', '\u{0}', '\u{0}']), + ('\u{1faa}', ['\u{1faa}', '\u{0}', '\u{0}']), ('\u{1fab}', ['\u{1fab}', '\u{0}', '\u{0}']), + ('\u{1fac}', ['\u{1fac}', '\u{0}', '\u{0}']), ('\u{1fad}', ['\u{1fad}', '\u{0}', '\u{0}']), + ('\u{1fae}', ['\u{1fae}', '\u{0}', '\u{0}']), ('\u{1faf}', ['\u{1faf}', '\u{0}', '\u{0}']), + ('\u{1fb2}', ['\u{1fba}', '\u{345}', '\u{0}']), + ('\u{1fb3}', ['\u{1fbc}', '\u{0}', '\u{0}']), ('\u{1fb4}', ['\u{386}', '\u{345}', '\u{0}']), + ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{345}']), + ('\u{1fbc}', ['\u{1fbc}', '\u{0}', '\u{0}']), + ('\u{1fc2}', ['\u{1fca}', '\u{345}', '\u{0}']), + ('\u{1fc3}', ['\u{1fcc}', '\u{0}', '\u{0}']), ('\u{1fc4}', ['\u{389}', '\u{345}', '\u{0}']), + ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{345}']), + ('\u{1fcc}', ['\u{1fcc}', '\u{0}', '\u{0}']), + ('\u{1ff2}', ['\u{1ffa}', '\u{345}', '\u{0}']), + ('\u{1ff3}', ['\u{1ffc}', '\u{0}', '\u{0}']), ('\u{1ff4}', ['\u{38f}', '\u{345}', '\u{0}']), + ('\u{1ff7}', ['\u{3a9}', '\u{342}', '\u{345}']), + ('\u{1ffc}', ['\u{1ffc}', '\u{0}', '\u{0}']), ('\u{fb00}', ['F', 'f', '\u{0}']), + ('\u{fb01}', ['F', 'i', '\u{0}']), ('\u{fb02}', ['F', 'l', '\u{0}']), + ('\u{fb03}', ['F', 'f', 'i']), ('\u{fb04}', ['F', 'f', 'l']), + ('\u{fb05}', ['S', 't', '\u{0}']), ('\u{fb06}', ['S', 't', '\u{0}']), + ('\u{fb13}', ['\u{544}', '\u{576}', '\u{0}']), + ('\u{fb14}', ['\u{544}', '\u{565}', '\u{0}']), + ('\u{fb15}', ['\u{544}', '\u{56b}', '\u{0}']), + ('\u{fb16}', ['\u{54e}', '\u{576}', '\u{0}']), + ('\u{fb17}', ['\u{544}', '\u{56d}', '\u{0}']), +]; diff --git a/library/portable-simd/crates/core_simd/src/simd/num/float.rs b/library/portable-simd/crates/core_simd/src/simd/num/float.rs index efd7c2469512..175cbce4f58b 100644 --- a/library/portable-simd/crates/core_simd/src/simd/num/float.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/float.rs @@ -385,13 +385,13 @@ fn copysign(self, sign: Self) -> Self { #[inline] fn simd_min(self, other: Self) -> Self { // Safety: `self` and `other` are float vectors - unsafe { core::intrinsics::simd::simd_fmin(self, other) } + unsafe { core::intrinsics::simd::simd_minimum_number_nsz(self, other) } } #[inline] fn simd_max(self, other: Self) -> Self { // Safety: `self` and `other` are floating point vectors - unsafe { core::intrinsics::simd::simd_fmax(self, other) } + unsafe { core::intrinsics::simd::simd_maximum_number_nsz(self, other) } } #[inline] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 1b7a41d69736..7a8ccdbc5043 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -62,7 +62,7 @@ path = "../windows_link" rand = { version = "0.9.0", default-features = false, features = ["alloc"] } rand_xorshift = "0.4.0" -[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", target_os = "vexos", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] +[target.'cfg(any(all(target_family = "wasm", not(any(unix, target_os = "wasi"))), target_os = "xous", target_os = "vexos", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] dlmalloc = { version = "0.2.10", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] diff --git a/library/std/benches/lib.rs b/library/std/benches/lib.rs index e749d9c0f799..2707b414f578 100644 --- a/library/std/benches/lib.rs +++ b/library/std/benches/lib.rs @@ -1,4 +1,4 @@ -// Disabling in Miri as these would take too long. +// This is marked as `test = true` and hence picked up by `./x miri`, but that would be too slow. #![cfg(not(miri))] #![feature(test)] diff --git a/library/std/benches/path.rs b/library/std/benches/path.rs index 912c783b31e4..b6d5a8672aa6 100644 --- a/library/std/benches/path.rs +++ b/library/std/benches/path.rs @@ -4,7 +4,6 @@ use std::path::*; #[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { let prefix = "my/home"; let mut paths: Vec<_> = @@ -18,7 +17,6 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { } #[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = @@ -37,7 +35,6 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { } #[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { let prefix = "my/home"; let paths: Vec<_> = @@ -80,7 +77,6 @@ fn bench_path_file_name(b: &mut test::Bencher) { } #[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_hashset(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = @@ -99,7 +95,6 @@ fn bench_path_hashset(b: &mut test::Bencher) { } #[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_hashset_miss(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = diff --git a/library/std/build.rs b/library/std/build.rs index c0a6e30b3808..5f2e441bf7d8 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -79,4 +79,28 @@ fn main() { println!("cargo:rustc-cfg=backtrace_in_libstd"); println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap()); + + println!("cargo:rustc-check-cfg=cfg(vxworks_lt_25_09)"); + + if target_os == "vxworks" { + match vxworks_version_code() { + Some((major, minor)) if (major, minor) < (25, 9) => { + println!("cargo:rustc-cfg=vxworks_lt_25_09"); + } + _ => {} + } + } +} + +/// Retrieve the VxWorks release version from the environment variable set by the VxWorks build +/// environment, in `(minor, patch)` form. +fn vxworks_version_code() -> Option<(u32, u32)> { + let version = env::var("WIND_RELEASE_ID").ok()?; + + let mut pieces = version.trim().split(['.']); + + let major: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + let minor: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + + Some((major, minor)) } diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs index 174d62813bd5..b68b528c1866 100644 --- a/library/std/src/backtrace/tests.rs +++ b/library/std/src/backtrace/tests.rs @@ -44,10 +44,9 @@ fn generate_fake_frames() -> Vec { #[test] fn test_debug() { let backtrace = Backtrace { - inner: Inner::Captured(LazyLock::preinit(Capture { - actual_start: 1, - frames: generate_fake_frames(), - })), + inner: Inner::Captured( + (Capture { actual_start: 1, frames: generate_fake_frames() }).into(), + ), }; #[rustfmt::skip] @@ -66,10 +65,9 @@ fn test_debug() { #[test] fn test_frames() { let backtrace = Backtrace { - inner: Inner::Captured(LazyLock::preinit(Capture { - actual_start: 1, - frames: generate_fake_frames(), - })), + inner: Inner::Captured( + (Capture { actual_start: 1, frames: generate_fake_frames() }).into(), + ), }; let frames = backtrace.frames(); diff --git a/library/std/src/env.rs b/library/std/src/env.rs index edf0127a665e..d3e4417656e9 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -15,7 +15,7 @@ use crate::num::NonZero; use crate::ops::Try; use crate::path::{Path, PathBuf}; -use crate::sys::{env as env_imp, os as os_imp}; +use crate::sys::{env as env_imp, paths as paths_imp}; use crate::{array, fmt, io, sys}; /// Returns the current working directory as a [`PathBuf`]. @@ -51,7 +51,7 @@ #[doc(alias = "GetCurrentDirectory")] #[stable(feature = "env", since = "1.0.0")] pub fn current_dir() -> io::Result { - os_imp::getcwd() + paths_imp::getcwd() } /// Changes the current working directory to the specified path. @@ -78,7 +78,7 @@ pub fn current_dir() -> io::Result { #[doc(alias = "chdir", alias = "SetCurrentDirectory", alias = "SetCurrentDirectoryW")] #[stable(feature = "env", since = "1.0.0")] pub fn set_current_dir>(path: P) -> io::Result<()> { - os_imp::chdir(path.as_ref()) + paths_imp::chdir(path.as_ref()) } /// An iterator over a snapshot of the environment variables of this process. @@ -444,7 +444,7 @@ pub unsafe fn remove_var>(key: K) { #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "env", since = "1.0.0")] pub struct SplitPaths<'a> { - inner: os_imp::SplitPaths<'a>, + inner: paths_imp::SplitPaths<'a>, } /// Parses input according to platform conventions for the `PATH` @@ -480,7 +480,7 @@ pub struct SplitPaths<'a> { /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn split_paths + ?Sized>(unparsed: &T) -> SplitPaths<'_> { - SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) } + SplitPaths { inner: paths_imp::split_paths(unparsed.as_ref()) } } #[stable(feature = "env", since = "1.0.0")] @@ -508,7 +508,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[derive(Debug)] #[stable(feature = "env", since = "1.0.0")] pub struct JoinPathsError { - inner: os_imp::JoinPathsError, + inner: paths_imp::JoinPathsError, } /// Joins a collection of [`Path`]s appropriately for the `PATH` @@ -579,7 +579,7 @@ pub fn join_paths(paths: I) -> Result I: IntoIterator, T: AsRef, { - os_imp::join_paths(paths.into_iter()).map_err(|e| JoinPathsError { inner: e }) + paths_imp::join_paths(paths.into_iter()).map_err(|e| JoinPathsError { inner: e }) } #[stable(feature = "env", since = "1.0.0")] @@ -641,7 +641,7 @@ fn description(&self) -> &str { #[must_use] #[stable(feature = "env", since = "1.0.0")] pub fn home_dir() -> Option { - os_imp::home_dir() + paths_imp::home_dir() } /// Returns the path of a temporary directory. @@ -701,7 +701,7 @@ pub fn home_dir() -> Option { #[doc(alias = "GetTempPath", alias = "GetTempPath2")] #[stable(feature = "env", since = "1.0.0")] pub fn temp_dir() -> PathBuf { - os_imp::temp_dir() + paths_imp::temp_dir() } /// Returns the full filesystem path of the current running executable. @@ -752,7 +752,7 @@ pub fn temp_dir() -> PathBuf { /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn current_exe() -> io::Result { - os_imp::current_exe() + paths_imp::current_exe() } /// An iterator over the arguments of a process, yielding a [`String`] value for diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ca910153e526..f0cebb05c76a 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -576,15 +576,21 @@ pub fn leak<'a>(self) -> &'a mut OsStr { /// Truncate the `OsString` to the specified length. /// + /// If `new_len` is greater than the string's current length, this has no + /// effect. + /// /// # Panics + /// /// Panics if `len` does not lie on a valid `OsStr` boundary /// (as described in [`OsStr::slice_encoded_bytes`]). #[inline] #[unstable(feature = "os_string_truncate", issue = "133262")] pub fn truncate(&mut self, len: usize) { - self.as_os_str().inner.check_public_boundary(len); - // SAFETY: The length was just checked to be at a valid boundary. - unsafe { self.inner.truncate_unchecked(len) }; + if len <= self.len() { + self.as_os_str().inner.check_public_boundary(len); + // SAFETY: The length was just checked to be at a valid boundary. + unsafe { self.inner.truncate_unchecked(len) }; + } } /// Provides plumbing to `Vec::extend_from_slice` without giving full diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 885bf376b98a..9643d3fcae66 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -815,7 +815,8 @@ pub fn sync_data(&self) -> io::Result<()> { /// Acquire an exclusive lock on the file. Blocks until the lock can be acquired. /// - /// This acquires an exclusive lock; no other file handle to this file may acquire another lock. + /// This acquires an exclusive lock; no other file handle to this file, in this or any other + /// process, may acquire another lock. /// /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with @@ -868,8 +869,8 @@ pub fn lock(&self) -> io::Result<()> { /// Acquire a shared (non-exclusive) lock on the file. Blocks until the lock can be acquired. /// - /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may - /// hold an exclusive lock at the same time. + /// This acquires a shared lock; more than one file handle, in this or any other process, may + /// hold a shared lock, but none may hold an exclusive lock at the same time. /// /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with @@ -923,7 +924,8 @@ pub fn lock_shared(&self) -> io::Result<()> { /// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file /// (via another handle/descriptor). /// - /// This acquires an exclusive lock; no other file handle to this file may acquire another lock. + /// This acquires an exclusive lock; no other file handle to this file, in this or any other + /// process, may acquire another lock. /// /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with @@ -987,8 +989,8 @@ pub fn try_lock(&self) -> Result<(), TryLockError> { /// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file /// (via another handle/descriptor). /// - /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may - /// hold an exclusive lock at the same time. + /// This acquires a shared lock; more than one file handle, in this or any other process, may + /// hold a shared lock, but none may hold an exclusive lock at the same time. /// /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index 6ad4158b9290..e335d8afdc48 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -391,16 +391,16 @@ fn test_read_until() { let mut v = Vec::new(); reader.read_until(0, &mut v).unwrap(); assert_eq!(v, [0]); - v.truncate(0); + v.clear(); reader.read_until(2, &mut v).unwrap(); assert_eq!(v, [1, 2]); - v.truncate(0); + v.clear(); reader.read_until(1, &mut v).unwrap(); assert_eq!(v, [1]); - v.truncate(0); + v.clear(); reader.read_until(8, &mut v).unwrap(); assert_eq!(v, [0]); - v.truncate(0); + v.clear(); reader.read_until(9, &mut v).unwrap(); assert_eq!(v, []); } @@ -429,13 +429,13 @@ fn test_read_line() { let mut s = String::new(); reader.read_line(&mut s).unwrap(); assert_eq!(s, "a\n"); - s.truncate(0); + s.clear(); reader.read_line(&mut s).unwrap(); assert_eq!(s, "b\n"); - s.truncate(0); + s.clear(); reader.read_line(&mut s).unwrap(); assert_eq!(s, "c"); - s.truncate(0); + s.clear(); reader.read_line(&mut s).unwrap(); assert_eq!(s, ""); } diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs index 25b1ece2745b..7bdba3a04416 100644 --- a/library/std/src/io/copy/tests.rs +++ b/library/std/src/io/copy/tests.rs @@ -97,16 +97,17 @@ fn copy_specializes_to_vec() { #[test] fn copy_specializes_from_vecdeque() { - let mut source = VecDeque::with_capacity(100 * 1024); - for _ in 0..20 * 1024 { + let num: usize = if cfg!(miri) { 512 } else { 20 * 1024 }; + let mut source = VecDeque::with_capacity(4 * num); + for _ in 0..num { source.push_front(0); } - for _ in 0..20 * 1024 { + for _ in 0..num { source.push_back(0); } let mut sink = WriteObserver { observed_buffer: 0 }; - assert_eq!(40 * 1024u64, io::copy(&mut source, &mut sink).unwrap()); - assert_eq!(20 * 1024, sink.observed_buffer); + assert_eq!(2 * num as u64, io::copy(&mut source, &mut sink).unwrap()); + assert_eq!(num, sink.observed_buffer); } #[test] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 623c34c6d291..cba578cd3a6f 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -3348,6 +3348,7 @@ fn upper_bound(&self) -> Option { /// [`split`]: BufRead::split #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoSplit")] pub struct Split { buf: B, delim: u8, diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index b22988d4a8a9..a56359dae765 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -17,10 +17,10 @@ fn read_until() { let mut v = Vec::new(); assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3); assert_eq!(v, b"123"); - v.truncate(0); + v.clear(); assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1); assert_eq!(v, b"3"); - v.truncate(0); + v.clear(); assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0); assert_eq!(v, []); } @@ -80,10 +80,10 @@ fn read_line() { let mut v = String::new(); assert_eq!(buf.read_line(&mut v).unwrap(), 3); assert_eq!(v, "12\n"); - v.truncate(0); + v.clear(); assert_eq!(buf.read_line(&mut v).unwrap(), 1); assert_eq!(v, "\n"); - v.truncate(0); + v.clear(); assert_eq!(buf.read_line(&mut v).unwrap(), 0); assert_eq!(v, ""); } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 6fcb28edc7d8..7497fa100eb9 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -94,8 +94,8 @@ //! pull-requests for your suggested changes. //! //! Contributions are appreciated! If you see a part of the docs that can be -//! improved, submit a PR, or chat with us first on [Zulip][rust-zulip] -//! #docs. +//! improved, submit a PR, or chat with us first on [Zulip][t-libs-zulip] +//! #t-libs. //! //! # A Tour of The Rust Standard Library //! @@ -209,7 +209,7 @@ //! [multithreading]: thread //! [other]: #what-is-in-the-standard-library-documentation //! [primitive types]: ../book/ch03-02-data-types.html -//! [rust-zulip]: https://rust-lang.zulipchat.com/ +//! [t-libs-zulip]: https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/ //! [array]: prim@array //! [slice]: prim@slice @@ -275,9 +275,7 @@ #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] -#![feature(const_default)] #![feature(const_trait_impl)] -#![feature(core_float_math)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] @@ -287,16 +285,11 @@ #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] -#![feature(formatting_options)] -#![feature(funnel_shifts)] #![feature(intra_doc_pointers)] -#![feature(iter_advance_by)] -#![feature(iter_next_chunk)] #![feature(lang_items)] #![feature(link_cfg)] #![feature(linkage)] #![feature(macro_metavar_expr_concat)] -#![feature(maybe_uninit_fill)] #![feature(min_specialization)] #![feature(must_not_suspend)] #![feature(needs_panic_runtime)] @@ -314,7 +307,6 @@ #![feature(try_blocks)] #![feature(try_trait_v2)] #![feature(type_alias_impl_trait)] -#![feature(uint_carryless_mul)] // tidy-alphabetical-end // // Library features (core): @@ -325,6 +317,8 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(const_convert)] +#![feature(const_default)] +#![feature(core_float_math)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(cstr_display)] @@ -340,13 +334,20 @@ #![feature(float_minimum_maximum)] #![feature(fmt_internals)] #![feature(fn_ptr_trait)] +#![feature(formatting_options)] +#![feature(funnel_shifts)] #![feature(generic_atomic)] +#![feature(hash_map_internals)] +#![feature(hash_map_macro)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(hint_must_use)] #![feature(int_from_ascii)] #![feature(ip)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] #![feature(maybe_uninit_array_assume_init)] +#![feature(maybe_uninit_fill)] #![feature(panic_can_unwind)] #![feature(panic_internals)] #![feature(pin_coerce_unsized_trait)] @@ -364,6 +365,7 @@ #![feature(sync_unsafe_cell)] #![feature(temporary_niche_types)] #![feature(ub_checks)] +#![feature(uint_carryless_mul)] #![feature(used_with_arg)] // tidy-alphabetical-end // diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 0bb14552432d..108cd3cd98eb 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -5,6 +5,9 @@ //! library. // ignore-tidy-dbg +#[cfg(test)] +mod tests; + #[doc = include_str!("../../core/src/macros/panic.md")] #[macro_export] #[rustc_builtin_macro(std_panic)] @@ -359,19 +362,16 @@ macro_rules! dbg { }; } -/// Internal macro that processes a list of expressions and produces a chain of -/// nested `match`es, one for each expression, before finally calling `eprint!` -/// with the collected information and returning all the evaluated expressions -/// in a tuple. +/// Internal macro that processes a list of expressions, binds their results +/// with `match`, calls `eprint!` with the collected information, and returns +/// all the evaluated expressions in a tuple. /// /// E.g. `dbg_internal!(() () (1, 2))` expands into /// ```rust, ignore -/// match 1 { -/// tmp_1 => match 2 { -/// tmp_2 => { -/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */); -/// (tmp_1, tmp_2) -/// } +/// match (1, 2) { +/// (tmp_1, tmp_2) => { +/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */); +/// (tmp_1, tmp_2) /// } /// } /// ``` @@ -380,37 +380,117 @@ macro_rules! dbg { #[doc(hidden)] #[rustc_macro_transparency = "semiopaque"] pub macro dbg_internal { - (($($piece:literal),+) ($($processed:expr => $bound:expr),+) ()) => {{ - $crate::eprint!( - $crate::concat!($($piece),+), - $( - $crate::stringify!($processed), - // The `&T: Debug` check happens here (not in the format literal desugaring) - // to avoid format literal related messages and suggestions. - &&$bound as &dyn $crate::fmt::Debug - ),+, - // The location returned here is that of the macro invocation, so - // it will be the same for all expressions. Thus, label these - // arguments so that they can be reused in every piece of the - // formatting template. - file=$crate::file!(), - line=$crate::line!(), - column=$crate::column!() - ); - // Comma separate the variables only when necessary so that this will - // not yield a tuple for a single expression, but rather just parenthesize - // the expression. - ($($bound),+) - }}, - (($($piece:literal),*) ($($processed:expr => $bound:expr),*) ($val:expr $(,$rest:expr)*)) => { + (($($piece:literal),+) ($($processed:expr => $bound:ident),+) ()) => { // Use of `match` here is intentional because it affects the lifetimes // of temporaries - https://stackoverflow.com/a/48732525/1063961 - match $val { - tmp => $crate::macros::dbg_internal!( - ($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n") - ($($processed => $bound,)* $val => tmp) - ($($rest),*) - ), + // Always put the arguments in a tuple to avoid an unused parens lint on the pattern. + match ($($processed,)+) { + ($($bound,)+) => { + $crate::eprint!( + $crate::concat!($($piece),+), + $( + $crate::stringify!($processed), + // The `&T: Debug` check happens here (not in the format literal desugaring) + // to avoid format literal related messages and suggestions. + &&$bound as &dyn $crate::fmt::Debug + ),+, + // The location returned here is that of the macro invocation, so + // it will be the same for all expressions. Thus, label these + // arguments so that they can be reused in every piece of the + // formatting template. + file=$crate::file!(), + line=$crate::line!(), + column=$crate::column!() + ); + // Comma separate the variables only when necessary so that this will + // not yield a tuple for a single expression, but rather just parenthesize + // the expression. + ($($bound),+) + + } } }, + (($($piece:literal),*) ($($processed:expr => $bound:ident),*) ($val:expr $(,$rest:expr)*)) => { + $crate::macros::dbg_internal!( + ($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n") + ($($processed => $bound,)* $val => tmp) + ($($rest),*) + ) + }, +} + +#[doc(hidden)] +#[macro_export] +#[allow_internal_unstable(hash_map_internals)] +#[unstable(feature = "hash_map_internals", issue = "none")] +macro_rules! repetition_utils { + (@count $($tokens:tt),*) => {{ + [$($crate::repetition_utils!(@replace $tokens => ())),*].len() + }}; + + (@replace $x:tt => $y:tt) => { $y } +} + +/// Creates a [`HashMap`] containing the arguments. +/// +/// `hash_map!` allows specifying the entries that make +/// up the [`HashMap`] where the key and value are separated by a `=>`. +/// +/// The entries are separated by commas with a trailing comma being allowed. +/// +/// It is semantically equivalent to using repeated [`HashMap::insert`] +/// on a newly created hashmap. +/// +/// `hash_map!` will attempt to avoid repeated reallocations by +/// using [`HashMap::with_capacity`]. +/// +/// # Examples +/// +/// ```rust +/// #![feature(hash_map_macro)] +/// use std::hash_map; +/// +/// let map = hash_map! { +/// "key" => "value", +/// "key1" => "value1" +/// }; +/// +/// assert_eq!(map.get("key"), Some(&"value")); +/// assert_eq!(map.get("key1"), Some(&"value1")); +/// assert!(map.get("brrrrrrooooommm").is_none()); +/// ``` +/// +/// And with a trailing comma +/// +///```rust +/// #![feature(hash_map_macro)] +/// use std::hash_map; +/// +/// let map = hash_map! { +/// "key" => "value", // notice the , +/// }; +/// +/// assert_eq!(map.get("key"), Some(&"value")); +/// ``` +/// +/// The key and value are moved into the HashMap. +/// +/// [`HashMap`]: crate::collections::HashMap +/// [`HashMap::insert`]: crate::collections::HashMap::insert +/// [`HashMap::with_capacity`]: crate::collections::HashMap::with_capacity +#[macro_export] +#[allow_internal_unstable(hash_map_internals)] +#[unstable(feature = "hash_map_macro", issue = "144032")] +macro_rules! hash_map { + () => {{ + $crate::collections::HashMap::new() + }}; + + ( $( $key:expr => $value:expr ),* $(,)? ) => {{ + let mut map = $crate::collections::HashMap::with_capacity( + const { $crate::repetition_utils!(@count $($key),*) } + ); + $( map.insert($key, $value); )* + map + }} } diff --git a/library/std/src/macros/tests.rs b/library/std/src/macros/tests.rs new file mode 100644 index 000000000000..db2be925ff30 --- /dev/null +++ b/library/std/src/macros/tests.rs @@ -0,0 +1,13 @@ +// ignore-tidy-dbg + +/// Test for : +/// `dbg!` shouldn't drop arguments' temporaries. +#[test] +fn no_dropping_temps() { + fn temp() {} + + *dbg!(&temp()); + *dbg!(&temp(), 1).0; + *dbg!(0, &temp()).1; + *dbg!(0, &temp(), 2).1; +} diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 39e374174646..0d96958b6cca 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -16,7 +16,7 @@ use crate::os::hermit::io::OwnedFd; #[cfg(all(not(target_os = "hermit"), not(target_os = "motor")))] use crate::os::raw; -#[cfg(all(doc, not(target_arch = "wasm32")))] +#[cfg(all(doc, not(any(target_arch = "wasm32", target_env = "sgx"))))] use crate::os::unix::io::AsFd; #[cfg(unix)] use crate::os::unix::io::OwnedFd; diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs index b88ed19b067a..a21748ce9fe0 100644 --- a/library/std/src/os/vxworks/fs.rs +++ b/library/std/src/os/vxworks/fs.rs @@ -69,24 +69,54 @@ fn st_rdev(&self) -> u64 { fn st_size(&self) -> u64 { self.as_inner().as_inner().st_size as u64 } + #[cfg(vxworks_lt_25_09)] fn st_atime(&self) -> i64 { self.as_inner().as_inner().st_atime as i64 } + #[cfg(not(vxworks_lt_25_09))] + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_sec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_atime_nsec(&self) -> i64 { 0 } + #[cfg(not(vxworks_lt_25_09))] + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_nsec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_mtime(&self) -> i64 { self.as_inner().as_inner().st_mtime as i64 } + #[cfg(not(vxworks_lt_25_09))] + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_sec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_mtime_nsec(&self) -> i64 { 0 } + #[cfg(not(vxworks_lt_25_09))] + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_nsec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_ctime(&self) -> i64 { self.as_inner().as_inner().st_ctime as i64 } + #[cfg(not(vxworks_lt_25_09))] + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_sec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_ctime_nsec(&self) -> i64 { 0 } + #[cfg(not(vxworks_lt_25_09))] + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_nsec as i64 + } fn st_blksize(&self) -> u64 { self.as_inner().as_inner().st_blksize as u64 } diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 73f3e589e243..7fd46b31f7d8 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -138,6 +138,8 @@ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result { } /// Windows-specific extensions to [`fs::OpenOptions`]. +// WARNING: This trait is not sealed. DON'T add any new methods! +// Add them to OpenOptionsExt2 instead. #[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] @@ -305,18 +307,6 @@ pub trait OpenOptionsExt { /// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level #[stable(feature = "open_options_ext", since = "1.10.0")] fn security_qos_flags(&mut self, flags: u32) -> &mut Self; - - /// If set to `true`, prevent the "last access time" of the file from being changed. - /// - /// Default to `false`. - #[unstable(feature = "windows_freeze_file_times", issue = "149715")] - fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self; - - /// If set to `true`, prevent the "last write time" of the file from being changed. - /// - /// Default to `false`. - #[unstable(feature = "windows_freeze_file_times", issue = "149715")] - fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self; } #[stable(feature = "open_options_ext", since = "1.10.0")] @@ -345,7 +335,28 @@ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions { self.as_inner_mut().security_qos_flags(flags); self } +} +#[unstable(feature = "windows_freeze_file_times", issue = "149715")] +pub trait OpenOptionsExt2: Sealed { + /// If set to `true`, prevent the "last access time" of the file from being changed. + /// + /// Default to `false`. + #[unstable(feature = "windows_freeze_file_times", issue = "149715")] + fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self; + + /// If set to `true`, prevent the "last write time" of the file from being changed. + /// + /// Default to `false`. + #[unstable(feature = "windows_freeze_file_times", issue = "149715")] + fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self; +} + +#[unstable(feature = "sealed", issue = "none")] +impl Sealed for OpenOptions {} + +#[unstable(feature = "windows_freeze_file_times", issue = "149715")] +impl OpenOptionsExt2 for OpenOptions { fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self { self.as_inner_mut().freeze_last_access_time(freeze); self diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 0b2b5f7e58f4..6b894f6bf424 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1364,7 +1364,7 @@ fn _push(&mut self, path: &Path) { // absolute `path` replaces `self` if need_clear { - self.inner.truncate(0); + self.inner.clear(); // verbatim paths need . and .. removed } else if comps.prefix_verbatim() && !path.inner.is_empty() { @@ -2725,6 +2725,41 @@ pub fn strip_prefix

(&self, base: P) -> Result<&Path, StripPrefixError> self._strip_prefix(base.as_ref()) } + /// Returns a path with the optional prefix removed. + /// + /// If `base` is not a prefix of `self` (i.e., [`starts_with`] returns `false`), returns the original path (`self`) + /// + /// [`starts_with`]: Path::starts_with + /// + /// # Examples + /// + /// ``` + /// #![feature(trim_prefix_suffix)] + /// use std::path::Path; + /// + /// let path = Path::new("/test/haha/foo.txt"); + /// + /// // Prefix present - remove it + /// assert_eq!(path.trim_prefix("/"), Path::new("test/haha/foo.txt")); + /// assert_eq!(path.trim_prefix("/test"), Path::new("haha/foo.txt")); + /// assert_eq!(path.trim_prefix("/test/"), Path::new("haha/foo.txt")); + /// assert_eq!(path.trim_prefix("/test/haha/foo.txt"), Path::new("")); + /// assert_eq!(path.trim_prefix("/test/haha/foo.txt/"), Path::new("")); + /// + /// // Prefix absent - return original + /// assert_eq!(path.trim_prefix("test"), path); + /// assert_eq!(path.trim_prefix("/te"), path); + /// assert_eq!(path.trim_prefix("/haha"), path); + /// ``` + #[must_use = "this returns the remaining path as a new path, without modifying the original"] + #[unstable(feature = "trim_prefix_suffix", issue = "142312")] + pub fn trim_prefix

(&self, base: P) -> &Path + where + P: AsRef, + { + self._strip_prefix(base.as_ref()).unwrap_or(self) + } + fn _strip_prefix(&self, base: &Path) -> Result<&Path, StripPrefixError> { iter_after(self.components(), base.components()) .map(|c| c.as_path()) diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 7274b5d10c75..9bdde0ae4a53 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -105,15 +105,6 @@ pub const fn new(f: F) -> LazyLock { LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } } - /// Creates a new lazy value that is already initialized. - #[inline] - #[cfg(test)] - pub(crate) fn preinit(value: T) -> LazyLock { - let once = Once::new(); - once.call_once(|| {}); - LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) } - } - /// Consumes this `LazyLock` returning the stored value. /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. @@ -404,6 +395,19 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } +#[stable(feature = "from_wrapper_impls", since = "CURRENT_RUSTC_VERSION")] +impl From for LazyLock { + /// Constructs a `LazyLock` that starts already initialized + /// with the provided value. + #[inline] + fn from(value: T) -> Self { + LazyLock { + once: Once::new_complete(), + data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }), + } + } +} + #[cold] #[inline(never)] fn panic_poisoned() -> ! { diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 8df81a580f7b..16ae8a88370b 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -623,6 +623,33 @@ pub fn same_channel(&self, other: &Sender) -> bool { _ => false, } } + + /// Returns `true` if the channel is disconnected. + /// + /// Note that a return value of `false` does not guarantee the channel will + /// remain connected. The channel may be disconnected immediately after this method + /// returns, so a subsequent [`Sender::send`] may still fail with [`SendError`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// + /// let (tx, rx) = channel::(); + /// assert!(!tx.is_disconnected()); + /// drop(rx); + /// assert!(tx.is_disconnected()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] + pub fn is_disconnected(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.is_disconnected(), + SenderFlavor::List(chan) => chan.is_disconnected(), + SenderFlavor::Zero(chan) => chan.is_disconnected(), + } + } } #[unstable(feature = "mpmc_channel", issue = "126840")] @@ -1349,6 +1376,33 @@ pub fn same_channel(&self, other: &Receiver) -> bool { pub fn iter(&self) -> Iter<'_, T> { Iter { rx: self } } + + /// Returns `true` if the channel is disconnected. + /// + /// Note that a return value of `false` does not guarantee the channel will + /// remain connected. The channel may be disconnected immediately after this method + /// returns, so a subsequent [`Receiver::recv`] may still fail with [`RecvError`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// + /// let (tx, rx) = channel::(); + /// assert!(!rx.is_disconnected()); + /// drop(tx); + /// assert!(rx.is_disconnected()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] + pub fn is_disconnected(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.is_disconnected(), + ReceiverFlavor::List(chan) => chan.is_disconnected(), + ReceiverFlavor::Zero(chan) => chan.is_disconnected(), + } + } } #[unstable(feature = "mpmc_channel", issue = "126840")] diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index f1ecf80fcb9f..c74346250192 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -316,4 +316,10 @@ pub(crate) fn is_empty(&self) -> bool { pub(crate) fn is_full(&self) -> bool { true } + + /// Returns `true` if the channel is disconnected. + pub(crate) fn is_disconnected(&self) -> bool { + let inner = self.inner.lock().unwrap(); + inner.is_disconnected + } } diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index 0ae23f6e13bf..a1c49bb83010 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -607,6 +607,29 @@ impl Sender { pub fn send(&self, t: T) -> Result<(), SendError> { self.inner.send(t) } + + /// Returns `true` if the channel is disconnected. + /// + /// Note that a return value of `false` does not guarantee the channel will + /// remain connected. The channel may be disconnected immediately after this method + /// returns, so a subsequent [`Sender::send`] may still fail with [`SendError`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpsc_is_disconnected)] + /// + /// use std::sync::mpsc::channel; + /// + /// let (tx, rx) = channel::(); + /// assert!(!tx.is_disconnected()); + /// drop(rx); + /// assert!(tx.is_disconnected()); + /// ``` + #[unstable(feature = "mpsc_is_disconnected", issue = "153668")] + pub fn is_disconnected(&self) -> bool { + self.inner.is_disconnected() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1038,6 +1061,29 @@ pub fn iter(&self) -> Iter<'_, T> { pub fn try_iter(&self) -> TryIter<'_, T> { TryIter { rx: self } } + + /// Returns `true` if the channel is disconnected. + /// + /// Note that a return value of `false` does not guarantee the channel will + /// remain connected. The channel may be disconnected immediately after this method + /// returns, so a subsequent [`Receiver::recv`] may still fail with [`RecvError`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpsc_is_disconnected)] + /// + /// use std::sync::mpsc::channel; + /// + /// let (tx, rx) = channel::(); + /// assert!(!rx.is_disconnected()); + /// drop(tx); + /// assert!(rx.is_disconnected()); + /// ``` + #[unstable(feature = "mpsc_is_disconnected", issue = "153668")] + pub fn is_disconnected(&self) -> bool { + self.inner.is_disconnected() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index bcfc9f581fd2..2556d1897b64 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -84,6 +84,13 @@ pub const fn new() -> Once { Once { inner: sys::Once::new() } } + /// Creates a new `Once` value that starts already completed. + #[inline] + #[must_use] + pub(crate) const fn new_complete() -> Once { + Once { inner: sys::Once::new_complete() } + } + /// Performs an initialization routine once and only once. The given closure /// will be executed if this is the first time `call_once` has been called, /// and otherwise the routine will *not* be invoked. diff --git a/library/std/src/sys/args/uefi.rs b/library/std/src/sys/args/uefi.rs index 02dada382eff..edf6f6873f8d 100644 --- a/library/std/src/sys/args/uefi.rs +++ b/library/std/src/sys/args/uefi.rs @@ -93,7 +93,7 @@ fn parse_lp_cmd_line(code_units: &[u16]) -> Option> { // If not `in_quotes`, a space or tab ends the argument. SPACE if !in_quotes => { ret_val.push(OsString::from(&cur[..])); - cur.truncate(0); + cur.clear(); // Skip whitespace. while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {} diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index c1988657ff1b..bd26db7fea55 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -12,9 +12,9 @@ use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; use crate::sys::helpers::WStrUnits; -use crate::sys::pal::os::current_exe; use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::path::get_long_path; +use crate::sys::paths::current_exe; use crate::sys::{AsInner, c, to_u16s}; use crate::{io, iter, ptr}; @@ -106,7 +106,7 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>( // If not `in_quotes`, a space or tab ends the argument. SPACE | TAB if !in_quotes => { ret_val.push(OsString::from_wide(&cur[..])); - cur.truncate(0); + cur.clear(); // Skip whitespace. code_units.advance_while(|w| w == SPACE || w == TAB); diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs index 66805ce3fa71..7a19f97b3ad5 100644 --- a/library/std/src/sys/env/unix.rs +++ b/library/std/src/sys/env/unix.rs @@ -38,8 +38,25 @@ pub unsafe fn environ() -> *mut *const *const c_char { unsafe { libc::_NSGetEnviron() as *mut *const *const c_char } } +// On FreeBSD, environ comes from CRT rather than libc +#[cfg(target_os = "freebsd")] +pub unsafe fn environ() -> *mut *const *const c_char { + use crate::sync::LazyLock; + + struct Environ(*mut *const *const c_char); + unsafe impl Send for Environ {} + unsafe impl Sync for Environ {} + + static ENVIRON: LazyLock = LazyLock::new(|| { + Environ(unsafe { + libc::dlsym(libc::RTLD_DEFAULT, c"environ".as_ptr()) as *mut *const *const c_char + }) + }); + ENVIRON.0 +} + // Use the `environ` static which is part of POSIX. -#[cfg(not(target_vendor = "apple"))] +#[cfg(not(any(target_os = "freebsd", target_vendor = "apple")))] pub unsafe fn environ() -> *mut *const *const c_char { unsafe extern "C" { static mut environ: *const *const c_char; diff --git a/library/std/src/sys/env/wasi.rs b/library/std/src/sys/env/wasi.rs index c970aac18260..6b892376fd0c 100644 --- a/library/std/src/sys/env/wasi.rs +++ b/library/std/src/sys/env/wasi.rs @@ -1,11 +1,16 @@ use core::slice::memchr; pub use super::common::Env; -use crate::ffi::{CStr, OsStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString, c_char}; use crate::io; use crate::os::wasi::prelude::*; use crate::sys::helpers::run_with_cstr; -use crate::sys::pal::os::{cvt, libc}; +use crate::sys::pal::cvt; + +// This is not available yet in libc. +unsafe extern "C" { + fn __wasilibc_get_environ() -> *mut *mut c_char; +} cfg_select! { target_feature = "atomics" => { @@ -37,7 +42,7 @@ pub fn env() -> Env { // Use `__wasilibc_get_environ` instead of `environ` here so that we // don't require wasi-libc to eagerly initialize the environment // variables. - let mut environ = libc::__wasilibc_get_environ(); + let mut environ = __wasilibc_get_environ(); let mut result = Vec::new(); if !environ.is_null() { diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 1e281eb0d9d1..5992766b5a42 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -109,15 +109,15 @@ pub struct DirBuilder { impl FileAttr { pub fn modified(&self) -> io::Result { - Ok(SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec)) + SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec.into()) } pub fn accessed(&self) -> io::Result { - Ok(SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec)) + SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec.into()) } pub fn created(&self) -> io::Result { - Ok(SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec)) + SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec.into()) } pub fn size(&self) -> u64 { diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 7db474544f04..2a8571871b73 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -634,7 +634,7 @@ pub fn modified(&self) -> io::Result { } #[cfg(any( - target_os = "vxworks", + all(target_os = "vxworks", vxworks_lt_25_09), target_os = "espidf", target_os = "vita", target_os = "rtems", @@ -643,7 +643,12 @@ pub fn modified(&self) -> io::Result { SystemTime::new(self.stat.st_mtime as i64, 0) } - #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))] + #[cfg(any( + target_os = "horizon", + target_os = "hurd", + target_os = "nuttx", + all(target_os = "vxworks", not(vxworks_lt_25_09)) + ))] pub fn modified(&self) -> io::Result { SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64) } @@ -669,7 +674,7 @@ pub fn accessed(&self) -> io::Result { } #[cfg(any( - target_os = "vxworks", + all(target_os = "vxworks", vxworks_lt_25_09), target_os = "espidf", target_os = "vita", target_os = "rtems" @@ -678,7 +683,12 @@ pub fn accessed(&self) -> io::Result { SystemTime::new(self.stat.st_atime as i64, 0) } - #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))] + #[cfg(any( + target_os = "horizon", + target_os = "hurd", + target_os = "nuttx", + all(target_os = "vxworks", not(vxworks_lt_25_09)) + ))] pub fn accessed(&self) -> io::Result { SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64) } diff --git a/library/std/src/sys/io/error/windows.rs b/library/std/src/sys/io/error/windows.rs index d7607082a30a..c093443f3033 100644 --- a/library/std/src/sys/io/error/windows.rs +++ b/library/std/src/sys/io/error/windows.rs @@ -1,6 +1,9 @@ use crate::sys::pal::{api, c}; use crate::{io, ptr}; +#[cfg(test)] +mod tests; + pub fn errno() -> i32 { api::get_last_error().code as i32 } diff --git a/library/std/src/sys/pal/windows/os/tests.rs b/library/std/src/sys/io/error/windows/tests.rs similarity index 93% rename from library/std/src/sys/pal/windows/os/tests.rs rename to library/std/src/sys/io/error/windows/tests.rs index 458d6e11c209..7fc545ad0066 100644 --- a/library/std/src/sys/pal/windows/os/tests.rs +++ b/library/std/src/sys/io/error/windows/tests.rs @@ -1,5 +1,5 @@ use crate::io::Error; -use crate::sys::c; +use crate::sys::pal::c; // tests `error_string` above #[test] diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 5ad23972860b..fe0c10395241 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -18,6 +18,7 @@ pub mod net; pub mod os_str; pub mod path; +pub mod paths; pub mod pipe; pub mod platform_version; pub mod process; diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 8c9c17d3f171..6a625664494b 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -68,8 +68,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// /// SGX doesn't support DNS resolution but rather accepts hostnames in /// the same place as socket addresses. So, to make e.g. -/// ```rust -/// TcpStream::connect("example.com:80")` +/// ```rust,ignore (incomplete example) +/// TcpStream::connect("example.com:80") /// ``` /// work, the DNS lookup returns a special error (`NonIpSockAddr`) instead, /// which contains the hostname being looked up. When `.to_socket_addrs()` diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 5e20c0ffdfa6..f3c860804de0 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -684,7 +684,7 @@ fn on_resolver_failure() { use crate::sys; // If the version fails to parse, we treat it the same as "not glibc". - if let Some(version) = sys::os::glibc_version() { + if let Some(version) = sys::pal::conf::glibc_version() { if version < (2, 26) { unsafe { libc::res_init() }; } diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 1e58db0d7046..85962ce880d5 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -9,7 +9,9 @@ pub(crate) enum Tcp { V4(tcp4::Tcp4), } -// SAFETY: UEFI has no threads. +// SAFETY: UEFI has no regular threads, and as per +// std does not support being invoked from "irregular threads" such as interrupt handlers or other +// CPU cores that run outside the scope of UEFI. unsafe impl Send for Tcp {} impl Tcp { diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index f10a090a6e91..53f6ddd7065d 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -22,7 +22,7 @@ use crate::sys::env; pub mod futex; -pub mod os; +#[path = "../unix/time.rs"] pub mod time; pub fn unsupported() -> io::Result { diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs deleted file mode 100644 index 188caded55d4..000000000000 --- a/library/std/src/sys/pal/hermit/os.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::ffi::{OsStr, OsString}; -use crate::marker::PhantomData; -use crate::path::{self, PathBuf}; -use crate::sys::unsupported; -use crate::{fmt, io}; - -pub fn getcwd() -> io::Result { - Ok(PathBuf::from("/")) -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on hermit yet".fmt(f) - } -} - -impl crate::error::Error for JoinPathsError {} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn temp_dir() -> PathBuf { - PathBuf::from("/tmp") -} - -pub fn home_dir() -> Option { - None -} diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs deleted file mode 100644 index b9851eb6754d..000000000000 --- a/library/std/src/sys/pal/hermit/time.rs +++ /dev/null @@ -1,110 +0,0 @@ -use hermit_abi::{self, timespec}; - -use crate::cmp::Ordering; -use crate::hash::{Hash, Hasher}; -use crate::time::Duration; - -const NSEC_PER_SEC: i32 = 1_000_000_000; - -#[derive(Copy, Clone, Debug)] -pub struct Timespec { - pub t: timespec, -} - -impl Timespec { - pub const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1); - - pub const MIN: Timespec = Self::new(i64::MIN, 0); - - pub const fn zero() -> Timespec { - Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } - } - - pub const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec { - assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC); - // SAFETY: The assert above checks tv_nsec is within the valid range - Timespec { t: timespec { tv_sec, tv_nsec } } - } - - pub fn sub_timespec(&self, other: &Timespec) -> Result { - fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { - debug_assert!(a >= b); - a.wrapping_sub(b).cast_unsigned() - } - - if self >= other { - // Logic here is identical to Unix version of `Timestamp::sub_timespec`, - // check comments there why operations do not overflow. - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new( - sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec), - (self.t.tv_nsec - other.t.tv_nsec) as u32, - ) - } else { - Duration::new( - sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec), - (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32, - ) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?; - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap(); - if nsec >= NSEC_PER_SEC.try_into().unwrap() { - nsec -= u32::try_from(NSEC_PER_SEC).unwrap(); - secs = secs.checked_add(1)?; - } - Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?; - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1)?; - } - Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} diff --git a/library/std/src/sys/pal/motor/mod.rs b/library/std/src/sys/pal/motor/mod.rs index a520375a4bbf..705413cbe0a7 100644 --- a/library/std/src/sys/pal/motor/mod.rs +++ b/library/std/src/sys/pal/motor/mod.rs @@ -1,7 +1,5 @@ #![allow(unsafe_op_in_unsafe_fn)] -pub mod os; - pub use moto_rt::futex; use crate::io; diff --git a/library/std/src/sys/pal/motor/os.rs b/library/std/src/sys/pal/motor/os.rs deleted file mode 100644 index 0af579303306..000000000000 --- a/library/std/src/sys/pal/motor/os.rs +++ /dev/null @@ -1,64 +0,0 @@ -use super::map_motor_error; -use crate::error::Error as StdError; -use crate::ffi::{OsStr, OsString}; -use crate::marker::PhantomData; -use crate::os::motor::ffi::OsStrExt; -use crate::path::{self, PathBuf}; -use crate::{fmt, io}; - -pub fn getcwd() -> io::Result { - moto_rt::fs::getcwd().map(PathBuf::from).map_err(map_motor_error) -} - -pub fn chdir(path: &path::Path) -> io::Result<()> { - moto_rt::fs::chdir(path.as_os_str().as_str()).map_err(map_motor_error) -} - -pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on this platform yet".fmt(f) - } -} - -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} - -pub fn current_exe() -> io::Result { - moto_rt::process::current_exe().map(PathBuf::from).map_err(map_motor_error) -} - -pub fn temp_dir() -> PathBuf { - PathBuf::from(moto_rt::fs::TEMP_DIR) -} - -pub fn home_dir() -> Option { - None -} diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index aaf380d1bef4..c2694316249a 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -8,7 +8,6 @@ use crate::convert::TryInto; use crate::mem::{self, ManuallyDrop, MaybeUninit}; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; -use crate::pin::PinCoerceUnsized; use crate::ptr::{self, NonNull}; use crate::slice::SliceIndex; use crate::{cmp, intrinsics, slice}; @@ -773,9 +772,6 @@ fn drop(&mut self) { #[unstable(feature = "sgx_platform", issue = "56975")] impl, U> CoerceUnsized> for UserRef {} -#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinCoerceUnsized for UserRef {} - #[unstable(feature = "sgx_platform", issue = "56975")] impl Index for UserRef<[T]> where diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 1de3ca4a5d79..2b284cc40b94 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -10,7 +10,6 @@ pub mod abi; mod libunwind_integration; -pub mod os; pub mod thread_parking; pub mod waitqueue; diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs deleted file mode 100644 index 5b0af37a3d37..000000000000 --- a/library/std/src/sys/pal/sgx/os.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::ffi::{OsStr, OsString}; -use crate::marker::PhantomData; -use crate::path::{self, PathBuf}; -use crate::sys::{sgx_ineffective, unsupported}; -use crate::{fmt, io}; - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - sgx_ineffective(()) -} - -pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported in SGX yet".fmt(f) - } -} - -impl crate::error::Error for JoinPathsError {} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn temp_dir() -> PathBuf { - panic!("no filesystem in SGX") -} - -pub fn home_dir() -> Option { - None -} diff --git a/library/std/src/sys/pal/solid/error.rs b/library/std/src/sys/pal/solid/error.rs index 3e85cdb3c1d9..a737abcc04ed 100644 --- a/library/std/src/sys/pal/solid/error.rs +++ b/library/std/src/sys/pal/solid/error.rs @@ -3,6 +3,14 @@ use crate::io; use crate::sys::net; +// SOLID directly maps `errno`s to μITRON error codes. +impl SolidError { + #[inline] + pub(crate) fn as_io_error(self) -> crate::io::Error { + crate::io::Error::from_raw_os_error(self.as_raw()) + } +} + /// Describe the specified SOLID error code. Returns `None` if it's an /// undefined error code. /// diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 1376af8304cf..c3f9e4794590 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -19,7 +19,6 @@ pub mod itron { // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` pub(crate) mod error; -pub mod os; pub use self::itron::thread_parking; // SAFETY: must be called only once during runtime initialization. diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs deleted file mode 100644 index 4a07d240d2e6..000000000000 --- a/library/std/src/sys/pal/solid/os.rs +++ /dev/null @@ -1,64 +0,0 @@ -use super::{itron, unsupported}; -use crate::ffi::{OsStr, OsString}; -use crate::path::{self, PathBuf}; -use crate::{fmt, io}; - -// `solid` directly maps `errno`s to μITRON error codes. -impl itron::error::ItronError { - #[inline] - pub(crate) fn as_io_error(self) -> crate::io::Error { - crate::io::Error::from_raw_os_error(self.as_raw()) - } -} - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(&'a !); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - *self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on this platform yet".fmt(f) - } -} - -impl crate::error::Error for JoinPathsError {} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn temp_dir() -> PathBuf { - panic!("no standard temporary directory on this platform") -} - -pub fn home_dir() -> Option { - None -} diff --git a/library/std/src/sys/pal/teeos/conf.rs b/library/std/src/sys/pal/teeos/conf.rs new file mode 100644 index 000000000000..1d13a283c458 --- /dev/null +++ b/library/std/src/sys/pal/teeos/conf.rs @@ -0,0 +1,5 @@ +// Hardcoded to return 4096, since `sysconf` is only implemented as a stub. +pub fn page_size() -> usize { + // unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; + 4096 +} diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index f76c26d3c966..5caed277dbf5 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -6,7 +6,7 @@ #![allow(unused_variables)] #![allow(dead_code)] -pub mod os; +pub mod conf; #[path = "../unix/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/teeos/os.rs b/library/std/src/sys/pal/teeos/os.rs deleted file mode 100644 index c09b84f42bab..000000000000 --- a/library/std/src/sys/pal/teeos/os.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Implementation of `std::os` functionality for teeos - -use core::marker::PhantomData; - -use super::unsupported; -use crate::ffi::{OsStr, OsString}; -use crate::path::PathBuf; -use crate::{fmt, io, path}; - -// Hardcoded to return 4096, since `sysconf` is only implemented as a stub. -pub fn page_size() -> usize { - // unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; - 4096 -} - -// Everything below are stubs and copied from unsupported.rs - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on this platform yet".fmt(f) - } -} - -impl crate::error::Error for JoinPathsError {} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn temp_dir() -> PathBuf { - panic!("no filesystem on this platform") -} - -pub fn home_dir() -> Option { - None -} diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index b785c2dbb789..ec2d938ed836 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -3,7 +3,5 @@ #[path = "../unsupported/common.rs"] #[deny(unsafe_op_in_unsafe_fn)] mod common; -#[path = "../unsupported/os.rs"] -pub mod os; pub use common::*; diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index e4a8f50e4274..67499d2c6f17 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -14,7 +14,6 @@ #![forbid(unsafe_op_in_unsafe_fn)] pub mod helpers; -pub mod os; pub mod system_time; #[cfg(test)] diff --git a/library/std/src/sys/pal/unix/conf.rs b/library/std/src/sys/pal/unix/conf.rs new file mode 100644 index 000000000000..a97173a1a35a --- /dev/null +++ b/library/std/src/sys/pal/unix/conf.rs @@ -0,0 +1,97 @@ +#[cfg(test)] +mod tests; + +#[cfg(not(target_os = "espidf"))] +pub fn page_size() -> usize { + unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } +} + +/// Returns the value for [`confstr(key, ...)`][posix_confstr]. Currently only +/// used on Darwin, but should work on any unix (in case we need to get +/// `_CS_PATH` or `_CS_V[67]_ENV` in the future). +/// +/// [posix_confstr]: +/// https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html +// +// FIXME: Support `confstr` in Miri. +#[cfg(all(target_vendor = "apple", not(miri)))] +pub fn confstr( + key: crate::ffi::c_int, + size_hint: Option, +) -> crate::io::Result { + use crate::ffi::OsString; + use crate::io; + use crate::os::unix::ffi::OsStringExt; + + let mut buf: Vec = Vec::with_capacity(0); + let mut bytes_needed_including_nul = size_hint + .unwrap_or_else(|| { + // Treat "None" as "do an extra call to get the length". In theory + // we could move this into the loop below, but it's hard to do given + // that it isn't 100% clear if it's legal to pass 0 for `len` when + // the buffer isn't null. + unsafe { libc::confstr(key, core::ptr::null_mut(), 0) } + }) + .max(1); + // If the value returned by `confstr` is greater than the len passed into + // it, then the value was truncated, meaning we need to retry. Note that + // while `confstr` results don't seem to change for a process, it's unclear + // if this is guaranteed anywhere, so looping does seem required. + while bytes_needed_including_nul > buf.capacity() { + // We write into the spare capacity of `buf`. This lets us avoid + // changing buf's `len`, which both simplifies `reserve` computation, + // allows working with `Vec` instead of `Vec>`, and + // may avoid a copy, since the Vec knows that none of the bytes are needed + // when reallocating (well, in theory anyway). + buf.reserve(bytes_needed_including_nul); + // `confstr` returns + // - 0 in the case of errors: we break and return an error. + // - The number of bytes written, iff the provided buffer is enough to + // hold the entire value: we break and return the data in `buf`. + // - Otherwise, the number of bytes needed (including nul): we go + // through the loop again. + bytes_needed_including_nul = + unsafe { libc::confstr(key, buf.as_mut_ptr().cast(), buf.capacity()) }; + } + // `confstr` returns 0 in the case of an error. + if bytes_needed_including_nul == 0 { + return Err(io::Error::last_os_error()); + } + // Safety: `confstr(..., buf.as_mut_ptr(), buf.capacity())` returned a + // non-zero value, meaning `bytes_needed_including_nul` bytes were + // initialized. + unsafe { + buf.set_len(bytes_needed_including_nul); + // Remove the NUL-terminator. + let last_byte = buf.pop(); + // ... and smoke-check that it *was* a NUL-terminator. + assert_eq!(last_byte, Some(0), "`confstr` provided a string which wasn't nul-terminated"); + }; + Ok(OsString::from_vec(buf)) +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub fn glibc_version() -> Option<(usize, usize)> { + use crate::ffi::CStr; + + unsafe extern "C" { + fn gnu_get_libc_version() -> *const libc::c_char; + } + let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) }; + if let Ok(version_str) = version_cstr.to_str() { + parse_glibc_version(version_str) + } else { + None + } +} + +/// Returns Some((major, minor)) if the string is a valid "x.y" version, +/// ignoring any extra dot-separated parts. Otherwise return None. +#[cfg(all(target_os = "linux", target_env = "gnu"))] +fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { + let mut parsed_ints = version.split('.').map(str::parse::).fuse(); + match (parsed_ints.next(), parsed_ints.next()) { + (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), + _ => None, + } +} diff --git a/library/std/src/sys/pal/unix/os/tests.rs b/library/std/src/sys/pal/unix/conf/tests.rs similarity index 100% rename from library/std/src/sys/pal/unix/os/tests.rs rename to library/std/src/sys/pal/unix/conf/tests.rs diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 0fbf37fda7fb..0be150a0bfaa 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -2,12 +2,12 @@ use crate::io; +pub mod conf; #[cfg(target_os = "fuchsia")] pub mod fuchsia; pub mod futex; #[cfg(target_os = "linux")] pub mod linux; -pub mod os; pub mod stack_overflow; pub mod sync; pub mod thread_parking; diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 040fda75a508..5d53de7fb7e2 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -70,7 +70,7 @@ mod imp { use super::thread_info::{delete_current_info, set_current_info, with_current_info}; use crate::ops::Range; use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, AtomicUsize, Ordering}; - use crate::sys::pal::unix::os; + use crate::sys::pal::unix::conf; use crate::{io, mem, ptr}; // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages @@ -150,7 +150,7 @@ mod imp { /// Must be called only once #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn init() { - PAGE_SIZE.store(os::page_size(), Ordering::Relaxed); + PAGE_SIZE.store(conf::page_size(), Ordering::Relaxed); let mut guard_page_range = unsafe { install_main_guard() }; @@ -429,6 +429,11 @@ unsafe fn install_main_guard() -> Option> { #[forbid(unsafe_op_in_unsafe_fn)] unsafe fn install_main_guard_linux(page_size: usize) -> Option> { + // See the corresponding conditional in init(). + // Avoid stack_start_aligned, which makes slow syscalls to read /proc/self/maps + if cfg!(panic = "immediate-abort") { + return None; + } // Linux doesn't allocate the whole stack right away, and // the kernel has its own stack-guard mechanism to fault // when growing too close to an existing mapping. If we map @@ -456,6 +461,10 @@ unsafe fn install_main_guard_linux_musl(_page_size: usize) -> Option Option> { + // See the corresponding conditional in install_main_guard_linux(). + if cfg!(panic = "immediate-abort") { + return None; + } // FreeBSD's stack autogrows, and optionally includes a guard page // at the bottom. If we try to remap the bottom of the stack // ourselves, FreeBSD's guard page moves upwards. So we'll just use @@ -489,6 +498,10 @@ unsafe fn install_main_guard_freebsd(page_size: usize) -> Option> { #[forbid(unsafe_op_in_unsafe_fn)] unsafe fn install_main_guard_bsds(page_size: usize) -> Option> { + // See the corresponding conditional in install_main_guard_linux(). + if cfg!(panic = "immediate-abort") { + return None; + } // OpenBSD stack already includes a guard page, and stack is // immutable. // NetBSD stack includes the guard page. diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index fbea94ec84e7..9acc7786b2ed 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -17,7 +17,7 @@ tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64, }; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub(crate) struct Timespec { pub tv_sec: i64, pub tv_nsec: Nanoseconds, @@ -66,6 +66,7 @@ pub const fn new(tv_sec: i64, tv_nsec: i64) -> Result { } } + #[allow(dead_code)] pub fn now(clock: libc::clockid_t) -> Timespec { use crate::mem::MaybeUninit; use crate::sys::cvt; diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index 0f157819d5a6..c4b14ab44436 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -1,6 +1,4 @@ #![deny(unsafe_op_in_unsafe_fn)] -pub mod os; - mod common; pub use common::*; diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs deleted file mode 100644 index fe8addeafd2b..000000000000 --- a/library/std/src/sys/pal/unsupported/os.rs +++ /dev/null @@ -1,57 +0,0 @@ -use super::unsupported; -use crate::ffi::{OsStr, OsString}; -use crate::marker::PhantomData; -use crate::path::{self, PathBuf}; -use crate::{fmt, io}; - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on this platform yet".fmt(f) - } -} - -impl crate::error::Error for JoinPathsError {} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn temp_dir() -> PathBuf { - panic!("no filesystem on this platform") -} - -pub fn home_dir() -> Option { - None -} diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index d1380ab8dff1..61bbe78f718a 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -1,6 +1,3 @@ -#[path = "../unsupported/os.rs"] -pub mod os; - #[expect(dead_code)] #[path = "../unsupported/common.rs"] mod unsupported_common; diff --git a/library/std/src/sys/pal/wasi/conf.rs b/library/std/src/sys/pal/wasi/conf.rs new file mode 100644 index 000000000000..cf76ae733358 --- /dev/null +++ b/library/std/src/sys/pal/wasi/conf.rs @@ -0,0 +1,4 @@ +#[allow(dead_code)] +pub fn page_size() -> usize { + unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } +} diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs deleted file mode 100644 index 4f2eb1148f0b..000000000000 --- a/library/std/src/sys/pal/wasi/helpers.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -pub fn abort_internal() -> ! { - unsafe { libc::abort() } -} - -#[inline] -#[cfg(target_env = "p1")] -pub(crate) fn err2io(err: wasi::Errno) -> crate::io::Error { - crate::io::Error::from_raw_os_error(err.raw().into()) -} diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 9b49db9af6b0..6f6099350925 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -4,34 +4,63 @@ //! OS level functionality for WASI. Currently this includes both WASIp1 and //! WASIp2. +use crate::io; + +pub mod conf; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; - -pub mod os; pub mod stack_overflow; #[path = "../unix/time.rs"] pub mod time; -#[path = "../unsupported/common.rs"] -#[deny(unsafe_op_in_unsafe_fn)] -#[allow(unused)] -mod common; - -pub use common::*; - -mod helpers; - -// The following exports are listed individually to work around Rust's glob -// import conflict rules. If we glob export `helpers` and `common` together, -// then the compiler complains about conflicts. - -pub(crate) use helpers::abort_internal; -#[cfg(target_env = "p1")] -pub(crate) use helpers::err2io; -#[cfg(not(target_env = "p1"))] -pub use os::IsMinusOne; -pub use os::{cvt, cvt_r}; - #[cfg(not(target_env = "p1"))] mod cabi_realloc; + +#[path = "../unsupported/common.rs"] +#[deny(unsafe_op_in_unsafe_fn)] +#[expect(dead_code)] +mod common; +pub use common::{cleanup, init, unsupported}; + +pub fn abort_internal() -> ! { + unsafe { libc::abort() } +} + +#[inline] +#[cfg(target_env = "p1")] +pub(crate) fn err2io(err: wasi::Errno) -> crate::io::Error { + crate::io::Error::from_raw_os_error(err.raw().into()) +} + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt(t: T) -> io::Result { + if t.is_minus_one() { Err(io::Error::last_os_error()) } else { Ok(t) } +} + +pub fn cvt_r(mut f: F) -> io::Result +where + T: IsMinusOne, + F: FnMut() -> T, +{ + loop { + match cvt(f()) { + Err(ref e) if e.is_interrupted() => {} + other => return other, + } + } +} diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs deleted file mode 100644 index c8f3ddf692bc..000000000000 --- a/library/std/src/sys/pal/wasi/os.rs +++ /dev/null @@ -1,135 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use crate::ffi::{CStr, OsStr, OsString}; -use crate::marker::PhantomData; -use crate::os::wasi::prelude::*; -use crate::path::{self, PathBuf}; -use crate::sys::helpers::run_path_with_cstr; -use crate::sys::unsupported; -use crate::{fmt, io}; - -// Add a few symbols not in upstream `libc` just yet. -pub mod libc { - pub use libc::*; - - unsafe extern "C" { - pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; - pub fn chdir(dir: *const c_char) -> c_int; - pub fn __wasilibc_get_environ() -> *mut *mut c_char; - } -} - -pub fn getcwd() -> io::Result { - let mut buf = Vec::with_capacity(512); - loop { - unsafe { - let ptr = buf.as_mut_ptr() as *mut libc::c_char; - if !libc::getcwd(ptr, buf.capacity()).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); - buf.set_len(len); - buf.shrink_to_fit(); - return Ok(PathBuf::from(OsString::from_vec(buf))); - } else { - let error = io::Error::last_os_error(); - if error.raw_os_error() != Some(libc::ERANGE) { - return Err(error); - } - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. - let cap = buf.capacity(); - buf.set_len(cap); - buf.reserve(1); - } - } -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let result = run_path_with_cstr(p, &|p| unsafe { Ok(libc::chdir(p.as_ptr())) })?; - match result == (0 as libc::c_int) { - true => Ok(()), - false => Err(io::Error::last_os_error()), - } -} - -pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on wasm yet".fmt(f) - } -} - -impl crate::error::Error for JoinPathsError {} - -pub fn current_exe() -> io::Result { - unsupported() -} - -#[allow(dead_code)] -pub fn page_size() -> usize { - unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } -} - -pub fn temp_dir() -> PathBuf { - panic!("no filesystem on wasm") -} - -pub fn home_dir() -> Option { - None -} - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 - } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -pub fn cvt(t: T) -> io::Result { - if t.is_minus_one() { Err(io::Error::last_os_error()) } else { Ok(t) } -} - -pub fn cvt_r(mut f: F) -> io::Result -where - T: IsMinusOne, - F: FnMut() -> T, -{ - loop { - match cvt(f()) { - Err(ref e) if e.is_interrupted() => {} - other => return other, - } - } -} diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 5f56eddd6a81..24a2ab8eca30 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -16,9 +16,6 @@ #![deny(unsafe_op_in_unsafe_fn)] -#[path = "../unsupported/os.rs"] -pub mod os; - #[cfg(target_feature = "atomics")] #[path = "atomics/futex.rs"] pub mod futex; diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 0cd915261471..b67ba3774978 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -18,7 +18,6 @@ #[cfg(not(target_vendor = "win7"))] pub mod futex; pub mod handle; -pub mod os; pub mod time; cfg_select! { // We don't care about printing nice error messages for panic=immediate-abort diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 9b22fb88c998..b5b3fd91b4fa 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,6 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -pub mod os; pub mod params; #[path = "../unsupported/common.rs"] diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 1b18adb811d9..1a64d3c93d70 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -11,7 +11,6 @@ pub const WORD_SIZE: usize = size_of::(); pub mod abi; -pub mod os; use crate::io as std_io; diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs deleted file mode 100644 index fe8addeafd2b..000000000000 --- a/library/std/src/sys/pal/zkvm/os.rs +++ /dev/null @@ -1,57 +0,0 @@ -use super::unsupported; -use crate::ffi::{OsStr, OsString}; -use crate::marker::PhantomData; -use crate::path::{self, PathBuf}; -use crate::{fmt, io}; - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on this platform yet".fmt(f) - } -} - -impl crate::error::Error for JoinPathsError {} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn temp_dir() -> PathBuf { - panic!("no filesystem on this platform") -} - -pub fn home_dir() -> Option { - None -} diff --git a/library/std/src/sys/paths/hermit.rs b/library/std/src/sys/paths/hermit.rs new file mode 100644 index 000000000000..36f667d30053 --- /dev/null +++ b/library/std/src/sys/paths/hermit.rs @@ -0,0 +1,10 @@ +use crate::io; +use crate::path::PathBuf; + +pub fn getcwd() -> io::Result { + Ok(PathBuf::from("/")) +} + +pub fn temp_dir() -> PathBuf { + PathBuf::from("/tmp") +} diff --git a/library/std/src/sys/paths/mod.rs b/library/std/src/sys/paths/mod.rs new file mode 100644 index 000000000000..8880a837af7f --- /dev/null +++ b/library/std/src/sys/paths/mod.rs @@ -0,0 +1,59 @@ +cfg_select! { + target_os = "hermit" => { + mod hermit; + #[expect(dead_code)] + mod unsupported; + mod imp { + pub use super::hermit::{getcwd, temp_dir}; + pub use super::unsupported::{chdir, SplitPaths, split_paths, JoinPathsError, join_paths, current_exe, home_dir}; + } + } + target_os = "motor" => { + mod motor; + #[expect(dead_code)] + mod unsupported; + mod imp { + pub use super::motor::{getcwd, chdir, current_exe, temp_dir}; + pub use super::unsupported::{SplitPaths, split_paths, JoinPathsError, join_paths, home_dir}; + } + } + all(target_vendor = "fortanix", target_env = "sgx") => { + mod sgx; + #[expect(dead_code)] + mod unsupported; + mod imp { + pub use super::sgx::chdir; + pub use super::unsupported::{getcwd, SplitPaths, split_paths, JoinPathsError, join_paths, current_exe, temp_dir, home_dir}; + } + } + target_os = "uefi" => { + mod uefi; + use uefi as imp; + } + target_family = "unix" => { + mod unix; + use unix as imp; + } + target_os = "wasi" => { + mod wasi; + #[expect(dead_code)] + mod unsupported; + mod imp { + pub use super::wasi::{getcwd, chdir, temp_dir}; + pub use super::unsupported::{current_exe, SplitPaths, split_paths, JoinPathsError, join_paths, home_dir}; + } + } + target_os = "windows" => { + mod windows; + use windows as imp; + } + _ => { + mod unsupported; + use unsupported as imp; + } +} + +pub use imp::{ + JoinPathsError, SplitPaths, chdir, current_exe, getcwd, home_dir, join_paths, split_paths, + temp_dir, +}; diff --git a/library/std/src/sys/paths/motor.rs b/library/std/src/sys/paths/motor.rs new file mode 100644 index 000000000000..33d746b13d59 --- /dev/null +++ b/library/std/src/sys/paths/motor.rs @@ -0,0 +1,20 @@ +use crate::io; +use crate::os::motor::ffi::OsStrExt; +use crate::path::{self, PathBuf}; +use crate::sys::pal::map_motor_error; + +pub fn getcwd() -> io::Result { + moto_rt::fs::getcwd().map(PathBuf::from).map_err(map_motor_error) +} + +pub fn chdir(path: &path::Path) -> io::Result<()> { + moto_rt::fs::chdir(path.as_os_str().as_str()).map_err(map_motor_error) +} + +pub fn current_exe() -> io::Result { + moto_rt::process::current_exe().map(PathBuf::from).map_err(map_motor_error) +} + +pub fn temp_dir() -> PathBuf { + PathBuf::from(moto_rt::fs::TEMP_DIR) +} diff --git a/library/std/src/sys/paths/sgx.rs b/library/std/src/sys/paths/sgx.rs new file mode 100644 index 000000000000..6a4cbe93b1b8 --- /dev/null +++ b/library/std/src/sys/paths/sgx.rs @@ -0,0 +1,7 @@ +use crate::io; +use crate::path::Path; +use crate::sys::pal::sgx_ineffective; + +pub fn chdir(_: &Path) -> io::Result<()> { + sgx_ineffective(()) +} diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/paths/uefi.rs similarity index 96% rename from library/std/src/sys/pal/uefi/os.rs rename to library/std/src/sys/paths/uefi.rs index b25be430a3f8..7fddcfdff772 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/paths/uefi.rs @@ -1,9 +1,9 @@ use r_efi::efi::protocols::{device_path, loaded_image_device_path}; -use super::{helpers, unsupported_err}; use crate::ffi::{OsStr, OsString}; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::path::{self, PathBuf}; +use crate::sys::pal::{helpers, unsupported_err}; use crate::{fmt, io}; const PATHS_SEP: u16 = b';' as u16; @@ -115,7 +115,7 @@ pub fn current_exe() -> io::Result { } pub fn temp_dir() -> PathBuf { - panic!("no filesystem on this platform") + panic!("UEFI doesn't have a dedicated temp directory") } pub fn home_dir() -> Option { diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/paths/unix.rs similarity index 77% rename from library/std/src/sys/pal/unix/os.rs rename to library/std/src/sys/paths/unix.rs index d11282682d08..544d495340db 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/paths/unix.rs @@ -2,16 +2,13 @@ #![allow(unused_imports)] // lots of cfg code here -#[cfg(test)] -mod tests; - use libc::{c_char, c_int, c_void}; use crate::ffi::{CStr, OsStr, OsString}; use crate::os::unix::prelude::*; use crate::path::{self, PathBuf}; -use crate::sys::cvt; use crate::sys::helpers::run_path_with_cstr; +use crate::sys::pal::cvt; use crate::{fmt, io, iter, mem, ptr, slice, str}; const PATH_SEPARATOR: u8 = b':'; @@ -50,7 +47,7 @@ pub fn getcwd() -> io::Result { #[cfg(target_os = "espidf")] pub fn chdir(_p: &path::Path) -> io::Result<()> { - super::unsupported::unsupported() + crate::sys::pal::unsupported::unsupported() } #[cfg(not(target_os = "espidf"))] @@ -375,7 +372,7 @@ pub fn current_exe() -> io::Result { #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] pub fn current_exe() -> io::Result { - super::unsupported::unsupported() + crate::sys::pal::unsupported::unsupported() } #[cfg(target_os = "fuchsia")] @@ -396,75 +393,15 @@ pub fn current_exe() -> io::Result { if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) } } -#[cfg(not(target_os = "espidf"))] -pub fn page_size() -> usize { - unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } -} - -// Returns the value for [`confstr(key, ...)`][posix_confstr]. Currently only -// used on Darwin, but should work on any unix (in case we need to get -// `_CS_PATH` or `_CS_V[67]_ENV` in the future). -// -// [posix_confstr]: -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html -// -// FIXME: Support `confstr` in Miri. -#[cfg(all(target_vendor = "apple", not(miri)))] -fn confstr(key: c_int, size_hint: Option) -> io::Result { - let mut buf: Vec = Vec::with_capacity(0); - let mut bytes_needed_including_nul = size_hint - .unwrap_or_else(|| { - // Treat "None" as "do an extra call to get the length". In theory - // we could move this into the loop below, but it's hard to do given - // that it isn't 100% clear if it's legal to pass 0 for `len` when - // the buffer isn't null. - unsafe { libc::confstr(key, core::ptr::null_mut(), 0) } - }) - .max(1); - // If the value returned by `confstr` is greater than the len passed into - // it, then the value was truncated, meaning we need to retry. Note that - // while `confstr` results don't seem to change for a process, it's unclear - // if this is guaranteed anywhere, so looping does seem required. - while bytes_needed_including_nul > buf.capacity() { - // We write into the spare capacity of `buf`. This lets us avoid - // changing buf's `len`, which both simplifies `reserve` computation, - // allows working with `Vec` instead of `Vec>`, and - // may avoid a copy, since the Vec knows that none of the bytes are needed - // when reallocating (well, in theory anyway). - buf.reserve(bytes_needed_including_nul); - // `confstr` returns - // - 0 in the case of errors: we break and return an error. - // - The number of bytes written, iff the provided buffer is enough to - // hold the entire value: we break and return the data in `buf`. - // - Otherwise, the number of bytes needed (including nul): we go - // through the loop again. - bytes_needed_including_nul = - unsafe { libc::confstr(key, buf.as_mut_ptr().cast::(), buf.capacity()) }; - } - // `confstr` returns 0 in the case of an error. - if bytes_needed_including_nul == 0 { - return Err(io::Error::last_os_error()); - } - // Safety: `confstr(..., buf.as_mut_ptr(), buf.capacity())` returned a - // non-zero value, meaning `bytes_needed_including_nul` bytes were - // initialized. - unsafe { - buf.set_len(bytes_needed_including_nul); - // Remove the NUL-terminator. - let last_byte = buf.pop(); - // ... and smoke-check that it *was* a NUL-terminator. - assert_eq!(last_byte, Some(0), "`confstr` provided a string which wasn't nul-terminated"); - }; - Ok(OsString::from_vec(buf)) -} - #[cfg(all(target_vendor = "apple", not(miri)))] fn darwin_temp_dir() -> PathBuf { - confstr(libc::_CS_DARWIN_USER_TEMP_DIR, Some(64)).map(PathBuf::from).unwrap_or_else(|_| { - // It failed for whatever reason (there are several possible reasons), - // so return the global one. - PathBuf::from("/tmp") - }) + crate::sys::pal::conf::confstr(libc::_CS_DARWIN_USER_TEMP_DIR, Some(64)) + .map(PathBuf::from) + .unwrap_or_else(|_| { + // It failed for whatever reason (there are several possible reasons), + // so return the global one. + PathBuf::from("/tmp") + }) } pub fn temp_dir() -> PathBuf { @@ -532,27 +469,3 @@ unsafe fn fallback() -> Option { } } } - -#[cfg(all(target_os = "linux", target_env = "gnu"))] -pub fn glibc_version() -> Option<(usize, usize)> { - unsafe extern "C" { - fn gnu_get_libc_version() -> *const libc::c_char; - } - let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) }; - if let Ok(version_str) = version_cstr.to_str() { - parse_glibc_version(version_str) - } else { - None - } -} - -// Returns Some((major, minor)) if the string is a valid "x.y" version, -// ignoring any extra dot-separated parts. Otherwise return None. -#[cfg(all(target_os = "linux", target_env = "gnu"))] -fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { - let mut parsed_ints = version.split('.').map(str::parse::).fuse(); - match (parsed_ints.next(), parsed_ints.next()) { - (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), - _ => None, - } -} diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/paths/unsupported.rs similarity index 97% rename from library/std/src/sys/pal/xous/os.rs rename to library/std/src/sys/paths/unsupported.rs index fe8addeafd2b..024830a254fd 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/paths/unsupported.rs @@ -1,7 +1,7 @@ -use super::unsupported; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; +use crate::sys::pal::unsupported; use crate::{fmt, io}; pub fn getcwd() -> io::Result { diff --git a/library/std/src/sys/paths/wasi.rs b/library/std/src/sys/paths/wasi.rs new file mode 100644 index 000000000000..1e1f951cd679 --- /dev/null +++ b/library/std/src/sys/paths/wasi.rs @@ -0,0 +1,45 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +use crate::ffi::{CStr, OsString}; +use crate::io; +use crate::os::wasi::prelude::*; +use crate::path::{self, PathBuf}; +use crate::sys::helpers::run_path_with_cstr; + +pub fn getcwd() -> io::Result { + let mut buf = Vec::with_capacity(512); + loop { + unsafe { + let ptr = buf.as_mut_ptr() as *mut libc::c_char; + if !libc::getcwd(ptr, buf.capacity()).is_null() { + let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); + buf.set_len(len); + buf.shrink_to_fit(); + return Ok(PathBuf::from(OsString::from_vec(buf))); + } else { + let error = io::Error::last_os_error(); + if error.raw_os_error() != Some(libc::ERANGE) { + return Err(error); + } + } + + // Trigger the internal buffer resizing logic of `Vec` by requiring + // more space than the current capacity. + let cap = buf.capacity(); + buf.set_len(cap); + buf.reserve(1); + } + } +} + +pub fn chdir(p: &path::Path) -> io::Result<()> { + let result = run_path_with_cstr(p, &|p| unsafe { Ok(libc::chdir(p.as_ptr())) })?; + match result == (0 as libc::c_int) { + true => Ok(()), + false => Err(io::Error::last_os_error()), + } +} + +pub fn temp_dir() -> PathBuf { + panic!("not supported by WASI yet") +} diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/paths/windows.rs similarity index 87% rename from library/std/src/sys/pal/windows/os.rs rename to library/std/src/sys/paths/windows.rs index 30cad2a05683..cfdc93847a97 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/paths/windows.rs @@ -2,17 +2,13 @@ #![allow(nonstandard_style)] -#[cfg(test)] -mod tests; - -use super::api; -#[cfg(not(target_vendor = "uwp"))] -use super::api::WinError; use crate::ffi::{OsStr, OsString}; use crate::os::windows::ffi::EncodeWide; use crate::os::windows::prelude::*; use crate::path::{self, PathBuf}; -use crate::sys::pal::{c, cvt}; +#[cfg(not(target_vendor = "uwp"))] +use crate::sys::pal::api::WinError; +use crate::sys::pal::{api, c, cvt, fill_utf16_buf, os2path}; use crate::{fmt, io, ptr}; pub struct SplitPaths<'a> { @@ -56,11 +52,7 @@ fn next(&mut self) -> Option { } } - if !must_yield && in_progress.is_empty() { - None - } else { - Some(super::os2path(&in_progress)) - } + if !must_yield && in_progress.is_empty() { None } else { Some(os2path(&in_progress)) } } } @@ -104,14 +96,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { - super::fill_utf16_buf( - |buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) }, - super::os2path, - ) + fill_utf16_buf(|buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) }, os2path) } pub fn getcwd() -> io::Result { - super::fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, super::os2path) + fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, os2path) } pub fn chdir(p: &path::Path) -> io::Result<()> { @@ -123,7 +112,7 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { } pub fn temp_dir() -> PathBuf { - super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap() + fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, os2path).unwrap() } #[cfg(all(not(target_vendor = "uwp"), not(target_vendor = "win7")))] @@ -132,7 +121,7 @@ fn home_dir_crt() -> Option { // Defined in processthreadsapi.h. const CURRENT_PROCESS_TOKEN: usize = -4_isize as usize; - super::fill_utf16_buf( + fill_utf16_buf( |buf, mut sz| { // GetUserProfileDirectoryW does not quite use the usual protocol for // negotiating the buffer size, so we have to translate. @@ -146,7 +135,7 @@ fn home_dir_crt() -> Option { _ => sz - 1, // sz includes the null terminator } }, - super::os2path, + os2path, ) .ok() } @@ -163,7 +152,7 @@ fn home_dir_crt() -> Option { return None; } let _handle = Handle::from_raw_handle(token); - super::fill_utf16_buf( + fill_utf16_buf( |buf, mut sz| { match c::GetUserProfileDirectoryW(token, buf, &mut sz) { 0 if api::get_last_error() != WinError::INSUFFICIENT_BUFFER => 0, @@ -171,7 +160,7 @@ fn home_dir_crt() -> Option { _ => sz - 1, // sz includes the null terminator } }, - super::os2path, + os2path, ) .ok() } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 82ff94fb1e03..a68be2543bc2 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -537,7 +537,7 @@ fn pidfd_spawnp( // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly. #[cfg(all(target_os = "linux", target_env = "gnu"))] { - if let Some(version) = sys::os::glibc_version() { + if let Some(version) = sys::pal::conf::glibc_version() { if version < (2, 24) { return Ok(None); } diff --git a/library/std/src/sys/sync/once/futex.rs b/library/std/src/sys/sync/once/futex.rs index 096f1d879ef2..236bc9ca4b7c 100644 --- a/library/std/src/sys/sync/once/futex.rs +++ b/library/std/src/sys/sync/once/futex.rs @@ -75,6 +75,11 @@ pub const fn new() -> Once { Once { state_and_queued: Futex::new(INCOMPLETE) } } + #[inline] + pub const fn new_complete() -> Once { + Once { state_and_queued: Futex::new(COMPLETE) } + } + #[inline] pub fn is_completed(&self) -> bool { // Use acquire ordering to make all initialization changes visible to the diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs index 576bbf644cbe..42fe2417307a 100644 --- a/library/std/src/sys/sync/once/no_threads.rs +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -39,6 +39,11 @@ pub const fn new() -> Once { Once { state: Cell::new(State::Incomplete) } } + #[inline] + pub const fn new_complete() -> Once { + Once { state: Cell::new(State::Complete) } + } + #[inline] pub fn is_completed(&self) -> bool { self.state.get() == State::Complete diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index d7219a7361cf..f64f6523d143 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -121,6 +121,11 @@ pub const fn new() -> Once { Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) } } + #[inline] + pub const fn new_complete() -> Once { + Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(COMPLETE)) } + } + #[inline] pub fn is_completed(&self) -> bool { // An `Acquire` load is enough because that makes all the initialization diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs index 573d0d602dbd..6b919bde80bb 100644 --- a/library/std/src/sys/sync/rwlock/no_threads.rs +++ b/library/std/src/sys/sync/rwlock/no_threads.rs @@ -37,8 +37,10 @@ pub fn try_read(&self) -> bool { #[inline] pub fn write(&self) { - if self.mode.replace(-1) != 0 { - rtabort!("rwlock locked for reading") + if self.mode.get() == 0 { + self.mode.set(-1); + } else { + rtabort!("rwlock locked for reading"); } } diff --git a/library/std/src/sys/thread/teeos.rs b/library/std/src/sys/thread/teeos.rs index 5e71f757eaa4..aa679e780c18 100644 --- a/library/std/src/sys/thread/teeos.rs +++ b/library/std/src/sys/thread/teeos.rs @@ -1,5 +1,5 @@ use crate::mem::{self, ManuallyDrop}; -use crate::sys::os; +use crate::sys::pal::conf; use crate::thread::ThreadInit; use crate::time::Duration; use crate::{cmp, io, ptr}; @@ -52,7 +52,7 @@ pub unsafe fn new(stack: usize, init: Box) -> io::Result { // multiple of the system page size. Because it's definitely // >= PTHREAD_STACK_MIN, it must be an alignment issue. // Round up to the nearest page and try again. - let page_size = os::page_size(); + let page_size = conf::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0); diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 22f9bfef5a38..5d4eabc226ed 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -76,7 +76,7 @@ pub unsafe fn new(stack: usize, init: Box) -> io::Result { // multiple of the system page size. Because it's definitely // >= PTHREAD_STACK_MIN, it must be an alignment issue. // Round up to the nearest page and try again. - let page_size = sys::os::page_size(); + let page_size = sys::pal::conf::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index 3f06c9bd1d77..e1d9d80c97b6 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -62,25 +62,7 @@ fn __rust_std_internal_init_fn() -> $t { $init } // by translating it into a `cfg`ed block and recursing. // https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate - (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { - #[cfg(true)] - { - $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); - } - - $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? - }, - - (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { - #[cfg(false)] - { - $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); - } - - $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? - }, - - (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { + (@align $final_align:ident, cfg_attr($cfg_pred:expr, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { #[cfg($cfg_pred)] { $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); diff --git a/library/std/src/sys/time/hermit.rs b/library/std/src/sys/time/hermit.rs index 18ece2e3010d..4e8e5dfe21c8 100644 --- a/library/std/src/sys/time/hermit.rs +++ b/library/std/src/sys/time/hermit.rs @@ -1,18 +1,21 @@ use hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME}; -use crate::hash::Hash; +use crate::io; use crate::sys::pal::time::Timespec; use crate::time::Duration; +fn clock_gettime(clock: hermit_abi::clockid_t) -> Timespec { + let mut t = hermit_abi::timespec { tv_sec: 0, tv_nsec: 0 }; + unsafe { hermit_abi::clock_gettime(clock, &raw mut t) }.unwrap(); + Timespec::new(t.tv_sec, t.tv_nsec.into()).unwrap() +} + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Timespec); impl Instant { pub fn now() -> Instant { - let mut time: Timespec = Timespec::zero(); - let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) }; - - Instant(time) + Instant(clock_gettime(CLOCK_MONOTONIC)) } pub fn checked_sub_instant(&self, other: &Instant) -> Option { @@ -38,15 +41,12 @@ impl SystemTime { pub const MIN: SystemTime = SystemTime(Timespec::MIN); - pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { - SystemTime(Timespec::new(tv_sec, tv_nsec)) + pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { + Ok(SystemTime(Timespec::new(tv_sec, tv_nsec)?)) } pub fn now() -> SystemTime { - let mut time: Timespec = Timespec::zero(); - let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) }; - - SystemTime(time) + SystemTime(clock_gettime(CLOCK_REALTIME)) } pub fn sub_time(&self, other: &SystemTime) -> Result { diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1318d8dc2780..5de001838faf 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -198,41 +198,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ); ), - // it's a nested `cfg_attr(true, ...)`; recurse into RHS - ( - [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; - @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; - $($rest:tt)* - ) => ( - $crate::thread::local_impl::thread_local_process_attrs!( - [] []; - @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] }; - [$($prev_align_attrs)*] [$($prev_other_attrs)*]; - @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; - $($rest)* - ); - ), - - // it's a nested `cfg_attr(false, ...)`; recurse into RHS - ( - [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; - @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; - $($rest:tt)* - ) => ( - $crate::thread::local_impl::thread_local_process_attrs!( - [] []; - @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] }; - [$($prev_align_attrs)*] [$($prev_other_attrs)*]; - @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; - $($rest)* - ); - ), - - // it's a nested `cfg_attr(..., ...)`; recurse into RHS ( [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; - @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:meta, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:expr, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; $($rest:tt)* ) => ( $crate::thread::local_impl::thread_local_process_attrs!( @@ -268,28 +237,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ); ), - // `cfg_attr(true, ...)` attribute; parse it - ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(true, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( - $crate::thread::local_impl::thread_local_process_attrs!( - [] []; - @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] }; - [$($prev_align_attrs)*] [$($prev_other_attrs)*]; - $($rest)* - ); - ), - - // `cfg_attr(false, ...)` attribute; parse it - ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(false, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( - $crate::thread::local_impl::thread_local_process_attrs!( - [] []; - @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] }; - [$($prev_align_attrs)*] [$($prev_other_attrs)*]; - $($rest)* - ); - ), - // `cfg_attr(..., ...)` attribute; parse it - ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:expr, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( $crate::thread::local_impl::thread_local_process_attrs!( [] []; @processing_cfg_attr { pred: ($cfg_pred), rhs: [$($cfg_rhs)*] }; diff --git a/library/std/tests/sync/mpmc.rs b/library/std/tests/sync/mpmc.rs index bf80ab96a88b..db221ff15890 100644 --- a/library/std/tests/sync/mpmc.rs +++ b/library/std/tests/sync/mpmc.rs @@ -475,7 +475,6 @@ fn stress_recv_timeout_two_threads() { }); let mut recv_count = 0; - let mut got_timeout = false; loop { match rx.recv_timeout(timeout) { Ok(n) => { @@ -483,7 +482,6 @@ fn stress_recv_timeout_two_threads() { recv_count += 1; } Err(RecvTimeoutError::Timeout) => { - got_timeout = true; continue; } Err(RecvTimeoutError::Disconnected) => break, @@ -491,7 +489,6 @@ fn stress_recv_timeout_two_threads() { } assert_eq!(recv_count, stress); - assert!(got_timeout); } #[test] diff --git a/library/std/tests/sync/mpsc.rs b/library/std/tests/sync/mpsc.rs index 9de4a71987b8..4dc4b955da7c 100644 --- a/library/std/tests/sync/mpsc.rs +++ b/library/std/tests/sync/mpsc.rs @@ -438,7 +438,6 @@ fn stress_recv_timeout_two_threads() { }); let mut recv_count = 0; - let mut got_timeout = false; loop { match rx.recv_timeout(timeout) { Ok(n) => { @@ -446,7 +445,6 @@ fn stress_recv_timeout_two_threads() { recv_count += 1; } Err(RecvTimeoutError::Timeout) => { - got_timeout = true; continue; } Err(RecvTimeoutError::Disconnected) => break, @@ -454,7 +452,6 @@ fn stress_recv_timeout_two_threads() { } assert_eq!(recv_count, stress); - assert!(got_timeout); } #[test] diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs index a23d65a23d81..5805d5cc3646 100644 --- a/library/std_detect/src/detect/os/darwin/aarch64.rs +++ b/library/std_detect/src/detect/os/darwin/aarch64.rs @@ -81,6 +81,7 @@ pub(crate) fn detect_features() -> cache::Initializer { let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64"); let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64"); let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS"); + let sve_b16b16 = _sysctlbyname(c"hw.optional.arm.FEAT_SVE_B16B16"); let wfxt = _sysctlbyname(c"hw.optional.arm.FEAT_WFxT"); // The following features are not exposed by `is_aarch64_feature_detected`, @@ -160,6 +161,7 @@ pub(crate) fn detect_features() -> cache::Initializer { enable_feature(Feature::sme_f64f64, sme_f64f64); enable_feature(Feature::sme_i16i64, sme_i16i64); enable_feature(Feature::ssbs, ssbs); + enable_feature(Feature::sve_b16b16, sve_b16b16); enable_feature(Feature::wfxt, wfxt); value diff --git a/library/std_detect/src/detect/os/x86.rs b/library/std_detect/src/detect/os/x86.rs index f2205ba07dd4..b24ef6a37ef5 100644 --- a/library/std_detect/src/detect/os/x86.rs +++ b/library/std_detect/src/detect/os/x86.rs @@ -202,6 +202,28 @@ pub(crate) fn detect_features() -> cache::Initializer { // Test `XCR0.APX[19]` with the mask `0b1000_0000_0000_0000_0000 == 0x80000` let os_apx_support = xcr0 & 0x80000 == 0x80000; + if os_amx_support { + enable(extended_features_edx, 24, Feature::amx_tile); + enable(extended_features_edx, 25, Feature::amx_int8); + enable(extended_features_edx, 22, Feature::amx_bf16); + enable(extended_features_eax_leaf_1, 21, Feature::amx_fp16); + enable(extended_features_edx_leaf_1, 8, Feature::amx_complex); + + if max_basic_leaf >= 0x1e { + let CpuidResult { eax: amx_feature_flags_eax, .. } = + __cpuid_count(0x1e_u32, 1); + + enable(amx_feature_flags_eax, 4, Feature::amx_fp8); + enable(amx_feature_flags_eax, 6, Feature::amx_tf32); + enable(amx_feature_flags_eax, 7, Feature::amx_avx512); + enable(amx_feature_flags_eax, 8, Feature::amx_movrs); + } + } + + if os_apx_support { + enable(extended_features_edx_leaf_1, 21, Feature::apxf); + } + // Only if the OS and the CPU support saving/restoring the AVX // registers we enable `xsave` support: if os_avx_support { @@ -236,9 +258,10 @@ pub(crate) fn detect_features() -> cache::Initializer { enable(extended_features_ebx, 5, Feature::avx2); // "Short" versions of AVX512 instructions - enable(extended_features_eax_leaf_1, 4, Feature::avxvnni); - enable(extended_features_eax_leaf_1, 23, Feature::avxifma); - enable(extended_features_edx_leaf_1, 4, Feature::avxvnniint8); + let avxvnni = enable(extended_features_eax_leaf_1, 4, Feature::avxvnni); + let avxvnniint8 = enable(extended_features_eax_leaf_1, 23, Feature::avxifma); + let avxvnniint16 = + enable(extended_features_edx_leaf_1, 4, Feature::avxvnniint8); enable(extended_features_edx_leaf_1, 5, Feature::avxneconvert); enable(extended_features_edx_leaf_1, 10, Feature::avxvnniint16); @@ -269,37 +292,18 @@ pub(crate) fn detect_features() -> cache::Initializer { enable(extended_features_edx, 8, Feature::avx512vp2intersect); enable(extended_features_edx, 23, Feature::avx512fp16); enable(extended_features_eax_leaf_1, 5, Feature::avx512bf16); - } - } - if os_amx_support { - enable(extended_features_edx, 24, Feature::amx_tile); - enable(extended_features_edx, 25, Feature::amx_int8); - enable(extended_features_edx, 22, Feature::amx_bf16); - enable(extended_features_eax_leaf_1, 21, Feature::amx_fp16); - enable(extended_features_edx_leaf_1, 8, Feature::amx_complex); + let avx10_1 = enable(extended_features_edx_leaf_1, 19, Feature::avx10_1); + if avx10_1 { + let CpuidResult { ebx, .. } = __cpuid(0x24); + let avx10_version = ebx & 0xff; - if max_basic_leaf >= 0x1e { - let CpuidResult { eax: amx_feature_flags_eax, .. } = - __cpuid_count(0x1e_u32, 1); - - enable(amx_feature_flags_eax, 4, Feature::amx_fp8); - enable(amx_feature_flags_eax, 6, Feature::amx_tf32); - enable(amx_feature_flags_eax, 7, Feature::amx_avx512); - enable(amx_feature_flags_eax, 8, Feature::amx_movrs); - } - } - - if os_apx_support { - enable(extended_features_edx_leaf_1, 21, Feature::apxf); - } - - let avx10_1 = enable(extended_features_edx_leaf_1, 19, Feature::avx10_1); - if avx10_1 { - let CpuidResult { ebx, .. } = __cpuid(0x24); - let avx10_version = ebx & 0xff; - if avx10_version >= 2 { - value.set(Feature::avx10_2 as u32); + // AVX10.2 supports masked versions of dot-product instructions available in avxvnni etc, + // so it doesn't make sense to have it without the unmasked versions + if avx10_version >= 2 && avxvnni && avxvnniint8 && avxvnniint16 { + value.set(Feature::avx10_2 as u32); + } + } } } } diff --git a/library/stdarch/crates/core_arch/src/mips/msa.rs b/library/stdarch/crates/core_arch/src/mips/msa.rs index 563e121a7bad..6246433da558 100644 --- a/library/stdarch/crates/core_arch/src/mips/msa.rs +++ b/library/stdarch/crates/core_arch/src/mips/msa.rs @@ -9187,7 +9187,6 @@ mod tests { core_arch::{mips::msa::*, simd::*}, mem, }; - use std::{f32, f64}; use stdarch_test::simd_test; #[simd_test(enable = "msa")] diff --git a/library/stdarch/crates/core_arch/src/nvptx/packed.rs b/library/stdarch/crates/core_arch/src/nvptx/packed.rs index 856aeea4b686..1c7e81268fc9 100644 --- a/library/stdarch/crates/core_arch/src/nvptx/packed.rs +++ b/library/stdarch/crates/core_arch/src/nvptx/packed.rs @@ -99,7 +99,7 @@ pub unsafe fn f16x2_neg(a: f16x2) -> f16x2 { #[cfg_attr(test, assert_instr(min.f16x2))] #[unstable(feature = "stdarch_nvptx", issue = "111199")] pub unsafe fn f16x2_min(a: f16x2, b: f16x2) -> f16x2 { - simd_fmin(a, b) + simd_minimum_number_nsz(a, b) } /// Find the minimum of two values, NaNs pass through. @@ -123,7 +123,7 @@ pub unsafe fn f16x2_min_nan(a: f16x2, b: f16x2) -> f16x2 { #[cfg_attr(test, assert_instr(max.f16x2))] #[unstable(feature = "stdarch_nvptx", issue = "111199")] pub unsafe fn f16x2_max(a: f16x2, b: f16x2) -> f16x2 { - simd_fmax(a, b) + simd_maximum_number_nsz(a, b) } /// Find the maximum of two values, NaNs pass through. diff --git a/library/stdarch/crates/core_arch/src/x86/sse.rs b/library/stdarch/crates/core_arch/src/x86/sse.rs index c6531e839a7d..867387290119 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse.rs @@ -208,7 +208,7 @@ pub fn _mm_min_ss(a: __m128, b: __m128) -> __m128 { #[cfg_attr(test, assert_instr(minps))] #[stable(feature = "simd_x86", since = "1.27.0")] pub fn _mm_min_ps(a: __m128, b: __m128) -> __m128 { - // See the `test_mm_min_ps` test why this can't be implemented using `simd_fmin`. + // See the `test_mm_min_ps` test why this can't be implemented using `simd_minimum_number_nsz`. unsafe { minps(a, b) } } @@ -234,7 +234,7 @@ pub fn _mm_max_ss(a: __m128, b: __m128) -> __m128 { #[cfg_attr(test, assert_instr(maxps))] #[stable(feature = "simd_x86", since = "1.27.0")] pub fn _mm_max_ps(a: __m128, b: __m128) -> __m128 { - // See the `test_mm_min_ps` test why this can't be implemented using `simd_fmax`. + // See the `test_mm_min_ps` test why this can't be implemented using `simd_maximum_number_nsz`. unsafe { maxps(a, b) } } @@ -2227,11 +2227,11 @@ fn test_mm_min_ps() { let r = _mm_min_ps(a, b); assert_eq_m128(r, _mm_setr_ps(-100.0, 5.0, 0.0, -10.0)); - // `_mm_min_ps` can **not** be implemented using the `simd_min` rust intrinsic. `simd_min` - // is lowered by the llvm codegen backend to `llvm.minnum.v*` llvm intrinsic. This intrinsic - // doesn't specify how -0.0 is handled. Unfortunately it happens to behave different from - // the `minps` x86 instruction on x86. The `llvm.minnum.v*` llvm intrinsic equals - // `r1` to `a` and `r2` to `b`. + // `_mm_min_ps` can **not** be implemented using the `simd_minimum_number_nsz` rust + // intrinsic. That intrinsic is lowered by the llvm codegen backend to `llvm.minimumnum.v*` + // llvm intrinsic with the `nsz` attribute. The `nsz` attribute means -0.0 is handled + // non-deterministically. The `minps` x86 instruction however has a deterministic semantics + // for signed zeros. let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0); let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0); let r1 = _mm_min_ps(a, b).as_f32x4().to_bits(); diff --git a/rustfmt.toml b/rustfmt.toml index 910eea103798..60808190d8a5 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -20,7 +20,6 @@ ignore = [ "/tests/incremental/", # These tests are somewhat sensitive to source code layout. "/tests/pretty/", # These tests are very sensitive to source code layout. "/tests/run-make/export", # These tests contain syntax errors. - "/tests/run-make/translation/test.rs", # This test contains syntax errors. "/tests/rustdoc-html/", # Some have syntax errors, some are whitespace-sensitive. "/tests/rustdoc-gui/", # Some tests are sensitive to source code layout. "/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive. @@ -55,8 +54,4 @@ ignore = [ # Code automatically generated and included. "compiler/rustc_codegen_gcc/src/intrinsic/archs.rs", "compiler/rustc_codegen_gcc/example", - - # Rustfmt doesn't support use closures yet - "tests/mir-opt/ergonomic-clones/closure.rs", - "tests/codegen-llvm/ergonomic-clones/closure.rs", ] diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index f9499d9927f2..a6d8d4610521 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -472,18 +472,18 @@ dependencies = [ [[package]] name = "objc2-core-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags", ] [[package]] name = "objc2-io-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ "libc", "objc2-core-foundation", @@ -743,9 +743,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.38.2" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efc19935b4b66baa6f654ac7924c192f55b175c00a7ab72410fc24284dacda8" +checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" dependencies = [ "libc", "memchr", @@ -757,9 +757,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" dependencies = [ "filetime", "libc", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 0019e9e6d92e..9b1039bbc4f6 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -50,14 +50,14 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" sha2 = "0.10" -tar = { version = "0.4.44", default-features = false } +tar = { version = "0.4.45", default-features = false } termcolor = "1.4" toml = "0.5" walkdir = "2.4" xz2 = "0.1" # Dependencies needed by the build-metrics feature -sysinfo = { version = "0.38.2", default-features = false, optional = true, features = ["system"] } +sysinfo = { version = "0.38.4", default-features = false, optional = true, features = ["system"] } # Dependencies needed by the `tracing` feature chrono = { version = "0.4", default-features = false, optional = true, features = ["now", "std"] } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 105e41ca45f6..b893bb3f5821 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1259,7 +1259,12 @@ class RustBuild(object): def parse_args(args): """Parse the command line arguments that the python script needs.""" - parser = argparse.ArgumentParser(add_help=False) + + # Pass allow_abbrev=False to remove support for inexact matches (e.g., + # `--json` turning on `--json-output`). The argument list here is partial, + # most flags are matched in the Rust bootstrap code. This prevents the the + # default ambiguity checks in argparse from functioning correctly. + parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False) parser.add_argument("-h", "--help", action="store_true") parser.add_argument("--config") parser.add_argument("--build-dir") diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 2ca19f082693..dd68964b7568 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/153179 +Last change is for: https://github.com/rust-lang/rust/pull/154485 diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 5f956f03ecb1..d675181f1941 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -64,7 +64,7 @@ check-aux: library/core \ library/alloc \ $(BOOTSTRAP_ARGS) \ - --no-doc + --tests # exclude doc tests # Some doctests use file system operations to demonstrate dealing with `Result`, # so we have to run them with isolation disabled. $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 0c607cb6ba6f..a2cf801afa11 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -631,11 +631,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { let version = get_llvm_version(builder, llvm_config); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) - && major >= 20 + && major >= 21 { return; } - panic!("\n\nbad LLVM version: {version}, need >=20\n\n") + panic!("\n\nbad LLVM version: {version}, need >=21\n\n") } fn configure_cmake( @@ -1151,12 +1151,18 @@ fn run(self, builder: &Builder<'_>) -> Self::Output { let LlvmResult { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); + // Enzyme links against LLVM. If we update the LLVM submodule libLLVM might get a new + // version number, in which case Enzyme will now fail to find LLVM. By including the LLVM + // hash into the Enzyme hash we force a rebuild of Enzyme when updating LLVM. + let enzyme_hash_input = builder.in_tree_llvm_info.sha().unwrap_or_default().to_owned() + + builder.enzyme_info.sha().unwrap_or_default(); + static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { generate_smart_stamp_hash( builder, &builder.config.src.join("src/tools/enzyme"), - builder.enzyme_info.sha().unwrap_or_default(), + &enzyme_hash_input, ) }); @@ -1552,6 +1558,8 @@ fn supported_sanitizers( &["asan", "dfsan", "lsan", "msan", "safestack", "tsan", "rtsan"], ), "x86_64-unknown-linux-gnuasan" => common_libs("linux", "x86_64", &["asan"]), + "x86_64-unknown-linux-gnumsan" => common_libs("linux", "x86_64", &["msan"]), + "x86_64-unknown-linux-gnutsan" => common_libs("linux", "x86_64", &["tsan"]), "x86_64-unknown-linux-musl" => { common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) } diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 1f6c2facc9c2..2079f3a19019 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -358,6 +358,8 @@ fn make_run(run: RunConfig<'_>) { } } +/// The build step for generating the tables in `core/src/char/unicode/unicode_data.rs` +/// and the tests in `library/coretests/tests/unicode/test_data.rs`. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct UnicodeTableGenerator; @@ -375,7 +377,9 @@ fn make_run(run: RunConfig<'_>) { fn run(self, builder: &Builder<'_>) { let mut cmd = builder.tool_cmd(Tool::UnicodeTableGenerator); + // Generated files that are checked into git: cmd.arg(builder.src.join("library/core/src/unicode/unicode_data.rs")); + cmd.arg(builder.src.join("library/coretests/tests/unicode/test_data.rs")); cmd.run(builder); } } diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 7dfd566a58cc..85c23ac18e76 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -5,14 +5,17 @@ //! allows setting up things that cannot be simply captured inside the bootstrap.toml, in addition to //! leading people away from manually editing most of the bootstrap.toml values. +use std::collections::BTreeMap; use std::env::consts::EXE_SUFFIX; use std::fmt::Write as _; use std::fs::File; use std::io::Write; use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf}; use std::str::FromStr; +use std::sync::LazyLock; use std::{fmt, fs, io}; +use serde_derive::{Deserialize, Serialize}; use sha2::Digest; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; @@ -529,7 +532,8 @@ fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result< } /// Handles editor-specific setup differences -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] enum EditorKind { Emacs, Helix, @@ -538,6 +542,13 @@ enum EditorKind { Zed, } +static PARSED_HASHES: LazyLock>> = LazyLock::new(|| { + const ALL_HASHES: &str = include_str!("setup/hashes.json"); + let mut map: BTreeMap<_, Vec<_>> = serde_json::from_str(ALL_HASHES).unwrap(); + map.insert(EditorKind::Vim, map.get(&EditorKind::VsCode).unwrap().clone()); + map +}); + impl EditorKind { // Used in `./tests.rs`. #[cfg(test)] @@ -588,56 +599,7 @@ fn prompt_user() -> io::Result> { /// New entries should be appended whenever this is updated so we can detect /// outdated vs. user-modified settings files. fn hashes(&self) -> &'static [&'static str] { - match self { - EditorKind::Emacs => &[ - "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", - "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", - "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088", - "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", - "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", - "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1", - "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308", - "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938", - ], - EditorKind::Helix => &[ - "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", - "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", - "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", - "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", - "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1", - "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6", - "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6", - ], - EditorKind::Vim | EditorKind::VsCode => &[ - "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", - "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", - "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", - "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", - "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", - "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", - "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", - "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", - "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", - "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", - "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", - "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", - "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", - "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", - "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", - "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798", - "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc", - ], - EditorKind::Zed => &[ - "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", - "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909", - "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", - "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", - "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382", - "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f", - "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9", - "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568", - ], - } + PARSED_HASHES.get(self).unwrap() } fn settings_path(&self, config: &Config) -> PathBuf { diff --git a/src/bootstrap/src/core/build_steps/setup/hashes.json b/src/bootstrap/src/core/build_steps/setup/hashes.json new file mode 100644 index 000000000000..067c8fffe0d5 --- /dev/null +++ b/src/bootstrap/src/core/build_steps/setup/hashes.json @@ -0,0 +1,73 @@ +{ + "emacs": [ + "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", + "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", + "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088", + "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", + "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", + "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1", + "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308", + "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938" + ], + "helix": [ + "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", + "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", + "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", + "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", + "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1", + "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6", + "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6", + "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed" + ], + "vim": [ + "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", + "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", + "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", + "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", + "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", + "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", + "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", + "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", + "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", + "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", + "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", + "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", + "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", + "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", + "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798", + "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc", + "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd" + ], + "vscode": [ + "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", + "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", + "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", + "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", + "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", + "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", + "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", + "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", + "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", + "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", + "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", + "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", + "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", + "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", + "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798", + "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc", + "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd" + ], + "zed": [ + "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", + "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909", + "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", + "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", + "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382", + "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f", + "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9", + "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568", + "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951" + ] +} diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs index e8f83ff75e40..57b549286661 100644 --- a/src/bootstrap/src/core/build_steps/setup/tests.rs +++ b/src/bootstrap/src/core/build_steps/setup/tests.rs @@ -1,3 +1,8 @@ +use std::collections::BTreeMap; +use std::fs::File; +use std::io::Write; +use std::path::Path; + use sha2::Digest; use super::EditorKind; @@ -5,16 +10,41 @@ #[test] fn check_matching_settings_hash() { + // Needs to be a btree so we serialize in a deterministic order. + let mut mismatched = BTreeMap::new(); + for editor in EditorKind::ALL { let mut hasher = sha2::Sha256::new(); hasher.update(&editor.settings_template()); - let hash = hex_encode(hasher.finalize().as_slice()); - assert_eq!( - &hash, - editor.hashes().last().unwrap(), - "Update `EditorKind::hashes()` with the new hash of `{}` for `EditorKind::{:?}`", - editor.settings_template(), - editor, - ); + let actual = hex_encode(hasher.finalize().as_slice()); + let expected = *editor.hashes().last().unwrap(); + + if expected != actual { + mismatched.insert(editor, (expected, actual)); + } + } + + if mismatched.is_empty() { + return; + } + + if option_env!("INSTA_UPDATE").is_some_and(|s| s != "0") { + let mut updated = super::PARSED_HASHES.clone(); + for (editor, (_, actual)) in &mismatched { + *updated.get_mut(editor).unwrap().last_mut().unwrap() = actual; + } + let hash_path = + Path::new(env!("CARGO_MANIFEST_DIR")).join("src/core/build_steps/setup/hashes.json"); + let mut hash_file = File::create(hash_path).unwrap(); + serde_json::to_writer_pretty(&mut hash_file, &updated).unwrap(); + hash_file.write_all(b"\n").unwrap(); + } else { + for (editor, (expected, actual)) in &mismatched { + eprintln!("recorded hash did not match actual hash: {expected} != {actual}"); + eprintln!( + "Run `x test --bless -- hash`, or manually update `setup/hashes.json` with the new hash of `{actual}` for `EditorKind::{editor:?}`" + ); + } + panic!("mismatched hashes"); } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 3b0e7b2e30af..7be45c5fa9d4 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -41,7 +41,7 @@ linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, }; use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; -use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, envify}; +use crate::{CLang, CodegenBackendKind, GitRepo, Mode, PathSet, TestTarget, envify}; mod compiletest; @@ -174,7 +174,7 @@ fn run(self, builder: &Builder<'_>) { ); run_cargo_test(cargo, &[], &[], "linkchecker self tests", bootstrap_host, builder); - if builder.doc_tests == DocTests::No { + if !builder.test_target.runs_doctests() { return; } @@ -827,15 +827,14 @@ fn run(self, builder: &Builder<'_>) { // We're not using `prepare_cargo_test` so we have to do this ourselves. // (We're not using that as the test-cargo-miri crate is not known to bootstrap.) - match builder.doc_tests { - DocTests::Yes => {} - DocTests::No => { - cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"]); + match builder.test_target { + TestTarget::AllTargets => { + cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"]) } - DocTests::Only => { - cargo.arg("--doc"); - } - } + TestTarget::Default => &mut cargo, + TestTarget::DocOnly => cargo.arg("--doc"), + TestTarget::Tests => cargo.arg("--tests"), + }; cargo.arg("--").args(builder.config.test_args()); // Finally, run everything. @@ -1213,7 +1212,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { fn is_default_step(builder: &Builder<'_>) -> bool { builder.config.nodejs.is_some() - && builder.doc_tests != DocTests::Only + && builder.test_target != TestTarget::DocOnly && get_browser_ui_test_version(builder).is_some() } @@ -1303,7 +1302,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { } fn is_default_step(builder: &Builder<'_>) -> bool { - builder.doc_tests != DocTests::Only + builder.test_target != TestTarget::DocOnly } fn make_run(run: RunConfig<'_>) { @@ -1862,7 +1861,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { } fn run(self, builder: &Builder<'_>) { - if builder.doc_tests == DocTests::Only { + if builder.test_target == TestTarget::DocOnly { return; } @@ -2980,15 +2979,12 @@ fn prepare_cargo_test( cargo.arg("--message-format=json"); } - match builder.doc_tests { - DocTests::Only => { - cargo.arg("--doc"); - } - DocTests::No => { - cargo.args(["--bins", "--examples", "--tests", "--benches"]); - } - DocTests::Yes => {} - } + match builder.test_target { + TestTarget::AllTargets => cargo.args(["--bins", "--examples", "--tests", "--benches"]), + TestTarget::Default => &mut cargo, + TestTarget::DocOnly => cargo.arg("--doc"), + TestTarget::Tests => cargo.arg("--tests"), + }; for krate in crates { cargo.arg("-p").arg(krate); @@ -3319,7 +3315,7 @@ fn run(self, builder: &Builder<'_>) { builder.kind, "src/rustdoc-json-types", SourceType::InTree, - &[], + &["rkyv_0_8".to_owned()], ); // FIXME: this looks very wrong, libtest doesn't accept `-C` arguments and the quotes are fishy. @@ -3868,7 +3864,7 @@ fn make_run(run: RunConfig<'_>) { let host = run.build_triple(); let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host); - if builder.doc_tests == DocTests::Only { + if builder.test_target == TestTarget::DocOnly { return; } @@ -3989,7 +3985,7 @@ fn make_run(run: RunConfig<'_>) { let host = run.build_triple(); let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host); - if builder.doc_tests == DocTests::Only { + if builder.test_target == TestTarget::DocOnly { return; } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index d86159d3cc7e..e6148af61767 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -600,6 +600,12 @@ fn make_run(run: RunConfig<'_>) { } fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + builder.require_submodule( + "src/doc/reference", + Some("error_index_generator requires mdbook-spec"), + ); + builder + .require_submodule("src/doc/book", Some("error_index_generator requires mdbook-trpl")); builder.ensure(ToolBuild { build_compiler: self.compilers.build_compiler, target: self.compilers.target(), diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 16065cbdae1f..b4ef00bd4ea0 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -122,6 +122,9 @@ pub fn new( cmd_kind: Kind, ) -> Cargo { let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind); + if target.synthetic { + cargo.arg("-Zjson-target-spec"); + } match cmd_kind { // No need to configure the target linker for these command types. @@ -165,7 +168,11 @@ pub fn new_for_mir_opt_tests( target: TargetSelection, cmd_kind: Kind, ) -> Cargo { - builder.cargo(compiler, mode, source_type, target, cmd_kind) + let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind); + if target.synthetic { + cargo.arg("-Zjson-target-spec"); + } + cargo } pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 17f256188e1b..2c3b5251e12f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -415,6 +415,12 @@ pub(crate) fn parse_inner( "flags.exclude" = ?flags_exclude ); + if flags_cmd.no_doc() { + eprintln!( + "WARN: `x.py test --no-doc` is renamed to `--all-targets`. `--no-doc` will be removed in the near future. Additionally `--tests` is added which only executes unit and integration tests." + ) + } + // Set config values based on flags. let mut exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast()); exec_ctx.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled }); diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index bf089d25ffec..1665448e6d3c 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -15,7 +15,7 @@ use crate::core::builder::{Builder, Kind}; use crate::core::config::Config; use crate::core::config::target_selection::{TargetSelectionList, target_selection_list}; -use crate::{Build, CodegenBackendKind, DocTests}; +use crate::{Build, CodegenBackendKind, TestTarget}; #[derive(Copy, Clone, Default, Debug, ValueEnum)] pub enum Color { @@ -357,7 +357,7 @@ pub enum Subcommand { should be compiled and run. For example: ./x.py test tests/ui ./x.py test library/std --test-args hash_map - ./x.py test library/std --stage 0 --no-doc + ./x.py test library/std --stage 0 --all-targets ./x.py test tests/ui --bless ./x.py test tests/ui --compare-mode next-solver Note that `test tests/* --stage N` does NOT depend on `build compiler/rustc --stage N`; @@ -382,11 +382,14 @@ pub enum Subcommand { #[arg(long, value_name = "ARGS", allow_hyphen_values(true))] compiletest_rustc_args: Vec, #[arg(long)] - /// do not run doc tests - no_doc: bool, + /// Run all test targets (no doc tests) + all_targets: bool, #[arg(long)] - /// only run doc tests + /// Only run doc tests doc: bool, + /// Only run unit and integration tests + #[arg(long)] + tests: bool, #[arg(long)] /// whether to automatically update stderr/stdout files bless: bool, @@ -425,6 +428,11 @@ pub enum Subcommand { #[arg(long)] /// Ignore `//@ ignore-backends` directives. bypass_ignore_backends: bool, + + /// Deprecated. Use `--all-targets` or `--tests` instead. + #[arg(long)] + #[doc(hidden)] + no_doc: bool, }, /// Build and run some test suites *in Miri* Miri { @@ -436,11 +444,19 @@ pub enum Subcommand { /// (e.g. libtest, compiletest or rustdoc) test_args: Vec, #[arg(long)] - /// do not run doc tests - no_doc: bool, + /// Run all test targets (no doc tests) + all_targets: bool, #[arg(long)] - /// only run doc tests + /// Only run doc tests doc: bool, + /// Only run unit and integration tests + #[arg(long)] + tests: bool, + + /// Deprecated. Use `--all-targets` or `--tests` instead. + #[arg(long)] + #[doc(hidden)] + no_doc: bool, }, /// Build and run some benchmarks Bench { @@ -552,18 +568,31 @@ pub fn fail_fast(&self) -> bool { } } - pub fn doc_tests(&self) -> DocTests { + pub fn test_target(&self) -> TestTarget { match *self { - Subcommand::Test { doc, no_doc, .. } | Subcommand::Miri { no_doc, doc, .. } => { - if doc { - DocTests::Only - } else if no_doc { - DocTests::No - } else { - DocTests::Yes + Subcommand::Test { mut all_targets, doc, tests, no_doc, .. } + | Subcommand::Miri { mut all_targets, doc, tests, no_doc, .. } => { + // for backwards compatibility --no-doc keeps working + all_targets = all_targets || no_doc; + + match (all_targets, doc, tests) { + (true, true, _) | (true, _, true) | (_, true, true) => { + panic!("You can only set one of `--all-targets`, `--doc` and `--tests`.") + } + (true, false, false) => TestTarget::AllTargets, + (false, true, false) => TestTarget::DocOnly, + (false, false, true) => TestTarget::Tests, + (false, false, false) => TestTarget::Default, } } - _ => DocTests::Yes, + _ => TestTarget::Default, + } + } + + pub fn no_doc(&self) -> bool { + match *self { + Subcommand::Test { no_doc, .. } | Subcommand::Miri { no_doc, .. } => no_doc, + _ => false, } } diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs index 47f6d6f386df..8457607b897d 100644 --- a/src/bootstrap/src/core/config/target_selection.rs +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -142,7 +142,7 @@ impl SplitDebuginfo { pub fn default_for_platform(target: TargetSelection) -> Self { if target.contains("apple") { SplitDebuginfo::Unpacked - } else if target.is_windows() { + } else if target.is_msvc() { SplitDebuginfo::Packed } else { SplitDebuginfo::Off diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index ca8af279b92b..c4a6b68aedee 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -37,6 +37,8 @@ pub struct Finder { /// when the newly-bumped stage 0 compiler now knows about the formerly-missing targets. const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined + "x86_64-unknown-linux-gnumsan", + "x86_64-unknown-linux-gnutsan", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index b9a914f53cec..6af11d9ae0a8 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -177,13 +177,21 @@ fn from_str(s: &str) -> Result { } #[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub enum DocTests { - /// Run normal tests and doc tests (default). - Yes, - /// Do not run any doc tests. - No, +pub enum TestTarget { + /// Run unit, integration and doc tests (default). + Default, + /// Run unit, integration, doc tests, examples, bins, benchmarks (no doc tests). + AllTargets, /// Only run doc tests. - Only, + DocOnly, + /// Only run unit and integration tests. + Tests, +} + +impl TestTarget { + fn runs_doctests(&self) -> bool { + matches!(self, TestTarget::DocOnly | TestTarget::Default) + } } pub enum GitRepo { @@ -222,7 +230,7 @@ pub struct Build { in_tree_gcc_info: GitInfo, local_rebuild: bool, fail_fast: bool, - doc_tests: DocTests, + test_target: TestTarget, verbosity: usize, /// Build triple for the pre-compiled snapshot compiler. @@ -540,7 +548,7 @@ pub fn new(mut config: Config) -> Build { initial_sysroot: config.initial_sysroot.clone(), local_rebuild: config.local_rebuild, fail_fast: config.cmd.fail_fast(), - doc_tests: config.cmd.doc_tests(), + test_target: config.cmd.test_target(), verbosity: config.exec_ctx.verbosity as usize, host_target: config.host_target, @@ -875,6 +883,12 @@ fn rustc_features(&self, kind: Kind, target: TargetSelection, crates: &[String]) features.push("check_only"); } + if crates.iter().any(|c| c == "rustc_transmute") { + // for `x test rustc_transmute`, this feature isn't enabled automatically by a + // dependent crate. + features.push("rustc"); + } + // If debug logging is on, then we want the default for tracing: // https://github.com/tokio-rs/tracing/blob/3dd5c03d907afdf2c39444a29931833335171554/tracing/src/level_filters.rs#L26 // which is everything (including debug/trace/etc.) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 1077077cb97a..3ae2373e1da2 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -73,7 +73,7 @@ pub fn human_readable_changes(changes: &[ChangeInfo]) -> String { /// Keeps track of major changes made to the bootstrap configuration. /// /// If you make any major changes (such as adding new values or changing default values), -/// please ensure adding `ChangeInfo` to the end(because the list must be sorted by the merge date) +/// please ensure adding `ChangeInfo` to the end (because the list must be sorted by the merge date) /// of this list. pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ ChangeInfo { @@ -611,4 +611,14 @@ pub fn human_readable_changes(changes: &[ChangeInfo]) -> String { severity: ChangeSeverity::Info, summary: "New option `llvm.offload-clang-dir` to allow building an in-tree llvm offload and openmp runtime with an external clang.", }, + ChangeInfo { + change_id: 153143, + severity: ChangeSeverity::Warning, + summary: "`x.py test --no-doc` is renamed to `--all-targets`. Additionally `--tests` is added which only executes unit and integration tests.", + }, + ChangeInfo { + change_id: 154508, + severity: ChangeSeverity::Info, + summary: "`x.py` stopped accepting partial argument names. Use full names to avoid errors.", + }, ]; diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index b264c961b659..f9b0d2dbb209 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -7,6 +7,7 @@ //! relevant to command execution in the bootstrap process. This includes settings such as //! dry-run mode, verbosity level, and failure behavior. +use std::backtrace::{Backtrace, BacktraceStatus}; use std::collections::HashMap; use std::ffi::{OsStr, OsString}; use std::fmt::{Debug, Formatter}; @@ -930,6 +931,16 @@ enum FailureReason { if stderr.captures() { writeln!(error_message, "\n--- STDERR vvv\n{}", output.stderr().trim()).unwrap(); } + let backtrace = if exec_ctx.verbosity > 1 { + Backtrace::force_capture() + } else if matches!(command.failure_behavior, BehaviorOnFailure::Ignore) { + Backtrace::disabled() + } else { + Backtrace::capture() + }; + if matches!(backtrace.status(), BacktraceStatus::Captured) { + writeln!(error_message, "\n--- BACKTRACE vvv\n{backtrace}").unwrap(); + } match command.failure_behavior { BehaviorOnFailure::DelayFail => { diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 245ab31fa644..cc93761e9604 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -200,12 +200,14 @@ fn equivalent_modulo_carve_out(pr_job: &Job, auto_job: &Job) -> anyhow::Result<( equivalent_modulo_carve_out(pr_job, auto_job)?; } - // Auto CI jobs must all "fail-fast" to avoid wasting Auto CI resources. For instance, `tidy`. + // Auto CI should "fail-fast" to avoid wasting Auto CI resources. + // However, some experimental auto jobs can be made optional, for example if we are unsure about + // their flakiness. Those have to be prefixed with `optional-`. for auto_job in &db.auto_jobs { - if auto_job.continue_on_error == Some(true) { + if auto_job.continue_on_error == Some(true) && !auto_job.name.starts_with("optional-") { return Err(anyhow!( - "Auto job `{}` cannot have `continue_on_error: true`", - auto_job.name + "Auto job `{job}` cannot have `continue_on_error: true`. If the job should be optional, name it `optional-{job}`.", + job = auto_job.name )); } } diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 59cea7aa79a5..6e5a38a3c515 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -14,9 +14,9 @@ To run a specific CI job locally, you can use the `citool` Rust crate: cargo run --manifest-path src/ci/citool/Cargo.toml run-local ``` -For example, to run the `x86_64-gnu-llvm-20-1` job: +For example, to run the `x86_64-gnu-llvm-21-1` job: ``` -cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-20-1 +cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-21-1 ``` The job will output artifacts in an `obj/` dir at the root of a repository. Note @@ -27,10 +27,10 @@ Docker image executed in the given CI job. while locally, to the `obj/` directory. This is primarily to prevent strange linker errors when using multiple Docker images. -For some Linux workflows (for example `x86_64-gnu-llvm-20-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-20-3` workflow, you can run the following script: +For some Linux workflows (for example `x86_64-gnu-llvm-21-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-21-3` workflow, you can run the following script: ``` -DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-20 +DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-21 ``` ## Local Development @@ -261,9 +261,9 @@ For targets: `loongarch64-unknown-linux-gnu` - Target options > Bitness = 64-bit - Operating System > Target OS = linux - Operating System > Linux kernel version = 5.19.16 -- Binary utilities > Version of binutils = 2.42 +- Binary utilities > Version of binutils = 2.45 - C-library > glibc version = 2.36 -- C compiler > gcc version = 14.2.0 +- C compiler > gcc version = 15.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM ### `loongarch64-unknown-linux-musl.defconfig` @@ -277,9 +277,9 @@ For targets: `loongarch64-unknown-linux-musl` - Target options > Bitness = 64-bit - Operating System > Target OS = linux - Operating System > Linux kernel version = 5.19.16 -- Binary utilities > Version of binutils = 2.42 +- Binary utilities > Version of binutils = 2.45 - C-library > musl version = 1.2.5 -- C compiler > gcc version = 14.2.0 +- C compiler > gcc version = 15.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM ### `mips-linux-gnu.defconfig` diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-21/Dockerfile similarity index 94% rename from src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile rename to src/ci/docker/host-aarch64/aarch64-gnu-llvm-21/Dockerfile index 5dbca7e7b675..c364ac27aaa5 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-21/Dockerfile @@ -15,8 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ sudo \ gdb \ - llvm-20-tools \ - llvm-20-dev \ + llvm-21-tools \ + llvm-21-dev \ libedit-dev \ libssl-dev \ pkg-config \ @@ -42,7 +42,7 @@ ENV EXTERNAL_LLVM="1" # Using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS="--build=aarch64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-20 \ + --llvm-root=/usr/lib/llvm-21 \ --enable-llvm-link-shared \ --set rust.randomize-layout=true \ --set rust.thin-lto-import-instr-limit=10" diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 7b73326e3590..25565564e8da 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -16,15 +16,14 @@ ENV TARGETS=$TARGETS,i686-linux-android ENV TARGETS=$TARGETS,aarch64-linux-android ENV TARGETS=$TARGETS,x86_64-linux-android -ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ +ENV RUST_CONFIGURE_ARGS="--enable-extended \ --enable-profiler \ --android-ndk=/android/ndk/ \ - --disable-docs + --disable-docs" ENV PATH=$PATH:/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin -ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS +ENV SCRIPT="python3 ../x.py dist --host= --target $TARGETS" COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile index a62f98b21d22..31d009b6969a 100644 --- a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile @@ -57,10 +57,9 @@ RUN ln -s /usr/lib32/libgcc_s.so.1 /musl-i686/lib/ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS \ - --musl-root-i586=/musl-i586 \ +ENV RUST_CONFIGURE_ARGS="--musl-root-i586=/musl-i586 \ --musl-root-i686=/musl-i686 \ - --disable-docs + --disable-docs" # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our @@ -73,6 +72,5 @@ ENV CFLAGS_i586_unknown_linux_musl=-Wa,-mrelax-relocations=no ENV TARGETS=i586-unknown-linux-gnu,i686-unknown-linux-musl -ENV SCRIPT \ - python3 ../x.py --stage 2 test --host='' --target $TARGETS && \ - python3 ../x.py dist --host='' --target $TARGETS,i586-unknown-linux-musl +ENV SCRIPT="python3 ../x.py --stage 2 test --host= --target $TARGETS && \ + python3 ../x.py dist --host= --target $TARGETS,i586-unknown-linux-musl" diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index ea5b208a7c1d..8165258cc49f 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -70,15 +70,14 @@ RUN sh /scripts/sccache.sh ENV HOSTS=i686-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS \ - --enable-full-tools \ +ENV RUST_CONFIGURE_ARGS="--enable-full-tools \ --enable-sanitizers \ --enable-profiler \ --set target.i686-unknown-linux-gnu.linker=clang \ --build=i686-unknown-linux-gnu \ --set llvm.ninja=false \ - --set rust.jemalloc -ENV SCRIPT python3 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS + --set rust.jemalloc" +ENV SCRIPT="python3 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS" ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=clang # This was added when we switched from gcc to clang. It's not clear why this is @@ -89,17 +88,17 @@ ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=clang # misaligned stack access. # # Added in #50200 there's some more logs there -ENV CFLAGS -mstackrealign +ENV CFLAGS="-mstackrealign" # When we build cargo in this container, we don't want it to use the system # libcurl, instead it should compile its own. -ENV LIBCURL_NO_PKG_CONFIG 1 +ENV LIBCURL_NO_PKG_CONFIG="1" # There was a bad interaction between "old" 32-bit binaries on current 64-bit # kernels with selinux enabled, where ASLR mmap would sometimes choose a low # address and then block it for being below `vm.mmap_min_addr` -> `EACCES`. # This is probably a kernel bug, but setting `ulimit -Hs` works around it. # See also `src/ci/run.sh` where this takes effect. -ENV SET_HARD_RLIMIT_STACK 1 +ENV SET_HARD_RLIMIT_STACK="1" -ENV DIST_REQUIRE_ALL_TOOLS 1 +ENV DIST_REQUIRE_ALL_TOOLS="1" diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile index 96acc5e97e94..3ee8cb9ed7e8 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile @@ -45,14 +45,13 @@ ENV TARGETS=$HOSTS ENV TARGETS=$TARGETS,loongarch64-unknown-none ENV TARGETS=$TARGETS,loongarch64-unknown-none-softfloat -ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ +ENV RUST_CONFIGURE_ARGS="--enable-extended \ --enable-full-tools \ --enable-profiler \ --enable-sanitizers \ --disable-docs \ --set rust.jemalloc \ --set rust.lto=thin \ - --set rust.codegen-units=1 + --set rust.codegen-units=1" -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $TARGETS +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $TARGETS" diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig index bb1d2d1f8038..9ff9791c0b2c 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/loongarch64-unknown-linux-gnu.defconfig @@ -12,7 +12,7 @@ CT_TARGET_LDFLAGS="-mcmodel=medium" CT_KERNEL_LINUX=y CT_LINUX_V_5_19=y CT_GLIBC_V_2_36=y -CT_BINUTILS_V_2_42=y -CT_GCC_V_14=y +CT_BINUTILS_V_2_45=y +CT_GCC_V_15=y CT_CC_GCC_ENABLE_DEFAULT_PIE=y CT_CC_LANG_CXX=y diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile index 44efc1089017..54c1869a2a04 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile @@ -27,8 +27,7 @@ ENV CC_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-gcc \ ENV HOSTS=loongarch64-unknown-linux-musl -ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ +ENV RUST_CONFIGURE_ARGS="--enable-extended \ --enable-full-tools \ --enable-profiler \ --enable-sanitizers \ @@ -37,6 +36,6 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.lto=thin \ --set rust.codegen-units=1 \ --set target.loongarch64-unknown-linux-musl.crt-static=false \ - --musl-root-loongarch64=/x-tools/loongarch64-unknown-linux-musl/loongarch64-unknown-linux-musl/sysroot/usr + --musl-root-loongarch64=/x-tools/loongarch64-unknown-linux-musl/loongarch64-unknown-linux-musl/sysroot/usr" -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig index aa1696e131d4..8c1562744fb5 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig +++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig @@ -13,8 +13,8 @@ CT_KERNEL_LINUX=y CT_LINUX_V_5_19=y CT_LIBC_MUSL=y CT_MUSL_V_1_2_5=y -CT_BINUTILS_V_2_42=y -CT_GCC_V_14=y +CT_BINUTILS_V_2_45=y +CT_GCC_V_15=y CT_CC_GCC_ENABLE_DEFAULT_PIE=y CT_CC_LANG_CXX=y CT_GETTEXT_NEEDED=y diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile index 4a090dcdd508..3d7f5f81fbec 100644 --- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile @@ -26,5 +26,5 @@ ENV \ ENV HOSTS=mips-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile index 18b0375f4008..3c798d737a48 100644 --- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile @@ -26,5 +26,5 @@ ENV \ ENV HOSTS=mips64-unknown-linux-gnuabi64 -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile index 87407203880b..32fd634555c2 100644 --- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile @@ -26,5 +26,5 @@ ENV \ ENV HOSTS=mips64el-unknown-linux-gnuabi64 -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile index 553f6ea86b72..73ab0cf5bab6 100644 --- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile @@ -26,5 +26,5 @@ ENV \ ENV HOSTS=mipsel-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile index adeaf809f420..f97092e9dd1f 100644 --- a/src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile @@ -40,14 +40,13 @@ ENV \ AR_aarch64_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \ CXX_aarch64_unknown_linux_ohos=/usr/local/bin/aarch64-unknown-linux-ohos-clang++.sh -ENV RUST_CONFIGURE_ARGS \ - --enable-profiler \ +ENV RUST_CONFIGURE_ARGS="--enable-profiler \ --disable-docs \ --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \ --enable-extended \ - --enable-sanitizers + --enable-sanitizers" -ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS +ENV SCRIPT="python3 ../x.py dist --host=$TARGETS --target $TARGETS" COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile index 98e402adf2a6..e3352e52d691 100644 --- a/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile @@ -40,14 +40,13 @@ ENV \ AR_x86_64_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \ CXX_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang++.sh -ENV RUST_CONFIGURE_ARGS \ - --enable-profiler \ +ENV RUST_CONFIGURE_ARGS="--enable-profiler \ --disable-docs \ --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \ --enable-extended \ - --enable-sanitizers + --enable-sanitizers" -ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS +ENV SCRIPT="python3 ../x.py dist --host=$TARGETS --target $TARGETS" COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile index 7081d9527f06..825392414671 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile @@ -26,5 +26,5 @@ ENV \ ENV HOSTS=powerpc-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --enable-profiler --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile index 046406224c34..ad0e21019017 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile @@ -26,5 +26,5 @@ ENV \ ENV HOSTS=powerpc64-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --enable-profiler --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile index 7c8a1e657ac2..17783b9c7358 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile @@ -27,13 +27,12 @@ ENV \ ENV HOSTS=powerpc64-unknown-linux-musl -ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ +ENV RUST_CONFIGURE_ARGS="--enable-extended \ --enable-full-tools \ --enable-profiler \ --enable-sanitizers \ --disable-docs \ --set target.powerpc64-unknown-linux-musl.crt-static=false \ - --musl-root-powerpc64=/x-tools/powerpc64-unknown-linux-musl/powerpc64-unknown-linux-musl/sysroot/usr + --musl-root-powerpc64=/x-tools/powerpc64-unknown-linux-musl/powerpc64-unknown-linux-musl/sysroot/usr" -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile index e3ba51e8ffce..6a9573cb4231 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile @@ -27,11 +27,10 @@ ENV \ ENV HOSTS=powerpc64le-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ +ENV RUST_CONFIGURE_ARGS="--enable-extended \ --enable-full-tools \ --enable-profiler \ --enable-sanitizers \ - --disable-docs + --disable-docs" -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile index 601c8e905858..be16966fbe1b 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile @@ -27,13 +27,12 @@ ENV \ ENV HOSTS=powerpc64le-unknown-linux-musl -ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ +ENV RUST_CONFIGURE_ARGS="--enable-extended \ --enable-full-tools \ --enable-profiler \ --enable-sanitizers \ --disable-docs \ --set target.powerpc64le-unknown-linux-musl.crt-static=false \ - --musl-root-powerpc64le=/x-tools/powerpc64le-unknown-linux-musl/powerpc64le-unknown-linux-musl/sysroot/usr + --musl-root-powerpc64le=/x-tools/powerpc64le-unknown-linux-musl/powerpc64le-unknown-linux-musl/sysroot/usr" -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile index 4a66564a90ac..51d9e8a5798a 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile @@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-riscv64-linux/patches/ /tmp/patches/ COPY host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh @@ -30,5 +29,5 @@ ENV CC_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-gcc \ ENV HOSTS=riscv64gc-unknown-linux-gnu ENV TARGETS=riscv64gc-unknown-linux-gnu,riscv64a23-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --enable-profiler --disable-docs -ENV SCRIPT python3 ../x.py dist --target $TARGETS --host $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler --disable-docs" +ENV SCRIPT="python3 ../x.py dist --target $TARGETS --host $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch deleted file mode 100644 index f688eaf8029e..000000000000 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 4013baf99c38f7bca06a51f8301e8fb195ccfa33 Mon Sep 17 00:00:00 2001 -From: Jim Wilson -Date: Tue, 2 Jun 2020 11:19:39 -0700 -Subject: [PATCH] RISC-V: Make __divdi3 handle div by zero same as hardware. - -The ISA manual specifies that divide by zero always returns -1 as the result. -We were failing to do that when the dividend was negative. - -Original patch from Virginie Moser. - - libgcc/ - * config/riscv/div.S (__divdi3): For negative arguments, change bgez - to bgtz. ---- - libgcc/config/riscv/div.S | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S -index 151f8e273ac77..17234324c1e41 100644 ---- a/libgcc/config/riscv/div.S -+++ b/libgcc/config/riscv/div.S -@@ -107,10 +107,12 @@ FUNC_END (__umoddi3) - /* Handle negative arguments to __divdi3. */ - .L10: - neg a0, a0 -- bgez a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ -+ /* Zero is handled as a negative so that the result will not be inverted. */ -+ bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ -+ - neg a1, a1 -- j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ --.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ -+ j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ -+.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ - neg a1, a1 - .L12: - move t0, ra diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch deleted file mode 100644 index 1ae0ecf6cb5e..000000000000 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 45116f342057b7facecd3d05c2091ce3a77eda59 Mon Sep 17 00:00:00 2001 -From: Nelson Chu -Date: Mon, 29 Nov 2021 04:48:20 -0800 -Subject: [PATCH] RISC-V: jal cannot refer to a default visibility symbol for - shared object. - -This is the original binutils bugzilla report, -https://sourceware.org/bugzilla/show_bug.cgi?id=28509 - -And this is the first version of the proposed binutils patch, -https://sourceware.org/pipermail/binutils/2021-November/118398.html - -After applying the binutils patch, I get the unexpected error when -building libgcc, - -/scratch/nelsonc/riscv-gnu-toolchain/riscv-gcc/libgcc/config/riscv/div.S:42: -/scratch/nelsonc/build-upstream/rv64gc-linux/build-install/riscv64-unknown-linux-gnu/bin/ld: relocation R_RISCV_JAL against `__udivdi3' which may bind externally can not be used when making a shared object; recompile with -fPIC - -Therefore, this patch add an extra hidden alias symbol for __udivdi3, and -then use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead. -The solution is similar to glibc as follows, -https://sourceware.org/git/?p=glibc.git;a=commit;h=68389203832ab39dd0dbaabbc4059e7fff51c29b - -libgcc/ChangeLog: - - * config/riscv/div.S: Add the hidden alias symbol for __udivdi3, and - then use HIDDEN_JUMPTARGET to target it since it is non-preemptible. - * config/riscv/riscv-asm.h: Added new macros HIDDEN_JUMPTARGET and - HIDDEN_DEF. ---- - libgcc/config/riscv/div.S | 15 ++++++++------- - libgcc/config/riscv/riscv-asm.h | 6 ++++++ - 2 files changed, 14 insertions(+), 7 deletions(-) - -diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S -index c9bd7879c1e36..723c3b82e48c6 100644 ---- a/libgcc/config/riscv/div.S -+++ b/libgcc/config/riscv/div.S -@@ -40,7 +40,7 @@ FUNC_BEGIN (__udivsi3) - sll a0, a0, 32 - sll a1, a1, 32 - move t0, ra -- jal __udivdi3 -+ jal HIDDEN_JUMPTARGET(__udivdi3) - sext.w a0, a0 - jr t0 - FUNC_END (__udivsi3) -@@ -52,7 +52,7 @@ FUNC_BEGIN (__umodsi3) - srl a0, a0, 32 - srl a1, a1, 32 - move t0, ra -- jal __udivdi3 -+ jal HIDDEN_JUMPTARGET(__udivdi3) - sext.w a0, a1 - jr t0 - FUNC_END (__umodsi3) -@@ -95,11 +95,12 @@ FUNC_BEGIN (__udivdi3) - .L5: - ret - FUNC_END (__udivdi3) -+HIDDEN_DEF (__udivdi3) - - FUNC_BEGIN (__umoddi3) - /* Call __udivdi3(a0, a1), then return the remainder, which is in a1. */ - move t0, ra -- jal __udivdi3 -+ jal HIDDEN_JUMPTARGET(__udivdi3) - move a0, a1 - jr t0 - FUNC_END (__umoddi3) -@@ -111,12 +112,12 @@ FUNC_END (__umoddi3) - bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ - - neg a1, a1 -- j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ -+ j HIDDEN_JUMPTARGET(__udivdi3) /* Compute __udivdi3(-a0, -a1). */ - .L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ - neg a1, a1 - .L12: - move t0, ra -- jal __udivdi3 -+ jal HIDDEN_JUMPTARGET(__udivdi3) - neg a0, a0 - jr t0 - FUNC_END (__divdi3) -@@ -126,7 +127,7 @@ FUNC_BEGIN (__moddi3) - bltz a1, .L31 - bltz a0, .L32 - .L30: -- jal __udivdi3 /* The dividend is not negative. */ -+ jal HIDDEN_JUMPTARGET(__udivdi3) /* The dividend is not negative. */ - move a0, a1 - jr t0 - .L31: -@@ -134,7 +135,7 @@ FUNC_BEGIN (__moddi3) - bgez a0, .L30 - .L32: - neg a0, a0 -- jal __udivdi3 /* The dividend is hella negative. */ -+ jal HIDDEN_JUMPTARGET(__udivdi3) /* The dividend is hella negative. */ - neg a0, a1 - jr t0 - FUNC_END (__moddi3) -diff --git a/libgcc/config/riscv/riscv-asm.h b/libgcc/config/riscv/riscv-asm.h -index 8550707a4a26a..96dd85b0df2e5 100644 ---- a/libgcc/config/riscv/riscv-asm.h -+++ b/libgcc/config/riscv/riscv-asm.h -@@ -33,3 +33,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - #define FUNC_ALIAS(X,Y) \ - .globl X; \ - X = Y -+ -+#define CONCAT1(a, b) CONCAT2(a, b) -+#define CONCAT2(a, b) a ## b -+#define HIDDEN_JUMPTARGET(X) CONCAT1(__hidden_, X) -+#define HIDDEN_DEF(X) FUNC_ALIAS(HIDDEN_JUMPTARGET(X), X); \ -+ .hidden HIDDEN_JUMPTARGET(X) diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch deleted file mode 100644 index d267b961d347..000000000000 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 68389203832ab39dd0dbaabbc4059e7fff51c29b Mon Sep 17 00:00:00 2001 -From: Fangrui Song -Date: Thu, 28 Oct 2021 11:39:49 -0700 -Subject: [PATCH] riscv: Fix incorrect jal with HIDDEN_JUMPTARGET - -A non-local STV_DEFAULT defined symbol is by default preemptible in a -shared object. j/jal cannot target a preemptible symbol. On other -architectures, such a jump instruction either causes PLT [BZ #18822], or -if short-ranged, sometimes rejected by the linker (but not by GNU ld's -riscv port [ld PR/28509]). - -Use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead. - -With this patch, ld.so and libc.so can be linked with LLD if source -files are compiled/assembled with -mno-relax/-Wa,-mno-relax. - -Acked-by: Palmer Dabbelt -Reviewed-by: Adhemerval Zanella ---- - sysdeps/riscv/setjmp.S | 2 +- - sysdeps/unix/sysv/linux/riscv/setcontext.S | 5 +++-- - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/sysdeps/riscv/setjmp.S b/sysdeps/riscv/setjmp.S -index 0b92016b311..bec7ff80f49 100644 ---- a/sysdeps/riscv/setjmp.S -+++ b/sysdeps/riscv/setjmp.S -@@ -21,7 +21,7 @@ - - ENTRY (_setjmp) - li a1, 0 -- j __sigsetjmp -+ j HIDDEN_JUMPTARGET (__sigsetjmp) - END (_setjmp) - ENTRY (setjmp) - li a1, 1 -diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S -index 9510518750a..e44a68aad47 100644 ---- a/sysdeps/unix/sysv/linux/riscv/setcontext.S -+++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S -@@ -95,6 +95,7 @@ LEAF (__setcontext) - 99: j __syscall_error - - END (__setcontext) -+libc_hidden_def (__setcontext) - weak_alias (__setcontext, setcontext) - - LEAF (__start_context) -@@ -108,7 +109,7 @@ LEAF (__start_context) - /* Invoke subsequent context if present, else exit(0). */ - mv a0, s2 - beqz s2, 1f -- jal __setcontext --1: j exit -+ jal HIDDEN_JUMPTARGET (__setcontext) -+1: j HIDDEN_JUMPTARGET (exit) - - END (__start_context) diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig index f7c93a9d5fc8..75eb356bc958 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig @@ -3,8 +3,6 @@ CT_EXPERIMENTAL=y CT_PREFIX_DIR="/x-tools/${CT_TARGET}" CT_USE_MIRROR=y CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" -CT_PATCH_BUNDLED_LOCAL=y -CT_LOCAL_PATCH_DIR="/tmp/patches" CT_ARCH_RISCV=y # CT_DEMULTILIB is not set CT_ARCH_USE_MMU=y diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile index de776911d628..413249e02e87 100644 --- a/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile @@ -26,5 +26,5 @@ ENV \ ENV HOSTS=s390x-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-sanitizers --enable-profiler --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --enable-lld --enable-sanitizers --enable-profiler --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-sparcv9-solaris/Dockerfile b/src/ci/docker/host-x86_64/dist-sparcv9-solaris/Dockerfile index f7852c6364dc..ffe28fca1165 100644 --- a/src/ci/docker/host-x86_64/dist-sparcv9-solaris/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-sparcv9-solaris/Dockerfile @@ -32,5 +32,5 @@ ENV \ ENV HOSTS=sparcv9-sun-solaris -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index ab29d0e80ac2..ff80d0e3c296 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -152,16 +152,14 @@ ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft CC_riscv64gc_unknown_none_elf=riscv64-unknown-elf-gcc \ CFLAGS_riscv64gc_unknown_none_elf=-march=rv64gc -mabi=lp64 -ENV RUST_CONFIGURE_ARGS \ - --musl-root-armv5te=/musl-armv5te \ +ENV RUST_CONFIGURE_ARGS="--musl-root-armv5te=/musl-armv5te \ --musl-root-arm=/musl-arm \ --musl-root-armhf=/musl-armhf \ --musl-root-armv7hf=/musl-armv7hf \ - --disable-docs + --disable-docs" -ENV SCRIPT \ - python3 ../x.py --stage 2 test --host='' --target $RUN_MAKE_TARGETS tests/run-make tests/run-make-cargo && \ - python3 ../x.py dist --host='' --target $TARGETS +ENV SCRIPT="python3 ../x.py --stage 2 test --host= --target $RUN_MAKE_TARGETS tests/run-make tests/run-make-cargo && \ + python3 ../x.py dist --host= --target $TARGETS" # sccache COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index dacf3c0db202..e248e1e44ca3 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -95,16 +95,14 @@ RUN /tmp/freebsd-toolchain.sh i686 COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar -ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS \ --C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \ +ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_AR="/usr/local/bin/llvm-ar" +ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \ -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \ --Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib -ENV CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar -ENV CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_RUSTFLAGS \ --C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot \ +-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" +ENV CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_AR="/usr/local/bin/llvm-ar" +ENV CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot \ -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot/lib \ --Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib +-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia @@ -126,6 +124,8 @@ ENV TARGETS=$TARGETS,x86_64-unknown-uefi ENV TARGETS=$TARGETS,riscv64gc-unknown-linux-musl ENV TARGETS_SANITIZERS=x86_64-unknown-linux-gnuasan +ENV TARGETS_SANITIZERS=$TARGETS_SANITIZERS,x86_64-unknown-linux-gnumsan +ENV TARGETS_SANITIZERS=$TARGETS_SANITIZERS,x86_64-unknown-linux-gnutsan # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211 # we need asm in the search path for gcc-9 (for gnux32) but not in the search path of the @@ -136,8 +136,8 @@ RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/local/include/asm # musl-gcc can't find libgcc_s.so.1 since it doesn't use the standard search paths. RUN ln -s /usr/riscv64-linux-gnu/lib/libgcc_s.so.1 /usr/lib/gcc-cross/riscv64-linux-gnu/11/ -ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-llvm-bitcode-linker --disable-docs \ +ENV RUST_CONFIGURE_ARGS="--enable-extended --enable-lld --enable-llvm-bitcode-linker --disable-docs \ --musl-root-armv7=/musl-armv7 \ - --musl-root-riscv64gc=/musl-riscv64gc + --musl-root-riscv64gc=/musl-riscv64gc" -ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS && python3 ../x.py dist --host='' --set build.sanitizers=true --target $TARGETS_SANITIZERS +ENV SCRIPT="python3 ../x.py dist --host= --target $TARGETS && python3 ../x.py dist --host= --set build.sanitizers=true --target $TARGETS_SANITIZERS" diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index f42e6f770ebe..e62aa74662be 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -35,10 +35,9 @@ ENV \ ENV HOSTS=x86_64-unknown-freebsd -ENV RUST_CONFIGURE_ARGS \ - --enable-full-tools \ +ENV RUST_CONFIGURE_ARGS="--enable-full-tools \ --enable-extended \ --enable-profiler \ --enable-sanitizers \ - --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS + --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile index 37a8dc56a5fa..0675c3cafd9e 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile @@ -36,5 +36,5 @@ ENV \ ENV HOSTS=x86_64-unknown-illumos -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs -ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --disable-docs" +ENV SCRIPT="python2.7 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index cb5747876199..b168c739c979 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -80,8 +80,7 @@ ENV PGO_HOST=x86_64-unknown-linux-gnu ENV HOSTS=x86_64-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS \ - --enable-full-tools \ +ENV RUST_CONFIGURE_ARGS="--enable-full-tools \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ @@ -94,23 +93,23 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.jemalloc \ --set rust.bootstrap-override-lld=true \ --set rust.lto=thin \ - --set rust.codegen-units=1 + --set rust.codegen-units=1" COPY host-x86_64/dist-x86_64-linux/dist.sh /scripts/ COPY host-x86_64/dist-x86_64-linux/dist-alt.sh /scripts/ -ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" +ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs -ENV DIST_SRC 1 +ENV DIST_SRC="1" # When we build cargo in this container, we don't want it to use the system # libcurl, instead it should compile its own. -ENV LIBCURL_NO_PKG_CONFIG 1 +ENV LIBCURL_NO_PKG_CONFIG="1" -ENV DIST_REQUIRE_ALL_TOOLS 1 +ENV DIST_REQUIRE_ALL_TOOLS="1" # FIXME: Without this, LLVMgold.so incorrectly resolves to the system # libstdc++, instead of the one we build. diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile index 32b5058bce70..68f914a81552 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile @@ -35,14 +35,13 @@ RUN sh /scripts/sccache.sh ENV HOSTS=x86_64-unknown-linux-musl -ENV RUST_CONFIGURE_ARGS \ - --musl-root-x86_64=/usr/local/x86_64-linux-musl \ +ENV RUST_CONFIGURE_ARGS="--musl-root-x86_64=/usr/local/x86_64-linux-musl \ --enable-extended \ --enable-sanitizers \ --enable-profiler \ --enable-lld \ --set target.x86_64-unknown-linux-musl.crt-static=false \ - --build $HOSTS + --build $HOSTS" # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our @@ -54,4 +53,4 @@ ENV CFLAGS_x86_64_unknown_linux_musl="-Wa,-mrelax-relocations=no -Wa,--compress- -Wl,--compress-debug-sections=none" # To run native tests replace `dist` below with `test` -ENV SCRIPT python3 ../x.py dist --build $HOSTS +ENV SCRIPT="python3 ../x.py dist --build $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile index effdc99d9a65..3bb2c7433e03 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile @@ -22,5 +22,5 @@ ENV \ ENV HOSTS=x86_64-unknown-netbsd -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/dist-x86_64-solaris/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-solaris/Dockerfile index 4d77f0aad26b..b11e8cdeaa73 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-solaris/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-solaris/Dockerfile @@ -32,5 +32,5 @@ ENV \ ENV HOSTS=x86_64-pc-solaris -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs -ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS +ENV RUST_CONFIGURE_ARGS="--enable-extended --disable-docs" +ENV SCRIPT="python3 ../x.py dist --host $HOSTS --target $HOSTS" diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile index be3df9d4036d..fdc296aa891f 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -22,8 +22,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests +ENV RUST_CONFIGURE_ARGS="--build=i686-unknown-linux-gnu --disable-optimize-tests" COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ COPY scripts/i686-gnu-nopt-2.sh /scripts/ -ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" +ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index 00cd24b89db8..d0f3d1afa4dc 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -23,7 +23,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu +ENV RUST_CONFIGURE_ARGS="--build=i686-unknown-linux-gnu" COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ -ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" +ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile b/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile new file mode 100644 index 000000000000..8f7c7ebe3555 --- /dev/null +++ b/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile @@ -0,0 +1,36 @@ +FROM ubuntu:22.04 + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + sudo \ + gdb \ + libssl-dev \ + pkg-config \ + xz-utils \ + mingw-w64 \ + zlib1g-dev \ + libzstd-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --enable-sanitizers \ + --enable-profiler \ + --enable-compiler-docs \ + --set llvm.libzstd=true + +# Build the toolchain with multiple parallel frontend threads and then run tests +# Tests are still compiled serially at the moment (intended to be changed in follow-ups). +ENV SCRIPT python3 ../x.py --stage 2 test --set rust.parallel-frontend-threads=4 diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile index c1742720f778..a595a079b48f 100644 --- a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile @@ -39,7 +39,7 @@ COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/ # Check library crates on all tier 1 targets. # We disable optimized compiler built-ins because that requires a C toolchain for the target. # We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs. -ENV SCRIPT \ +ENV SCRIPT=" \ # Check some tools that aren't included in `x check` by default, to # ensure that maintainers can still do check builds locally. python3 ../x.py check \ @@ -58,4 +58,4 @@ ENV SCRIPT \ python3 ../x.py check --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/validate-toolstate.sh && \ reuse --include-submodules lint && \ - python3 ../x.py test collect-license-metadata + python3 ../x.py test collect-license-metadata" diff --git a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile index 885bf0b30b18..6b843a6247e8 100644 --- a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile @@ -30,8 +30,7 @@ ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3" COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV SCRIPT \ - python3 ../x.py check && \ +ENV SCRIPT="python3 ../x.py check && \ python3 ../x.py clippy ci --stage 2 && \ python3 ../x.py test --stage 1 core alloc std test proc_macro && \ # Elsewhere, we run all tests for the host. A number of codegen tests are sensitive to the target pointer @@ -48,4 +47,4 @@ ENV SCRIPT \ RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library/test --stage 1 && \ # The BOOTSTRAP_TRACING flag is added to verify whether the # bootstrap process compiles successfully with this flag enabled. - BOOTSTRAP_TRACING=1 python3 ../x.py --help + BOOTSTRAP_TRACING=1 python3 ../x.py --help" diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 6512240730cc..10ea2646bf3b 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -45,9 +45,8 @@ RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-3 tar -xz ENV WASI_SDK_PATH=/wasi-sdk-30.0-x86_64-linux -ENV RUST_CONFIGURE_ARGS \ - --musl-root-x86_64=/usr/local/x86_64-linux-musl \ - --set rust.lld +ENV RUST_CONFIGURE_ARGS="--musl-root-x86_64=/usr/local/x86_64-linux-musl \ + --set rust.lld" # Some run-make tests have assertions about code size, and enabling debug # assertions in libstd causes the binary to be much bigger than it would @@ -58,10 +57,10 @@ ENV NO_OVERFLOW_CHECKS=1 RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v38.0.4/wasmtime-v38.0.4-x86_64-linux.tar.xz | \ tar -xJ -ENV PATH "$PATH:/wasmtime-v38.0.4-x86_64-linux" +ENV PATH="$PATH:/wasmtime-v38.0.4-x86_64-linux" ENV WASM_WASIP_TARGET=wasm32-wasip1 -ENV WASM_WASIP_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_WASIP_TARGET \ +ENV WASM_WASIP_SCRIPT="python3 /checkout/x.py --stage 2 test --host= --target $WASM_WASIP_TARGET \ tests/run-make \ tests/run-make-cargo \ tests/ui \ @@ -69,18 +68,18 @@ ENV WASM_WASIP_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $ tests/codegen-units \ tests/codegen-llvm \ tests/assembly-llvm \ - library/core + library/core" ENV NVPTX_TARGETS=nvptx64-nvidia-cuda -ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $NVPTX_TARGETS \ +ENV NVPTX_SCRIPT="python3 /checkout/x.py --stage 2 test --host= --target $NVPTX_TARGETS \ tests/run-make \ tests/run-make-cargo \ - tests/assembly-llvm + tests/assembly-llvm" ENV MUSL_TARGETS=x86_64-unknown-linux-musl \ CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \ CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++ -ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS +ENV MUSL_SCRIPT="python3 /checkout/x.py --stage 2 test --host= --target $MUSL_TARGETS" ENV UEFI_TARGETS=aarch64-unknown-uefi,i686-unknown-uefi,x86_64-unknown-uefi \ CC_aarch64_unknown_uefi=clang-11 \ @@ -89,9 +88,9 @@ ENV UEFI_TARGETS=aarch64-unknown-uefi,i686-unknown-uefi,x86_64-unknown-uefi \ CXX_i686_unknown_uefi=clang++-11 \ CC_x86_64_unknown_uefi=clang-11 \ CXX_x86_64_unknown_uefi=clang++-11 -ENV UEFI_SCRIPT python3 /checkout/x.py --stage 2 build --host='' --target $UEFI_TARGETS && \ +ENV UEFI_SCRIPT="python3 /checkout/x.py --stage 2 build --host= --target $UEFI_TARGETS && \ python3 /checkout/x.py --stage 2 test tests/run-make-cargo/uefi-qemu/rmake.rs --target aarch64-unknown-uefi && \ python3 /checkout/x.py --stage 2 test tests/run-make-cargo/uefi-qemu/rmake.rs --target i686-unknown-uefi && \ - python3 /checkout/x.py --stage 2 test tests/run-make-cargo/uefi-qemu/rmake.rs --target x86_64-unknown-uefi + python3 /checkout/x.py --stage 2 test tests/run-make-cargo/uefi-qemu/rmake.rs --target x86_64-unknown-uefi" -ENV SCRIPT $WASM_WASIP_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT && $UEFI_SCRIPT +ENV SCRIPT="$WASM_WASIP_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT && $UEFI_SCRIPT" diff --git a/src/ci/docker/host-x86_64/tidy/Dockerfile b/src/ci/docker/host-x86_64/tidy/Dockerfile index 133192e8ac21..e84d61e0b99c 100644 --- a/src/ci/docker/host-x86_64/tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/tidy/Dockerfile @@ -39,5 +39,5 @@ COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/ # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. -ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test \ - src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck +ENV SCRIPT="TIDY_PRINT_DIFF=1 python2.7 ../x.py test \ + src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck" diff --git a/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile b/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile index 0cae83a85b3a..ccb7841d83ac 100644 --- a/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile @@ -38,13 +38,12 @@ COPY scripts/shared.sh /tmp/ COPY scripts/build-fuchsia-toolchain.sh /tmp/ RUN /tmp/build-fuchsia-toolchain.sh -ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar -ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS \ - -C panic=abort \ +ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_AR="/usr/local/bin/llvm-ar" +ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C panic=abort \ -C force-unwind-tables=yes \ -C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \ -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \ - -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib + -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnu @@ -52,17 +51,16 @@ ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnu COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_INSTALL_DIR /checkout/obj/install +ENV RUST_INSTALL_DIR="/checkout/obj/install" RUN mkdir -p $RUST_INSTALL_DIR/etc # Fuchsia only supports LLVM. -ENV CODEGEN_BACKENDS llvm +ENV CODEGEN_BACKENDS="llvm" # download-rustc is not allowed for `x install` -ENV NO_DOWNLOAD_CI_RUSTC 1 +ENV NO_DOWNLOAD_CI_RUSTC="1" -ENV RUST_CONFIGURE_ARGS \ - --prefix=$RUST_INSTALL_DIR \ +ENV RUST_CONFIGURE_ARGS="--prefix=$RUST_INSTALL_DIR \ --sysconfdir=etc \ --enable-lld \ --llvm-libunwind=in-tree \ @@ -72,8 +70,7 @@ ENV RUST_CONFIGURE_ARGS \ --set target.x86_64-unknown-fuchsia.cxx=/usr/local/bin/clang++ \ --set target.x86_64-unknown-fuchsia.ar=/usr/local/bin/llvm-ar \ --set target.x86_64-unknown-fuchsia.ranlib=/usr/local/bin/llvm-ranlib \ - --set target.x86_64-unknown-fuchsia.linker=/usr/local/bin/ld.lld + --set target.x86_64-unknown-fuchsia.linker=/usr/local/bin/ld.lld" -ENV SCRIPT \ - python3 ../x.py install --target $TARGETS compiler/rustc library/std clippy && \ - bash ../src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh +ENV SCRIPT="python3 ../x.py install --target $TARGETS compiler/rustc library/std clippy && \ + bash ../src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index d4113736b544..95ddaab7f44b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -29,5 +29,5 @@ RUN sh /scripts/sccache.sh ENV NO_DEBUG_ASSERTIONS=1 ENV NO_OVERFLOW_CHECKS=1 -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu -ENV RUST_CHECK_TARGET check-aux +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu" +ENV RUST_CHECK_TARGET="check-aux" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index 54b13c4397f4..5287d6b8956f 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -29,20 +29,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 +ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS="1" # llvm.use-linker conflicts with downloading CI LLVM -ENV NO_DOWNLOAD_CI_LLVM 1 +ENV NO_DOWNLOAD_CI_LLVM="1" -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-debug \ --enable-lld \ --set rust.debuginfo-level-tests=2 \ --set llvm.use-linker=lld \ --set target.x86_64-unknown-linux-gnu.linker=clang \ --set target.x86_64-unknown-linux-gnu.cc=clang \ - --set target.x86_64-unknown-linux-gnu.cxx=clang++ + --set target.x86_64-unknown-linux-gnu.cxx=clang++" # This job checks: # - That ui tests can be built with `-Cdebuginfo=1` @@ -53,7 +52,6 @@ ENV RUST_CONFIGURE_ARGS \ # - That the tests with `//@ needs-force-clang-based-tests` pass, since they # don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set. -ENV SCRIPT \ - python3 ../x.py --stage 2 build && \ +ENV SCRIPT="python3 ../x.py --stage 2 build && \ python3 ../x.py --stage 2 test tests/ui && \ - python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo + python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 5bafd89cfd91..5ab44df7a803 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -1,5 +1,5 @@ # Runs `distcheck`, which is a collection of smoke tests: -# +# # - Run `make check` from an unpacked dist tarball to make sure we can at the # minimum run check steps from those sources. # - Check that selected dist components at least have expected directory shape @@ -34,6 +34,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh # Make distcheck builds faster -ENV DISTCHECK_CONFIGURE_ARGS "--enable-sccache" +ENV DISTCHECK_CONFIGURE_ARGS="--enable-sccache" -ENV SCRIPT python3 ../x.py test distcheck +ENV SCRIPT="python3 ../x.py test distcheck" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile index f9c1ea531add..2208ed3ffbe1 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile @@ -31,15 +31,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV NO_DEBUG_ASSERTIONS 1 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV NO_DEBUG_ASSERTIONS="1" +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ --set llvm.libzstd=true \ - --set 'rust.codegen-backends=[\"llvm\",\"gcc\"]' -ENV SCRIPT python3 ../x.py \ + --set rust.codegen-backends=[\\\"llvm\\\",\\\"gcc\\\"]" +ENV SCRIPT="python3 ../x.py \ --stage 2 \ test tests \ --test-codegen-backend gcc \ @@ -51,4 +50,4 @@ ENV SCRIPT python3 ../x.py \ --skip tests/rustdoc-js-std \ --skip tests/rustdoc-json \ --skip tests/rustdoc-ui \ - --set 'rust.codegen-backends=[\"llvm\",\"gcc\"]' + --set rust.codegen-backends=[\\\"llvm\\\",\\\"gcc\\\"]" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile index f0314854411f..fc9673552107 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile @@ -44,16 +44,15 @@ RUN sh /scripts/sccache.sh # We are disabling CI LLVM since this builder is intentionally using a host # LLVM, rather than the typical src/llvm-project LLVM. -ENV NO_DOWNLOAD_CI_LLVM 1 -ENV EXTERNAL_LLVM 1 +ENV NO_DOWNLOAD_CI_LLVM="1" +ENV EXTERNAL_LLVM="1" # Using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --llvm-root=/usr/lib/llvm-21 \ --enable-llvm-link-shared \ --set rust.randomize-layout=true \ - --set rust.thin-lto-import-instr-limit=10 + --set rust.thin-lto-import-instr-limit=10" COPY scripts/shared.sh /scripts/ @@ -63,4 +62,4 @@ COPY scripts/x86_64-gnu-llvm3.sh /scripts/ COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ -ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" +ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile similarity index 94% rename from src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile rename to src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile index 92c2631000f9..a22e8de90804 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:25.04 +FROM ubuntu:26.04 ARG DEBIAN_FRONTEND=noninteractive @@ -16,8 +16,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ sudo \ gdb \ - llvm-20-tools \ - llvm-20-dev \ + llvm-22-tools \ + llvm-22-dev \ libedit-dev \ libssl-dev \ pkg-config \ @@ -50,7 +50,7 @@ ENV EXTERNAL_LLVM 1 # Using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-20 \ + --llvm-root=/usr/lib/llvm-22 \ --enable-llvm-link-shared \ --set rust.randomize-layout=true \ --set rust.thin-lto-import-instr-limit=10 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile index db4fca71d637..e478b8004421 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile @@ -34,11 +34,10 @@ ENV GCC_EXEC_PREFIX="/usr/lib/gcc/" COPY host-x86_64/x86_64-gnu-miri/check-miri.sh /tmp/ -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --enable-new-symbol-mangling +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ + --enable-new-symbol-mangling" -ENV HOST_TARGET x86_64-unknown-linux-gnu +ENV HOST_TARGET="x86_64-unknown-linux-gnu" # FIXME(#133381): currently rustc alt builds do *not* have rustc debug # assertions enabled! Therefore, we cannot force download CI rustc. @@ -46,4 +45,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -ENV SCRIPT /tmp/check-miri.sh ../x.py +ENV SCRIPT="/tmp/check-miri.sh ../x.py" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile index 854c36ee01c1..6020dc8877c1 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile @@ -22,8 +22,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --disable-optimize-tests \ - --set rust.test-compare-mode -ENV SCRIPT python3 ../x.py test --stage 1 --set rust.optimize=false library/std \ - && python3 ../x.py --stage 2 test + --set rust.test-compare-mode" +ENV SCRIPT="python3 ../x.py test --stage 1 --set rust.optimize=false library/std \ + && python3 ../x.py --stage 2 test" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 278e40eb71fa..3eb424ceef4a 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -76,12 +76,11 @@ COPY scripts/nodejs.sh /scripts/ RUN sh /scripts/nodejs.sh /node ENV PATH="/node/bin:${PATH}" -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json \ - --enable-new-symbol-mangling + --enable-new-symbol-mangling" -ENV HOST_TARGET x86_64-unknown-linux-gnu +ENV HOST_TARGET="x86_64-unknown-linux-gnu" # FIXME(#133381): currently rustc alt builds do *not* have rustc debug # assertions enabled! Therefore, we cannot force download CI rustc. @@ -89,5 +88,5 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -ENV SCRIPT /tmp/checktools.sh ../x.py && \ - python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" +ENV SCRIPT="/tmp/checktools.sh ../x.py && \ + python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args '--jobs 1'" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 83c2aa8cfb3b..7ca2dbb7d9f3 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -24,10 +24,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ - --set llvm.libzstd=true -ENV SCRIPT python3 ../x.py --stage 2 test + --set llvm.libzstd=true" +ENV SCRIPT="python3 ../x.py --stage 2 test" diff --git a/src/ci/docker/host-x86_64/x86_64-rust-for-linux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-rust-for-linux/Dockerfile index 97298519cf20..28a51ca2d685 100644 --- a/src/ci/docker/host-x86_64/x86_64-rust-for-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-rust-for-linux/Dockerfile @@ -34,7 +34,7 @@ RUN sh /scripts/sccache.sh # RfL needs access to cland, lld and llvm tools ENV PATH="${PATH}:/usr/lib/llvm-15/bin" -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu" COPY /scripts/rfl-build.sh /tmp/rfl-build.sh -ENV SCRIPT bash /tmp/rfl-build.sh +ENV SCRIPT="bash /tmp/rfl-build.sh" diff --git a/src/ci/docker/scripts/crosstool-ng.sh b/src/ci/docker/scripts/crosstool-ng.sh index eee912b0d750..434c662c99c8 100644 --- a/src/ci/docker/scripts/crosstool-ng.sh +++ b/src/ci/docker/scripts/crosstool-ng.sh @@ -1,7 +1,7 @@ #!/bin/sh set -ex -CT_NG=1.27.0 +CT_NG=1.28.0 url="https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-$CT_NG.tar.gz" curl -Lf $url | tar xzf - diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 0687d142a350..7c0f1d3f2930 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -122,19 +122,19 @@ pr: # tidy. This speeds up the PR CI job by ~1 minute. SKIP_SUBMODULES: src/gcc <<: *job-linux-4c - - name: x86_64-gnu-llvm-20 + - name: x86_64-gnu-llvm-21 env: ENABLE_GCC_CODEGEN: "1" DOCKER_SCRIPT: x86_64-gnu-llvm.sh <<: *job-linux-4c - - name: aarch64-gnu-llvm-20-1 + - name: aarch64-gnu-llvm-21-1 env: - IMAGE: aarch64-gnu-llvm-20 + IMAGE: aarch64-gnu-llvm-21 DOCKER_SCRIPT: stage_2_test_set1.sh <<: *job-aarch64-linux - - name: aarch64-gnu-llvm-20-2 + - name: aarch64-gnu-llvm-21-2 env: - IMAGE: aarch64-gnu-llvm-20 + IMAGE: aarch64-gnu-llvm-21 DOCKER_SCRIPT: stage_2_test_set2.sh <<: *job-aarch64-linux - name: x86_64-gnu-tools @@ -348,6 +348,11 @@ auto: - name: x86_64-gnu <<: *job-linux-4c + - name: optional-x86_64-gnu-parallel-frontend + # This test can be flaky, so do not cancel CI if it fails, for now. + continue_on_error: true + <<: *job-linux-4c + - name: x86_64-gnu-gcc doc_url: https://rustc-dev-guide.rust-lang.org/tests/codegen-backend-tests/cg_gcc.html <<: *job-linux-4c @@ -376,31 +381,6 @@ auto: - name: x86_64-gnu-distcheck <<: *job-linux-4c - # The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel. - # x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}. - - name: x86_64-gnu-llvm-20-1 - env: - RUST_BACKTRACE: 1 - IMAGE: x86_64-gnu-llvm-20 - DOCKER_SCRIPT: stage_2_test_set2.sh - <<: *job-linux-4c - - # Skip tests that run in x86_64-gnu-llvm-20-{1,3} - - name: x86_64-gnu-llvm-20-2 - env: - RUST_BACKTRACE: 1 - IMAGE: x86_64-gnu-llvm-20 - DOCKER_SCRIPT: x86_64-gnu-llvm2.sh - <<: *job-linux-4c - - # Skip tests that run in x86_64-gnu-llvm-20-{1,2} - - name: x86_64-gnu-llvm-20-3 - env: - RUST_BACKTRACE: 1 - IMAGE: x86_64-gnu-llvm-20 - DOCKER_SCRIPT: x86_64-gnu-llvm3.sh - <<: *job-linux-4c - # The x86_64-gnu-llvm-21 job is split into multiple jobs to run tests in parallel. # x86_64-gnu-llvm-21-1 skips tests that run in x86_64-gnu-llvm-21-{2,3}. - name: x86_64-gnu-llvm-21-1 @@ -426,6 +406,31 @@ auto: DOCKER_SCRIPT: x86_64-gnu-llvm3.sh <<: *job-linux-4c + # The x86_64-gnu-llvm-22 job is split into multiple jobs to run tests in parallel. + # x86_64-gnu-llvm-22-1 skips tests that run in x86_64-gnu-llvm-22-{2,3}. + - name: x86_64-gnu-llvm-22-1 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-22 + DOCKER_SCRIPT: stage_2_test_set2.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-22-{1,3} + - name: x86_64-gnu-llvm-22-2 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-22 + DOCKER_SCRIPT: x86_64-gnu-llvm2.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-22-{1,2} + - name: x86_64-gnu-llvm-22-3 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-22 + DOCKER_SCRIPT: x86_64-gnu-llvm3.sh + <<: *job-linux-4c + - name: x86_64-gnu-nopt <<: *job-linux-4c diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 99d0341ff4e0..2463edeb8003 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 99d0341ff4e06757490af8fceee790c4ede50bc0 +Subproject commit 2463edeb8003c5743918b3739a9f6870b86396f5 diff --git a/src/doc/nomicon b/src/doc/nomicon index b8f254a991b8..cc6a6bae8c3b 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit b8f254a991b8b7e8f704527f0d4f343a4697dfa9 +Subproject commit cc6a6bae8c3bfa389974e533c54694662c1a9de6 diff --git a/src/doc/reference b/src/doc/reference index 50a1075e879b..7446bf9697c9 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 50a1075e879be75aeec436252c84eef0fad489f4 +Subproject commit 7446bf9697c95d155eef33c6a9d91fbd29a5e359 diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 4038f112d59f..a9b4d182bd40 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -15,7 +15,7 @@ struct Cli { /// Modify files that do not comply overwrite: bool, /// Applies to lines that are to be split - #[arg(long, default_value_t = 100)] + #[arg(long, default_value_t = 80)] line_length_limit: usize, } diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index b6e1b2bc55df..a51e46f6191a 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -c78a29473a68f07012904af11c92ecffa68fcc75 +562dee4820c458d823175268e41601d4c060588a diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index e05fdc1160f2..6b66a9dcb2d5 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -1,6 +1,50 @@ # Installation -In the near future, `std::autodiff` should become available in nightly builds for users. As a contributor however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you successfully build this project on a tier2/tier3 target. +In the near future, `std::autodiff` should become available for users via rustup. As a rustc/enzyme/autodiff contributor however, you will still need to build rustc from source. +For the meantime, you can download up-to-date builds to enable `std::autodiff` on your latest nightly toolchain, if you are using either of: +**Linux**, with `x86_64-unknown-linux-gnu` or `aarch64-unknown-linux-gnu` +**Windows**, with `x86_64-llvm-mingw` or `aarch64-llvm-mingw` + +You can also download slightly outdated builds for **Apple** (aarch64-apple), which should generally work for now. + +If you need any other platform, you can build rustc including autodiff from source. Please open an issue if you want to help enabling automatic builds for your prefered target. + +## Installation guide + +If you want to use `std::autodiff` and don't plan to contribute PR's to the project, then we recommend to just use your existing nightly installation and download the missing component. In the future, rustup will be able to do it for you. +For now, you'll have to manually download and copy it. + +1) On our github repository, find the last merged PR: [`Repo`] +2) Scroll down to the lower end of the PR, where you'll find a rust-bors message saying `Test successful` with a `CI` link. +3) Click on the `CI` link, and grep for your target. E.g. `dist-x86_64-linux` or `dist-aarch64-llvm-mingw` and click `Load summary`. +4) Under the `CI artifacts` section, find the `enzyme-nightly` artifact, download, and unpack it. +5) Copy the artifact (libEnzyme-22.so for linux, libEnzyme-22.dylib for apple, etc.), which should be in a folder named `enzyme-preview`, to your rust toolchain directory. E.g. for linux: `cp ~/Downloads/enzyme-nightly-x86_64-unknown-linux-gnu/enzyme-preview/lib/rustlib/x86_64-unknown-linux-gnu/lib/libEnzyme-22.so ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib` + +Apple support was temporarily reverted, due to downstream breakages. If you want to download autodiff for apple, please look at the artifacts from this [`run`]. + +## Installation guide for Nix user. + +This setup was recommended by a nix and autodiff user. It uses [`Overlay`]. Please verify for yourself if you are comfortable using that repository. +In that case you might use the following nix configuration to get a rustc that supports `std::autodiff`. +```nix +{ + enzymeLib = pkgs.fetchzip { + url = "https://ci-artifacts.rust-lang.org/rustc-builds/ec818fda361ca216eb186f5cf45131bd9c776bb4/enzyme-nightly-x86_64-unknown-linux-gnu.tar.xz"; + sha256 = "sha256-Rnrop44vzS+qmYNaRoMNNMFyAc3YsMnwdNGYMXpZ5VY="; + }; + + rustToolchain = pkgs.symlinkJoin { + name = "rust-with-enzyme"; + paths = [pkgs.rust-bin.nightly.latest.default]; + nativeBuildInputs = [pkgs.makeWrapper]; + postBuild = '' + libdir=$out/lib/rustlib/x86_64-unknown-linux-gnu/lib + cp ${enzymeLib}/enzyme-preview/lib/rustlib/x86_64-unknown-linux-gnu/lib/libEnzyme-22.so $libdir/ + wrapProgram $out/bin/rustc --add-flags "--sysroot $out" + ''; + }; +} +``` ## Build instructions @@ -87,3 +131,6 @@ ninja ``` This will build Enzyme, and you can find it in `Enzyme/enzyme/build/lib/Enzyme.so`. (Endings might differ based on your OS). +[`Repo`]: https://github.com/rust-lang/rust/ +[`run`]: https://github.com/rust-lang/rust/pull/153026#issuecomment-3950046599 +[`Overlay`]: https://github.com/oxalica/rust-overlay diff --git a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md index 3d0e130b6aaa..0b6bb0d0f206 100644 --- a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md +++ b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md @@ -1,12 +1,16 @@ # Updating LLVM - Rust supports building against multiple LLVM versions: * Tip-of-tree for the current LLVM development branch is usually supported within a few days. PRs for such fixes are tagged with `llvm-main`. * The latest released major version is always supported. -* The one or two preceding major versions are usually supported. +* The one or two preceding major versions are usually supported in the sense that they are expected + to build successfully and pass most tests. + However, fixes for miscompilations often do not get + backported to past LLVM versions, so using rustc with older versions of LLVM comes with an + increased risk of soundness bugs. + We strongly recommend using the latest version of LLVM. By default, Rust uses its own fork in the [rust-lang/llvm-project repository]. This fork is based on a `release/$N.x` branch of the upstream project, where @@ -86,7 +90,6 @@ An example PR: [#59089](https://github.com/rust-lang/rust/pull/59089) ## New LLVM Release Updates - Unlike bugfixes, updating to a new release of LLVM typically requires a lot more work. @@ -167,12 +170,14 @@ so let's go through each in detail. You'll change at least `src/llvm-project` and will likely also change [`llvm-wrapper`] as well. - + > For prior art, here are some previous LLVM updates: > - [LLVM 17](https://github.com/rust-lang/rust/pull/115959) > - [LLVM 18](https://github.com/rust-lang/rust/pull/120055) > - [LLVM 19](https://github.com/rust-lang/rust/pull/127513) > - [LLVM 20](https://github.com/rust-lang/rust/pull/135763) + > - [LLVM 21](https://github.com/rust-lang/rust/pull/143684) + > - [LLVM 22](https://github.com/rust-lang/rust/pull/150722) Note that sometimes it's easiest to land [`llvm-wrapper`] compatibility as a PR before actually updating `src/llvm-project`. diff --git a/src/doc/rustc-dev-guide/src/borrow-check/region-inference/member-constraints.md b/src/doc/rustc-dev-guide/src/borrow-check/region-inference/member-constraints.md index 2804c97724f5..21a56da9b707 100644 --- a/src/doc/rustc-dev-guide/src/borrow-check/region-inference/member-constraints.md +++ b/src/doc/rustc-dev-guide/src/borrow-check/region-inference/member-constraints.md @@ -1,17 +1,18 @@ # Member constraints A member constraint `'m member of ['c_1..'c_N]` expresses that the -region `'m` must be *equal* to some **choice regions** `'c_i` (for -some `i`). These constraints cannot be expressed by users, but they -arise from `impl Trait` due to its lifetime capture rules. Consider a -function such as the following: +region `'m` must be *equal* to some **choice regions** `'c_i` (for some `i`). +These constraints cannot be expressed by users, but they +arise from `impl Trait` due to its lifetime capture rules. +Consider a function such as the following: ```rust,ignore fn make(a: &'a u32, b: &'b u32) -> impl Trait<'a, 'b> { .. } ``` Here, the true return type (often called the "hidden type") is only -permitted to capture the lifetimes `'a` or `'b`. You can kind of see +permitted to capture the lifetimes `'a` or `'b`. +You can kind of see this more clearly by desugaring that `impl Trait` return type into its more explicit form: @@ -23,7 +24,8 @@ fn make(a: &'a u32, b: &'b u32) -> MakeReturn<'a, 'b> { .. } Here, the idea is that the hidden type must be some type that could have been written in place of the `impl Trait<'x, 'y>` -- but clearly such a type can only reference the regions `'x` or `'y` (or -`'static`!), as those are the only names in scope. This limitation is +`'static`!), as those are the only names in scope. +This limitation is then translated into a restriction to only access `'a` or `'b` because we are returning `MakeReturn<'a, 'b>`, where `'x` and `'y` have been replaced with `'a` and `'b` respectively. @@ -31,8 +33,8 @@ replaced with `'a` and `'b` respectively. ## Detailed example To help us explain member constraints in more detail, let's spell out -the `make` example in a bit more detail. First off, let's assume that -you have some dummy trait: +the `make` example in a bit more detail. +First off, let's assume that you have some dummy trait: ```rust,ignore trait Trait<'a, 'b> { } @@ -49,8 +51,8 @@ fn make(a: &'a u32, b: &'b u32) -> MakeReturn<'a, 'b> { ``` What happens in this case is that the return type will be `(&'0 u32, &'1 u32)`, -where `'0` and `'1` are fresh region variables. We will have the following -region constraints: +where `'0` and `'1` are fresh region variables. +We will have the following region constraints: ```txt '0 live at {L} @@ -67,11 +69,11 @@ return tuple is constructed to where it is returned (in fact, `'0` and `'1` might have slightly different liveness sets, but that's not very interesting to the point we are illustrating here). -The `'a: '0` and `'b: '1` constraints arise from subtyping. When we -construct the `(a, b)` value, it will be assigned type `(&'0 u32, &'1 +The `'a: '0` and `'b: '1` constraints arise from subtyping. +When we construct the `(a, b)` value, it will be assigned type `(&'0 u32, &'1 u32)` -- the region variables reflect that the lifetimes of these -references could be made smaller. For this value to be created from -`a` and `b`, however, we do require that: +references could be made smaller. +For this value to be created from `a` and `b`, however, we do require that: ```txt (&'a u32, &'b u32) <: (&'0 u32, &'1 u32) @@ -82,35 +84,39 @@ which means in turn that `&'a u32 <: &'0 u32` and hence that `'a: '0` Note that if we ignore member constraints, the value of `'0` would be inferred to some subset of the function body (from the liveness -constraints, which we did not write explicitly). It would never become +constraints, which we did not write explicitly). +It would never become `'a`, because there is no need for it too -- we have a constraint that -`'a: '0`, but that just puts a "cap" on how *large* `'0` can grow to -become. Since we compute the *minimal* value that we can, we are happy -to leave `'0` as being just equal to the liveness set. This is where -member constraints come in. +`'a: '0`, but that just puts a "cap" on how *large* `'0` can grow to become. +Since we compute the *minimal* value that we can, we are happy +to leave `'0` as being just equal to the liveness set. +This is where member constraints come in. ## Choices are always lifetime parameters At present, the "choice" regions from a member constraint are always lifetime -parameters from the current function. As of October 2021, +parameters from the current function. As of March 2026, this falls out from the placement of impl Trait, though in the future it may not -be the case. We take some advantage of this fact, as it simplifies the current -code. In particular, we don't have to consider a case like `'0 member of ['1, +be the case. +We take some advantage of this fact, as it simplifies the current code. +In particular, we don't have to consider a case like `'0 member of ['1, 'static]`, in which the value of both `'0` and `'1` are being inferred and hence -changing. See [rust-lang/rust#61773][#61773] for more information. +changing. +See [rust-lang/rust#61773][#61773] for more information. [#61773]: https://github.com/rust-lang/rust/issues/61773 ## Applying member constraints -Member constraints are a bit more complex than other forms of -constraints. This is because they have a "or" quality to them -- that +Member constraints are a bit more complex than other forms of constraints. +This is because they have a "or" quality to them -- that is, they describe multiple choices that we must select from. E.g., in our example constraint `'0 member of ['a, 'b, 'static]`, it might be -that `'0` is equal to `'a`, `'b`, *or* `'static`. How can we pick the -correct one? What we currently do is to look for a *minimal choice* --- if we find one, then we will grow `'0` to be equal to that minimal -choice. To find that minimal choice, we take two factors into +that `'0` is equal to `'a`, `'b`, *or* `'static`. +How can we pick the correct one? +What we currently do is to look for a *minimal choice* +-- if we find one, then we will grow `'0` to be equal to that minimal choice. +To find that minimal choice, we take two factors into consideration: lower and upper bounds. ### Lower bounds @@ -121,30 +127,34 @@ apply member constraints, we've already *computed* the lower bounds of `'0` because we computed its minimal value (or at least, the lower bounds considering everything but member constraints). -Let `LB` be the current value of `'0`. We know then that `'0: LB` must -hold, whatever the final value of `'0` is. Therefore, we can rule out +Let `LB` be the current value of `'0`. +We know then that `'0: LB` must hold, whatever the final value of `'0` is. +Therefore, we can rule out any choice `'choice` where `'choice: LB` does not hold. -Unfortunately, in our example, this is not very helpful. The lower -bound for `'0` will just be the liveness set `{L}`, and we know that -all the lifetime parameters outlive that set. So we are left with the -same set of choices here. (But in other examples, particularly those +Unfortunately, in our example, this is not very helpful. +The lower bound for `'0` will just be the liveness set `{L}`, and we know that +all the lifetime parameters outlive that set. +So we are left with the same set of choices here. +(But in other examples, particularly those with different variance, lower bound constraints may be relevant.) ### Upper bounds The *upper bounds* are those lifetimes that *must outlive* `'0` -- i.e., that `'0` must be *smaller* than. In our example, this would be -`'a`, because we have the constraint that `'a: '0`. In more complex -examples, the chain may be more indirect. +`'a`, because we have the constraint that `'a: '0`. +In more complex examples, the chain may be more indirect. We can use upper bounds to rule out members in a very similar way to -lower bounds. If UB is some upper bound, then we know that `UB: +lower bounds. +If UB is some upper bound, then we know that `UB: '0` must hold, so we can rule out any choice `'choice` where `UB: 'choice` does not hold. In our example, we would be able to reduce our choice set from `['a, -'b, 'static]` to just `['a]`. This is because `'0` has an upper bound +'b, 'static]` to just `['a]`. +This is because `'0` has an upper bound of `'a`, and neither `'a: 'b` nor `'a: 'static` is known to hold. (For notes on how we collect upper bounds in the implementation, see @@ -153,39 +163,45 @@ of `'a`, and neither `'a: 'b` nor `'a: 'static` is known to hold. ### Minimal choice After applying lower and upper bounds, we can still sometimes have -multiple possibilities. For example, imagine a variant of our example -using types with the opposite variance. In that case, we would have -the constraint `'0: 'a` instead of `'a: '0`. Hence the current value -of `'0` would be `{L, 'a}`. Using this as a lower bound, we would be +multiple possibilities. +For example, imagine a variant of our example +using types with the opposite variance. +In that case, we would have the constraint `'0: 'a` instead of `'a: '0`. +Hence the current value of `'0` would be `{L, 'a}`. +Using this as a lower bound, we would be able to narrow down the member choices to `['a, 'static]` because `'b: -'a` is not known to hold (but `'a: 'a` and `'static: 'a` do hold). We -would not have any upper bounds, so that would be our final set of choices. +'a` is not known to hold (but `'a: 'a` and `'static: 'a` do hold). +We would not have any upper bounds, so that would be our final set of choices. In that case, we apply the **minimal choice** rule -- basically, if -one of our choices if smaller than the others, we can use that. In -this case, we would opt for `'a` (and not `'static`). +one of our choices if smaller than the others, we can use that. +In this case, we would opt for `'a` (and not `'static`). This choice is consistent with the general 'flow' of region propagation, which always aims to compute a minimal value for the -region being inferred. However, it is somewhat arbitrary. +region being inferred. +However, it is somewhat arbitrary. ### Collecting upper bounds in the implementation In practice, computing upper bounds is a bit inconvenient, because our -data structures are setup for the opposite. What we do is to compute +data structures are setup for the opposite. +What we do is to compute the **reverse SCC graph** (we do this lazily and cache the result) -- -that is, a graph where `'a: 'b` induces an edge `SCC('b) -> -SCC('a)`. Like the normal SCC graph, this is a DAG. We can then do a -depth-first search starting from `SCC('0)` in this graph. This will -take us to all the SCCs that must outlive `'0`. +that is, a graph where `'a: 'b` induces an edge `SCC('b) -> SCC('a)`. +Like the normal SCC graph, this is a DAG. +We can then do a depth-first search starting from `SCC('0)` in this graph. +This will take us to all the SCCs that must outlive `'0`. One wrinkle is that, as we walk the "upper bound" SCCs, their values -will not yet have been fully computed. However, we **have** already +will not yet have been fully computed. +However, we **have** already applied their liveness constraints, so we have some information about -their value. In particular, for any regions representing lifetime +their value. +In particular, for any regions representing lifetime parameters, their value will contain themselves (i.e., the initial -value for `'a` includes `'a` and the value for `'b` contains `'b`). So -we can collect all of the lifetime parameters that are reachable, +value for `'a` includes `'a` and the value for `'b` contains `'b`). +So we can collect all of the lifetime parameters that are reachable, which is precisely what we are interested in. diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index fc8fe402bfa9..317b7c2564cb 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -110,7 +110,6 @@ Also, using `x` rather than `x.py` is recommended as: Notice that this is not absolute. For instance, using Nushell in VSCode on Win10, typing `x` or `./x` still opens `x.py` in an editor rather than invoking the program. -:) In the rest of this guide, we use `x` rather than `x.py` directly. The following command: diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 0e08ef9042d1..0440fb0c5e73 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -139,6 +139,8 @@ if foo { } ``` +If you want to leave a note in the codebase, use `// FIXME` instead. + ## Using crates from crates.io diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md index 9a302f9100f1..b5bb44cec348 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md @@ -10,7 +10,7 @@ Note that not all _historical_ (no longer emitted) error codes have explanations The explanations are written in Markdown (see the [CommonMark Spec] for specifics around syntax), and all of them are linked in the [`rustc_error_codes`] crate. Please read [RFC 1567] for details on how to format and write long error codes. -As of February 2023, there is an +As of March 2026, there is an effort[^new-explanations] to replace this largely outdated RFC with a new more flexible standard. Error explanations should expand on the error message and provide details about diff --git a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md index 7b98bc62116b..cda975a9a15e 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md @@ -3,15 +3,14 @@ This page documents some of the machinery around lint registration and how we run lints in the compiler. -The [`LintStore`] is the central piece of infrastructure, around which -everything rotates. The `LintStore` is held as part of the [`Session`], and it +The [`LintStore`] is the central piece of infrastructure, around which everything rotates. +The `LintStore` is held as part of the [`Session`], and it gets populated with the list of lints shortly after the `Session` is created. ## Lints vs. lint passes -There are two parts to the linting mechanism within the compiler: lints and -lint passes. Unfortunately, a lot of the documentation we have refers to both -of these as just "lints." +There are two parts to the linting mechanism within the compiler: lints and lint passes. +Unfortunately, a lot of the documentation we have refers to both of these as just "lints." First, we have the lint declarations themselves, and this is where the name and default lint level and other metadata come from. @@ -21,14 +20,14 @@ which boils down to a static with type [`&rustc_lint_defs::Lint`] as the macro is somewhat unwieldy to add new fields to, like all macros). -As of Aug 2022, we lint against direct declarations without the use of the macro. Lint declarations don't carry any "state" - they are merely global identifiers -and descriptions of lints. We assert at runtime that they are not registered -twice (by lint name). +and descriptions of lints. +We assert at runtime that they are not registered twice (by lint name). -Lint passes are the meat of any lint. Notably, there is not a one-to-one +Lint passes are the meat of any lint. +Notably, there is not a one-to-one relationship between lints and lint passes; a lint might not have any lint pass that emits it, it could have many, or just one -- the compiler doesn't track whether a pass is in any way associated with a particular lint, and frequently @@ -45,36 +44,33 @@ and all lints are registered. There are three 'sources' of lints: * internal lints: lints only used by the rustc codebase -* builtin lints: lints built into the compiler and not provided by some outside - source -* `rustc_interface::Config`[`register_lints`]: lints passed into the compiler - during construction +* builtin lints: lints built into the compiler and not provided by some outside source +* `rustc_interface::Config`[`register_lints`]: lints passed into the compiler during construction -Lints are registered via the [`LintStore::register_lint`] function. This should -happen just once for any lint, or an ICE will occur. +Lints are registered via the [`LintStore::register_lint`] function. +This should happen just once for any lint, or an ICE will occur. -Once the registration is complete, we "freeze" the lint store by placing it in -an `Arc`. +Once the registration is complete, we "freeze" the lint store by placing it in an `Arc`. Lint passes are registered separately into one of the categories -(pre-expansion, early, late, late module). Passes are registered as a closure +(pre-expansion, early, late, late module). +Passes are registered as a closure -- i.e., `impl Fn() -> Box`, where `dyn X` is either an early or late -lint pass trait object. When we run the lint passes, we run the closure and -then invoke the lint pass methods. The lint pass methods take `&mut self` so -they can keep track of state internally. +lint pass trait object. +When we run the lint passes, we run the closure and then invoke the lint pass methods. +The lint pass methods take `&mut self` so they can keep track of state internally. #### Internal lints -These are lints used just by the compiler or drivers like `clippy`. They can be -found in [`rustc_lint::internal`]. +These are lints used just by the compiler or drivers like `clippy`. +They can be found in [`rustc_lint::internal`]. An example of such a lint is the check that lint passes are implemented using -the `declare_lint_pass!` macro and not by hand. This is accomplished with the -`LINT_PASS_IMPL_WITHOUT_MACRO` lint. +the `declare_lint_pass!` macro and not by hand. +This is accomplished with the `LINT_PASS_IMPL_WITHOUT_MACRO` lint. Registration of these lints happens in the [`rustc_lint::register_internals`] -function which is called when constructing a new lint store inside -[`rustc_lint::new_lint_store`]. +function which is called when constructing a new lint store inside [`rustc_lint::new_lint_store`]. #### Builtin Lints @@ -84,19 +80,18 @@ Often the first provides the definitions for the lints themselves, and the latter provides the lint pass definitions (and implementations), but this is not always true. -The builtin lint registration happens in -the [`rustc_lint::register_builtins`] function. +The builtin lint registration happens in the [`rustc_lint::register_builtins`] function. Just like with internal lints, this happens inside of [`rustc_lint::new_lint_store`]. #### Driver lints These are the lints provided by drivers via the `rustc_interface::Config` -[`register_lints`] field, which is a callback. Drivers should, if finding it -already set, call the function currently set within the callback they add. The -best way for drivers to get access to this is by overriding the -`Callbacks::config` function which gives them direct access to the `Config` -structure. +[`register_lints`] field, which is a callback. +Drivers should, if finding it +already set, call the function currently set within the callback they add. +The best way for drivers to get access to this is by overriding the +`Callbacks::config` function which gives them direct access to the `Config` structure. ## Compiler lint passes are combined into one pass @@ -106,8 +101,8 @@ of lint passes. Instead, we have a single lint pass of each variety (e.g., individual lint passes; this is because then we get the benefits of static over dynamic dispatch for each of the (often empty) trait methods. -Ideally, we'd not have to do this, since it adds to the complexity of -understanding the code. However, with the current type-erased lint store +Ideally, we'd not have to do this, since it adds to the complexity of understanding the code. +However, with the current type-erased lint store approach, it is beneficial to do so for performance reasons. [`LintStore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html diff --git a/src/doc/rustc-dev-guide/src/diagnostics/translation.md b/src/doc/rustc-dev-guide/src/diagnostics/translation.md index cf95727e2a67..a22ede5e9c3b 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/translation.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/translation.md @@ -31,8 +31,7 @@ There are two ways of writing translatable diagnostics: ("Simple" diagnostics being those that don't require a lot of logic in deciding to emit subdiagnostics and can therefore be represented as diagnostic structs). See [the diagnostic and subdiagnostic structs documentation](./diagnostic-structs.md). -2. Using typed identifiers with `Diag` APIs (in - `Diagnostic` or `Subdiagnostic` implementations). +2. Using typed identifiers with `Diag` APIs (in `Diagnostic` or `Subdiagnostic` implementations). When adding or changing a translatable diagnostic, you don't need to worry about the translations. diff --git a/src/doc/rustc-dev-guide/src/early-late-parameters.md b/src/doc/rustc-dev-guide/src/early-late-parameters.md index c472bdc2c481..d78d5331baac 100644 --- a/src/doc/rustc-dev-guide/src/early-late-parameters.md +++ b/src/doc/rustc-dev-guide/src/early-late-parameters.md @@ -3,9 +3,16 @@ > **NOTE**: This chapter largely talks about early/late bound as being solely relevant when discussing function item types/function definitions. This is potentially not completely true, async blocks and closures should likely be discussed somewhat in this chapter. +See also these blog posts from when the distinction between early and late bound parameters was +introduced: [Intermingled parameter lists] and [Intermingled parameter lists, take 2]. + +[Intermingled parameter lists]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ +[Intermingled parameter lists, take 2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ + ## What does it mean to be "early" bound or "late" bound -Every function definition has a corresponding ZST that implements the `Fn*` traits known as a [function item type][function_item_type]. This part of the chapter will talk a little bit about the "desugaring" of function item types as it is useful context for explaining the difference between early bound and late bound generic parameters. +Every function definition has a corresponding ZST that implements the `Fn*` traits known as a [function item type][function_item_type]. +This part of the chapter will talk a little bit about the "desugaring" of function item types as it is useful context for explaining the difference between early bound and late bound generic parameters. Let's start with a very trivial example involving no generic parameters: @@ -30,7 +37,7 @@ The builtin impls for the `FnMut`/`FnOnce` traits as well as the impls for `Copy A slightly more complicated example would involve introducing generic parameters to the function: ```rust -fn foo(a: T) -> T { +fn foo(a: T) -> T { # a /* snip */ } @@ -45,7 +52,8 @@ impl Fn<(T,)> for FooFnItem { } ``` -Note that the function item type `FooFnItem` is generic over some type parameter `T` as defined on the function `foo`. However, not all generic parameters defined on functions are also defined on the function item type as demonstrated here: +Note that the function item type `FooFnItem` is generic over some type parameter `T` as defined on the function `foo`. +However, not all generic parameters defined on functions are also defined on the function item type as demonstrated here: ```rust fn foo<'a, T: Sized>(a: &'a T) -> &'a T { # a @@ -65,12 +73,13 @@ impl<'a, T: Sized> Fn<(&'a T,)> for FooFnItem { The lifetime parameter `'a` from the function `foo` is not present on the function item type `FooFnItem` and is instead introduced on the builtin impl solely for use in representing the argument types. Generic parameters not all being defined on the function item type means that there are two steps where generic arguments are provided when calling a function. -1. Naming the function (e.g. `let a = foo;`) the arguments for `FooFnItem` are provided. +1. Naming the function (e.g. `let a = foo;`) the arguments for `FooFnItem` are provided. 2. Calling the function (e.g. `a(&10);`) any parameters defined on the builtin impl are provided. -This two-step system is where the early vs late naming scheme comes from, early bound parameters are provided in the *earliest* step (naming the function), whereas late bound parameters are provided in the *latest* step (calling the function). +This two-step system is where the early vs late naming scheme comes from, early bound parameters are provided in the *earliest* step (naming the function), whereas late bound parameters are provided in the *latest* step (calling the function). -Looking at the desugaring from the previous example we can tell that `T` is an early bound type parameter and `'a` is a late bound lifetime parameter as `T` is present on the function item type but `'a` is not. See this example of calling `foo` annotated with where each generic parameter has an argument provided: +Looking at the desugaring from the previous example we can tell that `T` is an early bound type parameter and `'a` is a late bound lifetime parameter as `T` is present on the function item type but `'a` is not. +See this example of calling `foo` annotated with where each generic parameter has an argument provided: ```rust fn foo<'a, T: Sized>(a: &'a T) -> &'a T { # a @@ -90,15 +99,17 @@ my_func(&String::new()); ## Differences between early and late bound parameters -### Higher ranked function pointers and trait bounds +### Higher ranked function pointers and trait bounds -A generic parameter being late bound allows for more flexible usage of the function item. For example if we have some function `foo` with an early bound lifetime parameter and some function `bar` with a late bound lifetime parameter `'a` we would have the following builtin `Fn` impls: +A generic parameter being late bound allows for more flexible usage of the function item. +For example, if we have some function `foo` with an early bound lifetime parameter and some function `bar` with a late bound lifetime parameter `'a`, we would have the following builtin `Fn` impls: ```rust,ignore impl<'a> Fn<(&'a String,)> for FooFnItem<'a> { /* ... */ } impl<'a> Fn<(&'a String,)> for BarFnItem { /* ... */ } ``` -The `bar` function has a strictly more flexible signature as the function item type can be called with a borrow with *any* lifetime, whereas the `foo` function item type would only be callable with a borrow with the same lifetime on the function item type. We can show this by simply trying to call `foo`'s function item type multiple times with different lifetimes: +The `bar` function has a strictly more flexible signature as the function item type can be called with a borrow with *any* lifetime, whereas the `foo` function item type would only be callable with a borrow with the same lifetime on the function item type. +We can show this by simply trying to call `foo`'s function item type multiple times with different lifetimes: ```rust // The `'a: 'a` bound forces this lifetime to be early bound. @@ -119,9 +130,12 @@ f(&String::new()); f(&String::new()); ``` -In this example we call `foo`'s function item type twice, each time with a borrow of a temporary. These two borrows could not possible have lifetimes that overlap as the temporaries are only alive during the function call, not after. The lifetime parameter on `foo` being early bound requires all callers of `f` to provide a borrow with the same lifetime, as this is not possible the borrow checker errors. +In this example, we call `foo`'s function item type twice, each time with a borrow of a temporary. +These two borrows could not possibly have lifetimes that overlap as the temporaries are only alive during the function call, not after. +The lifetime parameter on `foo` being early bound requires all callers of `f` to provide a borrow with the same lifetime, as this is not possible the borrow checker errors. -If the lifetime parameter on `foo` was late bound this would be able to compile as each caller could provide a different lifetime argument for its borrow. See the following example which demonstrates this using the `bar` function defined above: +If the lifetime parameter on `foo` was late bound, this would be able to compile as each caller could provide a different lifetime argument for its borrow. +See the following example, which demonstrates this using the `bar` function defined above: ```rust # fn foo<'a: 'a>(b: &'a String) -> &'a String { b } @@ -137,7 +151,8 @@ b(&String::new()); b(&String::new()); ``` -This is reflected in the ability to coerce function item types to higher ranked function pointers and prove higher ranked `Fn` trait bounds. We can demonstrate this with the following example: +This is reflected in the ability to coerce function item types to higher ranked function pointers and prove higher ranked `Fn` trait bounds. +We can demonstrate this with the following example: ```rust // The `'a: 'a` bound forces this lifetime to be early bound. fn foo<'a: 'a>(b: &'a String) -> &'a String { b } @@ -157,14 +172,15 @@ fn higher_ranked_trait_bound() { fn higher_ranked_fn_ptr() { let bar_fn_item = bar; let fn_ptr: for<'a> fn(&'a String) -> &'a String = bar_fn_item; - + let foo_fn_item = foo::<'_>; // errors let fn_ptr: for<'a> fn(&'a String) -> &'a String = foo_fn_item; } ``` -In both of these cases the borrow checker errors as it does not consider `foo_fn_item` to be callable with a borrow of any lifetime. This is due to the fact that the lifetime parameter on `foo` is early bound, causing `foo_fn_item` to have a type of `FooFnItem<'_>` which (as demonstrated by the desugared `Fn` impl) is only callable with a borrow of the same lifetime `'_`. +In both of these cases, the borrow checker errors as it does not consider `foo_fn_item` to be callable with a borrow of any lifetime. +This is due to the fact that the lifetime parameter on `foo` is early bound, causing `foo_fn_item` to have a type of `FooFnItem<'_>` which (as demonstrated by the desugared `Fn` impl) is only callable with a borrow of the same lifetime `'_`. ### Turbofishing in the presence of late bound parameters @@ -182,15 +198,17 @@ fn foo<'a>(b: &'a u32) -> &'a u32 { b } let f /* : FooFnItem */ = foo::<'static>; ``` -The above example errors as the lifetime parameter `'a` is late bound and so cannot be instantiated as part of the "naming a function" step. If we make the lifetime parameter early bound we will see this code start to compile: +The above example errors as the lifetime parameter `'a` is late bound and so cannot be instantiated as part of the "naming a function" step. +If we make the lifetime parameter early bound we will see this code start to compile: ```rust fn foo<'a: 'a>(b: &'a u32) -> &'a u32 { b } let f /* : FooFnItem<'static> */ = foo::<'static>; ``` -What the current implementation of the compiler aims to do is error when specifying lifetime arguments to a function that has both early *and* late bound lifetime parameters. In practice, due to excessive breakage, some cases are actually only future compatibility warnings ([#42868](https://github.com/rust-lang/rust/issues/42868)): -- When the amount of lifetime arguments is the same as the number of early bound lifetime parameters a FCW is emitted instead of an error +What the current implementation of the compiler aims to do is error when specifying lifetime arguments to a function that has both early *and* late bound lifetime parameters. +In practice, due to excessive breakage, some cases are actually only future compatibility warnings ([#42868](https://github.com/rust-lang/rust/issues/42868)): +- When the amount of lifetime arguments is the same as the number of early bound lifetime parameters, a FCW is emitted instead of an error - An error is always downgraded to a FCW when using method call syntax To demonstrate this we can write out the different kinds of functions and give them both a late and early bound lifetime: @@ -281,7 +299,8 @@ Foo::inherent_function::<'static, 'static, 'static>(&(), &()); free_function::<'static, 'static, 'static>(&(), &()); ``` -Even when specifying enough lifetime arguments for both the late and early bound lifetime parameter, these arguments are not actually used to annotate the lifetime provided to late bound parameters. We can demonstrate this by turbofishing `'static` to a function while providing a non-static borrow: +Even when specifying enough lifetime arguments for both the late and early bound lifetime parameter, these arguments are not actually used to annotate the lifetime provided to late bound parameters. +We can demonstrate this by turbofishing `'static` to a function while providing a non-static borrow: ```rust struct Foo; @@ -296,7 +315,8 @@ This compiles even though the `&String::new()` function argument does not have a ### Liveness of types with late bound parameters -When checking type outlives bounds involving function item types we take into account early bound parameters. For example: +When checking type outlives bounds involving function item types we take into account early bound parameters. +For example: ```rust fn foo(_: T) {} @@ -309,9 +329,11 @@ fn bar() { } ``` -As the type parameter `T` is early bound, the desugaring of the function item type for `foo` would look something like `struct FooFnItem`. Then in order for `FooFnItem: 'static` to hold we must also require `T: 'static` to hold as otherwise we would wind up with soundness bugs. +As the type parameter `T` is early bound, the desugaring of the function item type for `foo` would look something like `struct FooFnItem`. +Then, in order for `FooFnItem: 'static` to hold, we must also require `T: 'static` to hold as otherwise we would wind up with soundness bugs. -Unfortunately, due to bugs in the compiler, we do not take into account early bound *lifetimes*, which is the cause of the open soundness bug [#84366](https://github.com/rust-lang/rust/issues/84366). This means that it's impossible to demonstrate a "difference" between early/late bound parameters for liveness/type outlives bounds as the only kind of generic parameters that are able to be late bound are lifetimes which are handled incorrectly. +Unfortunately, due to bugs in the compiler, we do not take into account early bound *lifetimes*, which is the cause of the open soundness bug [#84366](https://github.com/rust-lang/rust/issues/84366). +This means that it's impossible to demonstrate a "difference" between early/late bound parameters for liveness/type outlives bounds as the only kind of generic parameters that are able to be late bound are lifetimes which are handled incorrectly. Regardless, in theory the code example below *should* demonstrate such a difference once [#84366](https://github.com/rust-lang/rust/issues/84366) is fixed: ```rust @@ -335,17 +357,20 @@ fn bar<'b>() { ### Must be a lifetime parameter -Type and Const parameters are not able to be late bound as we do not have a way to support types such as `dyn for Fn(Box)` or `for fn(Box)`. Calling such types requires being able to monomorphize the underlying function which is not possible with indirection through dynamic dispatch. +Type and Const parameters are not able to be late bound as we do not have a way to support types such as `dyn for Fn(Box)` or `for fn(Box)`. +Calling such types requires being able to monomorphize the underlying function which is not possible with indirection through dynamic dispatch. ### Must not be used in a where clause -Currently when a generic parameter is used in a where clause it must be early bound. For example: +Currently when a generic parameter is used in a where clause it must be early bound. +For example: ```rust # trait Trait<'a> {} fn foo<'a, T: Trait<'a>>(_: &'a String, _: T) {} ``` -In this example the lifetime parameter `'a` is considered to be early bound as it appears in the where clause `T: Trait<'a>`. This is true even for "trivial" where clauses such as `'a: 'a` or those implied by wellformedness of function arguments, for example: +In this example the lifetime parameter `'a` is considered to be early bound as it appears in the where clause `T: Trait<'a>`. +This is true even for "trivial" where clauses such as `'a: 'a` or those implied by wellformedness of function arguments, for example: ```rust fn foo<'a: 'a>(_: &'a String) {} fn bar<'a, T: 'a>(_: &'a T) {} @@ -369,9 +394,12 @@ f(&String::new()); At *some point* during type checking an error should be emitted for this code as `String` does not implement `Trait` for any lifetime. -If the lifetime `'a` were late bound then this becomes difficult to check. When naming `foo` we do not know what lifetime should be used as part of the `T: Trait<'a>` trait bound as it has not yet been instantiated. When coercing the function item type to a function pointer we have no way of tracking the `String: Trait<'a>` trait bound that must be proven when calling the function. +If the lifetime `'a` were late bound then this becomes difficult to check. +When naming `foo` we do not know what lifetime should be used as part of the `T: Trait<'a>` trait bound as it has not yet been instantiated. +When coercing the function item type to a function pointer we have no way of tracking the `String: Trait<'a>` trait bound that must be proven when calling the function. -If the lifetime `'a` is early bound (which it is in the current implementation in rustc), then the trait bound can be checked when naming the function `foo`. Requiring parameters used in where clauses to be early bound gives a natural place to check where clauses defined on the function. +If the lifetime `'a` is early bound (which it is in the current implementation in rustc), then the trait bound can be checked when naming the function `foo`. +Requiring parameters used in where clauses to be early bound gives a natural place to check where clauses defined on the function. Finally, we do not require lifetimes to be early bound if they are used in *implied bounds*, for example: ```rust @@ -382,11 +410,13 @@ f(&String::new()); f(&String::new()); ``` -This code compiles, demonstrating that the lifetime parameter is late bound, even though `'a` is used in the type `&'a T` which implicitly requires `T: 'a` to hold. Implied bounds can be treated specially as any types introducing implied bounds are in the signature of the function pointer type, which means that when calling the function we know to prove `T: 'a`. +This code compiles, demonstrating that the lifetime parameter is late bound, even though `'a` is used in the type `&'a T` which implicitly requires `T: 'a` to hold. +Implied bounds can be treated specially as any types introducing implied bounds are in the signature of the function pointer type, which means that when calling the function we know to prove `T: 'a`. ### Must be constrained by argument types -It is important that builtin impls on function item types do not wind up with unconstrained generic parameters as this can lead to unsoundness. This is the same kind of restriction as applies to user written impls, for example the following code results in an error: +It is important that builtin impls on function item types do not wind up with unconstrained generic parameters as this can lead to unsoundness. +This is the same kind of restriction as applies to user written impls, for example the following code results in an error: ```rust trait Trait { type Assoc; diff --git a/src/doc/rustc-dev-guide/src/feature-gate-check.md b/src/doc/rustc-dev-guide/src/feature-gate-check.md index 59e50837c52e..038a14ac070e 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-check.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-check.md @@ -8,7 +8,7 @@ nightly-only `#![feature(...)]` opt-in. This chapter documents the implementation of feature gating: where gates are defined, how they are enabled, and how usage is verified. - + ## Feature Definitions diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index bf31e79a9a15..faa2d8f2a3a2 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -383,6 +383,13 @@ Both the upside and downside of this is that it simplifies the history. On the one hand, you lose track of the steps in which changes were made, but the history becomes easier to work with. +The easiest way to squash your commits in a PR on the `rust-lang/rust` repository is to use the `@bors squash` command in a comment on the PR. +By default, [bors] combines all commit messages of the PR into the squashed commit message. +To customize the commit message, use `@bors squash msg=`. + + +If you want to squash commits using local git operations, read on below. + If there are no conflicts and you are just squashing to clean up the history, use `git rebase --interactive --keep-base main`. This keeps the fork point of your PR the same, making it easier to review the diff of what happened @@ -410,11 +417,6 @@ because they only represent "fixups" and not real changes. For example, `git rebase --interactive HEAD~2` will allow you to edit the two commits only. -For pull requests in `rust-lang/rust`, you can ask [bors] to squash by commenting -`@bors squash` on the PR. -By default, [bors] combines all commit messages in the PR. -To customize the commit message, use `@bors squash [msg|message=]`. - [bors]: https://github.com/rust-lang/bors ### `git range-diff` diff --git a/src/doc/rustc-dev-guide/src/parallel-rustc.md b/src/doc/rustc-dev-guide/src/parallel-rustc.md index ce69b66c2daf..c4e0663068e6 100644 --- a/src/doc/rustc-dev-guide/src/parallel-rustc.md +++ b/src/doc/rustc-dev-guide/src/parallel-rustc.md @@ -11,7 +11,8 @@ Tracking issue: As of November 2024, most of the rust compiler is now parallelized. -- The codegen part is executed concurrently by default. You can use the `-C +- The codegen part is executed concurrently by default. + You can use the `-C codegen-units=n` option to control the number of concurrent tasks. - The parts after HIR lowering to codegen such as type checking, borrowing checking, and mir optimization are parallelized in the nightly version. @@ -31,24 +32,25 @@ The following sections are kept for now but are quite outdated. ## Code generation During monomorphization the compiler splits up all the code to -be generated into smaller chunks called _codegen units_. These are then generated by -independent instances of LLVM running in parallel. At the end, the linker -is run to combine all the codegen units together into one binary. This process -occurs in the [`rustc_codegen_ssa::base`] module. +be generated into smaller chunks called _codegen units_. +These are then generated by independent instances of LLVM running in parallel. +At the end, the linker +is run to combine all the codegen units together into one binary. +This process occurs in the [`rustc_codegen_ssa::base`] module. [`rustc_codegen_ssa::base`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/base/index.html ## Data structures The underlying thread-safe data-structures used in the parallel compiler -can be found in the [`rustc_data_structures::sync`] module. These data structures +can be found in the [`rustc_data_structures::sync`] module. +These data structures are implemented differently depending on whether `parallel-compiler` is true. | data structure | parallel | non-parallel | | -------------------------------- | --------------------------------------------------- | ------------ | | Lock\ | (parking_lot::Mutex\) | (std::cell::RefCell) | | RwLock\ | (parking_lot::RwLock\) | (std::cell::RefCell) | -| MTLock\ | (Lock\) | (T) | | ReadGuard | parking_lot::RwLockReadGuard | std::cell::Ref | | MappedReadGuard | parking_lot::MappedRwLockReadGuard | std::cell::Ref | | WriteGuard | parking_lot::RwLockWriteGuard | std::cell::RefMut | @@ -62,21 +64,25 @@ are implemented differently depending on whether `parallel-compiler` is true. or the authoring of persistent documentation covering the specific of the invariants, the atomicity, and the lock orderings. -- On the other hand, we still need to figure out what other invariants +- On the other hand, we still need to figure out what other invariants during compilation might not hold in parallel compilation. [`rustc_data_structures::sync`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/sync/index.html ### WorkerLocal -[`WorkerLocal`] is a special data structure implemented for parallel compilers. It -holds worker-locals values for each thread in a thread pool. You can only +[`WorkerLocal`] is a special data structure implemented for parallel compilers. +It holds worker-locals values for each thread in a thread pool. +You can only access the worker local value through the `Deref` `impl` on the thread pool it -was constructed on. It panics otherwise. +was constructed on. +It panics otherwise. `WorkerLocal` is used to implement the `Arena` allocator in the parallel -environment, which is critical in parallel queries. Its implementation is -located in the [`rustc_data_structures::sync::worker_local`] module. However, +environment, which is critical in parallel queries. +Its implementation is +located in the [`rustc_data_structures::sync::worker_local`] module. +However, in the non-parallel compiler, it is implemented as `(OneThread)`, whose `T` can be accessed directly through `Deref::deref`. @@ -86,10 +92,11 @@ can be accessed directly through `Deref::deref`. ## Parallel iterator The parallel iterators provided by the [`rayon`] crate are easy ways to -implement parallelism. In the current implementation of the parallel compiler -we use a custom [fork][rustc-rayon] of `rayon` to run tasks in parallel. +implement parallelism. +In the current implementation of the parallel compiler, +we use [a custom fork of `rayon`][rustc-rayon] to run tasks in parallel. -Some iterator functions are implemented to run loops in parallel +Some iterator functions are implemented to run loops in parallel when `parallel-compiler` is true. | Function(Omit `Send` and `Sync`) | Introduction | Owning Module | @@ -143,15 +150,17 @@ When a query `foo` is evaluated, the cache table for `foo` is locked. start evaluating. - If there *is* another query invocation for the same key in progress, we release the lock, and just block the thread until the other invocation has - computed the result we are waiting for. **Cycle error detection** in the parallel - compiler requires more complex logic than in single-threaded mode. When - worker threads in parallel queries stop making progress due to interdependence, - the compiler uses an extra thread *(named deadlock handler)* to detect, remove and + computed the result we are waiting for. + **Cycle error detection** in the parallel + compiler requires more complex logic than in single-threaded mode. + When + worker threads in parallel queries stop making progress due to interdependence, + the compiler uses an extra thread *(named deadlock handler)* to detect, remove and report the cycle error. The parallel query feature still has implementation to do, most of which is -related to the previous `Data Structures` and `Parallel Iterators`. See [this -open feature tracking issue][tracking]. +related to the previous `Data Structures` and `Parallel Iterators`. +See [this open feature tracking issue][tracking]. ## Rustdoc diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md index 988284620d5c..014d1a08af78 100644 --- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md @@ -418,6 +418,13 @@ deal with all of the above but so far that seemed like more trouble than it woul ## Query modifiers +> FIXME: Make [`rustc_middle::query::modifiers`] the home for query modifier documentation, +> and migrate all other useful modifier docs there after verifying that they are still accurate. + +[`rustc_middle::query::modifiers`]: + https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/modifiers/index.html + + The query system allows for applying [modifiers][mod] to queries. These modifiers affect certain aspects of how the system treats the query with respect to incremental compilation: @@ -437,6 +444,9 @@ respect to incremental compilation: as an optimization because the system can skip recording dependencies in the first place. + - `no_force` - Never "force" the dep nodes for this query, even if the query's + key type is recoverable. + - `no_hash` - Applying `no_hash` to a query tells the system to not compute the fingerprint of the query's result. This has two consequences: @@ -475,13 +485,6 @@ respect to incremental compilation: For example, it makes no sense to store values from upstream crates in the cache because they are already available in the upstream crate's metadata. - - `anon` - This attribute makes the system use "anonymous" dep-nodes for the given query. - An anonymous dep-node is not identified by the corresponding query key. - Instead, its ID is computed from the IDs of its dependencies. - This allows the red-green system to do its change detection even if there is no - query key available for a given dep-node -- something which is needed for - handling trait selection because it is not based on queries. - [mod]: ../query.html#adding-a-new-kind-of-query diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 5ab2ab428e81..680393a6d4f3 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -90,7 +90,7 @@ dependencies of the local crate) Note that what determines the crate that a query is targeting is not the *kind* of query, but the *key*. For example, when you invoke `tcx.type_of(def_id)`, that could be a local query or an external query, depending on what crate the `def_id` -is referring to (see the [`self::keys::Key`][Key] trait for more information on how that works). +is referring to (see the [`self::keys::QueryKey`][QueryKey] trait for more information on how that works). Providers always have the same signature: @@ -168,12 +168,6 @@ pub fn provide(providers: &mut rustc_middle::util::Providers) { } ``` -Note that `util::Providers` implements `DerefMut` to `query::Providers` so callers of the `provide` functions can pass in a `util::Providers` and it will just work for provider functions that accept `query::Providers` too - -- This function takes a mutable reference to the `query::Providers` struct and sets the fields to point to the correct provider functions. -- You can also assign queries individually, e.g. `providers.type_of = type_of;`. -- You can assign fields individually for each provider type (local, external, and hooks). - #### Adding a new provider Suppose you want to add a new query called `fubar`. @@ -308,7 +302,7 @@ Let's go over these elements one by one: Also used as the name of a struct (`ty::queries::type_of`) that will be generated to represent this query. - **Query key type:** the type of the argument to this query. - This type must implement the [`ty::query::keys::Key`][Key] trait, which + This type must implement the [`ty::query::keys::QueryKey`][QueryKey] trait, which defines (for example) how to map it to a crate, and so forth. - **Result type of query:** the type produced by this query. This type should (a) not use `RefCell` or other interior mutability and (b) be @@ -317,7 +311,7 @@ Let's go over these elements one by one: - **Query modifiers:** various flags and options that customize how the query is processed (mostly with respect to [incremental compilation][incrcomp]). -[Key]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/keys/trait.Key.html +[QueryKey]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/keys/trait.QueryKey.html [incrcomp]: queries/incremental-compilation-in-detail.html#query-modifiers So, to add a query: diff --git a/src/doc/rustc-dev-guide/src/solve/candidate-preference.md b/src/doc/rustc-dev-guide/src/solve/candidate-preference.md index 461523424b3c..7fc39269d116 100644 --- a/src/doc/rustc-dev-guide/src/solve/candidate-preference.md +++ b/src/doc/rustc-dev-guide/src/solve/candidate-preference.md @@ -1,16 +1,23 @@ # Candidate preference -There are multiple ways to prove `Trait` and `NormalizesTo` goals. Each such option is called a [`Candidate`]. If there are multiple applicable candidates, we prefer some candidates over others. We store the relevant information in their [`CandidateSource`]. +There are multiple ways to prove `Trait` and `NormalizesTo` goals. +Each such option is called a [`Candidate`]. +If there are multiple applicable candidates, we prefer some candidates over others. +We store the relevant information in their [`CandidateSource`]. -This preference may result in incorrect inference or region constraints and would therefore be unsound during coherence. Because of this, we simply try to merge all candidates in coherence. +This preference may result in incorrect inference or region constraints and would therefore be unsound during coherence. +Because of this, we simply try to merge all candidates in coherence. ## `Trait` goals -Trait goals merge their applicable candidates in [`fn merge_trait_candidates`]. This document provides additional details and references to explain *why* we've got the current preference rules. +Trait goals merge their applicable candidates in [`fn merge_trait_candidates`]. +This document provides additional details and references to explain *why* we've got the current preference rules. ### `CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))` -Trivial builtin impls are builtin impls which are known to be always applicable for well-formed types. This means that if one exists, using another candidate should never have fewer constraints. We currently only consider `Sized` - and `MetaSized` - impls to be trivial. +Trivial builtin impls are builtin impls which are known to be always applicable for well-formed types. +This means that if one exists, using another candidate should never have fewer constraints. +We currently only consider `Sized` - and `MetaSized` - impls to be trivial. This is necessary to prevent a lifetime error for the following pattern @@ -25,7 +32,7 @@ where { // Elaborating the `&'a str: Trait` where-bound results in a // `&'a str: Sized` where-bound. We do not want to prefer this - // over the builtin impl. + // over the builtin impl. is_sized(x); } ``` @@ -50,7 +57,8 @@ where ### `CandidateSource::ParamEnv` Once there's at least one *non-global* `ParamEnv` candidate, we prefer *all* `ParamEnv` candidates over other candidate kinds. -A where-bound is global if it is not higher-ranked and doesn't contain any generic parameters. It may contain `'static`. +A where-bound is global if it is not higher-ranked and doesn't contain any generic parameters. +It may contain `'static`. We try to apply where-bounds over other candidates as users tends to have the most control over them, so they can most easily adjust them in case our candidate preference is incorrect. @@ -68,7 +76,8 @@ fn foo<'a, T: Trait<'a>>() { } ``` -We also need this as shadowed impls can result in currently ambiguous solver cycles: [trait-system-refactor-initiative#76]. Without preference we'd be forced to fail with ambiguity +We also need this as shadowed impls can result in currently ambiguous solver cycles: [trait-system-refactor-initiative#76]. +Without preference, we'd be forced to fail with ambiguity errors if the where-bound results in region constraints to avoid incompleteness. ```rust trait Super { @@ -89,13 +98,15 @@ where fn overflow() { // We can use the elaborated `Super` where-bound // to prove the where-bound of the `T: Trait` implementation. This currently results in - // overflow. + // overflow. let x: ::TraitAssoc; } ``` -This preference causes a lot of issues. See [#24066]. Most of the -issues are caused by preferring where-bounds over impls even if the where-bound guides type inference: +This preference causes a lot of issues. +See [#24066]. +Most of the +issues are caused by preferring where-bounds over impls even, if the where-bound guides type inference: ```rust trait Trait { fn call_me(&self, x: T) {} @@ -167,7 +178,10 @@ where #### Why no preference for global where-bounds -Global where-bounds are either fully implied by an impl or unsatisfiable. If they are unsatisfiable, we don't really care what happens. If a where-bound is fully implied then using the impl to prove the trait goal cannot result in additional constraints. For trait goals this is only useful for where-bounds which use `'static`: +Global where-bounds are either fully implied by an impl or unsatisfiable. +If they are unsatisfiable, we don't really care what happens. +If a where-bound is fully implied, then using the impl to prove the trait goal cannot result in additional constraints. +For trait goals, this is only useful for where-bounds which use `'static`: ```rust trait A { @@ -181,13 +195,15 @@ where x.test(); } ``` -More importantly, by using impls here we prevent global where-bounds from shadowing impls when normalizing associated types. There are no known issues from preferring impls over global where-bounds. +More importantly, by using impls here, we prevent global where-bounds from shadowing impls when normalizing associated types. +There are no known issues from preferring impls over global where-bounds. #### Why still consider global where-bounds Given that we just use impls even if there exists a global where-bounds, you may ask why we don't just ignore these global where-bounds entirely: we use them to weaken the inference guidance from non-global where-bounds. -Without a global where-bound, we currently prefer non-global where bounds even though there would be an applicable impl as well. By adding a non-global where-bound, this unnecessary inference guidance is disabled, allowing the following to compile: +Without a global where-bound, we currently prefer non-global where bounds even though there would be an applicable impl as well. +By adding a non-global where-bound, this unnecessary inference guidance is disabled, allowing the following to compile: ```rust fn check(color: Color) where @@ -209,7 +225,9 @@ impl From for f32 { ### `CandidateSource::AliasBound` -We prefer alias-bound candidates over impls. We currently use this preference to guide type inference, causing the following to compile. I personally don't think this preference is desirable 🤷 +We prefer alias-bound candidates over impls. +We currently use this preference to guide type inference, causing the following to compile. +I personally don't think this preference is desirable 🤷 ```rust pub trait Dyn { type Word: Into; @@ -254,7 +272,9 @@ fn foo<'a, T: Trait<'a>>() { ### `CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_))` -We prefer builtin trait object impls over user-written impls. This is **unsound** and should be remoed in the future. See [#57893](https://github.com/rust-lang/rust/issues/57893) and [#141347](https://github.com/rust-lang/rust/pull/141347) for more details. +We prefer builtin trait object impls over user-written impls. +This is **unsound** and should be remoed in the future. +See [#57893] and [#141347] for more details. ## `NormalizesTo` goals @@ -336,7 +356,7 @@ Even if the trait goal was proven via an impl, we still prefer `ParamEnv` candid #### We prefer "orphaned" where-bounds We add "orphaned" `Projection` clauses into the `ParamEnv` when normalizing item bounds of GATs and RPITIT in `fn check_type_bounds`. -We need to prefer these `ParamEnv` candidates over impls and other where-bounds. +We need to prefer these `ParamEnv` candidates over impls and other where-bounds. ```rust #![feature(associated_type_defaults)] trait Foo { @@ -355,7 +375,8 @@ I don't fully understand the cases where this preference is actually necessary a #### We prefer global where-bounds over impls -This is necessary for the following to compile. I don't know whether anything relies on it in practice 🤷 +This is necessary for the following to compile. +I don't know whether anything relies on it in practice 🤷 ```rust trait Id { type This; @@ -423,7 +444,8 @@ where #### RPITIT `type_of` cycles -We currently have to avoid impl candidates if there are where-bounds to avoid query cycles for RPITIT, see [#139762]. It feels desirable to me to stop relying on auto-trait leakage of during RPITIT computation to remove this issue, see [#139788]. +We currently have to avoid impl candidates if there are where-bounds to avoid query cycles for RPITIT, see [#139762]. +It feels desirable to me to stop relying on auto-trait leakage of during RPITIT computation to remove this issue, see [#139788]. ```rust use std::future::Future; @@ -454,6 +476,31 @@ where } ``` + +#### Trait definition cannot use associated types from always applicable impls + +The `T: Trait` assumption in the trait definition prevents it from normalizing +`::Assoc` to `T` by using the blanket impl. +This feels like a somewhat desirable constraint, if not incredibly so. + +```rust +trait Eq {} +impl Eq for T {} +struct IsEqual, U>(T, U); + +trait Trait: Sized { + type Assoc; + fn foo() -> IsEqual { + //~^ ERROR the trait bound `Self: Eq<::Assoc>` is not satisfied + todo!() + } +} + +impl Trait for T { + type Assoc = T; +} +``` + [`Candidate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_next_trait_solver/solve/assembly/struct.Candidate.html [`CandidateSource`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_next_trait_solver/solve/enum.CandidateSource.html [`fn merge_trait_candidates`]: https://github.com/rust-lang/rust/blob/e3ee7f7aea5b45af3b42b5e4713da43876a65ac9/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs#L1342-L1424 @@ -462,4 +509,6 @@ where [#24066]: https://github.com/rust-lang/rust/issues/24066 [#133044]: https://github.com/rust-lang/rust/issues/133044 [#139762]: https://github.com/rust-lang/rust/pull/139762 -[#139788]: https://github.com/rust-lang/rust/issues/139788 \ No newline at end of file +[#139788]: https://github.com/rust-lang/rust/issues/139788 +[#57893]: https://github.com/rust-lang/rust/issues/57893 +[#141347]: https://github.com/rust-lang/rust/pull/141347 diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 6b63f68b29ee..5581b7eb9d8d 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -109,6 +109,14 @@ The live results can be seen on [the GitHub Actions workflows page]. At any given time, at most a single `auto` build is being executed. Find out more in [Merging PRs serially with bors](#merging-prs-serially-with-bors). +Normally, when an auto job fails, the whole CI workflow immediately ends. +However, it can be useful to +create auto jobs that are "non-blocking", or optional, to test them on CI for some time before blocking +merges on them. +This can be useful if those jobs can be flaky. + +To do that, prefix such a job with `optional-`, and set `continue_on_error: true` for it in [`jobs.yml`]. + [platform tiers]: https://forge.rust-lang.org/release/platform-support.html#rust-platform-support [auto]: https://github.com/rust-lang/rust/tree/automation/bors/auto diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 6ca9653c1854..a239310d124e 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -836,3 +836,20 @@ In CI, compare modes are only used in one Linux builder, and only with the follo Note that compare modes are separate to [revisions](#revisions). All revisions are tested when running `./x test tests/ui`, however compare-modes must be manually run individually via the `--compare-mode` flag. + +## Parallel frontend + +Compiletest can be run with the `--parallel-frontend-threads` flag to run the compiler in parallel mode. +This can be used to check that the compiler produces the same output in parallel mode as in non-parallel mode, and to check for any issues that might arise in parallel mode. + +To run the tests in parallel mode, you need to pass the `--parallel-frontend-threads` CLI flag: + +```bash +./x test tests/ui -- --parallel-frontend-threads=N --iteration-count=M +``` + +Where `N` is the number of threads to use for the parallel frontend, and `M` is the number of times to run each test in parallel mode (to increase the chances of catching any non-determinism). + +Also, when running with `--parallel-frontend-threads`, the `compare-output-by-lines` directive would be implied for all tests, since the output from the parallel frontend can be non-deterministic in terms of the order of lines. + +The parallel frontend is available in UI tests only at the moment, and is not currently supported in other test suites. diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index ac76a2e15d9a..f160f3fffc10 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -148,6 +148,7 @@ Some examples of `X` in `ignore-X` or `only-X`: - When [remote testing] is used: `remote` - When particular debuggers are being tested: `cdb`, `gdb`, `lldb` - When particular debugger versions are matched: `ignore-gdb-version` +- When the [parallel frontend] is enabled: `ignore-parallel-frontend` - Specific [compare modes]: `compare-mode-polonius`, `compare-mode-chalk`, `compare-mode-split-dwarf`, `compare-mode-split-dwarf-single` - The two different test modes used by coverage tests: @@ -233,6 +234,7 @@ The following directives will check LLVM support: See also [Debuginfo tests](compiletest.md#debuginfo-tests) for directives for ignoring debuggers. [remote testing]: running.md#running-tests-on-a-remote-machine +[parallel frontend]: compiletest.md#parallel-frontend [compare modes]: ui.md#compare-modes [`x86_64-gnu-debug`]: https://github.com/rust-lang/rust/blob/ab3dba92db355b8d97db915a2dca161a117e959c/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile#L32 [`aarch64-gnu-debug`]: https://github.com/rust-lang/rust/blob/20c909ff9cdd88d33768a4ddb8952927a675b0ad/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile#L32 diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md index c13f8bde2994..82fb9597cb50 100644 --- a/src/doc/rustc-dev-guide/src/tests/intro.md +++ b/src/doc/rustc-dev-guide/src/tests/intro.md @@ -62,7 +62,8 @@ would require recompiling the entire standard library, and the entirety of package tests: * `--doc` — Only runs documentation tests in the package. -* `--no-doc` — Run all tests *except* documentation tests. +* `--all-targets` — Run all tests *except* documentation tests. +* `--tests` — Only runs unit and integration tests [tidy-unit-tests]: https://github.com/rust-lang/rust/blob/HEAD/src/tools/tidy/src/unit_tests.rs diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index 151670d08997..78a0fe4af2ff 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -14,8 +14,8 @@ of `tracing-subscriber`](https://docs.rs/tracing-subscriber/0.2.24/tracing_subsc ## Environment variables -This is an overview of the environment variables rustc accepts to customize -its tracing output. The definition of these can mostly be found in `compiler/rustc_log/src/lib.rs`. +This is an overview of the environment variables rustc accepts to customize its tracing output. +The definition of these can mostly be found in `compiler/rustc_log/src/lib.rs`. | Name | Usage | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 9049828c8b12..cc10f476780c 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -155,5 +155,7 @@ - [x86_64-unknown-linux-none](platform-support/x86_64-unknown-linux-none.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [x86_64-unknown-linux-gnuasan](platform-support/x86_64-unknown-linux-gnuasan.md) + - [x86_64-unknown-linux-gnumsan](platform-support/x86_64-unknown-linux-gnumsan.md) + - [x86_64-unknown-linux-gnutsan](platform-support/x86_64-unknown-linux-gnutsan.md) - [xtensa-\*-none-elf](platform-support/xtensa.md) - [\*-nuttx-\*](platform-support/nuttx.md) diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index 1502e694bba5..1e5822d9c357 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -194,7 +194,7 @@ def minor_version(version): INSTALL_TOOLCHAIN = ["rustup", "toolchain", "install", "--profile", "minimal"] subprocess.run(INSTALL_TOOLCHAIN + ["nightly"]) -LOWER_BOUND = 87 +LOWER_BOUND = 91 NIGHTLY_VERSION = minor_version(subprocess.run( ["rustc", "+nightly", "--version"], capture_output=True, @@ -256,6 +256,6 @@ The following table shows known good combinations of toolchain versions. | 1.78 - 1.81 | 18 | | 1.82 - 1.86 | 19 | | 1.87 - 1.90 | 20 | -| 1.91 - 1.93 | 21 | +| 1.91 - 1.94 | 21 | Note that the compatibility policy for this feature might change in the future. diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index a8b2111a901e..26dd6b31b899 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -216,6 +216,8 @@ target | std | notes [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android [`x86_64-unknown-linux-gnuasan`](platform-support/x86_64-unknown-linux-gnuasan.md) | ✓ | 64-bit Linux (kernel 3.2+, glibc 2.17+) with ASAN enabled by default +[`x86_64-unknown-linux-gnumsan`](platform-support/x86_64-unknown-linux-gnumsan.md) | ✓ | 64-bit Linux (kernel 3.2+, glibc 2.17+) with MSAN enabled by default +[`x86_64-unknown-linux-gnutsan`](platform-support/x86_64-unknown-linux-gnutsan.md) | ✓ | 64-bit Linux (kernel 3.2+, glibc 2.17+) with TSAN enabled by default [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15+, glibc 2.27) [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md index baa46135d534..36609d5742cc 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md @@ -7,6 +7,7 @@ Target for 64-bit little endian ARMv8-A Linux 4.1+ programs using glibc 2.17+. ## Target maintainers - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml [arm_email]: mailto:rust@arm.com diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md index 5d1201bbf426..b9386f07fe2d 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md @@ -16,6 +16,7 @@ Processors in this family include the [Arm Cortex-A35, 53, 76, etc][aarch64-cpus - [Rust Embedded Devices Working Group Arm Team] - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml diff --git a/src/doc/rustc/src/platform-support/aarch64v8r-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64v8r-unknown-none.md index 9e232b320516..bbe9d8b3ba87 100644 --- a/src/doc/rustc/src/platform-support/aarch64v8r-unknown-none.md +++ b/src/doc/rustc/src/platform-support/aarch64v8r-unknown-none.md @@ -16,6 +16,7 @@ For Armv8-R CPUs running in AArch32 mode (such as the Arm Cortex-R52), see - [Rust Embedded Devices Working Group Arm Team] - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md index c2fe63a49087..c7888571df3d 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md @@ -8,6 +8,7 @@ Target for 32-bit little endian ARMv7-A Linux 3.2+ programs using glibc 2.17+. ## Target maintainers - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml [arm_email]: mailto:rust@arm.com diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md index 555f69e81a02..0fa09d3955ff 100644 --- a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md @@ -24,6 +24,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all - [Rust Embedded Devices Working Group Arm Team] - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md index 20fd55c6abd6..5f95af44a793 100644 --- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md @@ -22,6 +22,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all - [@chrisnc](https://github.com/chrisnc) - [Rust Embedded Devices Working Group Arm Team] - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md index 73d88bcb89a1..1ff36b47beb2 100644 --- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md +++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md @@ -26,6 +26,7 @@ For Armv8-R CPUs running in AArch64 mode (such as the Arm Cortex-R82), see - [@chrisnc](https://github.com/chrisnc) - [Rust Embedded Devices Working Group Arm Team] - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md index a923218282c1..7817ce6138a0 100644 --- a/src/doc/rustc/src/platform-support/loongarch-linux.md +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -44,8 +44,8 @@ The targets require a reasonably up-to-date LoongArch toolchain on the host. Currently the following components are used by the Rust CI to build the target, and the versions can be seen as the minimum requirement: -* GNU Binutils 2.42 -* GCC 14.x +* GNU Binutils 2.45 +* GCC 15.x * glibc 2.36 * linux-headers 5.19 diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md index 192e013d3a43..1f91e2f18631 100644 --- a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md @@ -24,6 +24,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all - [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml [arm_email]: mailto:rust@arm.com diff --git a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md index b04cb7bfacfa..90f641d6e4f8 100644 --- a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md @@ -25,6 +25,7 @@ only option because there is no FPU support in [Armv7-M]. - [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml [arm_email]: mailto:rust@arm.com diff --git a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md index 104520854b49..20fdb18eafa5 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md @@ -25,6 +25,7 @@ only option because there is no FPU support in [Armv8-M] Baseline. - [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml [arm_email]: mailto:rust@arm.com diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md index 5cc535ce376b..ab77153be92b 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md @@ -28,6 +28,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all - [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) - [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml [arm_email]: mailto:rust@arm.com diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md index e8989616b844..d286ab4fb35a 100644 --- a/src/doc/rustc/src/platform-support/unknown-uefi.md +++ b/src/doc/rustc/src/platform-support/unknown-uefi.md @@ -16,6 +16,7 @@ Available targets: - [@dvdhrm](https://github.com/dvdhrm) - [@nicholasbishop](https://github.com/nicholasbishop) - (for `aarch64-unknown-uefi` only) [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + - Use `@rustbot ping arm-maintainers` to ping us [arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml [arm_email]: mailto:rust@arm.com diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md index 091c757a2ee3..0cf3822f759e 100644 --- a/src/doc/rustc/src/platform-support/vxworks.md +++ b/src/doc/rustc/src/platform-support/vxworks.md @@ -28,6 +28,12 @@ Target triplets available: The minimum supported version is VxWorks 7. +### Environment + +#### `WIND_RELEASE_ID` + +In VxWorks build environment, the environment variable `WIND_RELEASE_ID` indicates the VxWorks release version used for the build. The `WIND_RELEASE_ID` can be used to conditionally compile features/code or handle version specific behaviour. + ## Building Rust for each target can be cross-compiled with its specific target vsb configuration. Std support is added but not yet fully tested. diff --git a/src/doc/rustc/src/platform-support/x86_64-unknown-linux-gnumsan.md b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-gnumsan.md new file mode 100644 index 000000000000..3b56436d0a1c --- /dev/null +++ b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-gnumsan.md @@ -0,0 +1,56 @@ +# `x86_64-unknown-linux-gnumsan` + +**Tier: 2** + +Target mirroring `x86_64-unknown-linux-gnu` with MemorySanitizer enabled by +default. +The goal of this target is to allow shipping MSAN-instrumented standard +libraries through rustup, enabling a fully instrumented binary without requiring +nightly features (build-std). +Once build-std stabilizes, this target is no longer needed and will be removed. + +## Target maintainers + +- [@jakos-sec](https://github.com/jakos-sec) +- [@1c3t3a](https://github.com/1c3t3a) +- [@rust-lang/project-exploit-mitigations][project-exploit-mitigations] + +## Requirements + +The target is for cross-compilation only. Host tools are not supported, since +there is no need to have the host tools instrumented with MSAN. std is fully +supported. + +In all other aspects the target is equivalent to `x86_64-unknown-linux-gnu`. + +## Building the target + +The target can be built by enabling it for a rustc build: + +```toml +[build] +target = ["x86_64-unknown-linux-gnumsan"] +``` + +## Building Rust programs + +Rust programs can be compiled by adding this target via rustup: + +```sh +$ rustup target add x86_64-unknown-linux-gnumsan +``` + +and then compiling with the target: + +```sh +$ rustc foo.rs --target x86_64-unknown-linux-gnumsan +``` + +## Testing + +Created binaries will run on Linux without any external requirements. + +## Cross-compilation toolchains and C code + +The target supports C code and should use the same toolchain target as +`x86_64-unknown-linux-gnu`. diff --git a/src/doc/rustc/src/platform-support/x86_64-unknown-linux-gnutsan.md b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-gnutsan.md new file mode 100644 index 000000000000..71488f476cd5 --- /dev/null +++ b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-gnutsan.md @@ -0,0 +1,56 @@ +# `x86_64-unknown-linux-gnutsan` + +**Tier: 2** + +Target mirroring `x86_64-unknown-linux-gnu` with ThreadSanitizer enabled by +default. +The goal of this target is to allow shipping TSAN-instrumented standard +libraries through rustup, enabling a fully instrumented binary without requiring +nightly features (build-std). +Once build-std stabilizes, this target is no longer needed and will be removed. + +## Target maintainers + +- [@jakos-sec](https://github.com/jakos-sec) +- [@1c3t3a](https://github.com/1c3t3a) +- [@rust-lang/project-exploit-mitigations][project-exploit-mitigations] + +## Requirements + +The target is for cross-compilation only. Host tools are not supported, since +there is no need to have the host tools instrumented with TSAN. std is fully +supported. + +In all other aspects the target is equivalent to `x86_64-unknown-linux-gnu`. + +## Building the target + +The target can be built by enabling it for a rustc build: + +```toml +[build] +target = ["x86_64-unknown-linux-gnutsan"] +``` + +## Building Rust programs + +Rust programs can be compiled by adding this target via rustup: + +```sh +$ rustup target add x86_64-unknown-linux-gnutsan +``` + +and then compiling with the target: + +```sh +$ rustc foo.rs --target x86_64-unknown-linux-gnutsan +``` + +## Testing + +Created binaries will run on Linux without any external requirements. + +## Cross-compilation toolchains and C code + +The target supports C code and should use the same toolchain target as +`x86_64-unknown-linux-gnu`. diff --git a/src/doc/unstable-book/src/compiler-flags/min-recursive-limit.md b/src/doc/unstable-book/src/compiler-flags/min-recursive-limit.md new file mode 100644 index 000000000000..c00cdb95c032 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/min-recursive-limit.md @@ -0,0 +1,12 @@ +# `min-recursion-limit` + +This flag sets a minimum recursion limit for the compiler. The final recursion limit is calculated as `max(min_recursion_limit, recursion_limit_from_crate)`. This cannot ever lower the recursion limit. Unless the current crate has an explicitly low `recursion_limit` attribute, any value less than the current default does not have an effect. + +The recursion limit affects (among other things): + +- macro expansion +- the trait solver +- const evaluation +- query depth + +This flag is particularly useful when using the next trait solver (`-Z next-solver`), which may require a higher recursion limit for crates that were compiled successfully with the old solver. diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 1771d1382f07..eb070c22dc28 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -22,6 +22,8 @@ This feature allows for use of one of following sanitizers: * [AddressSanitizer](#addresssanitizer) a fast memory error detector. * [HWAddressSanitizer](#hwaddresssanitizer) a memory error detector similar to AddressSanitizer, but based on partial hardware assistance. + * [KernelHWAddressSanitizer](#kernelhwaddresssanitizer) variant of + HWAddressSanitizer that is designed for bare metal environments. * [LeakSanitizer](#leaksanitizer) a run-time memory leak detector. * [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads. * [RealtimeSanitizer](#realtimesanitizer) a detector of calls to function with @@ -622,6 +624,16 @@ Registers where the failure occurred (pc 0xaaaae0ae4a98): SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94) ``` +# KernelHWAddressSanitizer + +KernelHWAddressSanitizer is the kernel version of [HWAddressSanitizer](#hwaddresssanitizer), +which achieves the same purpose but is designed for bare-metal environments. + +HWAddressSanitizer is supported on the `aarch64*-unknown-none` and +`aarch64*-unknown-none-softfloat` targets. + +See the [Clang HWAddressSanitizer documentation][clang-hwasan] for more details. + # KernelControlFlowIntegrity The LLVM Kernel Control Flow Integrity (CFI) support to the Rust compiler diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md index 23c2dc688400..a0c9a7e30277 100644 --- a/src/doc/unstable-book/src/language-features/deref-patterns.md +++ b/src/doc/unstable-book/src/language-features/deref-patterns.md @@ -6,8 +6,7 @@ The tracking issue for this feature is: [#87121] ------------------------ -> **Note**: This feature is incomplete. In the future, it is meant to supersede -> [`box_patterns`]. +> **Note**: This feature supersedes [`box_patterns`]. This feature permits pattern matching on [smart pointers in the standard library] through their `Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which @@ -15,7 +14,6 @@ is currently a placeholder). ```rust #![feature(deref_patterns)] -#![allow(incomplete_features)] let mut v = vec![Box::new(Some(0))]; @@ -58,7 +56,6 @@ Like [`box_patterns`], deref patterns may move out of boxes: ```rust # #![feature(deref_patterns)] -# #![allow(incomplete_features)] struct NoCopy; let deref!(x) = Box::new(NoCopy); drop::(x); @@ -69,7 +66,6 @@ allowing then to be used in deref patterns: ```rust # #![feature(deref_patterns)] -# #![allow(incomplete_features)] match ("test".to_string(), Box::from("test"), b"test".to_vec()) { ("test", "test", b"test") => {} _ => panic!(), diff --git a/src/doc/unstable-book/src/language-features/try-blocks.md b/src/doc/unstable-book/src/language-features/try-blocks.md index e342c260a739..f72467f06476 100644 --- a/src/doc/unstable-book/src/language-features/try-blocks.md +++ b/src/doc/unstable-book/src/language-features/try-blocks.md @@ -1,8 +1,8 @@ # `try_blocks` -The tracking issue for this feature is: [#31436] +The tracking issue for this feature is: [#154391] -[#31436]: https://github.com/rust-lang/rust/issues/31436 +[#154391]: https://github.com/rust-lang/rust/issues/154391 ------------------------ @@ -14,14 +14,14 @@ block creates a new scope one can use the `?` operator in. use std::num::ParseIntError; -let result: Result = try { +let result = try { "1".parse::()? + "2".parse::()? + "3".parse::()? }; assert_eq!(result, Ok(6)); -let result: Result = try { +let result = try { "1".parse::()? + "foo".parse::()? + "3".parse::()? diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index a837be680dcd..427e46a32a48 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -329,14 +329,16 @@ complete -c x -n "__fish_x_using_subcommand test" -l reproducible-artifact -d 'A complete -c x -n "__fish_x_using_subcommand test" -l set -d 'override options in bootstrap.toml' -r -f complete -c x -n "__fish_x_using_subcommand test" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" complete -c x -n "__fish_x_using_subcommand test" -l no-fail-fast -d 'run all tests regardless of failure' -complete -c x -n "__fish_x_using_subcommand test" -l no-doc -d 'do not run doc tests' -complete -c x -n "__fish_x_using_subcommand test" -l doc -d 'only run doc tests' +complete -c x -n "__fish_x_using_subcommand test" -l all-targets -d 'Run all test targets (no doc tests)' +complete -c x -n "__fish_x_using_subcommand test" -l doc -d 'Only run doc tests' +complete -c x -n "__fish_x_using_subcommand test" -l tests -d 'Only run unit and integration tests' complete -c x -n "__fish_x_using_subcommand test" -l bless -d 'whether to automatically update stderr/stdout files' complete -c x -n "__fish_x_using_subcommand test" -l force-rerun -d 'rerun tests even if the inputs are unchanged' complete -c x -n "__fish_x_using_subcommand test" -l only-modified -d 'only run tests that result has been changed' complete -c x -n "__fish_x_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`' complete -c x -n "__fish_x_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests' complete -c x -n "__fish_x_using_subcommand test" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' +complete -c x -n "__fish_x_using_subcommand test" -l no-doc -d 'Deprecated. Use `--all-targets` or `--tests` instead' complete -c x -n "__fish_x_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x -n "__fish_x_using_subcommand test" -s i -l incremental -d 'use incremental compilation' complete -c x -n "__fish_x_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -374,8 +376,10 @@ complete -c x -n "__fish_x_using_subcommand miri" -l reproducible-artifact -d 'A complete -c x -n "__fish_x_using_subcommand miri" -l set -d 'override options in bootstrap.toml' -r -f complete -c x -n "__fish_x_using_subcommand miri" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" complete -c x -n "__fish_x_using_subcommand miri" -l no-fail-fast -d 'run all tests regardless of failure' -complete -c x -n "__fish_x_using_subcommand miri" -l no-doc -d 'do not run doc tests' -complete -c x -n "__fish_x_using_subcommand miri" -l doc -d 'only run doc tests' +complete -c x -n "__fish_x_using_subcommand miri" -l all-targets -d 'Run all test targets (no doc tests)' +complete -c x -n "__fish_x_using_subcommand miri" -l doc -d 'Only run doc tests' +complete -c x -n "__fish_x_using_subcommand miri" -l tests -d 'Only run unit and integration tests' +complete -c x -n "__fish_x_using_subcommand miri" -l no-doc -d 'Deprecated. Use `--all-targets` or `--tests` instead' complete -c x -n "__fish_x_using_subcommand miri" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x -n "__fish_x_using_subcommand miri" -s i -l incremental -d 'use incremental compilation' complete -c x -n "__fish_x_using_subcommand miri" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index 1a02adbddfea..ffaadf247034 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -376,14 +376,16 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') [CompletionResult]::new('--no-fail-fast', '--no-fail-fast', [CompletionResultType]::ParameterName, 'run all tests regardless of failure') - [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'do not run doc tests') - [CompletionResult]::new('--doc', '--doc', [CompletionResultType]::ParameterName, 'only run doc tests') + [CompletionResult]::new('--all-targets', '--all-targets', [CompletionResultType]::ParameterName, 'Run all test targets (no doc tests)') + [CompletionResult]::new('--doc', '--doc', [CompletionResultType]::ParameterName, 'Only run doc tests') + [CompletionResult]::new('--tests', '--tests', [CompletionResultType]::ParameterName, 'Only run unit and integration tests') [CompletionResult]::new('--bless', '--bless', [CompletionResultType]::ParameterName, 'whether to automatically update stderr/stdout files') [CompletionResult]::new('--force-rerun', '--force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged') [CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed') [CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`') [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') + [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'Deprecated. Use `--all-targets` or `--tests` instead') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -428,8 +430,10 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') [CompletionResult]::new('--no-fail-fast', '--no-fail-fast', [CompletionResultType]::ParameterName, 'run all tests regardless of failure') - [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'do not run doc tests') - [CompletionResult]::new('--doc', '--doc', [CompletionResultType]::ParameterName, 'only run doc tests') + [CompletionResult]::new('--all-targets', '--all-targets', [CompletionResultType]::ParameterName, 'Run all test targets (no doc tests)') + [CompletionResult]::new('--doc', '--doc', [CompletionResultType]::ParameterName, 'Only run doc tests') + [CompletionResult]::new('--tests', '--tests', [CompletionResultType]::ParameterName, 'Only run unit and integration tests') + [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'Deprecated. Use `--all-targets` or `--tests` instead') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 63b7987fb290..df5e7f3a6dda 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -329,14 +329,16 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l reproducible-artifact complete -c x.py -n "__fish_x.py_using_subcommand test" -l set -d 'override options in bootstrap.toml' -r -f complete -c x.py -n "__fish_x.py_using_subcommand test" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-fail-fast -d 'run all tests regardless of failure' -complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-doc -d 'do not run doc tests' -complete -c x.py -n "__fish_x.py_using_subcommand test" -l doc -d 'only run doc tests' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l all-targets -d 'Run all test targets (no doc tests)' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l doc -d 'Only run doc tests' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l tests -d 'Only run unit and integration tests' complete -c x.py -n "__fish_x.py_using_subcommand test" -l bless -d 'whether to automatically update stderr/stdout files' complete -c x.py -n "__fish_x.py_using_subcommand test" -l force-rerun -d 'rerun tests even if the inputs are unchanged' complete -c x.py -n "__fish_x.py_using_subcommand test" -l only-modified -d 'only run tests that result has been changed' complete -c x.py -n "__fish_x.py_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`' complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests' complete -c x.py -n "__fish_x.py_using_subcommand test" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-doc -d 'Deprecated. Use `--all-targets` or `--tests` instead' complete -c x.py -n "__fish_x.py_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_x.py_using_subcommand test" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_x.py_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -374,8 +376,10 @@ complete -c x.py -n "__fish_x.py_using_subcommand miri" -l reproducible-artifact complete -c x.py -n "__fish_x.py_using_subcommand miri" -l set -d 'override options in bootstrap.toml' -r -f complete -c x.py -n "__fish_x.py_using_subcommand miri" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" complete -c x.py -n "__fish_x.py_using_subcommand miri" -l no-fail-fast -d 'run all tests regardless of failure' -complete -c x.py -n "__fish_x.py_using_subcommand miri" -l no-doc -d 'do not run doc tests' -complete -c x.py -n "__fish_x.py_using_subcommand miri" -l doc -d 'only run doc tests' +complete -c x.py -n "__fish_x.py_using_subcommand miri" -l all-targets -d 'Run all test targets (no doc tests)' +complete -c x.py -n "__fish_x.py_using_subcommand miri" -l doc -d 'Only run doc tests' +complete -c x.py -n "__fish_x.py_using_subcommand miri" -l tests -d 'Only run unit and integration tests' +complete -c x.py -n "__fish_x.py_using_subcommand miri" -l no-doc -d 'Deprecated. Use `--all-targets` or `--tests` instead' complete -c x.py -n "__fish_x.py_using_subcommand miri" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_x.py_using_subcommand miri" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_x.py_using_subcommand miri" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index cac70f722098..644c033d455f 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -376,14 +376,16 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') [CompletionResult]::new('--no-fail-fast', '--no-fail-fast', [CompletionResultType]::ParameterName, 'run all tests regardless of failure') - [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'do not run doc tests') - [CompletionResult]::new('--doc', '--doc', [CompletionResultType]::ParameterName, 'only run doc tests') + [CompletionResult]::new('--all-targets', '--all-targets', [CompletionResultType]::ParameterName, 'Run all test targets (no doc tests)') + [CompletionResult]::new('--doc', '--doc', [CompletionResultType]::ParameterName, 'Only run doc tests') + [CompletionResult]::new('--tests', '--tests', [CompletionResultType]::ParameterName, 'Only run unit and integration tests') [CompletionResult]::new('--bless', '--bless', [CompletionResultType]::ParameterName, 'whether to automatically update stderr/stdout files') [CompletionResult]::new('--force-rerun', '--force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged') [CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed') [CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`') [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') + [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'Deprecated. Use `--all-targets` or `--tests` instead') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -428,8 +430,10 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') [CompletionResult]::new('--no-fail-fast', '--no-fail-fast', [CompletionResultType]::ParameterName, 'run all tests regardless of failure') - [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'do not run doc tests') - [CompletionResult]::new('--doc', '--doc', [CompletionResultType]::ParameterName, 'only run doc tests') + [CompletionResult]::new('--all-targets', '--all-targets', [CompletionResultType]::ParameterName, 'Run all test targets (no doc tests)') + [CompletionResult]::new('--doc', '--doc', [CompletionResultType]::ParameterName, 'Only run doc tests') + [CompletionResult]::new('--tests', '--tests', [CompletionResultType]::ParameterName, 'Only run unit and integration tests') + [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'Deprecated. Use `--all-targets` or `--tests` instead') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index cff17f431d33..0d3765623c2f 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -2145,7 +2145,7 @@ _x.py() { return 0 ;; x.py__miri) - opts="-v -i -j -h --no-fail-fast --test-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --all-targets --doc --tests --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3875,7 +3875,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 47cdaf97befc..caed118ae845 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -376,14 +376,16 @@ _arguments "${_arguments_options[@]}" : \ '*--set=[override options in bootstrap.toml]:section.option=value:' \ '--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ '--no-fail-fast[run all tests regardless of failure]' \ -'--no-doc[do not run doc tests]' \ -'--doc[only run doc tests]' \ +'--all-targets[Run all test targets (no doc tests)]' \ +'--doc[Only run doc tests]' \ +'--tests[Only run unit and integration tests]' \ '--bless[whether to automatically update stderr/stdout files]' \ '--force-rerun[rerun tests even if the inputs are unchanged]' \ '--only-modified[only run tests that result has been changed]' \ '--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`//rustfix_missing_coverage.txt\`]' \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ '--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ +'--no-doc[Deprecated. Use \`--all-targets\` or \`--tests\` instead]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ @@ -430,8 +432,10 @@ _arguments "${_arguments_options[@]}" : \ '*--set=[override options in bootstrap.toml]:section.option=value:' \ '--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ '--no-fail-fast[run all tests regardless of failure]' \ -'--no-doc[do not run doc tests]' \ -'--doc[only run doc tests]' \ +'--all-targets[Run all test targets (no doc tests)]' \ +'--doc[Only run doc tests]' \ +'--tests[Only run unit and integration tests]' \ +'--no-doc[Deprecated. Use \`--all-targets\` or \`--tests\` instead]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index 700617bfeba0..d72258aa1b9f 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -2145,7 +2145,7 @@ _x() { return 0 ;; x__miri) - opts="-v -i -j -h --no-fail-fast --test-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --all-targets --doc --tests --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3875,7 +3875,7 @@ _x() { return 0 ;; x__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index b960be4a1b10..68aeb021b731 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -376,14 +376,16 @@ _arguments "${_arguments_options[@]}" : \ '*--set=[override options in bootstrap.toml]:section.option=value:' \ '--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ '--no-fail-fast[run all tests regardless of failure]' \ -'--no-doc[do not run doc tests]' \ -'--doc[only run doc tests]' \ +'--all-targets[Run all test targets (no doc tests)]' \ +'--doc[Only run doc tests]' \ +'--tests[Only run unit and integration tests]' \ '--bless[whether to automatically update stderr/stdout files]' \ '--force-rerun[rerun tests even if the inputs are unchanged]' \ '--only-modified[only run tests that result has been changed]' \ '--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`//rustfix_missing_coverage.txt\`]' \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ '--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ +'--no-doc[Deprecated. Use \`--all-targets\` or \`--tests\` instead]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ @@ -430,8 +432,10 @@ _arguments "${_arguments_options[@]}" : \ '*--set=[override options in bootstrap.toml]:section.option=value:' \ '--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ '--no-fail-fast[run all tests regardless of failure]' \ -'--no-doc[do not run doc tests]' \ -'--doc[only run doc tests]' \ +'--all-targets[Run all test targets (no doc tests)]' \ +'--doc[Only run doc tests]' \ +'--tests[Only run unit and integration tests]' \ +'--no-doc[Deprecated. Use \`--all-targets\` or \`--tests\` instead]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py deleted file mode 100755 index 2e810d7df97b..000000000000 --- a/src/etc/generate-deriving-span-tests.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python - -""" -This script creates a pile of UI tests check that all the -derives have spans that point to the fields, rather than the -#[derive(...)] line. - -sample usage: src/etc/generate-deriving-span-tests.py -""" - -import os -import stat - -TEST_DIR = os.path.abspath( - os.path.join(os.path.dirname(__file__), "../test/ui/derives/") -) - -TEMPLATE = """\ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -{error_deriving} -struct Error; -{code} -fn main() {{}} -""" - -ENUM_STRING = """ -#[derive({traits})] -enum Enum {{ - A( - Error {errors} - ) -}} -""" -ENUM_STRUCT_VARIANT_STRING = """ -#[derive({traits})] -enum Enum {{ - A {{ - x: Error {errors} - }} -}} -""" -STRUCT_STRING = """ -#[derive({traits})] -struct Struct {{ - x: Error {errors} -}} -""" -STRUCT_TUPLE_STRING = """ -#[derive({traits})] -struct Struct( - Error {errors} -); -""" - -ENUM_TUPLE, ENUM_STRUCT, STRUCT_FIELDS, STRUCT_TUPLE = range(4) - - -def create_test_case(type, trait, super_traits, error_count): - string = [ - ENUM_STRING, - ENUM_STRUCT_VARIANT_STRING, - STRUCT_STRING, - STRUCT_TUPLE_STRING, - ][type] - all_traits = ",".join([trait] + super_traits) - super_traits = ",".join(super_traits) - error_deriving = "#[derive(%s)]" % super_traits if super_traits else "" - - errors = "\n".join("//~%s ERROR" % ("^" * n) for n in range(error_count)) - code = string.format(traits=all_traits, errors=errors) - return TEMPLATE.format(error_deriving=error_deriving, code=code) - - -def write_file(name, string): - test_file = os.path.join(TEST_DIR, "derives-span-%s.rs" % name) - - # set write permission if file exists, so it can be changed - if os.path.exists(test_file): - os.chmod(test_file, stat.S_IWUSR) - - with open(test_file, "w") as f: - f.write(string) - - # mark file read-only - os.chmod(test_file, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) - - -ENUM = 1 -STRUCT = 2 -ALL = STRUCT | ENUM - -traits = { - "Default": (STRUCT, [], 1), - "FromPrimitive": (0, [], 0), # only works for C-like enums - "Decodable": (0, [], 0), # FIXME: quoting gives horrible spans - "Encodable": (0, [], 0), # FIXME: quoting gives horrible spans -} - -for trait, supers, errs in [ - ("Clone", [], 1), - ("PartialEq", [], 2), - ("PartialOrd", ["PartialEq"], 1), - ("Eq", ["PartialEq"], 1), - ("Ord", ["Eq", "PartialOrd", "PartialEq"], 1), - ("Debug", [], 1), - ("Hash", [], 1), -]: - traits[trait] = (ALL, supers, errs) - -for trait, (types, super_traits, error_count) in traits.items(): - - def mk(ty, t=trait, st=super_traits, ec=error_count): - return create_test_case(ty, t, st, ec) - - if types & ENUM: - write_file(trait + "-enum", mk(ENUM_TUPLE)) - write_file(trait + "-enum-struct-variant", mk(ENUM_STRUCT)) - if types & STRUCT: - write_file(trait + "-struct", mk(STRUCT_FIELDS)) - write_file(trait + "-tuple-struct", mk(STRUCT_TUPLE)) diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml index c9ee1ca181d5..ae2c2d906488 100644 --- a/src/etc/rust_analyzer_helix.toml +++ b/src/etc/rust_analyzer_helix.toml @@ -9,6 +9,9 @@ # x fmt --check # ``` # (if that doesn't work -- do `x clean` first) +# +# NOTE: helix doesn't support getting workspace root in configs, for this config +# to work replace WORKSPACE_ROOT with the path to your rustc checkout [language-server.rust-analyzer.config] linkedProjects = [ @@ -33,7 +36,7 @@ overrideCommand = [ [language-server.rust-analyzer.config.rustfmt] overrideCommand = [ - "build/host/rustfmt/bin/rustfmt", + "WORKSPACE_ROOT/build/host/rustfmt/bin/rustfmt", "--edition=2024" ] @@ -64,7 +67,8 @@ overrideCommand = [ ] [language-server.rust-analyzer.environment] -RUSTUP_TOOLCHAIN = "nightly" +RUSTC = "WORKSPACE_ROOT/build/host/stage0/bin/rustc" +CARGO = "WORKSPACE_ROOT/build/host/stage0/bin/cargo" [[language]] name = "rust" diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index 8e94fbaa163e..ea5bb544c700 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -1,3 +1,14 @@ +// This config uses a separate build directory for rust-analyzer, +// so that r-a's checks don't block user `x` commands and vice-verse. +// R-a's build directory is located in `build-rust-analyzer`. +// +// To download rustfmt and proc macro server for r-a run the following command +// (proc macro server is downloaded automatically with pretty much any command, +// this specific one also downloads rustfmt): +// ``` +// x fmt --check +// ``` +// (if that doesn't work -- do `x clean` first) { "git.detectSubmodulesLimit": 20, "rust-analyzer.linkedProjects": [ @@ -40,7 +51,8 @@ "build-rust-analyzer" ], "rust-analyzer.server.extraEnv": { - "RUSTUP_TOOLCHAIN": "nightly" + "RUSTC": "${workspaceFolder}/build/host/stage0/bin/rustc", + "CARGO": "${workspaceFolder}/build/host/stage0/bin/cargo" }, "files.associations": { "*.fixed": "rust", diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json index df1f7334556c..e69800c0624d 100644 --- a/src/etc/rust_analyzer_zed.json +++ b/src/etc/rust_analyzer_zed.json @@ -1,3 +1,14 @@ +// This config uses a separate build directory for rust-analyzer, +// so that r-a's checks don't block user `x` commands and vice-verse. +// R-a's build directory is located in `build-rust-analyzer`. +// +// To download rustfmt and proc macro server for r-a run the following command +// (proc macro server is downloaded automatically with pretty much any command, +// this specific one also downloads rustfmt): +// ``` +// x fmt --check +// ``` +// (if that doesn't work -- do `x clean` first) { "lsp": { "rust-analyzer": { @@ -55,7 +66,8 @@ }, "server": { "extraEnv": { - "RUSTUP_TOOLCHAIN": "nightly" + "RUSTC": "build/host/stage0/bin/rustc", + "CARGO": "build/host/stage0/bin/cargo" } } } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 033d3ecdd03d..440d54b007a1 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -22,7 +22,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.8.1" -stringdex = "=0.0.5" +stringdex = "=0.0.6" tempfile = "3" threadpool = "1.8.1" tracing = "0.1" diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 3ec2bc3af8d4..ee03431d036b 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -3,6 +3,7 @@ // FIXME: Once the portability lint RFC is implemented (see tracking issue #41619), // switch to use those structures instead. +use std::str::FromStr; use std::sync::Arc; use std::{fmt, mem, ops}; @@ -15,6 +16,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{Symbol, sym}; use rustc_span::{DUMMY_SP, Span}; +use rustc_target::spec; use crate::display::{Joined as _, MaybeDisplay, Wrapped}; use crate::html::escape::Escape; @@ -421,54 +423,10 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { (sym::unix, None) => "Unix", (sym::windows, None) => "Windows", (sym::debug_assertions, None) => "debug-assertions enabled", - (sym::target_os, Some(os)) => match os.as_str() { - "android" => "Android", - "cygwin" => "Cygwin", - "dragonfly" => "DragonFly BSD", - "emscripten" => "Emscripten", - "freebsd" => "FreeBSD", - "fuchsia" => "Fuchsia", - "haiku" => "Haiku", - "hermit" => "Hermit", - "illumos" => "illumos", - "ios" => "iOS", - "l4re" => "L4Re", - "linux" => "Linux", - "macos" => "macOS", - "netbsd" => "NetBSD", - "openbsd" => "OpenBSD", - "redox" => "Redox", - "solaris" => "Solaris", - "tvos" => "tvOS", - "wasi" => "WASI", - "watchos" => "watchOS", - "windows" => "Windows", - "visionos" => "visionOS", - _ => "", - }, - (sym::target_arch, Some(arch)) => match arch.as_str() { - "aarch64" => "AArch64", - "arm" => "ARM", - "loongarch32" => "LoongArch LA32", - "loongarch64" => "LoongArch LA64", - "m68k" => "M68k", - "csky" => "CSKY", - "mips" => "MIPS", - "mips32r6" => "MIPS Release 6", - "mips64" => "MIPS-64", - "mips64r6" => "MIPS-64 Release 6", - "msp430" => "MSP430", - "powerpc" => "PowerPC", - "powerpc64" => "PowerPC-64", - "riscv32" => "RISC-V RV32", - "riscv64" => "RISC-V RV64", - "s390x" => "s390x", - "sparc64" => "SPARC64", - "wasm32" | "wasm64" => "WebAssembly", - "x86" => "x86", - "x86_64" => "x86-64", - _ => "", - }, + (sym::target_os, Some(os)) => human_readable_target_os(*os).unwrap_or_default(), + (sym::target_arch, Some(arch)) => { + human_readable_target_arch(*arch).unwrap_or_default() + } (sym::target_vendor, Some(vendor)) => match vendor.as_str() { "apple" => "Apple", "pc" => "PC", @@ -476,15 +434,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { "fortanix" => "Fortanix", _ => "", }, - (sym::target_env, Some(env)) => match env.as_str() { - "gnu" => "GNU", - "msvc" => "MSVC", - "musl" => "musl", - "newlib" => "Newlib", - "uclibc" => "uClibc", - "sgx" => "SGX", - _ => "", - }, + (sym::target_env, Some(env)) => { + human_readable_target_env(*env).unwrap_or_default() + } (sym::target_endian, Some(endian)) => { return write!(fmt, "{endian}-endian"); } @@ -527,6 +479,135 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { } } +fn human_readable_target_os(os: Symbol) -> Option<&'static str> { + let os = spec::Os::from_str(os.as_str()).ok()?; + + use spec::Os::*; + Some(match os { + // tidy-alphabetical-start + Aix => "AIX", + AmdHsa => "AMD HSA", + Android => "Android", + Cuda => "CUDA", + Cygwin => "Cygwin", + Dragonfly => "DragonFly BSD", + Emscripten => "Emscripten", + EspIdf => "ESP-IDF", + FreeBsd => "FreeBSD", + Fuchsia => "Fuchsia", + Haiku => "Haiku", + HelenOs => "HelenOS", + Hermit => "Hermit", + Horizon => "Horizon", + Hurd => "GNU/Hurd", + IOs => "iOS", + Illumos => "illumos", + L4Re => "L4Re", + Linux => "Linux", + LynxOs178 => "LynxOS-178", + MacOs => "macOS", + Managarm => "Managarm", + Motor => "Motor OS", + NetBsd => "NetBSD", + None => "bare-metal", // FIXME(scrabsha): is this appropriate? + Nto => "QNX Neutrino", + NuttX => "NuttX", + OpenBsd => "OpenBSD", + Psp => "Play Station Portable", + Psx => "Play Station 1", + Qurt => "QuRT", + Redox => "Redox OS", + Rtems => "RTEMS OS", + Solaris => "Solaris", + SolidAsp3 => "SOLID ASP3", + TeeOs => "TEEOS", + Trusty => "Trusty", + TvOs => "tvOS", + Uefi => "UEFI", + VexOs => "VEXos", + VisionOs => "visionOS", + Vita => "Play Station Vita", + VxWorks => "VxWorks", + Wasi => "WASI", + WatchOs => "watchOS", + Windows => "Windows", + Xous => "Xous", + Zkvm => "zero knowledge Virtual Machine", + // tidy-alphabetical-end + Unknown | Other(_) => return Option::None, + }) +} + +fn human_readable_target_arch(os: Symbol) -> Option<&'static str> { + let arch = spec::Arch::from_str(os.as_str()).ok()?; + + use spec::Arch::*; + Some(match arch { + // tidy-alphabetical-start + AArch64 => "AArch64", + AmdGpu => "AMG GPU", + Arm => "ARM", + Arm64EC => "ARM64EC", + Avr => "AVR", + Bpf => "BPF", + CSky => "C-SKY", + Hexagon => "Hexagon", + LoongArch32 => "LoongArch64", + LoongArch64 => "LoongArch32", + M68k => "Motorola 680x0", + Mips => "MIPS", + Mips32r6 => "MIPS release 6", + Mips64 => "MIPS-64", + Mips64r6 => "MIPS-64 release 6", + Msp430 => "MSP430", + Nvptx64 => "NVidia GPU", + PowerPC => "PowerPC", + PowerPC64 => "PowerPC64", + RiscV32 => "RISC-V RV32", + RiscV64 => "RISC-V RV64", + S390x => "s390x", + Sparc => "SPARC", + Sparc64 => "SPARC-64", + SpirV => "SPIR-V", + Wasm32 | Wasm64 => "WebAssembly", + X86 => "x86", + X86_64 => "x86-64", + Xtensa => "Xtensa", + // tidy-alphabetical-end + Other(_) => return None, + }) +} + +fn human_readable_target_env(env: Symbol) -> Option<&'static str> { + let env = spec::Env::from_str(env.as_str()).ok()?; + + use spec::Env::*; + Some(match env { + // tidy-alphabetical-start + Gnu => "GNU", + MacAbi => "Catalyst", + Mlibc => "mac ABI", + Msvc => "MSVC", + Musl => "musl", + Newlib => "Newlib", + Nto70 => "Neutrino 7.0", + Nto71 => "Neutrino 7.1", + Nto71IoSock => "Neutrino 7.1 with io-sock", + Nto80 => "Neutrino 8.0", + Ohos => "OpenHarmony", + P1 => "WASIp1", + P2 => "WASIp2", + P3 => "WASIp3", + Relibc => "relibc", + Sgx => "SGX", + Sim => "Simulator", + Uclibc => "uClibc", + V5 => "V5", + // tidy-alphabetical-end + Unspecified | Other(_) => return None, + }) +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] struct NameValueCfg { name: Symbol, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 13a9c789e895..f54339429fa5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2776,7 +2776,12 @@ fn get_name( // These kinds of item either don't need a `name` or accept a `None` one so we handle them // before. match item.kind { - ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.owner_id.def_id, cx), + ItemKind::Impl(ref impl_) => { + // If `renamed` is `Some()` for an `impl`, it means it's been inlined because we use + // it as a marker to indicate that this is an inlined impl and that we should + // generate an impl placeholder and not a "real" impl item. + return clean_impl(impl_, item.owner_id.def_id, cx, renamed.is_some()); + } ItemKind::Use(path, kind) => { return clean_use_statement( item, @@ -2909,10 +2914,27 @@ fn clean_impl<'tcx>( impl_: &hir::Impl<'tcx>, def_id: LocalDefId, cx: &mut DocContext<'tcx>, + // If true, this is an inlined impl and it will be handled later on in the code. + // In here, we will generate a placeholder for it in order to be able to compute its + // `doc_cfg` info. + is_inlined: bool, ) -> Vec { let tcx = cx.tcx; let mut ret = Vec::new(); - let trait_ = impl_.of_trait.map(|t| clean_trait_ref(&t.trait_ref, cx)); + let trait_ = match impl_.of_trait { + Some(t) => { + if is_inlined { + return vec![Item::from_def_id_and_parts( + def_id.to_def_id(), + None, + PlaceholderImplItem, + cx, + )]; + } + Some(clean_trait_ref(&t.trait_ref, cx)) + } + None => None, + }; let items = impl_ .items .iter() diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c595a0ae2d48..ad70fc109669 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -885,6 +885,9 @@ pub(crate) enum ItemKind { TraitItem(Box), TraitAliasItem(TraitAlias), ImplItem(Box), + /// This variant is used only as a placeholder for trait impls in order to correctly compute + /// `doc_cfg` as trait impls are added to `clean::Crate` after we went through the whole tree. + PlaceholderImplItem, /// A required method in a trait declaration meaning it's only a function signature. RequiredMethodItem(Box, Defaultness), /// A method in a trait impl or a provided method in a trait declaration. @@ -964,7 +967,8 @@ pub(crate) fn inner_items(&self) -> impl Iterator { | AssocTypeItem(..) | StrippedItem(_) | KeywordItem - | AttributeItem => [].iter(), + | AttributeItem + | PlaceholderImplItem => [].iter(), } } } @@ -2430,7 +2434,7 @@ mod size_asserts { static_assert_size!(GenericParamDef, 40); static_assert_size!(Generics, 16); static_assert_size!(Item, 8); - static_assert_size!(ItemInner, 144); + static_assert_size!(ItemInner, 136); static_assert_size!(ItemKind, 48); static_assert_size!(PathSegment, 32); static_assert_size!(Type, 32); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 3d4b4e969157..3caff6edd504 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -322,8 +322,8 @@ pub(crate) enum ModuleSorting { #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum EmitType { - Toolchain, - InvocationSpecific, + HtmlStaticFiles, + HtmlNonStaticFiles, DepInfo(Option), } @@ -332,8 +332,12 @@ impl FromStr for EmitType { fn from_str(s: &str) -> Result { match s { - "toolchain-shared-resources" => Ok(Self::Toolchain), - "invocation-specific" => Ok(Self::InvocationSpecific), + // old nightly-only choices that are going away soon + "toolchain-shared-resources" => Ok(Self::HtmlStaticFiles), + "invocation-specific" => Ok(Self::HtmlNonStaticFiles), + // modern choices + "html-static-files" => Ok(Self::HtmlStaticFiles), + "html-non-static-files" => Ok(Self::HtmlNonStaticFiles), "dep-info" => Ok(Self::DepInfo(None)), option => match option.strip_prefix("dep-info=") { Some("-") => Ok(Self::DepInfo(Some(OutFileName::Stdout))), @@ -346,7 +350,7 @@ fn from_str(s: &str) -> Result { impl RenderOptions { pub(crate) fn should_emit_crate(&self) -> bool { - self.emit.is_empty() || self.emit.contains(&EmitType::InvocationSpecific) + self.emit.is_empty() || self.emit.contains(&EmitType::HtmlNonStaticFiles) } pub(crate) fn dep_info(&self) -> Option> { @@ -458,8 +462,13 @@ fn println_condition(condition: Condition) { return None; } + let should_test = matches.opt_present("test"); + let mut emit = FxIndexMap::<_, EmitType>::default(); for list in matches.opt_strs("emit") { + if should_test { + dcx.fatal("the `--test` flag and the `--emit` flag are not supported together"); + } for kind in list.split(',') { match kind.parse() { Ok(kind) => { @@ -513,6 +522,18 @@ fn println_condition(condition: Condition) { } } + if output_format == OutputFormat::Json { + if let Some(emit_flag) = emit.iter().find_map(|emit| match emit { + EmitType::HtmlStaticFiles => Some("html-static-files"), + EmitType::HtmlNonStaticFiles => Some("html-non-static-files"), + EmitType::DepInfo(_) => None, + }) { + dcx.fatal(format!( + "the `--emit={emit_flag}` flag is not supported with `--output-format=json`", + )); + } + } + let to_check = matches.opt_strs("check-theme"); if !to_check.is_empty() { let mut content = @@ -630,7 +651,6 @@ fn println_condition(condition: Condition) { let test_args: Vec = test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect(); - let should_test = matches.opt_present("test"); let no_run = matches.opt_present("no-run"); if !should_test && no_run { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index bb41758c7a2e..42d7237f68e5 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -232,6 +232,9 @@ pub(crate) fn create_config( rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(), rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(), rustc_lint::builtin::UNEXPECTED_CFGS.name.to_string(), + rustc_lint::builtin::DUPLICATE_FEATURES.name.to_string(), + rustc_lint::builtin::UNUSED_FEATURES.name.to_string(), + rustc_lint::builtin::STABLE_FEATURES.name.to_string(), // this lint is needed to support `#[expect]` attributes rustc_lint::builtin::UNFULFILLED_LINT_EXPECTATIONS.name.to_string(), ]; @@ -293,7 +296,7 @@ pub(crate) fn create_config( file_loader: None, lint_caps, psess_created: None, - hash_untracked_state: None, + track_state: None, register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: Some(|_sess, providers| { // We do not register late module lints, so this only runs `MissingDoc`. @@ -306,19 +309,14 @@ pub(crate) fn create_config( &EMPTY_SET }; // In case typeck does end up being called, don't ICE in case there were name resolution errors - providers.queries.typeck = move |tcx, def_id| { - // Closures' tables come from their outermost function, - // as they are part of the same "inference environment". - // This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`) - let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); - if typeck_root_def_id != def_id { - return tcx.typeck(typeck_root_def_id); - } + providers.queries.typeck_root = move |tcx, def_id| { + // Panic before code below breaks in case of someone calls typeck_root directly + assert!(!tcx.is_typeck_child(def_id.to_def_id())); let body = tcx.hir_body_owned_by(def_id); debug!("visiting body for {def_id:?}"); EmitIgnoredResolutionErrors::new(tcx).visit_body(body); - (rustc_interface::DEFAULT_QUERY_PROVIDERS.queries.typeck)(tcx, def_id) + (rustc_interface::DEFAULT_QUERY_PROVIDERS.queries.typeck_root)(tcx, def_id) }; }), extra_symbols: Vec::new(), @@ -400,16 +398,16 @@ pub(crate) fn run_global_ctxt( {}/rustdoc/how-to-write-documentation.html", crate::DOC_RUST_LANG_ORG_VERSION ); - tcx.node_lint( + tcx.emit_node_lint( crate::lint::MISSING_CRATE_LEVEL_DOCS, DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(), - |lint| { + rustc_errors::DiagDecorator(|lint| { if let Some(local_def_id) = krate.module.item_id.as_local_def_id() { lint.span(tcx.def_span(local_def_id)); } lint.primary_message("no documentation found for this crate's top-level module"); lint.help(help); - }, + }), ); } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 5d3715c70e08..bfcdc3a50558 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -32,7 +32,7 @@ use rustc_span::{FileName, RemapPathScopeComponents, Span}; use rustc_target::spec::{Target, TargetTuple}; use tempfile::{Builder as TempFileBuilder, TempDir}; -use tracing::debug; +use tracing::{debug, info}; use self::rust::HirCollector; use crate::config::{MergeDoctests, Options as RustdocOptions, OutputFormat}; @@ -190,7 +190,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions file_loader: None, lint_caps, psess_created: None, - hash_untracked_state: None, + track_state: None, register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: None, extra_symbols: Vec::new(), @@ -692,7 +692,7 @@ fn run_test( compiler.stderr(Stdio::piped()); } - debug!("compiler invocation for doctest: {compiler:?}"); + info!("compiler invocation for doctest: {compiler:?}"); let mut child = match compiler.spawn() { Ok(child) => child, @@ -759,7 +759,7 @@ fn run_test( runner_compiler.stderr(Stdio::inherit()); } runner_compiler.arg("--error-format=short"); - debug!("compiler invocation for doctest runner: {runner_compiler:?}"); + info!("compiler invocation for doctest runner: {runner_compiler:?}"); let status = if !status.success() { status @@ -859,6 +859,8 @@ fn drop(&mut self) { cmd.current_dir(run_directory); } + info!("running doctest executable: {cmd:?}"); + let result = if doctest.is_multiple_tests() || rustdoc_options.no_capture { cmd.status().map(|status| process::Output { status, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index a77efaaed8d5..7dd738abca43 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -555,7 +555,10 @@ fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option< // consider it only as a crate-level attribute. if attr.has_name(sym::allow) && let Some(list) = attr.meta_item_list() - && list.iter().any(|sub_attr| sub_attr.has_name(sym::internal_features)) + && list.iter().any(|sub_attr| { + sub_attr.has_name(sym::internal_features) + || sub_attr.has_name(sym::incomplete_features) + }) { push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi); } else { diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index c970fdbbc93a..8b9db4638e47 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -97,7 +97,8 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind { | RequiredAssocTypeItem(..) | AssocTypeItem(..) | KeywordItem - | AttributeItem => kind, + | AttributeItem + | PlaceholderImplItem => kind, } } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 5a97d8e5b5f4..35071f47a182 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -389,6 +389,8 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { // So would rather leave them to an expert, // as at least the list is better than `_ => {}`. } + + clean::PlaceholderImplItem => return None, } // Maintain the parent stack. diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 6830c1ec6560..eb3492e4625b 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -122,7 +122,7 @@ fn from(item: &'a clean::Item) -> ItemType { clean::StaticItem(..) => ItemType::Static, clean::ConstantItem(..) => ItemType::Constant, clean::TraitItem(..) => ItemType::Trait, - clean::ImplItem(..) => ItemType::Impl, + clean::ImplItem(..) | clean::PlaceholderImplItem => ItemType::Impl, clean::RequiredMethodItem(..) => ItemType::TyMethod, clean::MethodItem(..) => ItemType::Method, clean::StructFieldItem(..) => ItemType::StructField, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c472c20a7dc7..858545bd0984 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -109,13 +109,15 @@ pub(crate) struct MarkdownWithToc<'a> { pub(crate) edition: Edition, pub(crate) playground: &'a Option, } -/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags + +/// A struct like `Markdown` that renders the markdown escaping HTML tags /// and includes no paragraph tags. pub(crate) struct MarkdownItemInfo<'a> { pub(crate) content: &'a str, pub(crate) links: &'a [RenderedLink], pub(crate) ids: &'a mut IdMap, } + /// A tuple struct like `Markdown` that renders only the first paragraph. pub(crate) struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]); @@ -799,14 +801,7 @@ pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, sp: Span) -> ExtraInfo< } fn error_invalid_codeblock_attr(&self, msg: impl Into) { - self.tcx.node_span_lint( - crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, - self.tcx.local_def_id_to_hir_id(self.def_id), - self.sp, - |lint| { - lint.primary_message(msg); - }, - ); + self.error_invalid_codeblock_attr_with_help(msg, |_| {}); } fn error_invalid_codeblock_attr_with_help( @@ -814,14 +809,14 @@ fn error_invalid_codeblock_attr_with_help( msg: impl Into, f: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), ) { - self.tcx.node_span_lint( + self.tcx.emit_node_span_lint( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, self.tcx.local_def_id_to_hir_id(self.def_id), self.sp, - |lint| { + rustc_errors::DiagDecorator(|lint| { lint.primary_message(msg); f(lint); - }, + }), ); } } @@ -1497,10 +1492,10 @@ pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result { let p = SpannedLinkReplacer::new(p, links); let p = footnotes::Footnotes::new(p, existing_footnotes); let p = TableWrapper::new(p.map(|(ev, _)| ev)); - let p = p.filter(|event| { - !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph)) - }); - html::write_html_fmt(&mut f, p) + // in legacy wrap mode, strip

elements to avoid them inserting newlines + html::write_html_fmt(&mut f, p)?; + + Ok(()) }) } } diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 1c99ccc5228b..3655a52deee6 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -472,7 +472,7 @@ fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); let mut output = String::new(); MarkdownItemInfo::new(input, &[], &mut idmap).write_into(&mut output).unwrap(); - assert_eq!(output, expect, "original: {}", input); + assert_eq!(output, format!("

{}

\n", expect), "original: {}", input); } t("`Struct<'a, T>`", "Struct<'a, T>"); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 1b5dbeed8de8..b1c77063ca94 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -218,7 +218,7 @@ fn write_static_files( try_err!(fs::write(&dst_path, buffer), &dst_path); } - if opt.emit.is_empty() || opt.emit.contains(&EmitType::Toolchain) { + if opt.emit.is_empty() || opt.emit.contains(&EmitType::HtmlStaticFiles) { static_files::for_each(|f: &static_files::StaticFile| { let filename = static_dir.join(f.output_filename()); let contents: &[u8] = diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 9e47f80a7fe2..f0a812b97d04 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1606,7 +1606,6 @@ so that we can apply CSS-filters to change the arrow color in themes */ color: var(--main-color); background-color: var(--stab-background-color); width: fit-content; - white-space: pre-wrap; border-radius: 3px; display: inline; vertical-align: baseline; diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js index 720ac58e76e0..f5384e0fd58a 100644 --- a/src/librustdoc/html/static/js/stringdex.js +++ b/src/librustdoc/html/static/js/stringdex.js @@ -55,21 +55,66 @@ class RoaringBitmap { this.consumed_len_bytes = pspecial - i; return this; } else if (u8array[i] > 0xe0) { - // Special representation of tiny sets that are runs - const lspecial = u8array[i] & 0x0f; - this.keysAndCardinalities = new Uint8Array(lspecial * 4); - i += 1; - const key = u8array[i + 2] | (u8array[i + 3] << 8); - const value = u8array[i] | (u8array[i + 1] << 8); - const container = new RoaringBitmapRun(1, new Uint8Array(4)); - container.array[0] = value & 0xFF; - container.array[1] = (value >> 8) & 0xFF; - container.array[2] = lspecial - 1; - this.containers.push(container); - this.keysAndCardinalities[0] = key & 0xFF; - this.keysAndCardinalities[1] = (key >> 8) & 0xFF; - this.keysAndCardinalities[2] = lspecial - 1; - this.consumed_len_bytes = 5; + // Special representation of a node with multiple runs + const run_count_m1 = (u8array[i] & 0x0f); + const run_count = run_count_m1 + 1; + this.keysAndCardinalities = new Uint8Array(run_count * 4); + // the run keys and values + let pspecial = i + 1; + // the run lengths + let pnspecial = pspecial + (run_count * 4); + /** @type {number|null} */ + let previous_key = null; + /** @type {RoaringBitmapRun|null} */ + let previous_container = null; + for (let j = 0; j < run_count; j += 1) { + const key = u8array[pspecial + 2] | (u8array[pspecial + 3] << 8); + const value = u8array[pspecial] | (u8array[pspecial + 1] << 8); + const run_length_m1 = j % 2 === 0 ? + (u8array[pnspecial] >> 4) : + (u8array[pnspecial] & 0x0f); + if (j % 2 !== 0) { + pnspecial += 1; + } + pspecial += 4; + if (key === previous_key && previous_container !== null) { + const new_container_array = new Uint8Array( + (previous_container.runcount + 1) * 4, + ); + new_container_array.set(previous_container.array); + new_container_array[previous_container.runcount * 4] = value & 0xFF; + new_container_array[(previous_container.runcount * 4) + 1] = + (value >> 8) & 0xFF; + new_container_array[(previous_container.runcount * 4) + 2] = + run_length_m1; + previous_container.array = new_container_array; + previous_container.runcount += 1; + let cardinalitym1 = + this.keysAndCardinalities[(this.containers.length * 4) - 2] | + (this.keysAndCardinalities[(this.containers.length * 4) - 1] << 8); + cardinalitym1 += run_length_m1 + 1; + this.keysAndCardinalities[(this.containers.length * 4) - 2] = + cardinalitym1 & 0xFF; + this.keysAndCardinalities[(this.containers.length * 4) - 1] = + (cardinalitym1 >> 8) & 0xFF; + } else { + previous_key = key; + previous_container = new RoaringBitmapRun(1, Uint8Array.of( + value & 0xFF, + (value >> 8) & 0xFF, + run_length_m1, + 0, + )); + this.containers.push(previous_container); + this.keysAndCardinalities[(this.containers.length * 4) - 4] = key & 0xFF; + this.keysAndCardinalities[(this.containers.length * 4) - 3] = (key >> 8) & 0xFF; + this.keysAndCardinalities[(this.containers.length * 4) - 2] = run_length_m1; + } + } + if (run_count % 2 !== 0) { + pnspecial += 1; + } + this.consumed_len_bytes = pnspecial - i; return this; } else if (u8array[i] > 0xd0) { // Special representation of tiny sets that are close together @@ -100,6 +145,26 @@ class RoaringBitmap { } this.consumed_len_bytes = pspecial - i; return this; + } else if (u8array[i] > 0x80) { + // Special representation of tiny sets that are runs + const lspecial = u8array[i] & 0x3f; + const lspecialm1 = lspecial - 1; + this.keysAndCardinalities = new Uint8Array(4); + i += 1; + const key = u8array[i + 2] | (u8array[i + 3] << 8); + const value = u8array[i] | (u8array[i + 1] << 8); + const container = new RoaringBitmapRun(1, new Uint8Array(4)); + container.array[0] = value & 0xFF; + container.array[1] = (value >> 8) & 0xFF; + container.array[2] = lspecialm1 & 0xFF; + container.array[3] = lspecialm1 >> 8; + this.containers.push(container); + this.keysAndCardinalities[0] = key & 0xFF; + this.keysAndCardinalities[1] = (key >> 8) & 0xFF; + this.keysAndCardinalities[2] = lspecialm1 & 0xFF; + this.keysAndCardinalities[3] = lspecialm1 >> 8; + this.consumed_len_bytes = 5; + return this; } else if (u8array[i] < 0x3a) { // Special representation of tiny sets with arbitrary 32-bit integers const lspecial = u8array[i]; @@ -801,7 +866,7 @@ class HashTable { for (let i = 0; i < l; i += 1) { const value = values[i]; if (value !== undefined) { - yield [keys.subarray(i * 6, (i + 1) * 6), value]; + yield [keys.subarray(i * 5, (i + 1) * 5), value]; } } } @@ -818,7 +883,7 @@ class HashTable { const l = values.length; this.capacityClass += 1; const capacity = 1 << this.capacityClass; - this.keys = new Uint8Array(capacity * 6); + this.keys = new Uint8Array(capacity * 5); this.values = []; for (let i = 0; i < capacity; i += 1) { this.values.push(undefined); @@ -827,7 +892,7 @@ class HashTable { for (let i = 0; i < l; i += 1) { const oldValue = values[i]; if (oldValue !== undefined) { - this.setNoGrow(keys, i * 6, oldValue); + this.setNoGrow(keys, i * 5, oldValue); } } } @@ -844,25 +909,24 @@ class HashTable { const values = this.values; const l = 1 << this.capacityClass; // because we know that our values are already hashed, - // just chop off the lower four bytes + // just chop off the first byte let slot = ( - (key[start + 2] << 24) | - (key[start + 3] << 16) | - (key[start + 4] << 8) | - key[start + 5] + (key[start + 1] << 24) | + (key[start + 2] << 16) | + (key[start + 3] << 8) | + key[start + 4] ) & mask; for (let distance = 0; distance < l; ) { - const j = slot * 6; + const j = slot * 5; const otherValue = values[slot]; if (otherValue === undefined) { values[slot] = value; - const keysStart = slot * 6; + const keysStart = slot * 5; keys[keysStart + 0] = key[start + 0]; keys[keysStart + 1] = key[start + 1]; keys[keysStart + 2] = key[start + 2]; keys[keysStart + 3] = key[start + 3]; keys[keysStart + 4] = key[start + 4]; - keys[keysStart + 5] = key[start + 5]; this.size += 1; break; } else if ( @@ -870,15 +934,14 @@ class HashTable { key[start + 1] === keys[j + 1] && key[start + 2] === keys[j + 2] && key[start + 3] === keys[j + 3] && - key[start + 4] === keys[j + 4] && - key[start + 5] === keys[j + 5] + key[start + 4] === keys[j + 4] ) { values[slot] = value; break; } else { const otherPreferredSlot = ( - (keys[j + 2] << 24) | (keys[j + 3] << 16) | - (keys[j + 4] << 8) | keys[j + 5] + (keys[j + 1] << 24) | (keys[j + 2] << 16) | + (keys[j + 3] << 8) | keys[j + 4] ) & mask; const otherDistance = otherPreferredSlot <= slot ? slot - otherPreferredSlot : @@ -888,7 +951,7 @@ class HashTable { // then insert our node in its place and swap // // https://cglab.ca/~abeinges/blah/robinhood-part-1/ - const otherKey = keys.slice(j, j + 6); + const otherKey = keys.slice(j, j + 5); values[slot] = value; value = otherValue; keys[j + 0] = key[start + 0]; @@ -896,7 +959,6 @@ class HashTable { keys[j + 2] = key[start + 2]; keys[j + 3] = key[start + 3]; keys[j + 4] = key[start + 4]; - keys[j + 5] = key[start + 5]; key = otherKey; start = 0; distance = otherDistance; @@ -912,7 +974,7 @@ class HashTable { * @returns {T|undefined} */ get(key) { - if (key.length !== 6) { + if (key.length !== 5) { throw "invalid key"; } return this.getWithOffsetKey(key, 0); @@ -931,13 +993,13 @@ class HashTable { // because we know that our values are already hashed, // just chop off the lower four bytes let slot = ( - (key[start + 2] << 24) | - (key[start + 3] << 16) | - (key[start + 4] << 8) | - key[start + 5] + (key[start + 1] << 24) | + (key[start + 2] << 16) | + (key[start + 3] << 8) | + key[start + 4] ) & mask; for (let distance = 0; distance < l; distance += 1) { - const j = slot * 6; + const j = slot * 5; const value = values[slot]; if (value === undefined) { break; @@ -946,14 +1008,13 @@ class HashTable { key[start + 1] === keys[j + 1] && key[start + 2] === keys[j + 2] && key[start + 3] === keys[j + 3] && - key[start + 4] === keys[j + 4] && - key[start + 5] === keys[j + 5] + key[start + 4] === keys[j + 4] ) { return value; } else { const otherPreferredSlot = ( - (keys[j + 2] << 24) | (keys[j + 3] << 16) | - (keys[j + 4] << 8) | keys[j + 5] + (keys[j + 1] << 24) | (keys[j + 2] << 16) | + (keys[j + 3] << 8) | keys[j + 4] ) & mask; const otherDistance = otherPreferredSlot <= slot ? slot - otherPreferredSlot : @@ -1133,61 +1194,56 @@ function loadDatabase(hooks) { dataColumns: new Map(), dataColumnsBuckets: new HashTable(), searchTreeLoadByNodeID: function(nodeid) { - const existingPromise = registry.searchTreePromises.get(nodeid); - if (existingPromise) { - return existingPromise; - } /** @type {Promise} */ let newPromise; if ((nodeid[0] & 0x80) !== 0) { - const isWhole = (nodeid[0] & 0x40) !== 0; - let leaves; - if ((nodeid[0] & 0x10) !== 0) { - let id1 = (nodeid[2] << 8) | nodeid[3]; - if ((nodeid[0] & 0x20) !== 0) { - // when data is present, id1 can be up to 20 bits - id1 |= ((nodeid[1] & 0x0f) << 16); - } else { - // otherwise, we fit in 28 - id1 |= ((nodeid[0] & 0x0f) << 24) | (nodeid[1] << 16); - } - const id2 = id1 + ((nodeid[4] << 8) | nodeid[5]); - leaves = RoaringBitmap.makeSingleton(id1) - .union(RoaringBitmap.makeSingleton(id2)); - } else if (!isWhole && (nodeid[0] & 0xf0) === 0x80) { - const id1 = ((nodeid[0] & 0x0f) << 16) | (nodeid[1] << 8) | nodeid[2]; - const id2 = id1 + ((nodeid[3] << 4) | ((nodeid[4] >> 4) & 0x0f)); - const id3 = id2 + (((nodeid[4] & 0x0f) << 8) | nodeid[5]); - leaves = RoaringBitmap.makeSingleton(id1) - .union(RoaringBitmap.makeSingleton(id2)) - .union(RoaringBitmap.makeSingleton(id3)); + const isSuffixOnly = (nodeid[0] & 0x40) !== 0; + const isRun = (nodeid[0] & 0x20) !== 0; + const lengthOrData = nodeid[0] & 0x1F; + const id = (nodeid[1] << 24) | (nodeid[2] << 16) | (nodeid[3] << 8) | nodeid[4]; + let bitmap; + if (isRun) { + bitmap = new RoaringBitmap(null); + bitmap.containers.push(new RoaringBitmapRun( + 1, + Uint8Array.of( + id & 0xFF, + (id >> 8) & 0xFF, + lengthOrData, + 0, + ), + )); + bitmap.keysAndCardinalities = Uint8Array.of( + (id >> 16) & 0xff, + (id >> 24) & 0xff, + lengthOrData, + 0, + ); } else { - leaves = RoaringBitmap.makeSingleton( - (nodeid[2] << 24) | (nodeid[3] << 16) | - (nodeid[4] << 8) | nodeid[5], + bitmap = RoaringBitmap.makeSingleton(id); + } + let tree; + if (isSuffixOnly) { + tree = new SuffixSearchTree( + EMPTY_SEARCH_TREE_BRANCHES, + isRun ? 0 : (lengthOrData + 1), + bitmap, + ); + } else { + tree = new PrefixSearchTree( + EMPTY_SEARCH_TREE_BRANCHES, + EMPTY_SEARCH_TREE_BRANCHES, + isRun ? EMPTY_UINT8 : Uint8Array.of(LONG_ALPHABET.chars[lengthOrData]), + bitmap, + EMPTY_BITMAP, ); } - if (isWhole) { - const data = (nodeid[0] & 0x20) !== 0 ? - Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) : - EMPTY_UINT8; - newPromise = Promise.resolve(new PrefixSearchTree( - EMPTY_SEARCH_TREE_BRANCHES, - EMPTY_SEARCH_TREE_BRANCHES, - data, - leaves, - EMPTY_BITMAP, - )); - } else { - const data = (nodeid[0] & 0xf0) === 0x80 ? 0 : ( - ((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)); - newPromise = Promise.resolve(new SuffixSearchTree( - EMPTY_SEARCH_TREE_BRANCHES, - data, - leaves, - )); - } + newPromise = Promise.resolve(tree); } else { + const existingPromise = registry.searchTreePromises.get(nodeid); + if (existingPromise) { + return existingPromise; + } const hashHex = makeHexFromUint8Array(nodeid); newPromise = new Promise((resolve, reject) => { const cb = registry.searchTreeLoadPromiseCallbacks.get(nodeid); @@ -1211,8 +1267,8 @@ function loadDatabase(hooks) { hooks.loadTreeByHash(hashHex); } }); + registry.searchTreePromises.set(nodeid, newPromise); } - registry.searchTreePromises.set(nodeid, newPromise); return newPromise; }, dataLoadByNameAndHash: function(name, hash) { @@ -1277,8 +1333,8 @@ function loadDatabase(hooks) { getNodeID(i) { return new Uint8Array( this.nodeids.buffer, - this.nodeids.byteOffset + (i * 6), - 6, + this.nodeids.byteOffset + (i * 5), + 5, ); } // https://github.com/microsoft/TypeScript/issues/17227 @@ -1385,113 +1441,310 @@ function loadDatabase(hooks) { EMPTY_UINT8, ); - /** @type {number[]} */ - const SHORT_ALPHABITMAP_CHARS = []; + class Alphabet { + constructor() { + /** @type {number[]} */ + this.chars = []; + /** @type {number} */ + this.len = 0; + /** @type {number} */ + this.bytes = 0; + /** @type {number} */ + this.flag = 0; + /** @type {number} */ + this.bitwidth = 0; + } + /** + * @param {number} c + * @returns {boolean} + */ + contains(c) { + return this.chars.indexOf(c) !== -1; + } + /** + * @param {number} c + * @returns {number} + */ + index(c) { + return this.chars.indexOf(c); + } + } + + /** @type {Alphabet} */ + const VOWELONLY_ALPHABITMAP = Object.assign( + new Alphabet(), + { + chars: [0x61, 0x65, 0x69, 0x6f, 0x75], + len: 5, + bytes: 0, + flag: 0x80, + }, + ); + + /** @type {Alphabet} */ + const CONSONANTSONLY_ALPHABET = Object.assign( + new Alphabet(), + { + chars: [], + len: 21, + bytes: 2, + flag: 0xc0, + }, + ); + for (let i = 0x61; i <= 0x7A; ++i) { + if (i === 0x61 || i === 0x65 || i === 0x69 || i === 0x6f || i === 0x75) { + // 21 bits, 26 letters, so skip aeiou + continue; + } + CONSONANTSONLY_ALPHABET.chars.push(i); + } + + /** @type {Alphabet} */ + const HEX_ALPHABET = Object.assign( + new Alphabet(), + { + chars: [], + len: 16, + bytes: 2, + flag: 0xfc, + }, + ); + for (let i = 0x30; i <= 0x39; ++i) { + HEX_ALPHABET.chars.push(i); + } + for (let i = 0x61; i <= 0x66; ++i) { + HEX_ALPHABET.chars.push(i); + } + + /** @type {Alphabet} */ + const SHORT_ALPHABET = Object.assign( + new Alphabet(), + { + chars: [], + len: 24, + bytes: 3, + flag: 0xfd, + }, + ); for (let i = 0x61; i <= 0x7A; ++i) { if (i === 0x76 || i === 0x71) { // 24 entries, 26 letters, so we skip q and v continue; } - SHORT_ALPHABITMAP_CHARS.push(i); + SHORT_ALPHABET.chars.push(i); } - /** @type {number[]} */ - const LONG_ALPHABITMAP_CHARS = [0x31, 0x32, 0x33, 0x34, 0x35, 0x36]; + /** @type {Alphabet} */ + const LONG_ALPHABET = Object.assign( + new Alphabet(), + { + chars: [0x31, 0x32, 0x33, 0x34, 0x35, 0x36], + len: 32, + bytes: 4, + flag: 0xfe, + }, + ); for (let i = 0x61; i <= 0x7A; ++i) { - LONG_ALPHABITMAP_CHARS.push(i); + LONG_ALPHABET.chars.push(i); + } + + /** @type {Alphabet} */ + const ASCII_ALPHABET = Object.assign( + new Alphabet(), + { + chars: [], + len: 128, + bytes: 16, + flag: 0xf0, + /** + * @param {number} c + * @returns {boolean} + */ + contains(c) { + return c <= 0x7f; + }, + /** + * @param {number} c + * @returns {number} + */ + index(c) { + return c; + }, + }, + ); + for (let i = 0x00; i <= 0x7f; ++i) { + ASCII_ALPHABET.chars.push(i); + } + + /** @type {Alphabet} */ + const RAWBYTE_ALPHABET = Object.assign( + new Alphabet(), + { + chars: [], + len: 256, + bytes: 32, + flag: 0xff, + /** + * @param {number} _c + * @returns {boolean} + */ + contains(_c) { + return true; + }, + /** + * @param {number} c + * @returns {number} + */ + index(c) { + return c; + }, + }, + ); + for (let i = 0x00; i <= 0xff; ++i) { + RAWBYTE_ALPHABET.chars.push(i); } /** - * @template ST - * @param {number[]} alphabitmap_chars - * @param {number} width - * @return {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}} + * Parse an alphabet and buffer where the flag is right at the beginning. + * @param {number} start + * @param {Uint8Array} buf + * @returns {{"alphabet": Alphabet, "consumed_len_bytes": number, "len": number}?} */ - function makeSearchTreeBranchesAlphaBitmapClass(alphabitmap_chars, width) { - const bitwidth = width * 8; + Alphabet.parse = function(start, buf) { + const flag = buf[start]; + const parsed = Alphabet.parseFlag(flag, start + 1, buf); + if (!parsed) { + return null; + } + parsed.consumed_len_bytes += 1; + return parsed; + }; + + /** + * Parse an alphabet and buffer where the flag is not at the beginning. + * @param {number} flag + * @param {number} i + * @param {Uint8Array} buf + * @returns {{"alphabet": Alphabet, "consumed_len_bytes": number, "len": number}?} + */ + Alphabet.parseFlag = function(flag, i, buf) { + if (flag <= 0x80) { + return null; + } + const alphabet = flag === RAWBYTE_ALPHABET.flag ? RAWBYTE_ALPHABET : ( + flag === ASCII_ALPHABET.flag ? ASCII_ALPHABET : ( + flag === LONG_ALPHABET.flag ? LONG_ALPHABET : ( + flag === SHORT_ALPHABET.flag ? SHORT_ALPHABET : ( + flag === HEX_ALPHABET.flag ? HEX_ALPHABET : ( + flag >= CONSONANTSONLY_ALPHABET.flag ? CONSONANTSONLY_ALPHABET : VOWELONLY_ALPHABITMAP + ))))); + let len = alphabet === CONSONANTSONLY_ALPHABET || alphabet === VOWELONLY_ALPHABITMAP ? + bitCount(flag & 0x1f) : 0; + for (let ix = 0; ix < alphabet.bytes; ++ix) { + len += bitCount(buf[i]); + i += 1; + } + return {alphabet, consumed_len_bytes: alphabet.bytes, len}; + }; + + /** + * @template ST + * @extends SearchTreeBranches + */ + class SearchTreeBranchesAlphaBitmap extends SearchTreeBranches { /** - * @extends SearchTreeBranches + * @param {Alphabet} alphabet + * @param {Uint8Array} buffer + * @param {Uint8Array} nodeids */ - const cls = class SearchTreeBranchesAlphaBitmap extends SearchTreeBranches { - /** - * @param {number} bitmap - * @param {Uint8Array} nodeids - */ - constructor(bitmap, nodeids) { - super(nodeids.length / 6, nodeids); - if (nodeids.length / 6 !== bitCount(bitmap)) { - throw new Error(`mismatch ${bitmap} ${nodeids}`); + constructor(alphabet, buffer, nodeids) { + let bitmap; + if (alphabet === VOWELONLY_ALPHABITMAP) { + bitmap = new Uint8Array(1); + bitmap[0] = buffer[0] & 0x1f; + } else if (alphabet === CONSONANTSONLY_ALPHABET) { + bitmap = new Uint8Array(3); + bitmap[0] = buffer[1]; + bitmap[1] = buffer[2]; + bitmap[2] = buffer[0] & 0x1f; + } else { + bitmap = buffer.subarray(1); + } + let cardinality = 0; + for (let i = 0; i < bitmap.length; ++i) { + cardinality += bitCount(bitmap[i]); + } + super(cardinality, nodeids); + this.bitmap = bitmap; + this.alphabet = alphabet; + } + /** + * Yields [character, SearchTree] pairs. + * @returns {Generator<[number, Promise|null]>} + */ + * entries() { + let i = 0; + let j = 0; + while (i < this.alphabet.len) { + if (this.bitmap[i >> 3] & (1 << (i & 0x07))) { + yield [this.alphabet.chars[i], this.subtrees[j]]; + j += 1; } - this.bitmap = bitmap; - this.nodeids = nodeids; + i += 1; } - /** @returns {Generator<[number, Promise|null]>} */ - * entries() { - let i = 0; - let j = 0; - while (i < bitwidth) { - if (this.bitmap & (1 << i)) { - yield [alphabitmap_chars[i], this.subtrees[j]]; - j += 1; - } - i += 1; - } + } + /** + * Given a character, returns the numbered index of the search + * tree, or -1 if there isn't one. + * @param {number} c + * @returns {number} + */ + getIndex(c) { + //return this.getKeys().indexOf(c); + if (!this.alphabet.contains(c)) { + return -1; } - /** - * @param {number} k - * @returns {number} - */ - getIndex(k) { - //return this.getKeys().indexOf(k); - const ix = alphabitmap_chars.indexOf(k); - if (ix < 0) { - return ix; - } - const result = bitCount(~(0xffffffff << ix) & this.bitmap); - return result >= this.subtrees.length ? -1 : result; - } - /** - * @param {number} branch_index - * @returns {number} - */ - getKey(branch_index) { - return this.getKeys()[branch_index]; - } - /** - * @returns {Uint8Array} - */ - getKeys() { - const length = bitCount(this.bitmap); - const result = new Uint8Array(length); - let result_index = 0; - for (let alpha_index = 0; alpha_index < bitwidth; ++alpha_index) { - if (this.bitmap & (1 << alpha_index)) { - result[result_index] = alphabitmap_chars[alpha_index]; - result_index += 1; - } + const k = this.alphabet.index(c); + if (this.bitmap[k >> 3] & (1 << (k & 0x07))) { + let result = bitCount(~(0xff << (k & 0x07)) & this.bitmap[k >> 3]); + for (let ix = 0; ix < (k >> 3); ++ix) { + result += bitCount(this.bitmap[ix]); } return result; + } else { + return -1; } - }; - cls.ALPHABITMAP_CHARS = alphabitmap_chars; - cls.width = width; - return cls; + } + /** + * Given the numbered index of a search tree, returns the key. + * This is the exact opposite of getIndex(). + * @param {number} branch_index + * @returns {number} + */ + getKey(branch_index) { + return this.getKeys()[branch_index]; + } + /** + * Returns a list of one-byte keys. + * @returns {Uint8Array} + */ + getKeys() { + let length = 0; + for (let i = 0; i < this.bitmap.length; ++i) { + length += bitCount(this.bitmap[i]); + } + const result = new Uint8Array(length); + let result_index = 0; + for (let ix = 0; ix < this.alphabet.len; ++ix) { + if (this.bitmap[ix >> 3] & (1 << (ix & 0x07))) { + result[result_index] = this.alphabet.chars[ix]; + result_index += 1; + } + } + return result; + } } - /** - * @template ST - * @type {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}} - */ - const SearchTreeBranchesShortAlphaBitmap = - makeSearchTreeBranchesAlphaBitmapClass(SHORT_ALPHABITMAP_CHARS, 3); - - /** - * @template ST - * @type {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}} - */ - const SearchTreeBranchesLongAlphaBitmap = - makeSearchTreeBranchesAlphaBitmapClass(LONG_ALPHABITMAP_CHARS, 4); - /** * @typedef {PrefixSearchTree|SuffixSearchTree|InlineNeighborsTree} SearchTree * @typedef {PrefixTrie|SuffixTrie} Trie @@ -2347,19 +2600,15 @@ function loadDatabase(hooks) { const has_branches = (encoded[i] & 0x04) !== 0; /** @type {boolean} */ const is_suffixes_only = (encoded[i] & 0x01) !== 0; - let leaves_count = ((encoded[i] >> 4) & 0x07) + 1; - let leaves_is_run = (encoded[i] >> 7) !== 0; + const leaves_count = (encoded[i] >> 4) & 0x07; + const leaves_is_run = (encoded[i] >> 7) !== 0; i += 1; - let branch_count = 0; + let branch_flag = 0; if (has_branches) { - branch_count = encoded[i] + 1; + branch_flag = encoded[i]; i += 1; } const dlen = encoded[i] & 0x3f; - if ((encoded[i] & 0x80) !== 0) { - leaves_count = 0; - leaves_is_run = false; - } i += 1; /** @type {Uint8Array} */ let data = EMPTY_UINT8; @@ -2367,13 +2616,25 @@ function loadDatabase(hooks) { data = encoded.subarray(i, i + dlen); i += dlen; } + const branch_flag_alphabet = Alphabet.parseFlag(branch_flag, i, encoded); + let branch_alphabitmap = EMPTY_UINT8; + if (branch_flag_alphabet) { + branch_alphabitmap = new Uint8Array(branch_flag_alphabet.consumed_len_bytes + 1); + branch_alphabitmap[0] = branch_flag; + branch_alphabitmap.set( + encoded.subarray(i, i + branch_flag_alphabet.consumed_len_bytes), + 1, + ); + i += branch_flag_alphabet.consumed_len_bytes; + } + const branch_count = branch_flag_alphabet ? branch_flag_alphabet.len : branch_flag; const leaf_value_upper = encoded[i] | (encoded[i + 1] << 8); i += 2; /** @type {Promise[]} */ const branch_nodes = []; for (let j = 0; j < branch_count; j += 1) { const branch_dlen = encoded[i] & 0x0f; - const branch_leaves_count = ((encoded[i] >> 4) & 0x07) + 1; + const branch_leaves_count = (encoded[i] >> 4) & 0x07; const branch_leaves_is_run = (encoded[i] >> 7) !== 0; i += 1; /** @type {Uint8Array} */ @@ -2427,14 +2688,22 @@ function loadDatabase(hooks) { ), )); } - /** @type {SearchTreeBranchesArray} */ + /** @type {SearchTreeBranches} */ const branches = branch_count === 0 ? EMPTY_SEARCH_TREE_BRANCHES : - new SearchTreeBranchesArray( - encoded.subarray(i, i + branch_count), - EMPTY_UINT8, - ); - i += branch_count; + branch_flag_alphabet ? + new SearchTreeBranchesAlphaBitmap( + branch_flag_alphabet.alphabet, + branch_alphabitmap, + EMPTY_UINT8, + ) : + new SearchTreeBranchesArray( + encoded.subarray(i, i + branch_count), + EMPTY_UINT8, + ); + if (!branch_flag_alphabet) { + i += branch_count; + } branches.subtrees = branch_nodes; let leaves = EMPTY_BITMAP; if (leaves_count !== 0) { @@ -2556,7 +2825,7 @@ function loadDatabase(hooks) { k += 1; } const end = k; - const bucket = {hash: hashes.subarray(i * 6, (i + 1) * 6), data: null, end, count}; + const bucket = {hash: hashes.subarray(i * 5, (i + 1) * 5), data: null, end, count}; this.buckets.push(bucket); this.bucket_keys.push(start); } @@ -2698,7 +2967,7 @@ function loadDatabase(hooks) { */ function loadColumnFromBytes(data) { const hashBuf = Uint8Array.of(0, 0, 0, 0, 0, 0, 0, 0); - const truncatedHash = hashBuf.subarray(2, 8); + const truncatedHash = hashBuf.subarray(3, 8); siphashOfBytes(data, 0, 0, 0, 0, hashBuf); const cb = registry.dataColumnLoadPromiseCallbacks.get(truncatedHash); if (cb) { @@ -2744,7 +3013,7 @@ function loadDatabase(hooks) { /** @type {HashTable} */ const stash = new HashTable(); const hash = Uint8Array.of(0, 0, 0, 0, 0, 0, 0, 0); - const truncatedHash = new Uint8Array(hash.buffer, 2, 6); + const truncatedHash = hash.subarray(3, 8); // used for handling compressed (that is, relative-offset) nodes /** @type {{hash: Uint8Array, used: boolean}[]} */ const hash_history = []; @@ -2764,12 +3033,12 @@ function loadDatabase(hooks) { * @param {number} i * @param {number} compression_tag * @returns {{ - * "cpbranches": Uint8Array, - * "csbranches": Uint8Array, * "might_have_prefix_branches": SearchTreeBranches, * "branches": SearchTreeBranches, + * "branches_header": Uint8Array, * "cpnodes": Uint8Array, * "csnodes": Uint8Array, + * "branches_keys": Uint8Array, * "consumed_len_bytes": number, * }} */ @@ -2786,49 +3055,63 @@ function loadDatabase(hooks) { const any_children_are_compressed = (compression_tag & 0xF0) !== 0x00 || is_long_compressed; const start_point = i; - let cplen; - let cslen; /** - * @type {( - * typeof SearchTreeBranches & - * {"ALPHABITMAP_CHARS": number[], "width": number} - * )?} + * @type {Alphabet|null} */ - let alphabitmap = null; + let cpalphabet = null; + /** + * @type {Uint8Array} + */ + let cpalphabitmap = EMPTY_UINT8; + /** + * @type {number} + */ + let cplen; + /** + * @type {Alphabet|null} + */ + let csalphabet = null; + /** + * @type {Uint8Array} + */ + let csalphabitmap = EMPTY_UINT8; + /** + * @type {number} + */ + let cslen; + // might-have-prefix nodes if (is_pure_suffixes_only_node) { cplen = 0; - cslen = input[i]; - i += 1; - if (cslen >= 0xc0) { - alphabitmap = SearchTreeBranchesLongAlphaBitmap; - cslen = cslen & 0x3F; - } else if (cslen >= 0x80) { - alphabitmap = SearchTreeBranchesShortAlphaBitmap; - cslen = cslen & 0x7F; - } } else { - cplen = input[i]; - i += 1; - cslen = input[i]; - i += 1; - if (cplen === 0xff && cslen === 0xff) { - cplen = 0x100; - cslen = 0; - } else if (cplen >= 0xc0 && cslen >= 0xc0) { - alphabitmap = SearchTreeBranchesLongAlphaBitmap; - cplen = cplen & 0x3F; - cslen = cslen & 0x3F; - } else if (cplen >= 0x80 && cslen >= 0x80) { - alphabitmap = SearchTreeBranchesShortAlphaBitmap; - cplen = cplen & 0x7F; - cslen = cslen & 0x7F; + const parsed = Alphabet.parse(i, input); + if (parsed) { + cpalphabitmap = input.subarray(i, i + parsed.consumed_len_bytes); + cpalphabet = parsed.alphabet; + cplen = parsed.len; + i += parsed.consumed_len_bytes; + } else { + cplen = input[i]; + i += 1; } } + // suffix-only nodes + const parsed = Alphabet.parse(i, input); + if (parsed) { + csalphabitmap = input.subarray(i, i + parsed.consumed_len_bytes); + csalphabet = parsed.alphabet; + cslen = parsed.len; + i += parsed.consumed_len_bytes; + } else { + cslen = input[i]; + i += 1; + } + const branches_header = input.subarray(start_point, i); + // now process the hashes, offsets, or stack let j = 0; /** @type {Uint8Array} */ let cpnodes; if (any_children_are_compressed) { - cpnodes = cplen === 0 ? EMPTY_UINT8 : new Uint8Array(cplen * 6); + cpnodes = cplen === 0 ? EMPTY_UINT8 : new Uint8Array(cplen * 5); while (j < cplen) { const is_compressed = all_children_are_compressed || ((0x10 << j) & compression_tag) !== 0; @@ -2845,29 +3128,28 @@ function loadDatabase(hooks) { hash_history[slot].used = true; cpnodes.set( hash_history[slot].hash, - j * 6, + j * 5, ); } else { - const joff = j * 6; + const joff = j * 5; cpnodes[joff + 0] = input[i + 0]; cpnodes[joff + 1] = input[i + 1]; cpnodes[joff + 2] = input[i + 2]; cpnodes[joff + 3] = input[i + 3]; cpnodes[joff + 4] = input[i + 4]; - cpnodes[joff + 5] = input[i + 5]; - i += 6; + i += 5; } j += 1; } } else { - cpnodes = cplen === 0 ? EMPTY_UINT8 : input.subarray(i, i + (cplen * 6)); - i += cplen * 6; + cpnodes = cplen === 0 ? EMPTY_UINT8 : input.subarray(i, i + (cplen * 5)); + i += cplen * 5; } j = 0; /** @type {Uint8Array} */ let csnodes; if (any_children_are_compressed) { - csnodes = cslen === 0 ? EMPTY_UINT8 : new Uint8Array(cslen * 6); + csnodes = cslen === 0 ? EMPTY_UINT8 : new Uint8Array(cslen * 5); while (j < cslen) { const is_compressed = all_children_are_compressed || ((0x10 << (cplen + j)) & compression_tag) !== 0; @@ -2884,138 +3166,146 @@ function loadDatabase(hooks) { hash_history[slot].used = true; csnodes.set( hash_history[slot].hash, - j * 6, + j * 5, ); } else { - const joff = j * 6; + const joff = j * 5; csnodes[joff + 0] = input[i + 0]; csnodes[joff + 1] = input[i + 1]; csnodes[joff + 2] = input[i + 2]; csnodes[joff + 3] = input[i + 3]; csnodes[joff + 4] = input[i + 4]; - csnodes[joff + 5] = input[i + 5]; - i += 6; + i += 5; } j += 1; } } else { - csnodes = cslen === 0 ? EMPTY_UINT8 : input.subarray(i, i + (cslen * 6)); - i += cslen * 6; + csnodes = cslen === 0 ? EMPTY_UINT8 : input.subarray(i, i + (cslen * 5)); + i += cslen * 5; } - let cpbranches; + const start_point_keys = i; let might_have_prefix_branches; if (cplen === 0) { - cpbranches = EMPTY_UINT8; might_have_prefix_branches = EMPTY_SEARCH_TREE_BRANCHES; - } else if (alphabitmap) { - cpbranches = new Uint8Array(input.buffer, i + input.byteOffset, alphabitmap.width); - const branchset = (alphabitmap.width === 4 ? (input[i + 3] << 24) : 0) | - (input[i + 2] << 16) | - (input[i + 1] << 8) | - input[i]; - might_have_prefix_branches = new alphabitmap(branchset, cpnodes); - i += alphabitmap.width; + } else if (cpalphabet) { + might_have_prefix_branches = new SearchTreeBranchesAlphaBitmap( + cpalphabet, + cpalphabitmap, + cpnodes, + ); } else { - cpbranches = new Uint8Array(input.buffer, i + input.byteOffset, cplen); - might_have_prefix_branches = new SearchTreeBranchesArray(cpbranches, cpnodes); + might_have_prefix_branches = new SearchTreeBranchesArray( + new Uint8Array(input.buffer, i + input.byteOffset, cplen), + cpnodes, + ); i += cplen; } - let csbranches; let branches; if (cslen === 0) { - csbranches = EMPTY_UINT8; branches = might_have_prefix_branches; - } else if (alphabitmap) { - csbranches = new Uint8Array(input.buffer, i + input.byteOffset, alphabitmap.width); - const branchset = (alphabitmap.width === 4 ? (input[i + 3] << 24) : 0) | - (input[i + 2] << 16) | - (input[i + 1] << 8) | - input[i]; - if (cplen === 0) { - branches = new alphabitmap(branchset, csnodes); - } else { - const cpoffset = i - alphabitmap.width; - const cpbranchset = - (alphabitmap.width === 4 ? (input[cpoffset + 3] << 24) : 0) | - (input[cpoffset + 2] << 16) | - (input[cpoffset + 1] << 8) | - input[cpoffset]; - const hashes = new Uint8Array((cplen + cslen) * 6); - let cpi = 0; - let csi = 0; - let j = 0; - for (let k = 0; k < alphabitmap.ALPHABITMAP_CHARS.length; k += 1) { - if (branchset & (1 << k)) { - hashes[j + 0] = csnodes[csi + 0]; - hashes[j + 1] = csnodes[csi + 1]; - hashes[j + 2] = csnodes[csi + 2]; - hashes[j + 3] = csnodes[csi + 3]; - hashes[j + 4] = csnodes[csi + 4]; - hashes[j + 5] = csnodes[csi + 5]; - j += 6; - csi += 6; - } else if (cpbranchset & (1 << k)) { - hashes[j + 0] = cpnodes[cpi + 0]; - hashes[j + 1] = cpnodes[cpi + 1]; - hashes[j + 2] = cpnodes[cpi + 2]; - hashes[j + 3] = cpnodes[cpi + 3]; - hashes[j + 4] = cpnodes[cpi + 4]; - hashes[j + 5] = cpnodes[cpi + 5]; - j += 6; - cpi += 6; - } - } - branches = new alphabitmap(branchset | cpbranchset, hashes); - } - i += alphabitmap.width; } else { - csbranches = new Uint8Array(input.buffer, i + input.byteOffset, cslen); - if (cplen === 0) { - branches = new SearchTreeBranchesArray(csbranches, csnodes); + if (csalphabet) { + branches = new SearchTreeBranchesAlphaBitmap( + csalphabet, + csalphabitmap, + csnodes, + ); } else { - const branchset = new Uint8Array(cplen + cslen); - const hashes = new Uint8Array((cplen + cslen) * 6); - let cpi = 0; - let csi = 0; - let j = 0; - while (cpi < cplen || csi < cslen) { - if (cpi >= cplen || (csi < cslen && cpbranches[cpi] > csbranches[csi])) { - branchset[j] = csbranches[csi]; - const joff = j * 6; - const csioff = csi * 6; - hashes[joff + 0] = csnodes[csioff + 0]; - hashes[joff + 1] = csnodes[csioff + 1]; - hashes[joff + 2] = csnodes[csioff + 2]; - hashes[joff + 3] = csnodes[csioff + 3]; - hashes[joff + 4] = csnodes[csioff + 4]; - hashes[joff + 5] = csnodes[csioff + 5]; - csi += 1; - } else { - branchset[j] = cpbranches[cpi]; - const joff = j * 6; - const cpioff = cpi * 6; - hashes[joff + 0] = cpnodes[cpioff + 0]; - hashes[joff + 1] = cpnodes[cpioff + 1]; - hashes[joff + 2] = cpnodes[cpioff + 2]; - hashes[joff + 3] = cpnodes[cpioff + 3]; - hashes[joff + 4] = cpnodes[cpioff + 4]; - hashes[joff + 5] = cpnodes[cpioff + 5]; - cpi += 1; - } - j += 1; - } - branches = new SearchTreeBranchesArray(branchset, hashes); + branches = new SearchTreeBranchesArray( + new Uint8Array(input.buffer, i + input.byteOffset, cslen), + csnodes, + ); + i += cslen; + } + if (cplen !== 0) { + const hashes = new Uint8Array((cplen + cslen) * 5); + if (cplen + cslen > 32) { + const raw_bits = new Uint8Array(RAWBYTE_ALPHABET.bytes + 1); + raw_bits[0] = RAWBYTE_ALPHABET.flag; + const bits = raw_bits.subarray(1); + const mhp_keys = might_have_prefix_branches.getKeys(); + const so_keys = branches.getKeys(); + let mhp_i = 0; + let so_i = 0; + let j = 0; + while (mhp_i < cplen || so_i < cslen) { + if (so_i === cslen || mhp_keys[mhp_i] < so_keys[so_i]) { + const joff = j * 5; + const mhp_off = mhp_i * 5; + hashes[joff + 0] = cpnodes[mhp_off + 0]; + hashes[joff + 1] = cpnodes[mhp_off + 1]; + hashes[joff + 2] = cpnodes[mhp_off + 2]; + hashes[joff + 3] = cpnodes[mhp_off + 3]; + hashes[joff + 4] = cpnodes[mhp_off + 4]; + const ix = mhp_keys[mhp_i]; + bits[ix >> 3] |= 1 << (ix & 0x07); + mhp_i += 1; + } else { + const joff = j * 5; + const so_off = so_i * 5; + hashes[joff + 0] = csnodes[so_off + 0]; + hashes[joff + 1] = csnodes[so_off + 1]; + hashes[joff + 2] = csnodes[so_off + 2]; + hashes[joff + 3] = csnodes[so_off + 3]; + hashes[joff + 4] = csnodes[so_off + 4]; + const ix = so_keys[so_i]; + bits[ix >> 3] |= 1 << (ix & 0x07); + so_i += 1; + } + j += 1; + } + branches = new SearchTreeBranchesAlphaBitmap( + RAWBYTE_ALPHABET, + raw_bits, + hashes, + ); + } else { + const merged_keys = new Uint8Array(cplen + cslen); + const mhp_keys = might_have_prefix_branches.getKeys(); + const so_keys = branches.getKeys(); + let mhp_i = 0; + let so_i = 0; + let j = 0; + while (mhp_i < cplen || so_i < cslen) { + if (so_i === cslen || mhp_keys[mhp_i] < so_keys[so_i]) { + const joff = j * 5; + const mhp_off = mhp_i * 5; + hashes[joff + 0] = cpnodes[mhp_off + 0]; + hashes[joff + 1] = cpnodes[mhp_off + 1]; + hashes[joff + 2] = cpnodes[mhp_off + 2]; + hashes[joff + 3] = cpnodes[mhp_off + 3]; + hashes[joff + 4] = cpnodes[mhp_off + 4]; + merged_keys[j] = mhp_keys[mhp_i]; + mhp_i += 1; + } else { + const joff = j * 5; + const so_off = so_i * 5; + hashes[joff + 0] = csnodes[so_off + 0]; + hashes[joff + 1] = csnodes[so_off + 1]; + hashes[joff + 2] = csnodes[so_off + 2]; + hashes[joff + 3] = csnodes[so_off + 3]; + hashes[joff + 4] = csnodes[so_off + 4]; + merged_keys[j] = so_keys[so_i]; + so_i += 1; + } + j += 1; + } + branches = new SearchTreeBranchesArray( + merged_keys, + hashes, + ); + } } - i += cslen; } + const branches_keys = input.subarray(start_point_keys, i); return { consumed_len_bytes: i - start_point, - cpbranches, - csbranches, cpnodes, csnodes, branches, might_have_prefix_branches, + branches_header, + branches_keys, }; } while (i < l) { @@ -3038,26 +3328,23 @@ function loadDatabase(hooks) { /** @type {number} */ let no_leaves_flag; /** @type {number} */ - let inline_neighbors_flag; + let no_branches_flag; if (is_data_compressed && is_pure_suffixes_only_node) { dlen = 0; no_leaves_flag = 0x80; - inline_neighbors_flag = 0; + no_branches_flag = 0; } else { dlen = input[i] & 0x3F; no_leaves_flag = input[i] & 0x80; - inline_neighbors_flag = input[i] & 0x40; + no_branches_flag = input[i] & 0x40; i += 1; } - if (inline_neighbors_flag !== 0) { + if (no_leaves_flag !== 0 && no_branches_flag !== 0) { // node with packed leaves and common 16bit prefix - const leaves_count = no_leaves_flag !== 0 ? - 0 : - ((compression_tag >> 4) & 0x07) + 1; - const leaves_is_run = no_leaves_flag === 0 && - ((compression_tag >> 4) & 0x08) !== 0; - const branch_count = is_long_compressed ? - ((compression_tag >> 8) & 0xff) + 1 : + const leaves_count = (compression_tag >> 4) & 0x07; + const leaves_is_run = ((compression_tag >> 4) & 0x08) !== 0; + const branch_flag = is_long_compressed ? + (compression_tag >> 8) & 0xff : 0; if (is_data_compressed) { data = data_history[data_history.length - dlen - 1]; @@ -3071,12 +3358,17 @@ function loadDatabase(hooks) { i += dlen; } const branches_start = i; + const branch_flag_alphabet = Alphabet.parseFlag(branch_flag, i, input); + const branch_count = branch_flag_alphabet ? branch_flag_alphabet.len : branch_flag; + if (branch_flag_alphabet) { + i += branch_flag_alphabet.consumed_len_bytes; + } // leaf_value_upper i += 2; // branch_nodes for (let j = 0; j < branch_count; j += 1) { const branch_dlen = input[i] & 0x0f; - const branch_leaves_count = ((input[i] >> 4) & 0x0f) + 1; + const branch_leaves_count = (input[i] >> 4) & 0x0f; const branch_leaves_is_run = (input[i] >> 7) !== 0; i += 1; if (!is_pure_suffixes_only_node) { @@ -3089,7 +3381,9 @@ function loadDatabase(hooks) { } } // branch keys - i += branch_count; + if (!branch_flag_alphabet) { + i += branch_count; + } // leaves if (leaves_is_run) { i += 2; @@ -3099,7 +3393,7 @@ function loadDatabase(hooks) { if (is_data_compressed) { const clen = ( 1 + // first compression header byte - (is_long_compressed ? 1 : 0) + // branch count + (is_long_compressed ? 1 : 0) + // branch flag 1 + // data length and other flags dlen + // data (i - branches_start) // branches and leaves @@ -3112,7 +3406,7 @@ function loadDatabase(hooks) { canonical[ci] = input[start + ci]; ci += 1; } - canonical[ci] = dlen | no_leaves_flag | 0x40; + canonical[ci] = dlen | 0xc0; ci += 1; for (let j = 0; j < dlen; j += 1) { canonical[ci] = data[j]; @@ -3145,16 +3439,25 @@ function loadDatabase(hooks) { new Uint8Array(input.buffer, i + input.byteOffset, dlen); i += dlen; } - const coffset = i; const { - cpbranches, - csbranches, cpnodes, csnodes, consumed_len_bytes: branches_consumed_len_bytes, branches, might_have_prefix_branches, - } = makeBranchesFromBinaryData(input, i, compression_tag); + branches_header, + branches_keys, + } = no_branches_flag !== 0 ? + { + cpnodes: EMPTY_UINT8, + csnodes: EMPTY_UINT8, + consumed_len_bytes: 0, + branches: EMPTY_SEARCH_TREE_BRANCHES, + might_have_prefix_branches: EMPTY_SEARCH_TREE_BRANCHES, + branches_header: EMPTY_UINT8, + branches_keys: EMPTY_UINT8, + } : + makeBranchesFromBinaryData(input, i, compression_tag); i += branches_consumed_len_bytes; let whole; let suffix; @@ -3175,10 +3478,11 @@ function loadDatabase(hooks) { ); const clen = ( // lengths of children and data - (is_data_compressed ? 2 : 3) + + (is_data_compressed ? 1 : 2) + // branches + branches_header.length + csnodes.length + - csbranches.length + + branches_keys.length + // leaves suffix.consumed_len_bytes ); @@ -3192,15 +3496,15 @@ function loadDatabase(hooks) { } else { canonical[ci] = 1; ci += 1; - canonical[ci] = dlen | no_leaves_flag; + canonical[ci] = dlen | no_leaves_flag | no_branches_flag; ci += 1; } - canonical[ci] = input[coffset]; // suffix child count - ci += 1; + canonical.set(branches_header, ci); + ci += branches_header.length; canonical.set(csnodes, ci); ci += csnodes.length; - canonical.set(csbranches, ci); - ci += csbranches.length; + canonical.set(branches_keys, ci); + ci += branches_keys.length; const leavesOffset = i - suffix.consumed_len_bytes; for (let j = leavesOffset; j < i; j += 1) { canonical[ci + j - leavesOffset] = input[j]; @@ -3228,10 +3532,11 @@ function loadDatabase(hooks) { suffix, ); const clen = ( - 4 + // lengths of children and data + 2 + // lengths of children and data dlen + + branches_header.length + cpnodes.length + csnodes.length + - cpbranches.length + csbranches.length + + branches_keys.length + whole.consumed_len_bytes + suffix.consumed_len_bytes ); @@ -3241,22 +3546,18 @@ function loadDatabase(hooks) { let ci = 0; canonical[ci] = 0; ci += 1; - canonical[ci] = dlen | no_leaves_flag; + canonical[ci] = dlen | no_leaves_flag | no_branches_flag; ci += 1; canonical.set(data, ci); ci += data.length; - canonical[ci] = input[coffset]; // prefix child count - ci += 1; - canonical[ci] = input[coffset + 1]; // suffix child count - ci += 1; + canonical.set(branches_header, ci); + ci += branches_header.length; canonical.set(cpnodes, ci); ci += cpnodes.length; canonical.set(csnodes, ci); ci += csnodes.length; - canonical.set(cpbranches, ci); - ci += cpbranches.length; - canonical.set(csbranches, ci); - ci += csbranches.length; + canonical.set(branches_keys, ci); + ci += branches_keys.length; const leavesOffset = i - whole.consumed_len_bytes - suffix.consumed_len_bytes; for (let j = leavesOffset; j < i; j += 1) { canonical[ci + j - leavesOffset] = input[j]; @@ -3275,7 +3576,13 @@ function loadDatabase(hooks) { consumed_len_bytes: branches_consumed_len_bytes, branches, might_have_prefix_branches, - } = makeBranchesFromBinaryData(input, i, compression_tag); + } = no_branches_flag !== 0 ? + { + consumed_len_bytes: 0, + branches: EMPTY_SEARCH_TREE_BRANCHES, + might_have_prefix_branches: EMPTY_SEARCH_TREE_BRANCHES, + } : + makeBranchesFromBinaryData(input, i, compression_tag); i += branches_consumed_len_bytes; let whole; let suffix; @@ -3317,7 +3624,7 @@ function loadDatabase(hooks) { suffix, ); } - hash[2] &= 0x7f; + hash[3] &= 0x7f; hash_history.push({hash: truncatedHash.slice(), used: false}); if (data.length !== 0) { data_history.push(data); @@ -3330,8 +3637,8 @@ function loadDatabase(hooks) { while (j < lb) { // node id with a 1 in its most significant bit is inlined, and, so // it won't be in the stash - if ((tree_branch_nodeids[j * 6] & 0x80) === 0) { - const subtree = stash.getWithOffsetKey(tree_branch_nodeids, j * 6); + if ((tree_branch_nodeids[j * 5] & 0x80) === 0) { + const subtree = stash.getWithOffsetKey(tree_branch_nodeids, j * 5); if (subtree !== undefined) { tree_branch_subtrees[j] = Promise.resolve(subtree); } @@ -3347,8 +3654,8 @@ function loadDatabase(hooks) { while (j < lb) { // node id with a 1 in its most significant bit is inlined, and, so // it won't be in the stash - if ((tree_mhp_branch_nodeids[j * 6] & 0x80) === 0) { - const subtree = stash.getWithOffsetKey(tree_mhp_branch_nodeids, j * 6); + if ((tree_mhp_branch_nodeids[j * 5] & 0x80) === 0) { + const subtree = stash.getWithOffsetKey(tree_mhp_branch_nodeids, j * 5); if (subtree !== undefined) { tree_mhp_branch_subtrees[j] = Promise.resolve(subtree); } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index bc9ad1606b8a..5d1f4778f1c5 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -353,6 +353,8 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum name: name.as_ref().unwrap().to_string(), rename: src.map(|x| x.to_string()), }, + // All placeholder impl items should have been removed in the stripper passes. + PlaceholderImplItem => unreachable!(), } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 55075001e0fe..751db71ceff0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -535,7 +535,7 @@ fn opts() -> Vec { "", "emit", "Comma separated list of types of output for rustdoc to emit", - "[toolchain-shared-resources,invocation-specific,dep-info]", + "[html-static-files,html-non-static-files,dep-info]", ), opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""), opt( @@ -904,13 +904,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { return; } - for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { - if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { - for lint in &delayed_lints.lints { - rustc_hir_analysis::emit_delayed_lint(lint, tcx); - } - } - } + rustc_interface::passes::emit_delayed_lints(tcx); if render_opts.dep_info().is_some() { rustc_interface::passes::write_dep_info(tcx); @@ -954,15 +948,15 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { }) } -fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) { - let hash = tcxt.crate_hash(LOCAL_CRATE); - let crate_name = tcxt.crate_name(LOCAL_CRATE); +fn dump_feature_usage_metrics(tcx: TyCtxt<'_>, metrics_dir: &Path) { + let hash = tcx.crate_hash(LOCAL_CRATE); + let crate_name = tcx.crate_name(LOCAL_CRATE); let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json"); let metrics_path = metrics_dir.join(metrics_file_name); - if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) { + if let Err(error) = tcx.features().dump_feature_usage_metrics(metrics_path) { // FIXME(yaahc): once metrics can be enabled by default we will want "failure to emit // default metrics" to only produce a warning when metrics are enabled by default and emit // an error only when the user manually enables metrics - tcxt.dcx().err(format!("cannot emit feature usage metrics: {error}")); + tcx.dcx().err(format!("cannot emit feature usage metrics: {error}")); } } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 77b3a2e9c9f2..ac5e7805005e 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -203,6 +203,10 @@ fn visit_item(&mut self, i: &clean::Item) { // don't count items in stripped modules return; } + clean::PlaceholderImplItem => { + // The "real" impl items are handled below. + return; + } // docs on `use` and `extern crate` statements are not displayed, so they're not // worth counting clean::ImportItem(..) | clean::ExternCrateItem { .. } => {} diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 39116061f485..ff7535fea41c 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -6,6 +6,7 @@ //! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doctests. use rustc_hir as hir; +use rustc_macros::Diagnostic; use rustc_middle::lint::{LevelAndSource, LintLevelSource}; use rustc_session::lint; use tracing::debug; @@ -78,8 +79,8 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - | clean::ProvidedAssocConstItem(..) | clean::ImplAssocConstItem(..) | clean::RequiredAssocTypeItem(..) - // check for trait impl - | clean::ImplItem(box clean::Impl { trait_: Some(_), .. }) + | clean::ImplItem(_) + | clean::PlaceholderImplItem ) { return false; @@ -116,6 +117,14 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - } pub(crate) fn look_for_tests(cx: &DocContext<'_>, dox: &str, item: &Item) { + #[derive(Diagnostic)] + #[diag("missing code example in this documentation")] + struct MissingCodeExample; + + #[derive(Diagnostic)] + #[diag("documentation test in private item")] + struct DoctestInPrivateItem; + let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id) else { // If non-local, no need to check anything. return; @@ -129,20 +138,21 @@ pub(crate) fn look_for_tests(cx: &DocContext<'_>, dox: &str, item: &Item) { if should_have_doc_example(cx, item) { debug!("reporting error for {item:?} (hir_id={hir_id:?})"); let sp = item.attr_span(cx.tcx); - cx.tcx.node_span_lint(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, |lint| { - lint.primary_message("missing code example in this documentation"); - }); + cx.tcx.emit_node_span_lint( + crate::lint::MISSING_DOC_CODE_EXAMPLES, + hir_id, + sp, + MissingCodeExample, + ); } } else if tests.found_tests > 0 && !cx.cache.effective_visibilities.is_exported(cx.tcx, item.item_id.expect_def_id()) { - cx.tcx.node_span_lint( + cx.tcx.emit_node_span_lint( crate::lint::PRIVATE_DOC_TESTS, hir_id, item.attr_span(cx.tcx), - |lint| { - lint.primary_message("documentation test in private item"); - }, + DoctestInPrivateItem, ); } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 697b35ad8e85..8b66672cfa5e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1067,17 +1067,27 @@ impl LinkCollector<'_, '_> { #[instrument(level = "debug", skip_all)] fn resolve_links(&mut self, item: &Item) { let tcx = self.cx.tcx; - if !self.cx.document_private() - && let Some(def_id) = item.item_id.as_def_id() - && let Some(def_id) = def_id.as_local() - && !tcx.effective_visibilities(()).is_exported(def_id) - && !has_primitive_or_keyword_or_attribute_docs(&item.attrs.other_attrs) + let document_private = self.cx.document_private(); + let effective_visibilities = tcx.effective_visibilities(()); + let should_skip_link_resolution = |item_id: DefId| { + !document_private + && item_id + .as_local() + .is_some_and(|local_def_id| !effective_visibilities.is_exported(local_def_id)) + && !has_primitive_or_keyword_or_attribute_docs(&item.attrs.other_attrs) + }; + + if let Some(def_id) = item.item_id.as_def_id() + && should_skip_link_resolution(def_id) { // Skip link resolution for non-exported items. return; } - let mut insert_links = |item_id, doc: &str| { + let mut try_insert_links = |item_id, doc: &str| { + if should_skip_link_resolution(item_id) { + return; + } let module_id = match tcx.def_kind(item_id) { DefKind::Mod if item.inner_docs(tcx) => item_id, _ => find_nearest_parent_module(tcx, item_id).unwrap(), @@ -1108,7 +1118,7 @@ fn resolve_links(&mut self, item: &Item) { // NOTE: if there are links that start in one crate and end in another, this will not resolve them. // This is a degenerate case and it's not supported by rustdoc. let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); - insert_links(item_id, &doc) + try_insert_links(item_id, &doc) } // Also resolve links in the note text of `#[deprecated]`. @@ -1137,7 +1147,7 @@ fn resolve_links(&mut self, item: &Item) { } else { item.item_id.expect_def_id() }; - insert_links(item_id, note) + try_insert_links(item_id, note) } } @@ -1914,61 +1924,70 @@ fn report_diagnostic( let sp = item.attr_span(tcx); - tcx.node_span_lint(lint, hir_id, sp, |lint| { - lint.primary_message(msg); + tcx.emit_node_span_lint( + lint, + hir_id, + sp, + rustc_errors::DiagDecorator(|lint| { + lint.primary_message(msg); - let (span, link_range) = match link_range { - MarkdownLinkRange::Destination(md_range) => { - let mut md_range = md_range.clone(); - let sp = - source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings) - .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) => ( - source_span_for_markdown_range(tcx, dox, md_range, &item.attrs.doc_strings) - .map(|(sp, _)| sp), - link_range.clone(), - ), - }; + let (span, link_range) = match link_range { + MarkdownLinkRange::Destination(md_range) => { + let mut md_range = md_range.clone(); + let sp = source_span_for_markdown_range( + tcx, + dox, + &md_range, + &item.attrs.doc_strings, + ) + .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) => ( + source_span_for_markdown_range(tcx, dox, md_range, &item.attrs.doc_strings) + .map(|(sp, _)| sp), + link_range.clone(), + ), + }; - if let Some(sp) = span { - lint.span(sp); - } else { - // blah blah blah\nblah\nblah [blah] blah blah\nblah blah - // ^ ~~~~ - // | link_range - // last_new_line_offset - 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(""); + if let Some(sp) = span { + lint.span(sp); + } else { + // blah blah blah\nblah\nblah [blah] blah blah\nblah blah + // ^ ~~~~ + // | link_range + // last_new_line_offset + 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 `md_range` and manually mark it with '^'s. - lint.note(format!( - "the link appears in this line:\n\n{line}\n\ + // 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: , item: &Item, hir_id: HirId, dox: & let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings) .map(|(sp, _)| sp); let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx)); - cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| { - lint.primary_message(msg) - .note("bare URLs are not automatically turned into clickable links"); - // The fallback of using the attribute span is suitable for - // highlighting where the error is, but not for placing the < and > - if let Some(sp) = maybe_sp { - if let Some(without_brackets) = without_brackets { - lint.multipart_suggestion( - "use an automatic link instead", - vec![(sp, format!("<{without_brackets}>"))], - Applicability::MachineApplicable, - ); - } else { - lint.multipart_suggestion( - "use an automatic link instead", - vec![ - (sp.shrink_to_lo(), "<".to_string()), - (sp.shrink_to_hi(), ">".to_string()), - ], - Applicability::MachineApplicable, - ); + cx.tcx.emit_node_span_lint( + crate::lint::BARE_URLS, + hir_id, + sp, + DiagDecorator(|lint| { + lint.primary_message(msg) + .note("bare URLs are not automatically turned into clickable links"); + // The fallback of using the attribute span is suitable for + // highlighting where the error is, but not for placing the < and > + if let Some(sp) = maybe_sp { + if let Some(without_brackets) = without_brackets { + lint.multipart_suggestion( + "use an automatic link instead", + vec![(sp, format!("<{without_brackets}>"))], + Applicability::MachineApplicable, + ); + } else { + lint.multipart_suggestion( + "use an automatic link instead", + vec![ + (sp.shrink_to_lo(), "<".to_string()), + (sp.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } } - } - }); + }), + ); }; let mut p = Parser::new_ext(dox, main_body_opts()).into_offset_iter(); diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index e94fd996947b..1c017f9a635c 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -6,13 +6,13 @@ use rustc_data_structures::sync::Lock; use rustc_errors::emitter::Emitter; use rustc_errors::formatting::format_diag_message; -use rustc_errors::{Applicability, DiagCtxt, DiagInner}; +use rustc_errors::{Applicability, Diag, DiagCtxt, DiagCtxtHandle, DiagInner, Diagnostic, Level}; use rustc_parse::{source_str_to_stream, unwrap_or_emit_fatal}; use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, Transparency}; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{DUMMY_SP, FileName, InnerSpan}; +use rustc_span::{DUMMY_SP, FileName, InnerSpan, Span}; use crate::clean; use crate::core::DocContext; @@ -34,12 +34,72 @@ fn check_rust_syntax( dox: &str, code_block: RustCodeBlock, ) { + struct CodeblockError<'a> { + buffer: &'a Buffer, + code_block: RustCodeBlock, + span: Span, + is_precise_span: bool, + } + + impl<'a, 'b> Diagnostic<'a, ()> for CodeblockError<'b> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { buffer, code_block, span, is_precise_span } = self; + + let mut lint = Diag::new( + dcx, + level, + if buffer.has_errors { + "could not parse code block as Rust code" + } else { + "Rust code block is empty" + }, + ); + + let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; + let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; + + let explanation = if is_ignore { + "`ignore` code blocks require valid Rust code for syntax highlighting; \ + mark blocks that do not contain Rust code as text" + } else { + "mark blocks that do not contain Rust code as text" + }; + + if is_precise_span { + if is_ignore { + // Giving an accurate suggestion is hard because `ignore` might not have come + // first in the list. Just give a `help` instead. + lint.span_help( + span.from_inner(InnerSpan::new(0, 3)), + format!("{explanation}: ```text"), + ); + } else if empty_block { + lint.span_suggestion( + span.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(), + explanation, + "text", + Applicability::MachineApplicable, + ); + } + } else if empty_block || is_ignore { + lint.help(format!("{explanation}: ```text")); + } + + // FIXME(#67563): Provide more context for these errors by displaying the spans inline. + for message in buffer.messages.iter() { + lint.note(message.clone()); + } + + lint + } + } + let buffer = Arc::new(Lock::new(Buffer::default())); let emitter = BufferEmitter { buffer: Arc::clone(&buffer) }; let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); - let source = dox[code_block.code] + let source = dox[code_block.code.clone()] .lines() .map(|line| crate::html::markdown::map_line(line).for_code()) .intersperse(Cow::Borrowed("\n")) @@ -75,11 +135,8 @@ fn check_rust_syntax( return; }; - let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; - let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; - // The span and whether it is precise or not. - let (sp, precise_span) = match source_span_for_markdown_range( + let (span, is_precise_span) = match source_span_for_markdown_range( cx.tcx, dox, &code_block.range, @@ -89,51 +146,16 @@ fn check_rust_syntax( None => (item.attr_span(cx.tcx), false), }; - let msg = if buffer.has_errors { - "could not parse code block as Rust code" - } else { - "Rust code block is empty" - }; - // Finally build and emit the completed diagnostic. // All points of divergence have been handled earlier so this can be // done the same way whether the span is precise or not. let hir_id = cx.tcx.local_def_id_to_hir_id(local_id); - cx.tcx.node_span_lint(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, |lint| { - lint.primary_message(msg); - - let explanation = if is_ignore { - "`ignore` code blocks require valid Rust code for syntax highlighting; \ - mark blocks that do not contain Rust code as text" - } else { - "mark blocks that do not contain Rust code as text" - }; - - if precise_span { - if is_ignore { - // giving an accurate suggestion is hard because `ignore` might not have come first in the list. - // just give a `help` instead. - lint.span_help( - sp.from_inner(InnerSpan::new(0, 3)), - format!("{explanation}: ```text"), - ); - } else if empty_block { - lint.span_suggestion( - sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(), - explanation, - "text", - Applicability::MachineApplicable, - ); - } - } else if empty_block || is_ignore { - lint.help(format!("{explanation}: ```text")); - } - - // FIXME(#67563): Provide more context for these errors by displaying the spans inline. - for message in buffer.messages.iter() { - lint.note(message.clone()); - } - }); + cx.tcx.emit_node_span_lint( + crate::lint::INVALID_RUST_CODEBLOCKS, + hir_id, + span, + CodeblockError { buffer: &buffer, code_block, span, is_precise_span }, + ); } #[derive(Default)] diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 4e374fe3cd56..86b8e7b6f86a 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -21,86 +21,91 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & Some((sp, _)) => sp, None => item.attr_span(tcx), }; - tcx.node_span_lint(crate::lint::INVALID_HTML_TAGS, hir_id, sp, |lint| { - use rustc_lint_defs::Applicability; + tcx.emit_node_span_lint( + crate::lint::INVALID_HTML_TAGS, + hir_id, + sp, + rustc_errors::DiagDecorator(|lint| { + use rustc_lint_defs::Applicability; - lint.primary_message(msg); + lint.primary_message(msg); - // If a tag looks like ``, it might actually be a generic. - // We don't try to detect stuff `` because that's not valid HTML, - // and we don't try to detect stuff `` because that's not valid Rust. - let mut generics_end = range.end; - if is_open_tag - && dox[..generics_end].ends_with('>') - && let Some(mut generics_start) = 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'>' + // If a tag looks like ``, it might actually be a generic. + // We don't try to detect stuff `` because that's not valid HTML, + // and we don't try to detect stuff `` because that's not valid Rust. + let mut generics_end = range.end; + if is_open_tag + && dox[..generics_end].ends_with('>') + && let Some(mut generics_start) = 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.doc_strings, + ) { + Some((sp, _)) => sp, + None => item.attr_span(tcx), + }; + // Sometimes, we only extract part of a path. For example, consider this: + // + // <[u32] as IntoIter>::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`>::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] as IntoIter::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; + } + // multipart form is chosen here because ``Vec`` 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.doc_strings, - ) { - Some((sp, _)) => sp, - None => item.attr_span(tcx), - }; - // Sometimes, we only extract part of a path. For example, consider this: - // - // <[u32] as IntoIter>::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`>::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] as IntoIter::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; - } - // multipart form is chosen here because ``Vec`` 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, - ); - } - }); + }), + ); }; let mut tagp = TagParser::new(); diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index e49f54f6df94..13bc4c079aa7 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -1,7 +1,7 @@ use std::ops::Range; use rustc_ast::NodeId; -use rustc_errors::SuggestionStyle; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, SuggestionStyle}; use rustc_hir::HirId; use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res}; use rustc_lint_defs::Applicability; @@ -9,8 +9,8 @@ BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, OffsetIter, Parser, Tag, }; use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, source_span_for_markdown_range}; -use rustc_span::Symbol; use rustc_span::def_id::DefId; +use rustc_span::{Span, Symbol}; use crate::clean::Item; use crate::clean::utils::{find_nearest_parent_module, inherits_doc_hidden}; @@ -154,6 +154,40 @@ fn check_inline_or_reference_unknown_redundancy( link_data: LinkData, (open, close): (u8, u8), ) -> Option<()> { + struct RedundantExplicitLinks { + explicit_span: Span, + display_span: Span, + link_span: Span, + display_link: String, + } + + impl<'a> Diagnostic<'a, ()> for RedundantExplicitLinks { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { explicit_span, display_span, link_span, display_link } = self; + + Diag::new(dcx, level, "redundant explicit link target") + .with_span_label( + explicit_span, + "explicit target is redundant", + ) + .with_span_label( + display_span, + "because label contains path that resolves to same destination", + ) + .with_note( + "when a link's destination is not specified,\nthe label is used to resolve intra-doc links" + ) + // FIXME (GuillaumeGomez): We cannot use `derive(Diagnostic)` because of this method. + .with_span_suggestion_with_style( + link_span, + "remove explicit link target", + format!("[{}]", display_link), + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ) + } + } + let (resolvable_link, resolvable_link_range) = (&link_data.resolvable_link?, &link_data.resolvable_link_range?); let (dest_res, display_res) = @@ -192,13 +226,17 @@ fn check_inline_or_reference_unknown_redundancy( return None; }; - cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, |lint| { - lint.primary_message("redundant explicit link target") - .span_label(explicit_span, "explicit target is redundant") - .span_label(display_span, "because label contains path that resolves to same destination") - .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") - .span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways); - }); + cx.tcx.emit_node_span_lint( + crate::lint::REDUNDANT_EXPLICIT_LINKS, + hir_id, + explicit_span, + RedundantExplicitLinks { + explicit_span, + display_span, + link_span, + display_link: link_data.display_link, + }, + ); } None @@ -215,6 +253,39 @@ fn check_reference_redundancy( dest: &CowStr<'_>, link_data: LinkData, ) -> Option<()> { + struct RedundantExplicitLinkTarget { + explicit_span: Span, + display_span: Span, + def_span: Span, + link_span: Span, + display_link: String, + } + + impl<'a> Diagnostic<'a, ()> for RedundantExplicitLinkTarget { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { explicit_span, display_span, def_span, link_span, display_link } = self; + + Diag::new(dcx, level, "redundant explicit link target") + .with_span_label(explicit_span, "explicit target is redundant") + .with_span_label( + display_span, + "because label contains path that resolves to same destination", + ) + .with_span_note(def_span, "referenced explicit link target defined here") + .with_note( + "when a link's destination is not specified,\nthe label is used to resolve intra-doc links" + ) + // FIXME (GuillaumeGomez): We cannot use `derive(Diagnostic)` because of this method. + .with_span_suggestion_with_style( + link_span, + "remove explicit link target", + format!("[{}]", display_link), + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ) + } + } + let (resolvable_link, resolvable_link_range) = (&link_data.resolvable_link?, &link_data.resolvable_link_range?); let (dest_res, display_res) = @@ -259,14 +330,18 @@ fn check_reference_redundancy( &item.attrs.doc_strings, )?; - cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, |lint| { - lint.primary_message("redundant explicit link target") - .span_label(explicit_span, "explicit target is redundant") - .span_label(display_span, "because label contains path that resolves to same destination") - .span_note(def_span, "referenced explicit link target defined here") - .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") - .span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways); - }); + cx.tcx.emit_node_span_lint( + crate::lint::REDUNDANT_EXPLICIT_LINKS, + hir_id, + explicit_span, + RedundantExplicitLinkTarget { + explicit_span, + display_span, + def_span, + link_span, + display_link: link_data.display_link, + }, + ); } None diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs index b791e024545f..4c33b82d14b4 100644 --- a/src/librustdoc/passes/lint/unescaped_backticks.rs +++ b/src/librustdoc/passes/lint/unescaped_backticks.rs @@ -52,7 +52,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & None => item.attr_span(tcx), }; - tcx.node_span_lint(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, |lint| { + tcx.emit_node_span_lint(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, rustc_errors::DiagDecorator(|lint| { lint.primary_message("unescaped backtick"); let mut help_emitted = false; @@ -156,7 +156,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & '\\', "if you meant to use a literal backtick, escape it", ); - }); + })); } Event::Code(_) => { let element = element_stack diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 54da158d4d39..f73db253af06 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -1,10 +1,11 @@ //! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items. +use rustc_data_structures::fx::FxHashMap; use rustc_hir::Attribute; use rustc_hir::attrs::{AttributeKind, DocAttribute}; use crate::clean::inline::{load_attrs, merge_attrs}; -use crate::clean::{CfgInfo, Crate, Item, ItemKind}; +use crate::clean::{CfgInfo, Crate, Item, ItemId, ItemKind}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::passes::Pass; @@ -17,7 +18,8 @@ pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate { if cx.tcx.features().doc_cfg() { - CfgPropagator { cx, cfg_info: CfgInfo::default() }.fold_crate(cr) + CfgPropagator { cx, cfg_info: CfgInfo::default(), impl_cfg_info: FxHashMap::default() } + .fold_crate(cr) } else { cr } @@ -26,6 +28,10 @@ pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate { struct CfgPropagator<'a, 'tcx> { cx: &'a mut DocContext<'tcx>, cfg_info: CfgInfo, + + /// To ensure the `doc_cfg` feature works with how `rustdoc` handles impls, we need to store + /// the `cfg` info of `impl`s placeholder to use them later on the "real" impl item. + impl_cfg_info: FxHashMap, } /// This function goes through the attributes list (`new_attrs`) and extract the `cfg` tokens from @@ -78,7 +84,22 @@ impl DocFolder for CfgPropagator<'_, '_> { fn fold_item(&mut self, mut item: Item) -> Option { let old_cfg_info = self.cfg_info.clone(); - self.merge_with_parent_attributes(&mut item); + // If we have an impl, we check if it has an associated `cfg` "context", and if so we will + // use that context instead of the actual (wrong) one. + if let ItemKind::ImplItem(_) = item.kind + && let Some(cfg_info) = self.impl_cfg_info.remove(&item.item_id) + { + self.cfg_info = cfg_info; + } + + if let ItemKind::PlaceholderImplItem = item.kind { + // If we have a placeholder impl, we store the current `cfg` "context" to be used + // on the actual impl later on (the impls are generated after we go through the whole + // AST so they're stored in the `krate` object at the end). + self.impl_cfg_info.insert(item.item_id, self.cfg_info.clone()); + } else { + self.merge_with_parent_attributes(&mut item); + } let result = self.fold_item_recur(item); self.cfg_info = old_cfg_info; diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index 5139ca301dd3..c8691fd012bf 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -107,7 +107,8 @@ fn fold_item(&mut self, mut item: Item) -> Option { | ItemKind::AssocTypeItem(..) | ItemKind::PrimitiveItem(..) | ItemKind::KeywordItem - | ItemKind::AttributeItem => own_stability, + | ItemKind::AttributeItem + | ItemKind::PlaceholderImplItem => own_stability, ItemKind::StrippedItem(..) => unreachable!(), } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 99d22526f85b..bf4e842ceec3 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -120,6 +120,10 @@ fn fold_item(&mut self, i: Item) -> Option { clean::ImplItem(..) => {} + // Since the `doc_cfg` propagation was handled before the current pass, we can (and + // should) remove all placeholder impl items. + clean::PlaceholderImplItem => return None, + // tymethods etc. have no control over privacy clean::RequiredMethodItem(..) | clean::RequiredAssocConstItem(..) diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index cc78dec4eafa..63b869c0f2d5 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -3,7 +3,7 @@ use std::fs; use std::path::PathBuf; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::DiagCtxtHandle; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; @@ -15,7 +15,7 @@ use rustc_session::getopts; use rustc_span::def_id::{CrateNum, DefPathHash, LOCAL_CRATE}; use rustc_span::edition::Edition; -use rustc_span::{BytePos, FileName, SourceFile}; +use rustc_span::{BytePos, FileName, SourceFile, Span}; use tracing::{debug, trace, warn}; use crate::html::render::Context; @@ -114,6 +114,7 @@ struct FindCalls<'a, 'tcx> { target_crates: Vec, calls: &'a mut AllCallLocations, bin_crate: bool, + call_ident_spans: FxHashSet, } impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx> @@ -165,6 +166,10 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { } }; + if !self.call_ident_spans.insert(ident_span) { + return; + } + // If this span comes from a macro expansion, then the source code may not actually show // a use of the given item, so it would be a poor example. Hence, we skip all uses in // macros. @@ -300,7 +305,13 @@ pub(crate) fn run( // Run call-finder on all items let mut calls = FxIndexMap::default(); - let mut finder = FindCalls { calls: &mut calls, cx, target_crates, bin_crate }; + let mut finder = FindCalls { + calls: &mut calls, + cx, + target_crates, + bin_crate, + call_ident_spans: FxHashSet::default(), + }; tcx.hir_visit_all_item_likes_in_crate(&mut finder); // The visitor might have found a type error, which we need to diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index 9f6bf009a054..9cf7d6b29b10 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -50,7 +50,8 @@ fn visit_inner_recur(&mut self, kind: &'a ItemKind) { | RequiredAssocTypeItem(..) | AssocTypeItem(..) | KeywordItem - | AttributeItem => {} + | AttributeItem + | PlaceholderImplItem => {} } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index fd6ea21847c1..906289ba755e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -372,6 +372,19 @@ fn reexport_public_and_not_hidden( && !inherits_doc_hidden(tcx, item_def_id, None) } + #[inline] + fn add_impl_to_current_mod(&mut self, item: &'tcx hir::Item<'_>, impl_: hir::Impl<'_>) { + self.add_to_current_mod( + item, + // The symbol here is used as a "sentinel" value and has no meaning in + // itself. It just tells that this is an inlined impl and that it should not + // be cleaned as a normal `ImplItem` but instead as a `PlaceholderImplItem`. + // It's to ensure that `doc_cfg` inheritance works as expected. + if impl_.of_trait.is_none() { None } else { Some(rustc_span::symbol::kw::Impl) }, + None, + ); + } + #[inline] fn add_to_current_mod( &mut self, @@ -426,12 +439,8 @@ fn visit_item_inner( // } // Bar::bar(); // ``` - if let hir::ItemKind::Impl(impl_) = item.kind && - // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick - // them up regardless of where they're located. - impl_.of_trait.is_none() - { - self.add_to_current_mod(item, None, None); + if let hir::ItemKind::Impl(impl_) = item.kind { + self.add_impl_to_current_mod(item, impl_); } return; } @@ -530,10 +539,10 @@ fn visit_item_inner( } } hir::ItemKind::Impl(impl_) => { - // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick + // Don't duplicate impls when inlining, we'll pick // them up regardless of where they're located. - if !self.inlining && impl_.of_trait.is_none() { - self.add_to_current_mod(item, None, None); + if !self.inlining { + self.add_impl_to_current_mod(item, impl_); } } } diff --git a/src/llvm-project b/src/llvm-project index 41f177ed26a5..1cb4e3833c19 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 41f177ed26a5252a30ea6090a4da66ce0a96bf44 +Subproject commit 1cb4e3833c1919c2e6fb579a23ac0e2b22587b7e diff --git a/src/rustdoc-json-types/Cargo.toml b/src/rustdoc-json-types/Cargo.toml index a38d34ef0e7d..7e4e53ccaf0d 100644 --- a/src/rustdoc-json-types/Cargo.toml +++ b/src/rustdoc-json-types/Cargo.toml @@ -8,11 +8,13 @@ path = "lib.rs" [features] default = ["rustc-hash"] +rkyv_0_8 = ["dep:rkyv"] [dependencies] serde = "1.0" serde_derive = "1.0" rustc-hash = { version = "2.0", optional = true } +rkyv = { version = "0.8", optional = true } [dev-dependencies] serde_json = "1.0" diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 54fb833f40b6..37dd226b73ce 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -3,7 +3,11 @@ //! These types are the public API exposed through the `--output-format json` flag. The [`Crate`] //! struct is the root of the JSON blob and all other items are contained within. //! -//! We expose a `rustc-hash` feature that is disabled by default. This feature switches the +//! # Feature Flags +//! +//! ## `rustc-hash` +//! +//! We expose a `rustc-hash` feature, disabled by default. This feature switches the //! [`std::collections::HashMap`] for [`rustc_hash::FxHashMap`] to improve the performance of said //! `HashMap` in specific situations. //! @@ -12,8 +16,81 @@ //! turning this feature on, as [`FxHashMap`][2] only concerns itself with hash speed, and may //! increase the number of collisions. //! +//! ## `rkyv_0_8` +//! +//! We expose a `rkyv_0_8` feature, disabled by default. When enabled, it derives `rkyv`'s +//! [`Archive`][3], [`Serialize`][4] and [`Deserialize`][5] traits for all types in this crate. +//! Furthermore, it exposes the corresponding `Archived*` types (e.g. `ArchivedId` for [`Id`]). +//! +//! `rkyv` lets you works with JSON output without paying the deserialization cost _upfront_, +//! thanks to [zero-copy deserialization][6]. +//! You can perform various types of analyses on the `Archived*` version of the relevant types, +//! incurring the full deserialization cost only for the subset of items you actually need. +//! //! [1]: https://rust-lang.zulipchat.com/#narrow/channel/266220-t-rustdoc/topic/rustc-hash.20and.20performance.20of.20rustdoc-types/near/474855731 //! [2]: https://crates.io/crates/rustc-hash +//! [3]: https://docs.rs/rkyv/0.8.15/rkyv/trait.Archive.html +//! [4]: https://docs.rs/rkyv/0.8.15/rkyv/trait.Serialize.html +//! [5]: https://docs.rs/rkyv/0.8.15/rkyv/trait.Deserialize.html +//! [6]: https://rkyv.org/zero-copy-deserialization.html + +// # On `rkyv` Derives +// +// In most cases, it's enough to add `#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]` +// on top of a type to derive the relevant `rkyv` traits. +// +// There are a few exceptions, though, where more complex macro options are required. +// The following sections break down the patterns that are showcased by `rkyv'`s +// [JSON schema example](https://github.com/rkyv/rkyv/blob/985b0230a0b9cb9fce4a4ee9facb6af148e27c8e/rkyv/examples/json_like_schema.rs). +// +// ## Recursive Types +// +// Let's look at the `Type` enum as an example. It stores a `Box` in its `Slice` variant. +// A "vanilla" `rkyv` annotation will cause an overflow in the compiler when +// building the crate, since the bounds generated by the macro will be self-referential and thus +// trap the compiler into a never-ending loop. +// +// To prevent this issue, `#[rkyv(omit_bounds)]` must be added to the relevant field. +// +// ## Co-Recursive Types +// +// The same problem occurs if a type is co-recursive—i.e. it doesn't _directly_ store a pointer +// to another instance of the same type, but one of its fields does, transitively. +// +// For example, let's look at `Path`: +// +// - `Path` has a field of type `Option>` +// - One of the variants in `GenericArgs` has a field of type `Vec` +// - One of the variants of `GenericArg` has a field of type `Type` +// - `Type::ResolvedPath` stores a `Path` instance +// +// The same logic of the recursive case applies here: we must use `#[rkyv(omit_bounds)]` to break the cycle. +// +// ## Additional Bounds +// +// Whenever `#[rkyv(omit_bounds)]` is added to a field or variant, `rkyv` omits _all_ traits bounds for that +// field in the generated impl. This may result in compilation errors due to insufficient bounds in the +// generated code. +// +// To add _some_ bounds back, `rkyv` exposes four knobs: +// +// - `#[rkyv(archive_bounds(..))]` to add predicates to all generated impls +// - `#[rkyv(serialize_bounds(..))]` to add predicates to just the `Serialize` impl +// - `#[rkyv(deserialize_bounds(..))]` to add predicates to just the `Deserialize` impl +// - `#[rkyv(bytecheck(bounds(..)))]` to add predicates to just the `CheckBytes` impl +// +// In particular, we use the following annotations in this crate: +// +// - `serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, __S::Error: rkyv::rancor::Source)` for serializing +// variable-length types like `Vec`. `rkyv`'s zero-copy format requires the serializer to be able +// to write bytes (`Writer`) and allocate scratch space (`Allocator`) for these types +// ([`rkyv`'s `Vec` impl bounds](https://docs.rs/rkyv/0.8.15/rkyv/trait.Serialize.html#impl-Serialize%3CS%3E-for-Vec%3CT%3E)). +// The `Error: Source` bound lets error types compose. +// - `deserialize_bounds(__D::Error: rkyv::rancor::Source)` so that errors from deserializing fields behind +// `omit_bounds` (e.g. `Box`, `Vec`) can compose via the `Source` trait. +// - `bytecheck(bounds(__C: rkyv::validation::ArchiveContext, __C::Error: rkyv::rancor::Source))` for validating +// archived data. Checking that bytes represent a valid archived value requires an `ArchiveContext` that tracks +// validation state (e.g. subtree ranges, to prevent overlapping/out-of-bounds archived data). #[cfg(not(feature = "rustc-hash"))] use std::collections::HashMap; @@ -46,6 +123,8 @@ /// about the language items in the local crate, as well as info about external items to allow /// tools to find or link to them. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Crate { /// The id of the root [`Module`] item of the local crate. pub root: Id, @@ -69,6 +148,8 @@ pub struct Crate { /// Information about a target #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Target { /// The target triple for which this documentation was generated pub triple: String, @@ -99,6 +180,8 @@ pub struct Target { /// [1]: https://doc.rust-lang.org/stable/reference/attributes/codegen.html#the-target_feature-attribute /// [2]: https://doc.rust-lang.org/reference/conditional-compilation.html#target_feature #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct TargetFeature { /// The name of this target feature. pub name: String, @@ -123,6 +206,8 @@ pub struct TargetFeature { /// Metadata of a crate, either the same crate on which `rustdoc` was invoked, or its dependency. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct ExternalCrate { /// The name of the crate. /// @@ -140,6 +225,7 @@ pub struct ExternalCrate { /// /// This will typically be a `.rlib` or `.rmeta`. It can be used to determine which crate /// this was in terms of whatever build-system invoked rustc. + #[cfg_attr(feature = "rkyv_0_8", rkyv(with = rkyv::with::AsString))] pub path: PathBuf, } @@ -150,6 +236,8 @@ pub struct ExternalCrate { /// question, or can be used by a tool that takes the json output of multiple crates to find /// the actual item definition with all the relevant info. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct ItemSummary { /// Can be used to look up the name and html_root_url of the crate this item came from in the /// `external_crates` map. @@ -171,6 +259,8 @@ pub struct ItemSummary { /// The `Item` data type holds fields that can apply to any of these, /// and leaves kind-specific details (like function args or enum variants) to the `inner` field. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Item { /// The unique identifier of this item. Can be used to find this item in various mappings. pub id: Id, @@ -209,6 +299,8 @@ pub struct Item { } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] /// An attribute, e.g. `#[repr(C)]` /// @@ -256,6 +348,8 @@ pub enum Attribute { } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] /// The contents of a `#[repr(...)]` attribute. /// /// Used in [`Attribute::Repr`]. @@ -275,6 +369,8 @@ pub struct AttributeRepr { } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] /// The kind of `#[repr]`. /// @@ -294,8 +390,11 @@ pub enum ReprKind { /// A range of source code. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Span { /// The path to the source file for this span relative to the path `rustdoc` was invoked with. + #[cfg_attr(feature = "rkyv_0_8", rkyv(with = rkyv::with::AsString))] pub filename: PathBuf, /// One indexed Line and Column of the first character of the `Span`. pub begin: (usize, usize), @@ -305,6 +404,8 @@ pub struct Span { /// Information about the deprecation of an [`Item`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Deprecation { /// Usually a version number when this [`Item`] first became deprecated. pub since: Option, @@ -314,6 +415,8 @@ pub struct Deprecation { /// Visibility of an [`Item`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum Visibility { /// Explicitly public visibility set with `pub`. @@ -337,6 +440,8 @@ pub enum Visibility { /// Dynamic trait object type (`dyn Trait`). #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct DynTrait { /// All the traits implemented. One of them is the vtable, and the rest must be auto traits. pub traits: Vec, @@ -352,6 +457,8 @@ pub struct DynTrait { /// A trait and potential HRTBs #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct PolyTrait { /// The path to the trait. #[serde(rename = "trait")] @@ -371,6 +478,18 @@ pub struct PolyTrait { /// ^^^^^ /// ``` #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds( + __S: rkyv::ser::Writer + rkyv::ser::Allocator, + __S::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds( + __D::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds( + __C: rkyv::validation::ArchiveContext, +))))] #[serde(rename_all = "snake_case")] pub enum GenericArgs { /// `<'a, 32, B: Copy, C = u32>` @@ -387,8 +506,10 @@ pub enum GenericArgs { /// `Fn(A, B) -> C` Parenthesized { /// The input types, enclosed in parentheses. + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] inputs: Vec, /// The output type provided after the `->`, if present. + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] output: Option, }, /// `T::method(..)` @@ -399,6 +520,8 @@ pub enum GenericArgs { /// /// Part of [`GenericArgs`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum GenericArg { /// A lifetime argument. @@ -429,6 +552,8 @@ pub enum GenericArg { /// A constant. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Constant { /// The stringified expression of this constant. Note that its mapping to the original /// source code is unstable and it's not guaranteed that it'll match the source code. @@ -448,10 +573,24 @@ pub struct Constant { /// ^^^^^^^^^^ ^^^^^^^^^^^^^^^ /// ``` #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds( + __S: rkyv::ser::Writer + rkyv::ser::Allocator, + __S::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds( + __D::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds( + __C: rkyv::validation::ArchiveContext, + <__C as rkyv::rancor::Fallible>::Error: rkyv::rancor::Source, +))))] pub struct AssocItemConstraint { /// The name of the associated type/constant. pub name: String, /// Arguments provided to the associated type/constant. + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] pub args: Option>, /// The kind of bound applied to the associated type/constant. pub binding: AssocItemConstraintKind, @@ -459,6 +598,8 @@ pub struct AssocItemConstraint { /// The way in which an associate type/constant is bound. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum AssocItemConstraintKind { /// The required value/type is specified exactly. e.g. @@ -487,6 +628,8 @@ pub enum AssocItemConstraintKind { /// should treat them as opaque keys to lookup items, and avoid attempting /// to parse them, or otherwise depend on any implementation details. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)))] // FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types. pub struct Id(pub u32); @@ -494,6 +637,9 @@ pub enum AssocItemConstraintKind { /// /// Part of [`ItemSummary`]. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(compare(PartialEq)))] #[serde(rename_all = "snake_case")] pub enum ItemKind { /// A module declaration, e.g. `mod foo;` or `mod foo {}` @@ -569,6 +715,8 @@ pub enum ItemKind { /// /// Part of [`Item`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum ItemEnum { /// A module declaration, e.g. `mod foo;` or `mod foo {}` @@ -683,7 +831,13 @@ pub enum ItemEnum { } impl ItemEnum { - /// Returns the [`ItemKind`] of this item. + /// Get just the kind of this item, but with no further data. + /// + /// ```rust + /// # use rustdoc_json_types::{ItemKind, ItemEnum}; + /// let item = ItemEnum::ExternCrate { name: "libc".to_owned(), rename: None }; + /// assert_eq!(item.item_kind(), ItemKind::ExternCrate); + /// ``` pub fn item_kind(&self) -> ItemKind { match self { ItemEnum::Module(_) => ItemKind::Module, @@ -717,6 +871,8 @@ pub fn item_kind(&self) -> ItemKind { /// A module declaration, e.g. `mod foo;` or `mod foo {}`. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Module { /// Whether this is the root item of a crate. /// @@ -732,6 +888,8 @@ pub struct Module { /// A `union`. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Union { /// The generic parameters and where clauses on this union. pub generics: Generics, @@ -749,6 +907,8 @@ pub struct Union { /// A `struct`. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Struct { /// The kind of the struct (e.g. unit, tuple-like or struct-like) and the data specific to it, /// i.e. fields. @@ -762,6 +922,8 @@ pub struct Struct { /// The kind of a [`Struct`] and the data specific to it, i.e. fields. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum StructKind { /// A struct with no fields and no parentheses. @@ -799,6 +961,8 @@ pub enum StructKind { /// An `enum`. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Enum { /// Information about the type parameters and `where` clauses of the enum. pub generics: Generics, @@ -814,6 +978,8 @@ pub struct Enum { /// A variant of an enum. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Variant { /// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields. pub kind: VariantKind, @@ -823,6 +989,8 @@ pub struct Variant { /// The kind of an [`Enum`] [`Variant`] and the data specific to it, i.e. fields. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum VariantKind { /// A variant with no parentheses @@ -866,6 +1034,8 @@ pub enum VariantKind { /// The value that distinguishes a variant in an [`Enum`] from other variants. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Discriminant { /// The expression that produced the discriminant. /// @@ -884,6 +1054,8 @@ pub struct Discriminant { /// A set of fundamental properties of a function. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct FunctionHeader { /// Is this function marked as `const`? pub is_const: bool, @@ -904,6 +1076,8 @@ pub struct FunctionHeader { /// See the [Rustonomicon section](https://doc.rust-lang.org/nightly/nomicon/ffi.html#ffi-and-unwinding) /// on unwinding for more info. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub enum Abi { // We only have a concrete listing here for stable ABI's because there are so many // See rustc_ast_passes::feature_gate::PostExpansionVisitor::check_abi for the list @@ -931,6 +1105,8 @@ pub enum Abi { /// A function declaration (including methods and other associated functions). #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Function { /// Information about the function signature, or declaration. pub sig: FunctionSignature, @@ -944,6 +1120,8 @@ pub struct Function { /// Generic parameters accepted by an item and `where` clauses imposed on it and the parameters. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Generics { /// A list of generic parameter definitions (e.g. ``). pub params: Vec, @@ -953,6 +1131,8 @@ pub struct Generics { /// One generic parameter accepted by an item. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct GenericParamDef { /// Name of the parameter. /// ```rust @@ -967,6 +1147,18 @@ pub struct GenericParamDef { /// The kind of a [`GenericParamDef`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds( + __S: rkyv::ser::Writer + rkyv::ser::Allocator, + __S::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds( + __D::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds( + __C: rkyv::validation::ArchiveContext, +))))] #[serde(rename_all = "snake_case")] pub enum GenericParamDefKind { /// Denotes a lifetime parameter. @@ -989,6 +1181,7 @@ pub enum GenericParamDefKind { /// fn default2() -> [T; 2] where T: Clone { todo!() } /// // ^^^^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] bounds: Vec, /// The default type for this parameter, if provided, e.g. /// @@ -996,6 +1189,7 @@ pub enum GenericParamDefKind { /// trait PartialEq {} /// // ^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] default: Option, /// This is normally `false`, which means that this generic parameter is /// declared in the Rust source text. @@ -1027,6 +1221,7 @@ pub enum GenericParamDefKind { Const { /// The type of the constant as declared. #[serde(rename = "type")] + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] type_: Type, /// The stringified expression for the default value, if provided. It's not guaranteed that /// it'll match the actual source code for the default value. @@ -1040,6 +1235,8 @@ pub enum GenericParamDefKind { /// // ^^^^^^^^^^ /// ``` #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum WherePredicate { /// A type is expected to comply with a set of bounds @@ -1086,6 +1283,8 @@ pub enum WherePredicate { /// Either a trait bound or a lifetime bound. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum GenericBound { /// A trait bound. @@ -1116,6 +1315,8 @@ pub enum GenericBound { /// A set of modifiers applied to a trait. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum TraitBoundModifier { /// Marks the absence of a modifier. @@ -1131,6 +1332,8 @@ pub enum TraitBoundModifier { /// One precise capturing argument. See [the rust reference](https://doc.rust-lang.org/reference/types/impl-trait.html#precise-capturing). #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum PreciseCapturingArg { /// A lifetime. @@ -1148,6 +1351,8 @@ pub enum PreciseCapturingArg { /// Either a type or a constant, usually stored as the right-hand side of an equation in places like /// [`AssocItemConstraint`] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum Term { /// A type. @@ -1172,6 +1377,18 @@ pub enum Term { /// A type. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds( + __S: rkyv::ser::Writer + rkyv::ser::Allocator, + __S::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds( + __D::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds( + __C: rkyv::validation::ArchiveContext, +))))] #[serde(rename_all = "snake_case")] pub enum Type { /// Structs, enums, unions and type aliases, e.g. `std::option::Option` @@ -1183,15 +1400,16 @@ pub enum Type { /// Built-in numeric types (e.g. `u32`, `f32`), `bool`, `char`. Primitive(String), /// A function pointer type, e.g. `fn(u32) -> u32`, `extern "C" fn() -> *const u8` - FunctionPointer(Box), + FunctionPointer(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Box), /// A tuple type, e.g. `(String, u32, Box)` - Tuple(Vec), + Tuple(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Vec), /// An unsized slice type, e.g. `[u32]`. - Slice(Box), + Slice(#[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] Box), /// An array type, e.g. `[u32; 15]` Array { /// The type of the contained element. #[serde(rename = "type")] + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] type_: Box, /// The stringified expression that is the length of the array. /// @@ -1204,6 +1422,7 @@ pub enum Type { Pat { /// The base type, e.g. the `u32` in `u32 is 1..` #[serde(rename = "type")] + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] type_: Box, #[doc(hidden)] __pat_unstable_do_not_use: String, @@ -1218,6 +1437,7 @@ pub enum Type { is_mutable: bool, /// The type of the pointee. #[serde(rename = "type")] + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] type_: Box, }, /// `&'a mut String`, `&str`, etc. @@ -1228,6 +1448,7 @@ pub enum Type { is_mutable: bool, /// The type of the pointee, e.g. the `i32` in `&'a mut i32` #[serde(rename = "type")] + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] type_: Box, }, /// Associated types like `::Name` and `T::Item` where @@ -1246,6 +1467,7 @@ pub enum Type { /// as BetterIterator>::Item<'static> /// // ^^^^^^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] args: Option>, /// The type with which this type is associated. /// @@ -1253,6 +1475,7 @@ pub enum Type { /// as Iterator>::Item /// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] self_type: Box, /// `None` iff this is an *inherent* associated type. #[serde(rename = "trait")] @@ -1262,6 +1485,19 @@ pub enum Type { /// A type that has a simple path to it. This is the kind of type of structs, unions, enums, etc. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(serialize_bounds( + __S: rkyv::ser::Writer + rkyv::ser::Allocator, + __S::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(deserialize_bounds( + __D::Error: rkyv::rancor::Source, +)))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(bytecheck(bounds( + __C: rkyv::validation::ArchiveContext, + <__C as rkyv::rancor::Fallible>::Error: rkyv::rancor::Source, +))))] pub struct Path { /// The path of the type. /// @@ -1285,11 +1521,14 @@ pub struct Path { /// std::borrow::Cow<'static, str> /// // ^^^^^^^^^^^^^^ /// ``` + #[cfg_attr(feature = "rkyv_0_8", rkyv(omit_bounds))] pub args: Option>, } /// A type that is a function pointer. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct FunctionPointer { /// The signature of the function. pub sig: FunctionSignature, @@ -1306,6 +1545,8 @@ pub struct FunctionPointer { /// The signature of a function. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct FunctionSignature { /// List of argument names and their type. /// @@ -1324,6 +1565,8 @@ pub struct FunctionSignature { /// A `trait` declaration. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Trait { /// Whether the trait is marked `auto` and is thus implemented automatically /// for all applicable types. @@ -1348,6 +1591,8 @@ pub struct Trait { /// /// See [the tracking issue](https://github.com/rust-lang/rust/issues/41517) #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct TraitAlias { /// Information about the type parameters and `where` clauses of the alias. pub generics: Generics, @@ -1357,6 +1602,8 @@ pub struct TraitAlias { /// An `impl` block. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Impl { /// Whether this impl is for an unsafe trait. pub is_unsafe: bool, @@ -1395,6 +1642,8 @@ pub struct Impl { /// A `use` statement. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub struct Use { /// The full path being imported. @@ -1413,6 +1662,8 @@ pub struct Use { /// A procedural macro. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct ProcMacro { /// How this macro is supposed to be called: `foo!()`, `#[foo]` or `#[derive(foo)]` pub kind: MacroKind, @@ -1436,6 +1687,8 @@ pub struct ProcMacro { /// The way a [`ProcMacro`] is declared to be used. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] #[serde(rename_all = "snake_case")] pub enum MacroKind { /// A bang macro `foo!()`. @@ -1448,6 +1701,8 @@ pub enum MacroKind { /// A type alias declaration, e.g. `type Pig = std::borrow::Cow<'static, str>;` #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct TypeAlias { /// The type referred to by this alias. #[serde(rename = "type")] @@ -1458,6 +1713,8 @@ pub struct TypeAlias { /// A `static` declaration. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Static { /// The type of the static. #[serde(rename = "type")] @@ -1488,6 +1745,8 @@ pub struct Static { /// A primitive type declaration. Declarations of this kind can only come from the core library. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] pub struct Primitive { /// The name of the type. pub name: String, diff --git a/src/rustdoc-json-types/tests.rs b/src/rustdoc-json-types/tests.rs index b9363fcf1b71..e878350e43b9 100644 --- a/src/rustdoc-json-types/tests.rs +++ b/src/rustdoc-json-types/tests.rs @@ -38,3 +38,118 @@ fn test_union_info_roundtrip() { let decoded: ItemEnum = bincode::deserialize(&encoded).unwrap(); assert_eq!(u, decoded); } + +#[cfg(feature = "rkyv_0_8")] +mod rkyv { + use std::fmt::Debug; + + use rkyv::Archive; + use rkyv::api::high::{HighDeserializer, HighSerializer}; + use rkyv::bytecheck::CheckBytes; + use rkyv::rancor::Strategy; + use rkyv::ser::allocator::ArenaHandle; + use rkyv::util::AlignedVec; + use rkyv::validation::Validator; + use rkyv::validation::archive::ArchiveValidator; + use rkyv::validation::shared::SharedValidator; + + use crate::*; + + #[test] + /// A test to exercise the (de)serialization roundtrip for a representative selection of types, + /// covering most of the rkyv-specific attributes we had to had. + fn test_rkyv_roundtrip() { + // Standard derives: a plain struct and union, mirroring the existing serde/bincode tests. + let s = ItemEnum::Struct(Struct { + generics: Generics { params: vec![], where_predicates: vec![] }, + kind: StructKind::Plain { fields: vec![Id(1), Id(2)], has_stripped_fields: false }, + impls: vec![Id(3)], + }); + rkyv_roundtrip(&s); + + let u = ItemEnum::Union(Union { + generics: Generics { params: vec![], where_predicates: vec![] }, + has_stripped_fields: false, + fields: vec![Id(1)], + impls: vec![], + }); + rkyv_roundtrip(&u); + + // Extra trait derives, via rkyv(derive(PartialEq, Eq, PartialOrd, Ord, Hash)), on the archived type. + rkyv_roundtrip(&Id(99)); + + // Recursive cycle-breaking: `BorrowedRef` has omit_bounds on its `Box` field. + let ty = Type::BorrowedRef { + lifetime: Some("'a".to_string()), + is_mutable: false, + type_: Box::new(Type::Primitive("str".to_string())), + }; + rkyv_roundtrip(&ty); + + // `Slice` and `Tuple` are tuple-variant fields with omit_bounds on the unnamed field, + // which required special syntax (attribute inside the parentheses) to compile. + let ty = Type::Slice(Box::new(Type::Tuple(vec![ + Type::Primitive("u32".to_string()), + Type::Generic("T".to_string()), + ]))); + rkyv_roundtrip(&ty); + + // `Path` has serialize_bounds/deserialize_bounds and omit_bounds on its `args` field. + // `GenericArgs::AngleBracketed` exercises the full recursive chain: `Path` -> `GenericArgs` -> `GenericArg` -> `Type`. + let path = Path { + path: "std::option::Option".to_string(), + id: Id(42), + args: Some(Box::new(GenericArgs::AngleBracketed { + args: vec![GenericArg::Type(Type::Primitive("u32".to_string()))], + constraints: vec![], + })), + }; + rkyv_roundtrip(&path); + + // `FunctionPointer` is a `Box` behind `omit_bounds` in `Type`. + // It transitively contains `Type` via `FunctionSignature`, exercising the cycle from the other direction. + let fp = Type::FunctionPointer(Box::new(FunctionPointer { + sig: FunctionSignature { + inputs: vec![("x".to_string(), Type::Primitive("i32".to_string()))], + output: Some(Type::Primitive("bool".to_string())), + is_c_variadic: false, + }, + generic_params: vec![], + header: FunctionHeader { + is_const: false, + is_unsafe: false, + is_async: false, + abi: Abi::Rust, + }, + })); + rkyv_roundtrip(&fp); + } + + /// A helper function for roundtrip testing of rkyv-powered deserialization. + fn rkyv_roundtrip(value: &T) + where + T: PartialEq + + Debug + + Archive + + for<'a> rkyv::Serialize< + HighSerializer, rkyv::rancor::Error>, + >, + T::Archived: rkyv::Deserialize> + + Debug + + for<'a> CheckBytes< + Strategy, SharedValidator>, rkyv::rancor::Error>, + >, + { + let bytes = + rkyv::api::high::to_bytes_in::<_, rkyv::rancor::Error>(value, AlignedVec::new()) + .unwrap(); + let archived = rkyv::api::high::access::(&bytes) + .expect("Failed to access archived data"); + let deserialized: T = rkyv::api::deserialize_using::<_, _, rkyv::rancor::Error>( + archived, + &mut rkyv::de::Pool::new(), + ) + .unwrap(); + assert_eq!(value, &deserialized); + } +} diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index c0271bbc89b5..2b0afae76da4 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -10,7 +10,7 @@ serde_json = "1.0" anyhow = "1.0.32" flate2 = "1.0.26" xz2 = "0.1.7" -tar = "0.4.29" +tar = "0.4.45" sha2 = "0.10.1" rayon = "1.5.1" hex = "0.4.2" diff --git a/src/tools/cargo b/src/tools/cargo index 90ed291a50ef..888f675344eb 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 90ed291a50efc459e0c380d7b455777ed41c6799 +Subproject commit 888f675344eb1cf2308fd53183e667bdd2c58e51 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 7c798a3c2e5a..45bfb65b2e67 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,7 +6,103 @@ document. ## Unreleased / Beta / In Rust Nightly -[92b4b68...master](https://github.com/rust-lang/rust-clippy/compare/92b4b68...master) +[500e0ff...master](https://github.com/rust-lang/rust-clippy/compare/500e0ff...master) + +## Rust 1.94 + +Current stable, released 2026-03-05 + +[View all 94 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-11-29T21%3A01%3A29Z..2026-01-08T20%3A33%3A22Z+base%3Amaster) + +### New Lints + +* Added [`same_length_and_capacity`] to `pedantic` + [#15656](https://github.com/rust-lang/rust-clippy/pull/15656) +* Added [`manual_ilog2`] to `pedantic` + [#15865](https://github.com/rust-lang/rust-clippy/pull/15865) +* Added [`needless_type_cast`] to `nursery` + [#16139](https://github.com/rust-lang/rust-clippy/pull/16139) +* Added [`ptr_offset_by_literal`] to `pedantic` + [#15606](https://github.com/rust-lang/rust-clippy/pull/15606) +* Added [`decimal_bitwise_operands`] to `pedantic` + [#15215](https://github.com/rust-lang/rust-clippy/pull/15215) + +### Moves and Deprecations + +* Moved [`multiple_bound_locations`] from `suspicious` to `style` + [#16302](https://github.com/rust-lang/rust-clippy/pull/16302) +* Moved [`collapsible_else_if`] from `style` to `pedantic` + [#16211](https://github.com/rust-lang/rust-clippy/pull/16211) +* Moved [`needless_type_cast`] from `pedantic` to `nursery` + [#16246](https://github.com/rust-lang/rust-clippy/pull/16246) + +### Enhancements + +* [`never_loop`] do not consider `return` as preventing the iterator from looping; lint diverging + iterator reduction closures like `for_each` and `fold` + [#16364](https://github.com/rust-lang/rust-clippy/pull/16364) +* [`single_range_in_vec_init`] don't apply the suggestion automatically + [#16365](https://github.com/rust-lang/rust-clippy/pull/16365) +* [`useless_conversion`] refine `.into_iter()` suggestions to stop at final target type + [#16238](https://github.com/rust-lang/rust-clippy/pull/16238) +* Multiple lints fix wrongly unmangled macros + [#16337](https://github.com/rust-lang/rust-clippy/pull/16337) +* [`large_stack_arrays`] do not warn for libtest harness + [#16347](https://github.com/rust-lang/rust-clippy/pull/16347) +* [`derive_ord_xor_partial_ord`] allow `expect` on `impl` block + [#16303](https://github.com/rust-lang/rust-clippy/pull/16303) +* [`match_bool`] restrict to 2 arms + [#16333](https://github.com/rust-lang/rust-clippy/pull/16333) +* [`multiple_inherent_impl`] fix false negatives for generic impl blocks + [#16284](https://github.com/rust-lang/rust-clippy/pull/16284) +* [`unnecessary_fold`] warn about semantics change and lint `Add::add`/`Mul::mul` folds + [#16324](https://github.com/rust-lang/rust-clippy/pull/16324) +* [`transmuting_null`] check const blocks and const integer casts + [#16260](https://github.com/rust-lang/rust-clippy/pull/16260) +* [`needless_pass_by_ref_mut`] preserve user-provided lifetime information + [#16273](https://github.com/rust-lang/rust-clippy/pull/16273) +* [`while_let_on_iterator`] use reborrow for non-`Sized` trait references + [#16100](https://github.com/rust-lang/rust-clippy/pull/16100) +* [`collapsible_else_if`] prevent emitting when arms only `if {..} else {..}` + [#16286](https://github.com/rust-lang/rust-clippy/pull/16286) +* [`multiple_unsafe_ops_per_block`] count only towards innermost unsafe block + [#16117](https://github.com/rust-lang/rust-clippy/pull/16117) +* [`manual_saturating_arithmetic`] lint `x.checked_sub(y).unwrap_or_default()` + [#15845](https://github.com/rust-lang/rust-clippy/pull/15845) +* [`transmute_ptr_to_ref`] handle pointer in struct + [#15948](https://github.com/rust-lang/rust-clippy/pull/15948) +* [`disallowed_methods`] skip compiler-generated code + [#16186](https://github.com/rust-lang/rust-clippy/pull/16186) +* [`missing_enforced_import_renames`] do not enforce for "as _" + [#16352](https://github.com/rust-lang/rust-clippy/pull/16352) + +### False Positive Fixes + +* [`double_parens`] fix FP on macro repetition patterns + [#16301](https://github.com/rust-lang/rust-clippy/pull/16301) +* [`assertions_on_constants`] fix false positive when there is non-constant value in condition expr + [#16297](https://github.com/rust-lang/rust-clippy/pull/16297) +* [`use_self`] fix FP on type in const generics + [#16172](https://github.com/rust-lang/rust-clippy/pull/16172) +* [`set_contains_or_insert`] fix FP when set is mutated before `insert` + [#16009](https://github.com/rust-lang/rust-clippy/pull/16009) +* [`if_then_some_else_none`] fix FP when then block contains `await` + [#16178](https://github.com/rust-lang/rust-clippy/pull/16178) +* [`match_like_matches_macro`] fix FP with guards containing `if let` + [#15876](https://github.com/rust-lang/rust-clippy/pull/15876) +* [`tuple_array_conversions`] fix FP when binded vars are used before conversion + [#16197](https://github.com/rust-lang/rust-clippy/pull/16197) +* [`map_entry`] fix FP when it would cause `MutexGuard` to be held across await + [#16199](https://github.com/rust-lang/rust-clippy/pull/16199) +* [`panicking_unwrap`] fix FP on field access with implicit deref + [#16196](https://github.com/rust-lang/rust-clippy/pull/16196) +* [`large_stack_frames`] fix FP on compiler generated targets + [#15101](https://github.com/rust-lang/rust-clippy/pull/15101) + +### ICE Fixes + +* [`needless_type_cast`] do not ICE on struct constructor + [#16245](https://github.com/rust-lang/rust-clippy/pull/16245) ### New Lints @@ -6705,6 +6801,7 @@ Released 2018-09-13 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_option_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_as_slice [`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison +[`manual_pop_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pop_if [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml index d9bcfd17606e..6f9db8da6c71 100644 --- a/src/tools/clippy/clippy.toml +++ b/src/tools/clippy/clippy.toml @@ -5,13 +5,13 @@ check-inconsistent-struct-field-initializers = true lint-commented-code = true [[disallowed-methods]] -path = "rustc_lint::context::LintContext::lint" +path = "rustc_lint::context::LintContext::opt_span_lint" reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead" [[disallowed-methods]] -path = "rustc_lint::context::LintContext::span_lint" +path = "rustc_lint::context::LintContext::emit_span_lint" reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead" [[disallowed-methods]] -path = "rustc_middle::ty::context::TyCtxt::node_span_lint" +path = "rustc_middle::ty::context::TyCtxt::emit_node_span_lint" reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead" diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 359bf17c68c5..99709ed2e4f2 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -5,8 +5,7 @@ os_str_slice, os_string_truncate, pattern, - rustc_private, - slice_split_once + rustc_private )] #![warn( trivial_casts, diff --git a/src/tools/clippy/clippy_lints/src/bool_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_comparison.rs index 722095909a6f..feeefefc3b8f 100644 --- a/src/tools/clippy/clippy_lints/src/bool_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_comparison.rs @@ -6,8 +6,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::Span; -use rustc_span::source_map::Spanned; +use rustc_span::{Span, Spanned}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs index b98a20a90ccb..8b45473687e6 100644 --- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs +++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::HasSession; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, is_else_clause, is_in_const_context, span_contains_comment}; use rustc_ast::LitKind; @@ -60,7 +59,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { && !is_in_const_context(cx) { let ty = cx.typeck_results().expr_ty(then); - let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + let mut applicability = if span_contains_comment(cx, expr.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs index 56779e8ce3d9..55b0945f0962 100644 --- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::MANUAL_DANGLING_PTR; diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index 75761de4ae73..151f9c956c6d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -691,7 +691,7 @@ /// const SIZE: usize = 15; /// let arr: [u8; SIZE] = [0; SIZE]; /// ``` - #[clippy::version = "1.93.0"] + #[clippy::version = "1.94.0"] pub NEEDLESS_TYPE_CAST, nursery, "binding defined with one type but always cast to another" diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index a76027caebc8..3850c55c49f8 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::Msrv; -use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; +use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; use clippy_utils::{can_use_if_let_chains, span_contains_non_whitespace, sym, tokenize_with_text}; use rustc_ast::{BinOpKind, MetaItemInner}; use rustc_errors::Applicability; @@ -9,7 +9,6 @@ use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::impl_lint_pass; -use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span, Symbol}; declare_clippy_lint! { @@ -111,10 +110,8 @@ fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_ let up_to_else = then_span.between(else_block.span); let else_before_if = else_.span.shrink_to_lo().with_hi(else_if_cond.span.lo() - BytePos(1)); if self.lint_commented_code - && let Some(else_keyword_span) = - span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else") - && let Some(else_if_keyword_span) = - span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if") + && let Some(else_keyword_span) = span_extract_keyword(cx, up_to_else, "else") + && let Some(else_if_keyword_span) = span_extract_keyword(cx, else_before_if, "if") { let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span(); let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span(); @@ -139,7 +136,7 @@ fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_ } // Peel off any parentheses. - let (_, else_block_span, _) = peel_parens(cx.tcx.sess.source_map(), else_.span); + let (_, else_block_span, _) = peel_parens(cx, else_.span); // Prevent "elseif" // Check that the "else" is followed by whitespace @@ -187,7 +184,7 @@ fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check: .with_leading_whitespace(cx) .into_span() }; - let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner.span); + let (paren_start, inner_if_span, paren_end) = peel_parens(cx, inner.span); let inner_if = inner_if_span.split_at(2).0; let mut sugg = vec![ // Remove the outer then block `{` @@ -320,33 +317,36 @@ pub(super) fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> { } } -fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option { - let snippet = sm.span_to_snippet(span).ok()?; - tokenize_with_text(&snippet) - .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword)) - .map(|(_, _, inner)| { - span.split_at(u32::try_from(inner.start).unwrap()) - .1 - .split_at(u32::try_from(inner.end - inner.start).unwrap()) - .0 - }) - .next() +fn span_extract_keyword(cx: &impl HasSession, span: Span, keyword: &str) -> Option { + span.with_source_text(cx, |snippet| { + tokenize_with_text(snippet) + .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword)) + .map(|(_, _, inner)| { + span.split_at(u32::try_from(inner.start).unwrap()) + .1 + .split_at(u32::try_from(inner.end - inner.start).unwrap()) + .0 + }) + .next() + }) + .flatten() } /// Peel the parentheses from an `if` expression, e.g. `((if true {} else {}))`. -pub(super) fn peel_parens(sm: &SourceMap, mut span: Span) -> (Span, Span, Span) { +pub(super) fn peel_parens(cx: &impl HasSession, mut span: Span) -> (Span, Span, Span) { use crate::rustc_span::Pos; let start = span.shrink_to_lo(); let end = span.shrink_to_hi(); - let snippet = sm.span_to_snippet(span).unwrap(); - if let Some((trim_start, _, trim_end)) = peel_parens_str(&snippet) { - let mut data = span.data(); - data.lo = data.lo + BytePos::from_usize(trim_start); - data.hi = data.hi - BytePos::from_usize(trim_end); - span = data.span(); - } + span.with_source_text(cx, |snippet| { + if let Some((trim_start, _, trim_end)) = peel_parens_str(snippet) { + let mut data = span.data(); + data.lo = data.lo + BytePos::from_usize(trim_start); + data.hi = data.hi - BytePos::from_usize(trim_end); + span = data.span(); + } + }); (start.with_hi(span.lo()), span, end.with_lo(span.hi())) } diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index eb14ef18c03d..63968a8b5e04 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_in_test, sym}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Arm, Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind}; +use rustc_hir::{Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::{Span, SyntaxContext}; @@ -92,16 +92,15 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { (macro_call.span, String::from("()")) } }, - ExprKind::Match(first, arms, _) => { - let vals = collect_vals(first, arms); - let suggestion = match *vals.as_slice() { + ExprKind::Match(args, _, _) => { + let suggestion = match args.kind { // dbg!(1) => 1 - [val] => { + ExprKind::Tup([val]) => { snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability) .to_string() }, // dbg!(2, 3) => (2, 3) - [first, .., last] => { + ExprKind::Tup([first, .., last]) => { let snippet = snippet_with_applicability( cx, first.span.source_callsite().to(last.span.source_callsite()), @@ -165,39 +164,3 @@ fn is_async_move_desugar<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option { macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id)) } - -/// Extracts all value expressions from the `match`-tree generated by `dbg!`. -/// -/// E.g. from -/// ```rust, ignore -/// match 1 { -/// tmp_1 => match 2 { -/// tmp_2 => { -/// /* printing */ -/// (tmp_1, tmp_2) -/// } -/// } -/// } -/// ``` -/// this extracts `1` and `2`. -fn collect_vals<'hir>(first: &'hir Expr<'hir>, mut arms: &'hir [Arm<'hir>]) -> Vec<&'hir Expr<'hir>> { - let mut vals = vec![first]; - loop { - let [arm] = arms else { - unreachable!("dbg! macro expansion only has single-arm matches") - }; - - match is_async_move_desugar(arm.body) - .unwrap_or(arm.body) - .peel_drop_temps() - .kind - { - ExprKind::Block(..) => return vals, - ExprKind::Match(val, a, _) => { - vals.push(val); - arms = a; - }, - _ => unreachable!("dbg! macro expansion only results in block or match expressions"), - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index e16b194c0cad..441b907eaf2f 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -312,6 +312,7 @@ crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, crate::manual_option_as_slice::MANUAL_OPTION_AS_SLICE_INFO, + crate::manual_pop_if::MANUAL_POP_IF_INFO, crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/custom_abs.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/custom_abs.rs index d12a32e15881..f476abae708d 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/custom_abs.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/custom_abs.rs @@ -6,8 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; -use rustc_span::SyntaxContext; -use rustc_span::source_map::Spanned; +use rustc_span::{Spanned, SyntaxContext}; use super::SUBOPTIMAL_FLOPS; diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/expm1.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/expm1.rs index 9a4c97569308..bf376a51fec9 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/expm1.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/expm1.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::IMPRECISE_FLOPS; diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/hypot.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/hypot.rs index 49f8ba4bf825..8d3bd8084db8 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/hypot.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/hypot.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::IMPRECISE_FLOPS; diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/ln1p.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/ln1p.rs index 4c9aa96b5042..f37737c71aee 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/ln1p.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/ln1p.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::IMPRECISE_FLOPS; diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/log_division.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/log_division.rs index e3419ffad72a..947935369de1 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/log_division.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/log_division.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::SUBOPTIMAL_FLOPS; diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/mul_add.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/mul_add.rs index e0a6498f62fd..888d5b7b762a 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/mul_add.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/mul_add.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::SUBOPTIMAL_FLOPS; diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/powi.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/powi.rs index a61a2a82c023..b0b65b357d7a 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/powi.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/powi.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::SUBOPTIMAL_FLOPS; diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/radians.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/radians.rs index 2021f00a97e8..8480626133fd 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/radians.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic/radians.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 04c657104fe1..7c1b3ef225c6 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -24,7 +24,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), MustUse { span, reason } => (span, reason)); + let attr = find_attr!(cx.tcx, item.hir_id(), MustUse { span, reason } => (span, reason)); if let hir::ItemKind::Fn { ref sig, body: ref body_id, @@ -65,7 +65,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), MustUse { span, reason } => (span, reason)); + let attr = find_attr!(cx.tcx, item.hir_id(), MustUse { span, reason } => (span, reason)); if let Some((attr_span, reason)) = attr { check_needless_must_use( cx, @@ -98,7 +98,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), MustUse { span, reason } => (span, reason)); + let attr = find_attr!(cx.tcx, item.hir_id(), MustUse { span, reason } => (span, reason)); if let Some((attr_span, reason)) = attr { check_needless_must_use( cx, diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index ad81810b58cb..1ae8198a432d 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -269,5 +269,5 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &'tcx hir::Ty<'tcx, Ambig fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx .hir_parent_id_iter(hir_id) - .any(|id| find_attr!(cx.tcx.hir_attrs(id), CfgTrace(..) | CfgAttrTrace)) + .any(|id| find_attr!(cx.tcx, id, CfgTrace(..) | CfgAttrTrace)) } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index d683abd3d33b..f906bba423b3 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -13,8 +13,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Spanned, Symbol}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 4d67c158c043..719484b30de8 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -210,6 +210,7 @@ mod manual_main_separator_str; mod manual_non_exhaustive; mod manual_option_as_slice; +mod manual_pop_if; mod manual_range_patterns; mod manual_rem_euclid; mod manual_retain; @@ -863,6 +864,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(move |tcx| Box::new(duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf))), Box::new(move |_| Box::new(manual_take::ManualTake::new(conf))), Box::new(|_| Box::new(manual_checked_ops::ManualCheckedOps)), + Box::new(move |_| Box::new(manual_pop_if::ManualPopIf::new(conf))), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs index 96de118b5233..2c89afc73974 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, is_refutable, peel_blocks_with_stmt, span_contains_comment}; use rustc_errors::Applicability; @@ -50,7 +50,7 @@ pub(super) fn check<'tcx>( format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); // Prepare the help message - let mut applicability = if span_contains_comment(cx.sess().source_map(), body.span) { + let mut applicability = if span_contains_comment(cx, body.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs index a2ff60a3d8ac..ffc6f7186922 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{HasSession, snippet_with_applicability}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_slice_like}; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment}; @@ -13,8 +13,7 @@ use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind, Pat}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; -use rustc_span::sym; +use rustc_span::{Spanned, sym}; use super::MANUAL_SLICE_FILL; @@ -94,7 +93,7 @@ fn sugg<'tcx>( slice_span: rustc_span::Span, assignval_span: rustc_span::Span, ) { - let mut app = if span_contains_comment(cx.sess().source_map(), body.span) { + let mut app = if span_contains_comment(cx, body.span) { Applicability::MaybeIncorrect // Comments may be informational. } else { Applicability::MachineApplicable diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 2c37e2679d97..86f4e606a176 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -8,7 +8,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use rustc_span::symbol::{Symbol, sym}; #[derive(Debug, PartialEq, Eq)] diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs index e3886517fdd3..400cfcd18f2c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs +++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs @@ -3,7 +3,6 @@ use clippy_utils::higher::If; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::HasSession as _; use clippy_utils::sugg::Sugg; use clippy_utils::ty::peel_and_count_ty_refs; use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment, sym}; @@ -76,10 +75,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { (a, b) = (b, a); } let applicability = { - let source_map = cx.sess().source_map(); - if span_contains_comment(source_map, if_expr.then.span) - || span_contains_comment(source_map, r#else.span) - { + if span_contains_comment(cx, if_expr.then.span) || span_contains_comment(cx, r#else.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index c34e0d33e713..c77133130ba4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -58,7 +58,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { "only a `panic!` in `if`-then statement", |diag| { let mut applicability = Applicability::MachineApplicable; - let mut comments = span_extract_comment(cx.sess().source_map(), expr.span); + let mut comments = span_extract_comment(cx, expr.span); if !comments.is_empty() { comments += "\n"; } diff --git a/src/tools/clippy/clippy_lints/src/manual_ilog2.rs b/src/tools/clippy/clippy_lints/src/manual_ilog2.rs index 7c397bd3f5e8..2c368f15d670 100644 --- a/src/tools/clippy/clippy_lints/src/manual_ilog2.rs +++ b/src/tools/clippy/clippy_lints/src/manual_ilog2.rs @@ -31,7 +31,7 @@ /// let log = x.ilog2(); /// let log = x.ilog2(); /// ``` - #[clippy::version = "1.93.0"] + #[clippy::version = "1.94.0"] pub MANUAL_ILOG2, pedantic, "manually reimplementing `ilog2`" diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 9ababe87f9de..703c9137d543 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -92,7 +92,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { .then_some((v.def_id, v.span)) }); if let Ok((id, span)) = iter.exactly_one() - && !find_attr!(cx.tcx.hir_attrs(item.hir_id()), NonExhaustive(..)) + && !find_attr!(cx.tcx, item.hir_id(), NonExhaustive(..)) { self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); } @@ -113,7 +113,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { "this seems like a manual implementation of the non-exhaustive pattern", |diag| { if let Some(non_exhaustive_span) = - find_attr!(cx.tcx.hir_attrs(item.hir_id()), NonExhaustive(span) => *span) + find_attr!(cx.tcx, item.hir_id(), NonExhaustive(span) => *span) { diag.span_note(non_exhaustive_span, "the struct is already non-exhaustive"); } else { diff --git a/src/tools/clippy/clippy_lints/src/manual_pop_if.rs b/src/tools/clippy/clippy_lints/src/manual_pop_if.rs new file mode 100644 index 000000000000..6662a34bc332 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_pop_if.rs @@ -0,0 +1,434 @@ +use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::res::MaybeDef; +use clippy_utils::source::snippet_with_context; +use clippy_utils::visitors::is_local_used; +use clippy_utils::{eq_expr_value, is_else_clause, is_lang_item_or_ctor, peel_blocks_with_stmt, sym}; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem, PatKind, RustcVersion, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::impl_lint_pass; +use rustc_span::{Span, Symbol}; +use std::fmt; + +declare_clippy_lint! { + /// ### What it does + /// Checks for code to be replaced by `pop_if` methods. + /// + /// ### Why is this bad? + /// Using `pop_if` is more concise and idiomatic. + /// + /// ### Known issues + /// Currently, the lint does not handle the case where the + /// `if` condition is part of an `else if` branch. + /// + /// The lint also does not handle the case where + /// the popped value is assigned and used. + /// + /// ### Examples + /// ```no_run + /// # use std::collections::VecDeque; + /// # let mut vec = vec![1, 2, 3, 4, 5]; + /// # let mut deque: VecDeque = VecDeque::from([1, 2, 3, 4, 5]); + /// if vec.last().is_some_and(|x| *x > 5) { + /// vec.pop().unwrap(); + /// } + /// if deque.back().is_some_and(|x| *x > 5) { + /// deque.pop_back().unwrap(); + /// } + /// if deque.front().is_some_and(|x| *x > 5) { + /// deque.pop_front().unwrap(); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// # use std::collections::VecDeque; + /// # let mut vec = vec![1, 2, 3, 4, 5]; + /// # let mut deque: VecDeque = VecDeque::from([1, 2, 3, 4, 5]); + /// vec.pop_if(|x| *x > 5); + /// deque.pop_back_if(|x| *x > 5); + /// deque.pop_front_if(|x| *x > 5); + /// ``` + #[clippy::version = "1.95.0"] + pub MANUAL_POP_IF, + complexity, + "manual implementation of `pop_if` methods" +} + +impl_lint_pass!(ManualPopIf => [MANUAL_POP_IF]); + +pub struct ManualPopIf { + msrv: Msrv, +} + +impl ManualPopIf { + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } +} + +#[allow(clippy::enum_variant_names)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ManualPopIfKind { + Vec, + VecDequeBack, + VecDequeFront, +} + +impl ManualPopIfKind { + fn check_method(self) -> Symbol { + match self { + ManualPopIfKind::Vec => sym::last, + ManualPopIfKind::VecDequeBack => sym::back, + ManualPopIfKind::VecDequeFront => sym::front, + } + } + + fn pop_method(self) -> Symbol { + match self { + ManualPopIfKind::Vec => sym::pop, + ManualPopIfKind::VecDequeBack => sym::pop_back, + ManualPopIfKind::VecDequeFront => sym::pop_front, + } + } + + fn pop_if_method(self) -> Symbol { + match self { + ManualPopIfKind::Vec => sym::pop_if, + ManualPopIfKind::VecDequeBack => sym::pop_back_if, + ManualPopIfKind::VecDequeFront => sym::pop_front_if, + } + } + + fn is_diag_item(self, cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + match self { + ManualPopIfKind::Vec => ty.is_diag_item(cx, sym::Vec), + ManualPopIfKind::VecDequeBack | ManualPopIfKind::VecDequeFront => ty.is_diag_item(cx, sym::VecDeque), + } + } + + fn msrv(self) -> RustcVersion { + match self { + ManualPopIfKind::Vec => msrvs::VEC_POP_IF, + ManualPopIfKind::VecDequeBack => msrvs::VEC_DEQUE_POP_BACK_IF, + ManualPopIfKind::VecDequeFront => msrvs::VEC_DEQUE_POP_FRONT_IF, + } + } +} + +impl fmt::Display for ManualPopIfKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ManualPopIfKind::Vec => write!(f, "`Vec::pop_if`"), + ManualPopIfKind::VecDequeBack => write!(f, "`VecDeque::pop_back_if`"), + ManualPopIfKind::VecDequeFront => write!(f, "`VecDeque::pop_front_if`"), + } + } +} + +struct ManualPopIfPattern<'tcx> { + kind: ManualPopIfKind, + + /// The collection (`vec` in `vec.last()`) + collection_expr: &'tcx Expr<'tcx>, + + /// The closure (`*x > 5` in `|x| *x > 5`) + predicate: &'tcx Expr<'tcx>, + + /// Parameter name for the closure (`x` in `|x| *x > 5`) + param_name: Symbol, + + /// Span of the if expression (including the `if` keyword) + if_span: Span, +} + +impl ManualPopIfPattern<'_> { + fn emit_lint(&self, cx: &LateContext<'_>) { + let mut app = Applicability::MachineApplicable; + let ctxt = self.if_span.ctxt(); + let collection_snippet = snippet_with_context(cx, self.collection_expr.span, ctxt, "..", &mut app).0; + let predicate_snippet = snippet_with_context(cx, self.predicate.span, ctxt, "..", &mut app).0; + let param_name = self.param_name; + let pop_if_method = self.kind.pop_if_method(); + + let suggestion = format!("{collection_snippet}.{pop_if_method}(|{param_name}| {predicate_snippet});"); + + span_lint_and_sugg( + cx, + MANUAL_POP_IF, + self.if_span, + format!("manual implementation of {}", self.kind), + "try", + suggestion, + app, + ); + } +} + +fn pop_value_is_used(then_block: &Expr<'_>) -> bool { + let ExprKind::Block(block, _) = then_block.kind else { + return true; + }; + + if block.expr.is_some() { + return true; + } + + match block.stmts { + [stmt] => !matches!(stmt.kind, StmtKind::Semi(_) | StmtKind::Item(_)), + [.., last] => matches!(last.kind, StmtKind::Expr(_)), + [] => false, + } +} + +/// Checks for the pattern: +/// ```ignore +/// if vec.last().is_some_and(|x| *x > 5) { +/// vec.pop().unwrap(); +/// } +/// ``` +fn check_is_some_and_pattern<'tcx>( + cx: &LateContext<'tcx>, + cond: &'tcx Expr<'_>, + then_block: &'tcx Expr<'_>, + if_expr_span: Span, + kind: ManualPopIfKind, +) -> Option> { + if pop_value_is_used(then_block) { + return None; + } + + let check_method = kind.check_method(); + let pop_method = kind.pop_method(); + + if let ExprKind::MethodCall(path, receiver, [closure_arg], _) = cond.kind + && path.ident.name == sym::is_some_and + && let ExprKind::MethodCall(check_path, collection_expr, [], _) = receiver.kind + && check_path.ident.name == check_method + && kind.is_diag_item(cx, collection_expr) + && let ExprKind::Closure(closure) = closure_arg.kind + && let body = cx.tcx.hir_body(closure.body) + && let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method) + && eq_expr_value(cx, collection_expr, pop_collection) + && let Some(param) = body.params.first() + && let Some(ident) = param.pat.simple_ident() + { + return Some(ManualPopIfPattern { + kind, + collection_expr, + predicate: body.value, + param_name: ident.name, + if_span: if_expr_span, + }); + } + + None +} + +/// Checks for the pattern: +/// ```ignore +/// if let Some(x) = vec.last() { +/// if *x > 5 { +/// vec.pop().unwrap(); +/// } +/// } +/// ``` +fn check_if_let_pattern<'tcx>( + cx: &LateContext<'tcx>, + cond: &'tcx Expr<'_>, + then_block: &'tcx Expr<'_>, + if_expr_span: Span, + kind: ManualPopIfKind, +) -> Option> { + let check_method = kind.check_method(); + let pop_method = kind.pop_method(); + + if let ExprKind::Let(let_expr) = cond.kind + && let PatKind::TupleStruct(qpath, [binding_pat], _) = let_expr.pat.kind + { + let res = cx.qpath_res(&qpath, let_expr.pat.hir_id); + + if let Some(def_id) = res.opt_def_id() + && is_lang_item_or_ctor(cx, def_id, LangItem::OptionSome) + && let PatKind::Binding(_, binding_id, binding_name, _) = binding_pat.kind + && let ExprKind::MethodCall(path, collection_expr, [], _) = let_expr.init.kind + && path.ident.name == check_method + && kind.is_diag_item(cx, collection_expr) + && let ExprKind::Block(block, _) = then_block.kind + { + // The inner if can be either a statement or a block expression + let inner_if = match (block.stmts, block.expr) { + ([stmt], _) => match stmt.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr, + _ => return None, + }, + ([], Some(expr)) => expr, + _ => return None, + }; + + if let ExprKind::If(inner_cond, inner_then, None) = inner_if.kind + && is_local_used(cx, inner_cond, binding_id) + && !pop_value_is_used(inner_then) + && let Some((pop_collection, _pop_span)) = check_pop_unwrap(inner_then, pop_method) + && eq_expr_value(cx, collection_expr, pop_collection) + { + return Some(ManualPopIfPattern { + kind, + collection_expr, + predicate: inner_cond, + param_name: binding_name.name, + if_span: if_expr_span, + }); + } + } + } + + None +} + +/// Checks for the pattern: +/// ```ignore +/// if let Some(x) = vec.last() && *x > 5 { +/// vec.pop().unwrap(); +/// } +/// ``` +fn check_let_chain_pattern<'tcx>( + cx: &LateContext<'tcx>, + cond: &'tcx Expr<'_>, + then_block: &'tcx Expr<'_>, + if_expr_span: Span, + kind: ManualPopIfKind, +) -> Option> { + if pop_value_is_used(then_block) { + return None; + } + + let check_method = kind.check_method(); + let pop_method = kind.pop_method(); + + if let ExprKind::Binary(op, left, right) = cond.kind + && op.node == rustc_ast::BinOpKind::And + && let ExprKind::Let(let_expr) = left.kind + && let PatKind::TupleStruct(qpath, [binding_pat], _) = let_expr.pat.kind + { + let res = cx.qpath_res(&qpath, let_expr.pat.hir_id); + + if let Some(def_id) = res.opt_def_id() + && is_lang_item_or_ctor(cx, def_id, LangItem::OptionSome) + && let PatKind::Binding(_, binding_id, binding_name, _) = binding_pat.kind + && let ExprKind::MethodCall(path, collection_expr, [], _) = let_expr.init.kind + && path.ident.name == check_method + && kind.is_diag_item(cx, collection_expr) + && is_local_used(cx, right, binding_id) + && !pop_value_is_used(then_block) + && let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method) + && eq_expr_value(cx, collection_expr, pop_collection) + { + return Some(ManualPopIfPattern { + kind, + collection_expr, + predicate: right, + param_name: binding_name.name, + if_span: if_expr_span, + }); + } + } + + None +} + +/// Checks for the pattern: +/// ```ignore +/// if vec.last().map(|x| *x > 5).unwrap_or(false) { +/// vec.pop().unwrap(); +/// } +/// ``` +fn check_map_unwrap_or_pattern<'tcx>( + cx: &LateContext<'tcx>, + cond: &'tcx Expr<'_>, + then_block: &'tcx Expr<'_>, + if_expr_span: Span, + kind: ManualPopIfKind, +) -> Option> { + if pop_value_is_used(then_block) { + return None; + } + + let check_method = kind.check_method(); + let pop_method = kind.pop_method(); + + if let ExprKind::MethodCall(unwrap_path, receiver, [default_arg], _) = cond.kind + && unwrap_path.ident.name == sym::unwrap_or + && matches!(default_arg.kind, ExprKind::Lit(lit) if matches!(lit.node, LitKind::Bool(false))) + && let ExprKind::MethodCall(map_path, map_receiver, [closure_arg], _) = receiver.kind + && map_path.ident.name == sym::map + && let ExprKind::MethodCall(check_path, collection_expr, [], _) = map_receiver.kind + && check_path.ident.name == check_method + && kind.is_diag_item(cx, collection_expr) + && let ExprKind::Closure(closure) = closure_arg.kind + && let body = cx.tcx.hir_body(closure.body) + && cx.typeck_results().expr_ty(body.value).is_bool() + && let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method) + && eq_expr_value(cx, collection_expr, pop_collection) + && let Some(param) = body.params.first() + && let Some(ident) = param.pat.simple_ident() + { + return Some(ManualPopIfPattern { + kind, + collection_expr, + predicate: body.value, + param_name: ident.name, + if_span: if_expr_span, + }); + } + + None +} + +/// Checks for `collection.().unwrap()` or `collection.().expect(..)` +/// and returns the collection and the span of the peeled expr +fn check_pop_unwrap<'tcx>(expr: &'tcx Expr<'_>, pop_method: Symbol) -> Option<(&'tcx Expr<'tcx>, Span)> { + let inner_expr = peel_blocks_with_stmt(expr); + + if let ExprKind::MethodCall(unwrap_path, receiver, _, _) = inner_expr.kind + && matches!(unwrap_path.ident.name, sym::unwrap | sym::expect) + && let ExprKind::MethodCall(pop_path, collection_expr, [], _) = receiver.kind + && pop_path.ident.name == pop_method + { + return Some((collection_expr, inner_expr.span)); + } + + None +} + +impl<'tcx> LateLintPass<'tcx> for ManualPopIf { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let ExprKind::If(cond, then_block, None) = expr.kind else { + return; + }; + + // Do not lint if we are in an else-if branch. + if is_else_clause(cx.tcx, expr) { + return; + } + + for kind in [ + ManualPopIfKind::Vec, + ManualPopIfKind::VecDequeBack, + ManualPopIfKind::VecDequeFront, + ] { + if let Some(pattern) = check_is_some_and_pattern(cx, cond, then_block, expr.span, kind) + .or_else(|| check_if_let_pattern(cx, cond, then_block, expr.span, kind)) + .or_else(|| check_let_chain_pattern(cx, cond, then_block, expr.span, kind)) + .or_else(|| check_map_unwrap_or_pattern(cx, cond, then_block, expr.span, kind)) + && self.msrv.meets(cx, kind.msrv()) + { + pattern.emit_lint(cx); + return; + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 526163244596..e0a60e3747a0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -15,8 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext as _}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; -use rustc_span::{Symbol, SyntaxContext}; +use rustc_span::{Spanned, Symbol, SyntaxContext}; use std::iter; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index c95a72da6e29..de5f83b4745f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -154,7 +154,7 @@ fn check_arm<'tcx>( } else { outer_pat.span.shrink_to_hi() }; - let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner_expr.span); + let (paren_start, inner_if_span, paren_end) = peel_parens(cx, inner_expr.span); let inner_if = inner_if_span.split_at(2).0; let mut sugg = vec![ (inner.then.span.shrink_to_lo(), "=> ".to_string()), diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs index 1fc8bb9acce2..abbf60019c5c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs @@ -9,7 +9,7 @@ use rustc_hir::LangItem::ResultErr; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath}; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::LateContext; use rustc_middle::ty::Ty; use rustc_span::symbol::Ident; @@ -130,7 +130,7 @@ fn is_none(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// `err`, depending on `is_ok`. fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok: bool) { let method = if is_ok { "ok" } else { "err" }; - let mut app = if span_contains_comment(cx.sess().source_map(), expr.span) { + let mut app = if span_contains_comment(cx, expr.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs index 421c6064284d..e3a112d1f780 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, QPath}; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::LateContext; use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_span::sym; @@ -101,7 +101,7 @@ fn handle( && local_id == binding_id { // Machine applicable only if there are no comments present - let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + let mut applicability = if span_contains_comment(cx, expr.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index 347560b14eea..7b3ad2596b9e 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -8,9 +8,9 @@ use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Pat, PatKind, QPath}; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::MATCH_LIKE_MATCHES_MACRO; @@ -22,7 +22,7 @@ pub(crate) fn check_if_let<'tcx>( then_expr: &'tcx Expr<'_>, else_expr: &'tcx Expr<'_>, ) { - if !span_contains_comment(cx.sess().source_map(), expr.span) + if !span_contains_comment(cx, expr.span) && cx.typeck_results().expr_ty(expr).is_bool() && let Some(b0) = find_bool_lit(then_expr) && let Some(b1) = find_bool_lit(else_expr) @@ -71,7 +71,7 @@ pub(super) fn check_match<'tcx>( ) -> bool { if let Some((last_arm, arms_without_last)) = arms.split_last() && let Some((first_arm, middle_arms)) = arms_without_last.split_first() - && !span_contains_comment(cx.sess().source_map(), e.span) + && !span_contains_comment(cx, e.span) && cx.typeck_results().expr_ty(e).is_bool() && let Some(b0) = find_bool_lit(first_arm.body) && let Some(b1) = find_bool_lit(last_arm.body) diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 5b0de80e67fd..a8312a04f36f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -12,7 +12,7 @@ use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd}; use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::ty; +use rustc_middle::ty::{self, TypeckResults}; use rustc_span::{ByteSymbol, ErrorGuaranteed, Span, Symbol}; use super::MATCH_SAME_ARMS; @@ -61,7 +61,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { let check_eq_with_pat = |expr_a: &Expr<'_>, expr_b: &Expr<'_>| { let mut local_map: HirIdMap = HirIdMap::default(); - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + let eq_fallback = |a_typeck_results: &TypeckResults<'tcx>, + a: &Expr<'_>, + b_typeck_results: &TypeckResults<'tcx>, + b: &Expr<'_>| { if let Some(a_id) = a.res_local_id() && let Some(b_id) = b.res_local_id() && let entry = match local_map.entry(a_id) { @@ -71,7 +74,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { } // the names technically don't have to match; this makes the lint more conservative && cx.tcx.hir_name(a_id) == cx.tcx.hir_name(b_id) - && cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b) + && a_typeck_results.expr_ty(a) == b_typeck_results.expr_ty(b) && pat_contains_local(lhs.pat, a_id) && pat_contains_local(rhs.pat, b_id) { diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index dc8c06ffd79e..717c47b8aed3 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1093,12 +1093,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { } redundant_pattern_match::check_match(cx, expr, ex, arms); - let source_map = cx.tcx.sess.source_map(); - let mut match_comments = span_extract_comments(source_map, expr.span); + let mut match_comments = span_extract_comments(cx, expr.span); // We remove comments from inside arms block. if !match_comments.is_empty() { for arm in arms { - for comment in span_extract_comments(source_map, arm.body.span) { + for comment in span_extract_comments(cx, arm.body.span) { if let Some(index) = match_comments .iter() .enumerate() diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index b4b10e972f6d..229670486db3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -7,8 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::Span; -use rustc_span::source_map::Spanned; +use rustc_span::{Span, Spanned}; use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 7b10c37de42d..d2e593fc17df 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -9,6 +9,7 @@ use rustc_hir::def::Res; use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; +use rustc_middle::ty::TypeckResults; use rustc_middle::ty::adjustment::Adjust; use rustc_span::Span; use rustc_span::symbol::{Ident, Symbol}; @@ -136,7 +137,9 @@ pub fn check_map_call( // .map(|y| y[.acceptable_method()].unwrap()) && let simple_equal = (receiver.res_local_id() == Some(filter_param_id) && map_arg_peeled.res_local_id() == Some(map_param_id)) - && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| { + && let eq_fallback = + (|a_typeck_results: &TypeckResults<'tcx>, a: &Expr<'_>, + b_typeck_results: &TypeckResults<'tcx>, b: &Expr<'_>| { // in `filter(|x| ..)`, replace `*x` with `x` let a_path = if !is_filter_param_ref && let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind @@ -144,7 +147,7 @@ pub fn check_map_call( // let the filter closure arg and the map closure arg be equal a_path.res_local_id() == Some(filter_param_id) && b.res_local_id() == Some(map_param_id) - && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + && a_typeck_results.expr_ty_adjusted(a) == b_typeck_results.expr_ty_adjusted(b) }) && (simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled)) diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs index 414c4e0cd381..cb5d1ec374fc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::GET_FIRST; diff --git a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs index 171079f52d9a..14e40328a416 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs @@ -5,7 +5,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::GET_LAST_WITH_LEN; diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs index 4577be34d4a7..cfda39ed08ff 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs @@ -39,7 +39,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx .hir_parent_id_iter(id) - .any(|id| find_attr!(cx.tcx.hir_attrs(id), CfgTrace(..))) + .any(|id| find_attr!(cx.tcx, id, CfgTrace(..))) } /// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs index aaface3aa971..3aa666145b86 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs @@ -1,7 +1,7 @@ use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::ty::get_iterator_item_ty; use hir::ExprKind; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::LateContext; use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME}; @@ -144,7 +144,7 @@ fn expression_type( ) -> Option { if !cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) || parent_is_map(cx, expr) - || span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi())) + || span_contains_comment(cx, filter_span.with_hi(expr.span.hi())) { return None; } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs b/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs index d2906b2776f8..f1d399e1bbd2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs @@ -9,7 +9,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::MANUAL_CONTAINS; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs index e4ae14b6cf59..09733953255e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs @@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_ let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability); let span = expr.span.with_lo(map_span.lo()); // If the methods are separated with comments, we don't apply suggestion automatically. - if span_contains_comment(cx.tcx.sess.source_map(), span) { + if span_contains_comment(cx, span) { applicability = Applicability::Unspecified; } span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 0ed166f8dd5b..b647dbdc8468 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -134,9 +134,8 @@ mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; mod unnecessary_map_or; +mod unnecessary_map_or_else; mod unnecessary_min_or_max; -mod unnecessary_option_map_or_else; -mod unnecessary_result_map_or_else; mod unnecessary_sort_by; mod unnecessary_to_owned; mod unwrap_expect_used; @@ -3030,7 +3029,7 @@ /// ptr.sub(8); /// } /// ``` - #[clippy::version = "1.92.0"] + #[clippy::version = "1.94.0"] pub PTR_OFFSET_BY_LITERAL, pedantic, "unneeded pointer offset" @@ -4347,6 +4346,7 @@ } declare_clippy_lint! { + /// ### What it does /// Checks for usage of `.map_or_else()` "map closure" for `Option` type. /// /// ### Why is this bad? @@ -5449,8 +5449,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { }, (sym::map_or_else, [def, map]) => { result_map_or_else_none::check(cx, expr, recv, def, map); - unnecessary_option_map_or_else::check(cx, expr, recv, def, map); - unnecessary_result_map_or_else::check(cx, expr, recv, def, map); + unnecessary_map_or_else::check(cx, expr, recv, def, map, call_span); }, (sym::next, []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index 1b520a9edb56..36dd4e952a2d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -7,8 +7,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::Span; -use rustc_span::source_map::Spanned; +use rustc_span::{Span, Spanned}; use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs index be1481ebb996..cbb7da327506 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs @@ -2,8 +2,7 @@ use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::Symbol; -use rustc_span::source_map::Spanned; +use rustc_span::{Spanned, Symbol}; use super::SUSPICIOUS_SPLITN; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or_else.rs new file mode 100644 index 000000000000..7c1c31d2bd38 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or_else.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_expr_identity_function; +use clippy_utils::res::MaybeDef; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::Span; +use rustc_span::symbol::sym; + +use super::{UNNECESSARY_OPTION_MAP_OR_ELSE, UNNECESSARY_RESULT_MAP_OR_ELSE}; + +/// lint use of `_.map_or_else(|err| err, |n| n)` for `Result`s and `Option`s. +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + recv: &Expr<'_>, + def_arg: &Expr<'_>, + map_arg: &Expr<'_>, + call_span: Span, +) { + let (symbol, lint) = match cx.typeck_results().expr_ty(recv).opt_diag_name(cx) { + Some(x @ sym::Result) => (x, UNNECESSARY_RESULT_MAP_OR_ELSE), + Some(x @ sym::Option) => (x, UNNECESSARY_OPTION_MAP_OR_ELSE), + _ => return, + }; + + if is_expr_identity_function(cx, map_arg) { + let msg = format!("unused \"map closure\" when calling `{symbol}::map_or_else` value"); + + span_lint_and_then(cx, lint, expr.span, msg, |diag| { + let mut applicability = Applicability::MachineApplicable; + let err_snippet = snippet_with_applicability(cx, def_arg.span, "..", &mut applicability); + let sugg = format!("unwrap_or_else({err_snippet})"); + + diag.span_suggestion_verbose(call_span, "consider using `unwrap_or_else`", sugg, applicability); + }); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs deleted file mode 100644 index 265619e26376..000000000000 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs +++ /dev/null @@ -1,111 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{expr_or_init, find_binding_init, peel_blocks}; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Body, BodyId, Closure, Expr, ExprKind, HirId, QPath}; -use rustc_lint::LateContext; -use rustc_span::symbol::sym; - -use super::UNNECESSARY_OPTION_MAP_OR_ELSE; -use super::utils::get_last_chain_binding_hir_id; - -fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) { - let msg = "unused \"map closure\" when calling `Option::map_or_else` value"; - let mut applicability = Applicability::MachineApplicable; - let self_snippet = snippet_with_applicability(cx, recv.span, "_", &mut applicability); - let err_snippet = snippet_with_applicability(cx, def_arg.span, "..", &mut applicability); - span_lint_and_sugg( - cx, - UNNECESSARY_OPTION_MAP_OR_ELSE, - expr.span, - msg, - "consider using `unwrap_or_else`", - format!("{self_snippet}.unwrap_or_else({err_snippet})"), - Applicability::MachineApplicable, - ); -} - -fn handle_qpath( - cx: &LateContext<'_>, - expr: &Expr<'_>, - recv: &Expr<'_>, - def_arg: &Expr<'_>, - expected_hir_id: HirId, - qpath: QPath<'_>, -) { - if let QPath::Resolved(_, path) = qpath - && let Res::Local(hir_id) = path.res - && expected_hir_id == hir_id - { - emit_lint(cx, expr, recv, def_arg); - } -} - -fn handle_closure(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body_id: BodyId) { - let body = cx.tcx.hir_body(body_id); - handle_fn_body(cx, expr, recv, def_arg, body); -} - -fn handle_fn_body(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body: &Body<'_>) { - if let Some(first_param) = body.params.first() { - let body_expr = peel_blocks(body.value); - match body_expr.kind { - ExprKind::Path(qpath) => { - handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath); - }, - // If this is a block (that wasn't peeled off), then it means there are statements. - ExprKind::Block(block, _) => { - if let Some(block_expr) = block.expr - // First we ensure that this is a "binding chain" (each statement is a binding - // of the previous one) and that it is a binding of the closure argument. - && let Some(last_chain_binding_id) = - get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts) - && let ExprKind::Path(qpath) = block_expr.kind - { - handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath); - } - }, - _ => {}, - } - } -} - -/// lint use of `_.map_or_else(|err| err, |n| n)` for `Option`s. -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, map_arg: &Expr<'_>) { - // lint if the caller of `map_or_else()` is an `Option` - if !cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option) { - return; - } - match map_arg.kind { - // If the second argument is a closure, we can check its body. - ExprKind::Closure(&Closure { body, .. }) => { - handle_closure(cx, expr, recv, def_arg, body); - }, - ExprKind::Path(qpath) => { - let res = cx.qpath_res(&qpath, map_arg.hir_id); - match res { - // Case 1: Local variable (could be a closure) - Res::Local(hir_id) => { - if let Some(init_expr) = find_binding_init(cx, hir_id) { - let origin = expr_or_init(cx, init_expr); - if let ExprKind::Closure(&Closure { body, .. }) = origin.kind { - handle_closure(cx, expr, recv, def_arg, body); - } - } - }, - // Case 2: Function definition - Res::Def(DefKind::Fn, def_id) => { - if let Some(local_def_id) = def_id.as_local() - && let Some(body) = cx.tcx.hir_maybe_body_owned_by(local_def_id) - { - handle_fn_body(cx, expr, recv, def_arg, body); - } - }, - _ => (), - } - }, - _ => (), - } -} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs deleted file mode 100644 index 1f6bb60414ae..000000000000 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs +++ /dev/null @@ -1,80 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::peel_blocks; -use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath}; -use rustc_lint::LateContext; -use rustc_span::symbol::sym; - -use super::UNNECESSARY_RESULT_MAP_OR_ELSE; -use super::utils::get_last_chain_binding_hir_id; - -fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) { - let msg = "unused \"map closure\" when calling `Result::map_or_else` value"; - let self_snippet = snippet(cx, recv.span, ".."); - let err_snippet = snippet(cx, def_arg.span, ".."); - span_lint_and_sugg( - cx, - UNNECESSARY_RESULT_MAP_OR_ELSE, - expr.span, - msg, - "consider using `unwrap_or_else`", - format!("{self_snippet}.unwrap_or_else({err_snippet})"), - Applicability::MachineApplicable, - ); -} - -fn handle_qpath( - cx: &LateContext<'_>, - expr: &Expr<'_>, - recv: &Expr<'_>, - def_arg: &Expr<'_>, - expected_hir_id: HirId, - qpath: QPath<'_>, -) { - if let QPath::Resolved(_, path) = qpath - && let hir::def::Res::Local(hir_id) = path.res - && expected_hir_id == hir_id - { - emit_lint(cx, expr, recv, def_arg); - } -} - -/// lint use of `_.map_or_else(|err| err, |n| n)` for `Result`s. -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - recv: &'tcx Expr<'_>, - def_arg: &'tcx Expr<'_>, - map_arg: &'tcx Expr<'_>, -) { - // lint if the caller of `map_or_else()` is a `Result` - if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result) - && let ExprKind::Closure(&Closure { body, .. }) = map_arg.kind - && let body = cx.tcx.hir_body(body) - && let Some(first_param) = body.params.first() - { - let body_expr = peel_blocks(body.value); - - match body_expr.kind { - ExprKind::Path(qpath) => { - handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath); - }, - // If this is a block (that wasn't peeled off), then it means there are statements. - ExprKind::Block(block, _) => { - if let Some(block_expr) = block.expr - // First we ensure that this is a "binding chain" (each statement is a binding - // of the previous one) and that it is a binding of the closure argument. - && let Some(last_chain_binding_id) = - get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts) - && let ExprKind::Path(qpath) = block_expr.kind - { - handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath); - } - }, - _ => {}, - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs index 5debaab2067b..8979f9973d6f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -5,8 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Spanned, sym}; use super::VEC_RESIZE_TO_ZERO; diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 2773f537efc6..b5becbdeb30d 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -15,8 +15,7 @@ use rustc_hir::{Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Spanned, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index 387b6f8bf223..a0ad1fe00c62 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -108,7 +108,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { then, r#else: Some(else_expr), }) = higher::If::hir(e) - && !span_contains_comment(cx.tcx.sess.source_map(), e.span) + && !span_contains_comment(cx, e.span) { let reduce = |ret, not| { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 8b0743c8d9d5..6c45964da0da 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -332,7 +332,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { if let ImplItemImplKind::Trait { trait_item_def_id, .. } = impl_kind && let Ok(trait_item_id) = trait_item_def_id { - let impl_id = cx.tcx.parent(owner_id.into()); + let impl_id = cx.tcx.local_parent(owner_id.def_id); let trait_ref = cx.tcx.impl_trait_ref(impl_id).instantiate_identity(); ( trait_item_id, diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs index 56001a185771..e5a5b46b7b2e 100644 --- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs @@ -7,8 +7,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_span::Span; -use rustc_span::source_map::Spanned; +use rustc_span::{Span, Spanned}; use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_note; diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs index 97b3c0d02e84..6c6221525b57 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs @@ -6,7 +6,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::FLOAT_EQUALITY_WITHOUT_ABS; diff --git a/src/tools/clippy/clippy_lints/src/operators/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/operators/manual_div_ceil.rs index 6751532ecbc7..a0f61f6d36c4 100644 --- a/src/tools/clippy/clippy_lints/src/operators/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/operators/manual_div_ceil.rs @@ -9,7 +9,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; use super::MANUAL_DIV_CEIL; diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 567443b8e86d..b4519d654722 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -221,7 +221,7 @@ /// ```rust,no_run /// let a = 0b1110 & 0b0110; /// ``` - #[clippy::version = "1.93.0"] + #[clippy::version = "1.94.0"] pub DECIMAL_BITWISE_OPERANDS, pedantic, "use binary, hex, or octal literals for bitwise operations" diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index 034fe8edc715..1f0371c78200 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; use rustc_session::declare_lint_pass; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index e79ce91d8b32..dfd7834a149b 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -143,7 +143,7 @@ fn init_expr_can_use_question_mark(cx: &LateContext<'_>, init_expr: &Expr<'_>) - && init_expr_can_use_question_mark(cx, init_expr) && let Some(ret) = find_let_else_ret_expression(els) && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret) - && !span_contains_comment(cx.tcx.sess.source_map(), els.span) + && !span_contains_comment(cx, els.span) && !span_contains_cfg(cx, els.span) { let mut applicability = Applicability::MaybeIncorrect; @@ -501,7 +501,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); - let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_)); + let parent = cx.tcx.parent_hir_node(expr.hir_id); + let requires_semi = matches!(parent, Node::Stmt(_)) || cx.typeck_results().expr_ty(expr).is_unit(); let method_call_str = match by_ref { ByRef::Yes(_, Mutability::Mut) => ".as_mut()", ByRef::Yes(_, Mutability::Not) => ".as_ref()", @@ -512,7 +513,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: "{receiver_str}{method_call_str}?{}", if requires_semi { ";" } else { "" } ); - if is_else_clause(cx.tcx, expr) { + if is_else_clause(cx.tcx, expr) || (requires_semi && !matches!(parent, Node::Stmt(_) | Node::Block(_))) { sugg = format!("{{ {sugg} }}"); } diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 61087ad88457..39019c646bd5 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -14,8 +14,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::{self, ClauseKind, GenericArgKind, PredicatePolarity, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; -use rustc_span::{DesugaringKind, Span}; +use rustc_span::{DesugaringKind, Span, Spanned}; use std::cmp::Ordering; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/same_length_and_capacity.rs b/src/tools/clippy/clippy_lints/src/same_length_and_capacity.rs index b200fd1fe25f..ebf649c24307 100644 --- a/src/tools/clippy/clippy_lints/src/same_length_and_capacity.rs +++ b/src/tools/clippy/clippy_lints/src/same_length_and_capacity.rs @@ -65,7 +65,7 @@ /// // This time, leverage the previously saved capacity: /// let reconstructed = unsafe { Vec::from_raw_parts(ptr, len, cap) }; /// ``` - #[clippy::version = "1.93.0"] + #[clippy::version = "1.94.0"] pub SAME_LENGTH_AND_CAPACITY, pedantic, "`from_raw_parts` with same length and capacity" diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index 7c68762b22c0..e806123596b8 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs @@ -170,7 +170,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { StmtKind::Semi(Expr { kind: ExprKind::Block(block, _), .. - }) if !block.span.from_expansion() => { + }) if !block.span.from_expansion() && !block.targeted_by_break => { let attrs = cx.tcx.hir_attrs(stmt.hir_id); if !attrs.is_empty() && !cx.tcx.features().stmt_expr_attributes() { return; diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 4fa22ff0cdb5..4ddf82773d87 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -179,7 +179,7 @@ fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { } fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool { - let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id()); + let scope_tree = cx.tcx.region_scope_tree(owner); if let Some(first_scope) = scope_tree.var_scope(first) && let Some(second_scope) = scope_tree.var_scope(second) { diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 8524497c387c..c99f2e2fb942 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -208,7 +208,7 @@ fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocati .with_lo(vec_alloc.allocation_expr.span.source_callsite().lo()); // If there is no comment in `span_to_replace`, Clippy can automatically fix the code. - let app = if span_contains_comment(cx.tcx.sess.source_map(), span_to_replace) { + let app = if span_contains_comment(cx, span_to_replace) { Applicability::Unspecified } else { Applicability::MachineApplicable diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index ab11c37b5041..61b5842ea542 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -11,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::source_map::Spanned; +use rustc_span::Spanned; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 9fa4d2c142b5..ac2d3741338a 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -7,9 +7,8 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::Span; -use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; +use rustc_span::{Span, Spanned}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 0c78ed84adc4..01482b2475f7 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -14,9 +14,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::{Span, SyntaxContext}; +use rustc_span::{Span, Spanned, SyntaxContext}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 60775d1856eb..2bf1d8be4653 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -826,7 +826,9 @@ fn text_has_safety_comment( // Don't lint if the safety comment is part of a codeblock in a doc comment. // It may or may not be required, and we can't very easily check it (and we shouldn't, since // the safety comment isn't referring to the node we're currently checking) - if line.trim_start_matches("///").trim_start().starts_with("```") { + if let Some(doc) = line.strip_prefix("///").or_else(|| line.strip_prefix("//!")) + && doc.trim_start().starts_with("```") + { in_codeblock = !in_codeblock; } diff --git a/src/tools/clippy/clippy_lints/src/useless_vec.rs b/src/tools/clippy/clippy_lints/src/useless_vec.rs index 28c339ce2b7d..7b6122213d60 100644 --- a/src/tools/clippy/clippy_lints/src/useless_vec.rs +++ b/src/tools/clippy/clippy_lints/src/useless_vec.rs @@ -251,7 +251,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { let help_msg = format!("you can use {} directly", suggest_ty.desc()); // If the `vec!` macro contains comment, better not make the suggestion machine applicable as it // would remove them. - let applicability = if span_contains_comment(cx.tcx.sess.source_map(), span) { + let applicability = if span_contains_comment(cx, span) { Applicability::Unspecified } else { Applicability::MachineApplicable diff --git a/src/tools/clippy/clippy_lints/src/write/empty_string.rs b/src/tools/clippy/clippy_lints/src/write/empty_string.rs index 1291f2489a21..fa2ad4ba94a2 100644 --- a/src/tools/clippy/clippy_lints/src/write/empty_string.rs +++ b/src/tools/clippy/clippy_lints/src/write/empty_string.rs @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: macro_call.span, format!("empty string literal in `{name}!`"), |diag| { - if span_extract_comments(cx.sess().source_map(), macro_call.span).is_empty() { + if span_extract_comments(cx, macro_call.span).is_empty() { let closing_paren = cx.sess().source_map().span_extend_to_prev_char_before( macro_call.span.shrink_to_hi(), ')', diff --git a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs index f56b6f31550b..cab1422c3000 100644 --- a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -12,9 +12,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; -use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; +use rustc_span::{Span, Spanned}; declare_tool_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_test_deps/Cargo.lock b/src/tools/clippy/clippy_test_deps/Cargo.lock index b22cf9d107d7..63e41e8abd10 100644 --- a/src/tools/clippy/clippy_test_deps/Cargo.lock +++ b/src/tools/clippy/clippy_test_deps/Cargo.lock @@ -55,9 +55,9 @@ checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cfg-if" diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index d7e40130380d..b5e2e0fbf6c5 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2026-03-05 +nightly-2026-03-21 ``` diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 50cfb0ed89de..9a463d1a9d71 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -280,7 +280,7 @@ pub fn eq_arm(l: &Arm, r: &Arm) -> bool { l.is_placeholder == r.is_placeholder && eq_pat(&l.pat, &r.pat) && eq_expr_opt(l.body.as_deref(), r.body.as_deref()) - && eq_expr_opt(l.guard.as_deref(), r.guard.as_deref()) + && eq_expr_opt(l.guard.as_deref().map(|g| &g.cond), r.guard.as_deref().map(|g| &g.cond)) && over(&l.attrs, &r.attrs, eq_attr) } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 1a75bdff8124..51db6b6b64c7 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -841,12 +841,18 @@ fn fetch_path(&self, qpath: &QPath<'_>, id: HirId) -> Option { && ty.span.ctxt() == self.ctxt.get() && ty_name.ident.span.ctxt() == self.ctxt.get() && matches!(ty_path.res, Res::PrimTy(_)) - && let Some((DefKind::AssocConst { .. }, did)) = self.typeck.type_dependent_def(id) => + && let Some((DefKind::AssocConst { .. }, did)) = self.typeck.type_dependent_def(id) + && self.tcx.inherent_impl_of_assoc(did).is_some() => { did }, - _ if let Res::Def(DefKind::Const { .. } | DefKind::AssocConst { .. }, did) = - self.typeck.qpath_res(qpath, id) => + // TODO: revisit when feature `min_generic_const_args` is stabilized. In the meantime, + // `TyCtxt::const_eval_resolve()` will trigger an ICE when evaluating the body of the + // `type const` definition. + _ if let Res::Def( + DefKind::Const { is_type_const: false } | DefKind::AssocConst { is_type_const: false }, + did, + ) = self.typeck.qpath_res(qpath, id) => { self.source.set(ConstantSource::NonLocal); did diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index c0d02aaa6ee8..f3c4ae3500af 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,7 +8,7 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{Applicability, Diag, Diagnostic, DiagCtxtHandle, DiagMessage, Level, MultiSpan}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, Level, MultiSpan}; #[cfg(debug_assertions)] use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions}; use rustc_hir::HirId; @@ -252,15 +252,19 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { let sp = sp.into(); #[expect(clippy::disallowed_methods)] - cx.emit_span_lint(lint, sp.clone(), ClippyDiag(|diag: &mut Diag<'_, ()>| { - diag.primary_message(msg); - diag.span(sp); - f(diag); - docs_link(diag, lint); + cx.emit_span_lint( + lint, + sp.clone(), + ClippyDiag(|diag: &mut Diag<'_, ()>| { + diag.primary_message(msg); + diag.span(sp); + f(diag); + docs_link(diag, lint); - #[cfg(debug_assertions)] - validate_diag(diag); - })); + #[cfg(debug_assertions)] + validate_diag(diag); + }), + ); } /// Like [`span_lint`], but emits the lint at the node identified by the given `HirId`. @@ -326,14 +330,19 @@ pub fn span_lint_hir_and_then( f: impl FnOnce(&mut Diag<'_, ()>), ) { #[expect(clippy::disallowed_methods)] - cx.tcx.node_span_lint(lint, hir_id, sp, |diag| { - diag.primary_message(msg); - f(diag); - docs_link(diag, lint); + cx.tcx.emit_node_span_lint( + lint, + hir_id, + sp, + rustc_errors::DiagDecorator(|diag| { + diag.primary_message(msg); + f(diag); + docs_link(diag, lint); - #[cfg(debug_assertions)] - validate_diag(diag); - }); + #[cfg(debug_assertions)] + validate_diag(diag); + }), + ); } /// Add a span lint with a suggestion on how to fix it. diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 4e9c64dd63c7..a4d8fd20e4d3 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -26,7 +26,8 @@ /// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but /// other conditions would make them equal. -type SpanlessEqCallback<'a> = dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a; +type SpanlessEqCallback<'a, 'tcx> = + dyn FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a; /// Determines how paths are hashed and compared for equality. #[derive(Copy, Clone, Debug, Default)] @@ -59,7 +60,7 @@ pub struct SpanlessEq<'a, 'tcx> { cx: &'a LateContext<'tcx>, maybe_typeck_results: Option<(&'tcx TypeckResults<'tcx>, &'tcx TypeckResults<'tcx>)>, allow_side_effects: bool, - expr_fallback: Option>>, + expr_fallback: Option>>, path_check: PathCheck, } @@ -94,7 +95,10 @@ pub fn paths_by_resolution(self) -> Self { } #[must_use] - pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self { + pub fn expr_fallback( + self, + expr_fallback: impl FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a, + ) -> Self { Self { expr_fallback: Some(Box::new(expr_fallback)), ..self @@ -639,7 +643,15 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool { ) => false, }; (is_eq && (!self.should_ignore(left) || !self.should_ignore(right))) - || self.inner.expr_fallback.as_mut().is_some_and(|f| f(left, right)) + || self + .inner + .maybe_typeck_results + .is_some_and(|(left_typeck_results, right_typeck_results)| { + self.inner + .expr_fallback + .as_mut() + .is_some_and(|f| f(left_typeck_results, left, right_typeck_results, right)) + }) } fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 1e73e43e0a71..8f028ba0878c 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1710,7 +1710,7 @@ pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool { } pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { - find_attr!(cx.tcx.hir_attrs(hir_id), Repr { .. }) + find_attr!(cx.tcx, hir_id, Repr { .. }) } pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool { @@ -1838,13 +1838,38 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// * `|[x, y]| [x, y]` /// * `|Foo(bar, baz)| Foo(bar, baz)` /// * `|Foo { bar, baz }| Foo { bar, baz }` +/// * `|x| { let y = x; ...; let z = y; z }` +/// * `|x| { let y = x; ...; let z = y; return z }` /// /// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead. -fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { +fn is_body_identity_function<'hir>(cx: &LateContext<'_>, func: &Body<'hir>) -> bool { let [param] = func.params else { return false; }; + let mut param_pat = param.pat; + + // Given a sequence of `Stmt`s of the form `let p = e` where `e` is an expr identical to the + // current `param_pat`, advance the current `param_pat` to `p`. + // + // Note: This is similar to `clippy_utils::get_last_chain_binding_hir_id`, but it works + // directly over a `Pattern` rather than a `HirId`. And it checks for compatibility via + // `is_expr_identity_of_pat` rather than `HirId` equality + let mut advance_param_pat_over_stmts = |stmts: &[Stmt<'hir>]| { + for stmt in stmts { + if let StmtKind::Let(local) = stmt.kind + && let Some(init) = local.init + && is_expr_identity_of_pat(cx, param_pat, init, true) + { + param_pat = local.pat; + } else { + return false; + } + } + + true + }; + let mut expr = func.value; loop { match expr.kind { @@ -1873,7 +1898,30 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { return false; } }, - _ => return is_expr_identity_of_pat(cx, param.pat, expr, true), + ExprKind::Block( + &Block { + stmts, expr: Some(e), .. + }, + _, + ) => { + if !advance_param_pat_over_stmts(stmts) { + return false; + } + + expr = e; + }, + ExprKind::Block(&Block { stmts, expr: None, .. }, _) => { + if let Some((last_stmt, stmts)) = stmts.split_last() + && advance_param_pat_over_stmts(stmts) + && let StmtKind::Semi(e) | StmtKind::Expr(e) = last_stmt.kind + && let ExprKind::Ret(Some(ret_val)) = e.kind + { + expr = ret_val; + } else { + return false; + } + }, + _ => return is_expr_identity_of_pat(cx, param_pat, expr, true), } } } @@ -2362,7 +2410,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(& && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind // We could also check for the type name `test::TestDescAndFn` && let Res::Def(DefKind::Struct, _) = path.res - && find_attr!(tcx.hir_attrs(item.hir_id()), RustcTestMarker(..)) + && find_attr!(tcx, item.hir_id(), RustcTestMarker(..)) { names.push(ident.name); } @@ -2420,7 +2468,7 @@ pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool { /// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent /// use [`is_in_cfg_test`] pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { - if let Some(cfgs) = find_attr!(tcx.hir_attrs(id), CfgTrace(cfgs) => cfgs) + if let Some(cfgs) = find_attr!(tcx, id, CfgTrace(cfgs) => cfgs) && cfgs .iter() .any(|(cfg, _)| matches!(cfg, CfgEntry::NameValue { name: sym::test, .. })) @@ -2762,16 +2810,15 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator bool { - let Ok(snippet) = sm.span_to_snippet(span) else { - return false; - }; - return tokenize(&snippet, FrontmatterAllowed::No).any(|token| { - matches!( - token.kind, - TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } - ) - }); +pub fn span_contains_comment(cx: &impl source::HasSession, span: Span) -> bool { + span.check_source_text(cx, |snippet| { + tokenize(snippet, FrontmatterAllowed::No).any(|token| { + matches!( + token.kind, + TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } + ) + }) + }) } /// Checks whether a given span has any significant token. A significant token is a non-whitespace @@ -2779,30 +2826,32 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { /// This is useful to determine if there are any actual code tokens in the span that are omitted in /// the late pass, such as platform-specific code. pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool { - matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)| - match token { + span.check_source_text(cx, |snippet| { + tokenize_with_text(snippet).any(|(token, _, _)| match token { TokenKind::Whitespace => false, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments, _ => true, - } - )) + }) + }) } /// Returns all the comments a given span contains /// /// Comments are returned wrapped with their relevant delimiters -pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { - span_extract_comments(sm, span).join("\n") +pub fn span_extract_comment(cx: &impl source::HasSession, span: Span) -> String { + span_extract_comments(cx, span).join("\n") } /// Returns all the comments a given span contains. /// /// Comments are returned wrapped with their relevant delimiters. -pub fn span_extract_comments(sm: &SourceMap, span: Span) -> Vec { - let snippet = sm.span_to_snippet(span).unwrap_or_default(); - tokenize_with_text(&snippet) - .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) - .map(|(_, s, _)| s.to_string()) - .collect::>() +pub fn span_extract_comments(cx: &impl source::HasSession, span: Span) -> Vec { + span.with_source_text(cx, |snippet| { + tokenize_with_text(snippet) + .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) + .map(|(_, s, _)| s.to_string()) + .collect::>() + }) + .unwrap_or_default() } pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 5aa457b9d19c..ecadc3322e14 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -23,9 +23,11 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,93,0 { VEC_DEQUE_POP_BACK_IF, VEC_DEQUE_POP_FRONT_IF } 1,91,0 { DURATION_FROM_MINUTES_HOURS } 1,88,0 { LET_CHAINS } 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST } + 1,86,0 { VEC_POP_IF } 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL } 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index d6ba678434bc..7d579d85d808 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -140,6 +140,7 @@ macro_rules! generate { as_str, assert_failed, author, + back, binaryheap_iter, bool_then, borrow, @@ -199,7 +200,6 @@ macro_rules! generate { cx, cycle, cyclomatic_complexity, - dbg_macro, de, debug_struct, deprecated_in_future, @@ -295,6 +295,7 @@ macro_rules! generate { from_str_method, from_str_radix, from_weeks, + front, fs, fs_create_dir, fuse, @@ -464,6 +465,12 @@ macro_rules! generate { peekable, permissions_from_mode, pin_macro, + pop, + pop_back, + pop_back_if, + pop_front, + pop_front_if, + pop_if, position, pow, powf, diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index af514778f968..1ac417a8d692 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -29,8 +29,7 @@ use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::collections::hash_map::Entry; -use std::debug_assert_matches; -use std::{iter, mem}; +use std::{debug_assert_matches, iter, mem}; use crate::paths::{PathNS, lookup_path_str}; use crate::res::{MaybeDef, MaybeQPath}; diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index c9bb94cededb..1f8bcdea8251 100644 --- a/src/tools/clippy/rust-toolchain.toml +++ b/src/tools/clippy/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2026-03-05" +channel = "nightly-2026-03-21" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index f27cb6708709..7b7aac09643a 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -23,9 +23,8 @@ use clippy_utils::sym; use declare_clippy_lint::LintListBuilder; use rustc_interface::interface; -use rustc_session::EarlyDiagCtxt; use rustc_session::config::ErrorOutputType; -use rustc_session::parse::ParseSess; +use rustc_session::{EarlyDiagCtxt, Session}; use rustc_span::symbol::Symbol; use std::env; @@ -81,17 +80,16 @@ fn test_has_arg() { assert!(!has_arg(args, "--bar")); } -fn track_clippy_args(psess: &mut ParseSess, args_env_var: Option<&str>) { - psess - .env_depinfo - .get_mut() +fn track_clippy_args(sess: &Session, args_env_var: Option<&str>) { + sess.env_depinfo + .borrow_mut() .insert((sym::CLIPPY_ARGS, args_env_var.map(Symbol::intern))); } /// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy /// when any of them are modified -fn track_files(psess: &mut ParseSess) { - let file_depinfo = psess.file_depinfo.get_mut(); +fn track_files(sess: &Session) { + let mut file_depinfo = sess.file_depinfo.borrow_mut(); // Used by `clippy::cargo` lints and to determine the MSRV. `cargo clippy` executes `clippy-driver` // with the current directory set to `CARGO_MANIFEST_DIR` so a relative path is fine @@ -123,8 +121,8 @@ struct RustcCallbacks { impl rustc_driver::Callbacks for RustcCallbacks { fn config(&mut self, config: &mut interface::Config) { let clippy_args_var = self.clippy_args_var.take(); - config.psess_created = Some(Box::new(move |psess| { - track_clippy_args(psess, clippy_args_var.as_deref()); + config.track_state = Some(Box::new(move |sess, _hasher| { + track_clippy_args(sess, clippy_args_var.as_deref()); })); config.extra_symbols = sym::EXTRA_SYMBOLS.into(); } @@ -140,13 +138,13 @@ fn config(&mut self, config: &mut interface::Config) { let conf_path = clippy_config::lookup_conf_file(); let previous = config.register_lints.take(); let clippy_args_var = self.clippy_args_var.take(); - config.psess_created = Some(Box::new(move |psess| { - track_clippy_args(psess, clippy_args_var.as_deref()); - track_files(psess); + config.track_state = Some(Box::new(move |sess, _hasher| { + track_clippy_args(sess, clippy_args_var.as_deref()); + track_files(sess); // Trigger a rebuild if CLIPPY_CONF_DIR changes. The value must be a valid string so // changes between dirs that are invalid UTF-8 will not trigger rebuilds - psess.env_depinfo.get_mut().insert(( + sess.env_depinfo.borrow_mut().insert(( sym::CLIPPY_CONF_DIR, env::var("CLIPPY_CONF_DIR").ok().map(|dir| Symbol::intern(&dir)), )); diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs b/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs index 36e4158f6e68..efb57e6a1b00 100644 --- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs +++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs @@ -6,23 +6,32 @@ extern crate rustc_lint; extern crate rustc_middle; -use rustc_errors::{DiagMessage, MultiSpan}; +use rustc_errors::{DiagDecorator, DiagMessage, MultiSpan}; use rustc_hir::hir_id::HirId; use rustc_lint::{Lint, LintContext}; use rustc_middle::ty::TyCtxt; pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into, msg: impl Into) { - cx.span_lint(lint, span, |lint| { + cx.emit_span_lint( //~^ disallowed_methods - lint.primary_message(msg); - }); + lint, + span, + DiagDecorator(|lint| { + lint.primary_message(msg); + }), + ); } pub fn b(tcx: TyCtxt<'_>, lint: &'static Lint, hir_id: HirId, span: impl Into, msg: impl Into) { - tcx.node_span_lint(lint, hir_id, span, |lint| { + tcx.emit_node_span_lint( //~^ disallowed_methods - lint.primary_message(msg); - }); + lint, + hir_id, + span, + DiagDecorator(|lint| { + lint.primary_message(msg); + }), + ); } fn main() {} diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr index e9d53c64dd9b..8631ddbb2cf4 100644 --- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr +++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr @@ -1,8 +1,8 @@ -error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` +error: use of a disallowed method `rustc_lint::context::LintContext::emit_span_lint` --> tests/ui-internal/disallow_span_lint.rs:15:8 | -LL | cx.span_lint(lint, span, |lint| { - | ^^^^^^^^^ +LL | cx.emit_span_lint( + | ^^^^^^^^^^^^^^ | = note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead note: the lint level is defined here @@ -11,11 +11,11 @@ note: the lint level is defined here LL | #![deny(clippy::disallowed_methods)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> tests/ui-internal/disallow_span_lint.rs:22:9 +error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::emit_node_span_lint` + --> tests/ui-internal/disallow_span_lint.rs:26:9 | -LL | tcx.node_span_lint(lint, hir_id, span, |lint| { - | ^^^^^^^^^^^^^^ +LL | tcx.emit_node_span_lint( + | ^^^^^^^^^^^^^^^^^^^ | = note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead diff --git a/src/tools/clippy/tests/ui/crashes/mgca-16691.rs b/src/tools/clippy/tests/ui/crashes/mgca-16691.rs new file mode 100644 index 000000000000..b7039240770b --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/mgca-16691.rs @@ -0,0 +1,16 @@ +//@ check-pass +#![allow(incomplete_features)] +#![feature(min_generic_const_args)] + +trait Trait { + type const N: usize; + fn process(); +} + +impl Trait for () { + type const N: usize = 3; + fn process() { + const N: usize = <()>::N; + _ = 0..Self::N; + } +} diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index 41e5bbe3cbed..36300aa56eb3 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -13,7 +13,8 @@ clippy::uninlined_format_args, clippy::useless_vec, clippy::unnecessary_map_on_constructor, - clippy::needless_lifetimes + clippy::needless_lifetimes, + clippy::unnecessary_option_map_or_else )] use std::path::{Path, PathBuf}; diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index de0d3fb63c51..63b441851ec1 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -13,7 +13,8 @@ clippy::uninlined_format_args, clippy::useless_vec, clippy::unnecessary_map_on_constructor, - clippy::needless_lifetimes + clippy::needless_lifetimes, + clippy::unnecessary_option_map_or_else )] use std::path::{Path, PathBuf}; diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index c19947cddafa..b57038963b7e 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure - --> tests/ui/eta.rs:34:27 + --> tests/ui/eta.rs:35:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -8,31 +8,31 @@ LL | let a = Some(1u8).map(|a| foo(a)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: redundant closure - --> tests/ui/eta.rs:39:40 + --> tests/ui/eta.rs:40:40 | LL | let _: Option> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> tests/ui/eta.rs:42:35 + --> tests/ui/eta.rs:43:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: redundant closure - --> tests/ui/eta.rs:45:26 + --> tests/ui/eta.rs:46:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> tests/ui/eta.rs:54:27 + --> tests/ui/eta.rs:55:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> tests/ui/eta.rs:107:51 + --> tests/ui/eta.rs:108:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -41,229 +41,229 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]` error: redundant closure - --> tests/ui/eta.rs:109:51 + --> tests/ui/eta.rs:110:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> tests/ui/eta.rs:112:42 + --> tests/ui/eta.rs:113:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> tests/ui/eta.rs:117:29 + --> tests/ui/eta.rs:118:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> tests/ui/eta.rs:119:27 + --> tests/ui/eta.rs:120:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> tests/ui/eta.rs:122:65 + --> tests/ui/eta.rs:123:65 | LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> tests/ui/eta.rs:139:23 + --> tests/ui/eta.rs:140:23 | LL | let _ = x.map(|x| x.parse::()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::` error: redundant closure - --> tests/ui/eta.rs:192:22 + --> tests/ui/eta.rs:193:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> tests/ui/eta.rs:200:27 + --> tests/ui/eta.rs:201:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> tests/ui/eta.rs:206:27 + --> tests/ui/eta.rs:207:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> tests/ui/eta.rs:239:28 + --> tests/ui/eta.rs:240:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:241:28 + --> tests/ui/eta.rs:242:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:243:28 + --> tests/ui/eta.rs:244:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> tests/ui/eta.rs:251:21 + --> tests/ui/eta.rs:252:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> tests/ui/eta.rs:256:21 + --> tests/ui/eta.rs:257:21 | LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` error: redundant closure - --> tests/ui/eta.rs:350:18 + --> tests/ui/eta.rs:351:18 | LL | takes_fn_mut(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:354:19 + --> tests/ui/eta.rs:355:19 | LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:359:26 + --> tests/ui/eta.rs:360:26 | LL | move || takes_fn_mut(|| f_used_once()) | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` error: redundant closure - --> tests/ui/eta.rs:372:19 + --> tests/ui/eta.rs:373:19 | LL | array_opt.map(|a| a.as_slice()); | ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice` error: redundant closure - --> tests/ui/eta.rs:376:19 + --> tests/ui/eta.rs:377:19 | LL | slice_opt.map(|s| s.len()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len` error: redundant closure - --> tests/ui/eta.rs:380:17 + --> tests/ui/eta.rs:381:17 | LL | ptr_opt.map(|p| p.is_null()); | ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null` error: redundant closure - --> tests/ui/eta.rs:385:17 + --> tests/ui/eta.rs:386:17 | LL | dyn_opt.map(|d| d.method_on_dyn()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `::method_on_dyn` error: redundant closure - --> tests/ui/eta.rs:446:19 + --> tests/ui/eta.rs:447:19 | LL | let _ = f(&0, |x, y| f2(x, y)); | ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2` error: redundant closure - --> tests/ui/eta.rs:475:22 + --> tests/ui/eta.rs:476:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method` error: redundant closure - --> tests/ui/eta.rs:480:22 + --> tests/ui/eta.rs:481:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method` error: redundant closure - --> tests/ui/eta.rs:494:18 + --> tests/ui/eta.rs:495:18 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method` error: redundant closure - --> tests/ui/eta.rs:502:30 + --> tests/ui/eta.rs:503:30 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method` error: redundant closure - --> tests/ui/eta.rs:522:38 + --> tests/ui/eta.rs:523:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `&f` error: redundant closure - --> tests/ui/eta.rs:527:38 + --> tests/ui/eta.rs:528:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `f` error: redundant closure - --> tests/ui/eta.rs:545:35 + --> tests/ui/eta.rs:546:35 | LL | let _field = bind.or_else(|| get_default()).unwrap(); | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default` error: redundant closure - --> tests/ui/eta.rs:592:16 + --> tests/ui/eta.rs:593:16 | LL | accepts_fn(|| f()); | ^^^^^^ help: replace the closure with the function itself: `**f` error: redundant closure - --> tests/ui/eta.rs:596:16 + --> tests/ui/eta.rs:597:16 | LL | accepts_fn(|| g()); | ^^^^^^ help: replace the closure with the function itself: `g` error: redundant closure - --> tests/ui/eta.rs:609:16 + --> tests/ui/eta.rs:610:16 | LL | accepts_fn(|| b()); | ^^^^^^ help: replace the closure with the function itself: `***b` error: redundant closure - --> tests/ui/eta.rs:633:14 + --> tests/ui/eta.rs:634:14 | LL | .map(|n| MyError::A(n)) | ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A` error: redundant closure - --> tests/ui/eta.rs:630:14 + --> tests/ui/eta.rs:631:14 | LL | .map(|n| S(n)) | ^^^^^^^^ help: replace the closure with the tuple struct itself: `S` error: redundant closure - --> tests/ui/eta.rs:627:14 + --> tests/ui/eta.rs:628:14 | LL | .map(|n| g(n)) | ^^^^^^^^ help: replace the closure with the function itself: `g` error: redundant closure - --> tests/ui/eta.rs:624:14 + --> tests/ui/eta.rs:625:14 | LL | .map(|n| f(n)) | ^^^^^^^^ help: replace the closure with the function itself: `f` error: redundant closure - --> tests/ui/eta.rs:651:31 + --> tests/ui/eta.rs:652:31 | LL | array.iter().for_each(|item| item.method()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Self::method` error: redundant closure - --> tests/ui/eta.rs:661:38 + --> tests/ui/eta.rs:662:38 | LL | (0..10).flat_map(|x| (0..10).map(|y| closure(y))).count(); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&*closure` diff --git a/src/tools/clippy/tests/ui/manual_pop_if.fixed b/src/tools/clippy/tests/ui/manual_pop_if.fixed new file mode 100644 index 000000000000..6e30786c8097 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_pop_if.fixed @@ -0,0 +1,247 @@ +#![warn(clippy::manual_pop_if)] +#![allow(clippy::collapsible_if, clippy::redundant_closure)] + +use std::collections::VecDeque; +use std::marker::PhantomData; + +// FakeVec has the same methods as Vec but isn't actually a Vec +struct FakeVec(PhantomData); + +impl FakeVec { + fn last(&self) -> Option<&T> { + None + } + + fn pop(&mut self) -> Option { + None + } +} + +fn is_some_and_pattern_positive(mut vec: Vec, mut deque: VecDeque) { + vec.pop_if(|x| *x > 2); + + vec.pop_if(|x| *x > 2); + + deque.pop_back_if(|x| *x > 2); + + deque.pop_front_if(|x| *x > 2); +} + +fn is_some_and_pattern_negative(mut vec: Vec, mut deque: VecDeque) { + // Do not lint, different vectors + let mut vec2 = vec![0]; + if vec.last().is_some_and(|x| *x > 2) { + vec2.pop().unwrap(); + } + + // Do not lint, non-Vec type + let mut fake_vec: FakeVec = FakeVec(PhantomData); + if fake_vec.last().is_some_and(|x| *x > 2) { + fake_vec.pop().unwrap(); + } + + // Do not lint, else-if branch + if false { + // something + } else if vec.last().is_some_and(|x| *x > 2) { + vec.pop().unwrap(); + } + + // Do not lint, value used in let binding + if vec.last().is_some_and(|x| *x > 2) { + let _value = vec.pop().unwrap(); + println!("Popped: {}", _value); + } + + // Do not lint, value used in expression + if vec.last().is_some_and(|x| *x > 2) { + println!("Popped: {}", vec.pop().unwrap()); + } + + // Do not lint, else block + let _result = if vec.last().is_some_and(|x| *x > 2) { + vec.pop().unwrap() + } else { + 0 + }; +} + +fn if_let_pattern_positive(mut vec: Vec, mut deque: VecDeque) { + vec.pop_if(|x| *x > 2); + + vec.pop_if(|x| *x > 2); + + deque.pop_back_if(|x| *x > 2); + + deque.pop_front_if(|x| *x > 2); +} + +fn if_let_pattern_negative(mut vec: Vec) { + // Do not lint, different vectors + let mut vec2 = vec![0]; + if let Some(x) = vec.last() { + if *x > 2 { + vec2.pop().unwrap(); + } + } + + // Do not lint, intervening statements + if let Some(x) = vec.last() { + println!("Checking {}", x); + if *x > 2 { + vec.pop().unwrap(); + } + } + + // Do not lint, bound variable not used in condition + if let Some(_x) = vec.last() { + if vec.len() > 2 { + vec.pop().unwrap(); + } + } + + // Do not lint, value used in let binding + if let Some(x) = vec.last() { + if *x > 2 { + let _val = vec.pop().unwrap(); + } + } + + // Do not lint, else block + let _result = if let Some(x) = vec.last() { + if *x > 2 { vec.pop().unwrap() } else { 0 } + } else { + 0 + }; +} + +fn let_chain_pattern_positive(mut vec: Vec, mut deque: VecDeque) { + vec.pop_if(|x| *x > 2); + + vec.pop_if(|x| *x > 2); + + deque.pop_back_if(|x| *x > 2); + + deque.pop_front_if(|x| *x > 2); +} + +fn let_chain_pattern_negative(mut vec: Vec) { + // Do not lint, different vectors + let mut vec2 = vec![0]; + if let Some(x) = vec.last() + && *x > 2 + { + vec2.pop().unwrap(); + } + + // Do not lint, bound variable not used in condition + if let Some(_x) = vec.last() + && vec.len() > 2 + { + vec.pop().unwrap(); + } + + // Do not lint, value used in let binding + if let Some(x) = vec.last() + && *x > 2 + { + let _val = vec.pop().unwrap(); + } + + // Do not lint, value used in expression + if let Some(x) = vec.last() + && *x > 2 + { + println!("Popped: {}", vec.pop().unwrap()); + } + + // Do not lint, else block + let _result = if let Some(x) = vec.last() + && *x > 2 + { + vec.pop().unwrap() + } else { + 0 + }; +} + +fn map_unwrap_or_pattern_positive(mut vec: Vec, mut deque: VecDeque) { + vec.pop_if(|x| *x > 2); + + vec.pop_if(|x| *x > 2); + + deque.pop_back_if(|x| *x > 2); + + deque.pop_front_if(|x| *x > 2); +} + +fn map_unwrap_or_pattern_negative(mut vec: Vec) { + // Do not lint, unwrap_or(true) instead of false + if vec.last().map(|x| *x > 2).unwrap_or(true) { + vec.pop().unwrap(); + } + + // Do not lint, different vectors + let mut vec2 = vec![0]; + if vec.last().map(|x| *x > 2).unwrap_or(false) { + vec2.pop().unwrap(); + } + + // Do not lint, non-Vec type + let mut fake_vec: FakeVec = FakeVec(PhantomData); + if fake_vec.last().map(|x| *x > 2).unwrap_or(false) { + fake_vec.pop().unwrap(); + } + + // Do not lint, map returns non-boolean + if vec.last().map(|x| x + 1).unwrap_or(0) > 2 { + vec.pop().unwrap(); + } + + // Do not lint, value used in let binding + if vec.last().map(|x| *x > 2).unwrap_or(false) { + let _val = vec.pop().unwrap(); + } + + // Do not lint, else block + let _result = if vec.last().map(|x| *x > 2).unwrap_or(false) { + vec.pop().unwrap() + } else { + 0 + }; +} + +// this makes sure we do not expand vec![] in the suggestion +fn handle_macro_in_closure(mut vec: Vec>) { + vec.pop_if(|e| *e == vec![1]); +} + +#[clippy::msrv = "1.85.0"] +fn msrv_too_low_vec(mut vec: Vec) { + if vec.last().is_some_and(|x| *x > 2) { + vec.pop().unwrap(); + } +} + +#[clippy::msrv = "1.92.0"] +fn msrv_too_low_vecdeque(mut deque: VecDeque) { + if deque.back().is_some_and(|x| *x > 2) { + deque.pop_back().unwrap(); + } + + if deque.front().is_some_and(|x| *x > 2) { + deque.pop_front().unwrap(); + } +} + +#[clippy::msrv = "1.86.0"] +fn msrv_high_enough_vec(mut vec: Vec) { + vec.pop_if(|x| *x > 2); +} + +#[clippy::msrv = "1.93.0"] +fn msrv_high_enough_vecdeque(mut deque: VecDeque) { + deque.pop_back_if(|x| *x > 2); + + deque.pop_front_if(|x| *x > 2); +} diff --git a/src/tools/clippy/tests/ui/manual_pop_if.rs b/src/tools/clippy/tests/ui/manual_pop_if.rs new file mode 100644 index 000000000000..a2f679dfc6b3 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_pop_if.rs @@ -0,0 +1,319 @@ +#![warn(clippy::manual_pop_if)] +#![allow(clippy::collapsible_if, clippy::redundant_closure)] + +use std::collections::VecDeque; +use std::marker::PhantomData; + +// FakeVec has the same methods as Vec but isn't actually a Vec +struct FakeVec(PhantomData); + +impl FakeVec { + fn last(&self) -> Option<&T> { + None + } + + fn pop(&mut self) -> Option { + None + } +} + +fn is_some_and_pattern_positive(mut vec: Vec, mut deque: VecDeque) { + if vec.last().is_some_and(|x| *x > 2) { + //~^ manual_pop_if + vec.pop().unwrap(); + } + + if vec.last().is_some_and(|x| *x > 2) { + //~^ manual_pop_if + vec.pop().expect("element"); + } + + if deque.back().is_some_and(|x| *x > 2) { + //~^ manual_pop_if + deque.pop_back().unwrap(); + } + + if deque.front().is_some_and(|x| *x > 2) { + //~^ manual_pop_if + deque.pop_front().unwrap(); + } +} + +fn is_some_and_pattern_negative(mut vec: Vec, mut deque: VecDeque) { + // Do not lint, different vectors + let mut vec2 = vec![0]; + if vec.last().is_some_and(|x| *x > 2) { + vec2.pop().unwrap(); + } + + // Do not lint, non-Vec type + let mut fake_vec: FakeVec = FakeVec(PhantomData); + if fake_vec.last().is_some_and(|x| *x > 2) { + fake_vec.pop().unwrap(); + } + + // Do not lint, else-if branch + if false { + // something + } else if vec.last().is_some_and(|x| *x > 2) { + vec.pop().unwrap(); + } + + // Do not lint, value used in let binding + if vec.last().is_some_and(|x| *x > 2) { + let _value = vec.pop().unwrap(); + println!("Popped: {}", _value); + } + + // Do not lint, value used in expression + if vec.last().is_some_and(|x| *x > 2) { + println!("Popped: {}", vec.pop().unwrap()); + } + + // Do not lint, else block + let _result = if vec.last().is_some_and(|x| *x > 2) { + vec.pop().unwrap() + } else { + 0 + }; +} + +fn if_let_pattern_positive(mut vec: Vec, mut deque: VecDeque) { + if let Some(x) = vec.last() { + //~^ manual_pop_if + if *x > 2 { + vec.pop().unwrap(); + } + } + + if let Some(x) = vec.last() { + //~^ manual_pop_if + if *x > 2 { + vec.pop().expect("element"); + } + } + + if let Some(x) = deque.back() { + //~^ manual_pop_if + if *x > 2 { + deque.pop_back().unwrap(); + } + } + + if let Some(x) = deque.front() { + //~^ manual_pop_if + if *x > 2 { + deque.pop_front().unwrap(); + } + } +} + +fn if_let_pattern_negative(mut vec: Vec) { + // Do not lint, different vectors + let mut vec2 = vec![0]; + if let Some(x) = vec.last() { + if *x > 2 { + vec2.pop().unwrap(); + } + } + + // Do not lint, intervening statements + if let Some(x) = vec.last() { + println!("Checking {}", x); + if *x > 2 { + vec.pop().unwrap(); + } + } + + // Do not lint, bound variable not used in condition + if let Some(_x) = vec.last() { + if vec.len() > 2 { + vec.pop().unwrap(); + } + } + + // Do not lint, value used in let binding + if let Some(x) = vec.last() { + if *x > 2 { + let _val = vec.pop().unwrap(); + } + } + + // Do not lint, else block + let _result = if let Some(x) = vec.last() { + if *x > 2 { vec.pop().unwrap() } else { 0 } + } else { + 0 + }; +} + +fn let_chain_pattern_positive(mut vec: Vec, mut deque: VecDeque) { + if let Some(x) = vec.last() //~ manual_pop_if + && *x > 2 + { + vec.pop().unwrap(); + } + + if let Some(x) = vec.last() //~ manual_pop_if + && *x > 2 + { + vec.pop().expect("element"); + } + + if let Some(x) = deque.back() //~ manual_pop_if + && *x > 2 + { + deque.pop_back().unwrap(); + } + + if let Some(x) = deque.front() //~ manual_pop_if + && *x > 2 + { + deque.pop_front().unwrap(); + } +} + +fn let_chain_pattern_negative(mut vec: Vec) { + // Do not lint, different vectors + let mut vec2 = vec![0]; + if let Some(x) = vec.last() + && *x > 2 + { + vec2.pop().unwrap(); + } + + // Do not lint, bound variable not used in condition + if let Some(_x) = vec.last() + && vec.len() > 2 + { + vec.pop().unwrap(); + } + + // Do not lint, value used in let binding + if let Some(x) = vec.last() + && *x > 2 + { + let _val = vec.pop().unwrap(); + } + + // Do not lint, value used in expression + if let Some(x) = vec.last() + && *x > 2 + { + println!("Popped: {}", vec.pop().unwrap()); + } + + // Do not lint, else block + let _result = if let Some(x) = vec.last() + && *x > 2 + { + vec.pop().unwrap() + } else { + 0 + }; +} + +fn map_unwrap_or_pattern_positive(mut vec: Vec, mut deque: VecDeque) { + if vec.last().map(|x| *x > 2).unwrap_or(false) { + //~^ manual_pop_if + vec.pop().unwrap(); + } + + if vec.last().map(|x| *x > 2).unwrap_or(false) { + //~^ manual_pop_if + vec.pop().expect("element"); + } + + if deque.back().map(|x| *x > 2).unwrap_or(false) { + //~^ manual_pop_if + deque.pop_back().unwrap(); + } + + if deque.front().map(|x| *x > 2).unwrap_or(false) { + //~^ manual_pop_if + deque.pop_front().unwrap(); + } +} + +fn map_unwrap_or_pattern_negative(mut vec: Vec) { + // Do not lint, unwrap_or(true) instead of false + if vec.last().map(|x| *x > 2).unwrap_or(true) { + vec.pop().unwrap(); + } + + // Do not lint, different vectors + let mut vec2 = vec![0]; + if vec.last().map(|x| *x > 2).unwrap_or(false) { + vec2.pop().unwrap(); + } + + // Do not lint, non-Vec type + let mut fake_vec: FakeVec = FakeVec(PhantomData); + if fake_vec.last().map(|x| *x > 2).unwrap_or(false) { + fake_vec.pop().unwrap(); + } + + // Do not lint, map returns non-boolean + if vec.last().map(|x| x + 1).unwrap_or(0) > 2 { + vec.pop().unwrap(); + } + + // Do not lint, value used in let binding + if vec.last().map(|x| *x > 2).unwrap_or(false) { + let _val = vec.pop().unwrap(); + } + + // Do not lint, else block + let _result = if vec.last().map(|x| *x > 2).unwrap_or(false) { + vec.pop().unwrap() + } else { + 0 + }; +} + +// this makes sure we do not expand vec![] in the suggestion +fn handle_macro_in_closure(mut vec: Vec>) { + if vec.last().is_some_and(|e| *e == vec![1]) { + //~^ manual_pop_if + vec.pop().unwrap(); + } +} + +#[clippy::msrv = "1.85.0"] +fn msrv_too_low_vec(mut vec: Vec) { + if vec.last().is_some_and(|x| *x > 2) { + vec.pop().unwrap(); + } +} + +#[clippy::msrv = "1.92.0"] +fn msrv_too_low_vecdeque(mut deque: VecDeque) { + if deque.back().is_some_and(|x| *x > 2) { + deque.pop_back().unwrap(); + } + + if deque.front().is_some_and(|x| *x > 2) { + deque.pop_front().unwrap(); + } +} + +#[clippy::msrv = "1.86.0"] +fn msrv_high_enough_vec(mut vec: Vec) { + if vec.last().is_some_and(|x| *x > 2) { + //~^ manual_pop_if + vec.pop().unwrap(); + } +} + +#[clippy::msrv = "1.93.0"] +fn msrv_high_enough_vecdeque(mut deque: VecDeque) { + if deque.back().is_some_and(|x| *x > 2) { + //~^ manual_pop_if + deque.pop_back().unwrap(); + } + + if deque.front().is_some_and(|x| *x > 2) { + //~^ manual_pop_if + deque.pop_front().unwrap(); + } +} diff --git a/src/tools/clippy/tests/ui/manual_pop_if.stderr b/src/tools/clippy/tests/ui/manual_pop_if.stderr new file mode 100644 index 000000000000..d57e20dc6205 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_pop_if.stderr @@ -0,0 +1,197 @@ +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:21:5 + | +LL | / if vec.last().is_some_and(|x| *x > 2) { +LL | | +LL | | vec.pop().unwrap(); +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + | + = note: `-D clippy::manual-pop-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_pop_if)]` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:26:5 + | +LL | / if vec.last().is_some_and(|x| *x > 2) { +LL | | +LL | | vec.pop().expect("element"); +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_back_if` + --> tests/ui/manual_pop_if.rs:31:5 + | +LL | / if deque.back().is_some_and(|x| *x > 2) { +LL | | +LL | | deque.pop_back().unwrap(); +LL | | } + | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_front_if` + --> tests/ui/manual_pop_if.rs:36:5 + | +LL | / if deque.front().is_some_and(|x| *x > 2) { +LL | | +LL | | deque.pop_front().unwrap(); +LL | | } + | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:82:5 + | +LL | / if let Some(x) = vec.last() { +LL | | +LL | | if *x > 2 { +LL | | vec.pop().unwrap(); +LL | | } +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:89:5 + | +LL | / if let Some(x) = vec.last() { +LL | | +LL | | if *x > 2 { +LL | | vec.pop().expect("element"); +LL | | } +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_back_if` + --> tests/ui/manual_pop_if.rs:96:5 + | +LL | / if let Some(x) = deque.back() { +LL | | +LL | | if *x > 2 { +LL | | deque.pop_back().unwrap(); +LL | | } +LL | | } + | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_front_if` + --> tests/ui/manual_pop_if.rs:103:5 + | +LL | / if let Some(x) = deque.front() { +LL | | +LL | | if *x > 2 { +LL | | deque.pop_front().unwrap(); +LL | | } +LL | | } + | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:151:5 + | +LL | / if let Some(x) = vec.last() +LL | | && *x > 2 +LL | | { +LL | | vec.pop().unwrap(); +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:157:5 + | +LL | / if let Some(x) = vec.last() +LL | | && *x > 2 +LL | | { +LL | | vec.pop().expect("element"); +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_back_if` + --> tests/ui/manual_pop_if.rs:163:5 + | +LL | / if let Some(x) = deque.back() +LL | | && *x > 2 +LL | | { +LL | | deque.pop_back().unwrap(); +LL | | } + | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_front_if` + --> tests/ui/manual_pop_if.rs:169:5 + | +LL | / if let Some(x) = deque.front() +LL | | && *x > 2 +LL | | { +LL | | deque.pop_front().unwrap(); +LL | | } + | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:217:5 + | +LL | / if vec.last().map(|x| *x > 2).unwrap_or(false) { +LL | | +LL | | vec.pop().unwrap(); +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:222:5 + | +LL | / if vec.last().map(|x| *x > 2).unwrap_or(false) { +LL | | +LL | | vec.pop().expect("element"); +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_back_if` + --> tests/ui/manual_pop_if.rs:227:5 + | +LL | / if deque.back().map(|x| *x > 2).unwrap_or(false) { +LL | | +LL | | deque.pop_back().unwrap(); +LL | | } + | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_front_if` + --> tests/ui/manual_pop_if.rs:232:5 + | +LL | / if deque.front().map(|x| *x > 2).unwrap_or(false) { +LL | | +LL | | deque.pop_front().unwrap(); +LL | | } + | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:276:5 + | +LL | / if vec.last().is_some_and(|e| *e == vec![1]) { +LL | | +LL | | vec.pop().unwrap(); +LL | | } + | |_____^ help: try: `vec.pop_if(|e| *e == vec![1]);` + +error: manual implementation of `Vec::pop_if` + --> tests/ui/manual_pop_if.rs:302:5 + | +LL | / if vec.last().is_some_and(|x| *x > 2) { +LL | | +LL | | vec.pop().unwrap(); +LL | | } + | |_____^ help: try: `vec.pop_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_back_if` + --> tests/ui/manual_pop_if.rs:310:5 + | +LL | / if deque.back().is_some_and(|x| *x > 2) { +LL | | +LL | | deque.pop_back().unwrap(); +LL | | } + | |_____^ help: try: `deque.pop_back_if(|x| *x > 2);` + +error: manual implementation of `VecDeque::pop_front_if` + --> tests/ui/manual_pop_if.rs:315:5 + | +LL | / if deque.front().is_some_and(|x| *x > 2) { +LL | | +LL | | deque.pop_front().unwrap(); +LL | | } + | |_____^ help: try: `deque.pop_front_if(|x| *x > 2);` + +error: aborting due to 20 previous errors + diff --git a/src/tools/clippy/tests/ui/match_same_arms.fixed b/src/tools/clippy/tests/ui/match_same_arms.fixed index 31684a5759fe..b0ab833c7835 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.fixed +++ b/src/tools/clippy/tests/ui/match_same_arms.fixed @@ -140,3 +140,35 @@ fn main() { _ => false, }; } + +fn issue16678() { + // ICE in Rust 1.94.0 + match true { + true => { + fn wrapper(_arg: ()) { + _arg; + } + }, + false => { + fn wrapper(_arg: ()) { + _arg; + } + }, + } +} + +fn issue16698() { + trait Foo { + const X: u8; + } + impl Foo for u8 { + const X: u8 = 2; + } + impl Foo for i8 { + const X: u8 = 2; + } + match true { + false => u8::X, + true => i8::X, + }; +} diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs index 39bee01bac22..9c7899122afb 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.rs +++ b/src/tools/clippy/tests/ui/match_same_arms.rs @@ -149,3 +149,35 @@ fn main() { _ => false, }; } + +fn issue16678() { + // ICE in Rust 1.94.0 + match true { + true => { + fn wrapper(_arg: ()) { + _arg; + } + }, + false => { + fn wrapper(_arg: ()) { + _arg; + } + }, + } +} + +fn issue16698() { + trait Foo { + const X: u8; + } + impl Foo for u8 { + const X: u8 = 2; + } + impl Foo for i8 { + const X: u8 = 2; + } + match true { + false => u8::X, + true => i8::X, + }; +} diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index 102517d34c61..e209da5c8258 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -524,3 +524,16 @@ fn issue16429(b: i32) -> Option { Some(0) } + +fn issue16654() -> Result<(), i32> { + let result = func_returning_result(); + + #[allow(clippy::collapsible_if)] + if true { + result?; + } + + _ = [{ result?; }]; + + Ok(()) +} diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index cfea1277fe76..579b51461d13 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -649,3 +649,22 @@ fn issue16429(b: i32) -> Option { Some(0) } + +fn issue16654() -> Result<(), i32> { + let result = func_returning_result(); + + #[allow(clippy::collapsible_if)] + if true { + if let Err(err) = result { + //~^ question_mark + return Err(err); + } + } + + _ = [if let Err(err) = result { + //~^ question_mark + return Err(err); + }]; + + Ok(()) +} diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index c243f12de040..1d7f665a2662 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -362,5 +362,24 @@ LL | | return None; LL | | }; | |_____^ help: replace it with: `{ a? }` -error: aborting due to 38 previous errors +error: this block may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:658:9 + | +LL | / if let Err(err) = result { +LL | | +LL | | return Err(err); +LL | | } + | |_________^ help: replace it with: `result?;` + +error: this block may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:664:10 + | +LL | _ = [if let Err(err) = result { + | __________^ +LL | | +LL | | return Err(err); +LL | | }]; + | |_____^ help: replace it with: `{ result?; }` + +error: aborting due to 40 previous errors diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed index 468f0a5b1e47..c7174881a4fa 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed @@ -7,6 +7,7 @@ clippy::double_parens )] #![warn(clippy::semicolon_inside_block)] +#![feature(try_blocks)] macro_rules! m { (()) => { @@ -106,3 +107,11 @@ pub fn issue15388() { #[rustfmt::skip] {0; 0}; } + +fn issue_try_blocks() { + // try blocks should NOT trigger semicolon_inside_block: + // moving `;` inside changes the return type (e.g. `Option` -> `Option<()>`) + // which in turn changes the type constraints on `?` operators inside the block, + // causing type errors. + try { Some(1)? }; +} diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs index 101374af2647..25be9bee4f53 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.rs +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs @@ -7,6 +7,7 @@ clippy::double_parens )] #![warn(clippy::semicolon_inside_block)] +#![feature(try_blocks)] macro_rules! m { (()) => { @@ -106,3 +107,11 @@ pub fn issue15388() { #[rustfmt::skip] {0; 0}; } + +fn issue_try_blocks() { + // try blocks should NOT trigger semicolon_inside_block: + // moving `;` inside changes the return type (e.g. `Option` -> `Option<()>`) + // which in turn changes the type constraints on `?` operators inside the block, + // causing type errors. + try { Some(1)? }; +} diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr index 2046dd1c36be..e16590374295 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr @@ -1,5 +1,5 @@ error: consider moving the `;` inside the block for consistent formatting - --> tests/ui/semicolon_inside_block.rs:39:5 + --> tests/ui/semicolon_inside_block.rs:40:5 | LL | { unit_fn_block() }; | ^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + { unit_fn_block(); } | error: consider moving the `;` inside the block for consistent formatting - --> tests/ui/semicolon_inside_block.rs:41:5 + --> tests/ui/semicolon_inside_block.rs:42:5 | LL | unsafe { unit_fn_block() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + unsafe { unit_fn_block(); } | error: consider moving the `;` inside the block for consistent formatting - --> tests/ui/semicolon_inside_block.rs:50:5 + --> tests/ui/semicolon_inside_block.rs:51:5 | LL | / { LL | | @@ -41,7 +41,7 @@ LL ~ } | error: consider moving the `;` inside the block for consistent formatting - --> tests/ui/semicolon_inside_block.rs:64:5 + --> tests/ui/semicolon_inside_block.rs:65:5 | LL | { m!(()) }; | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr index 45262ba618f2..438d3ac378e1 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics.stderr +++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> tests/ui/track-diagnostics.rs:LL:CC | LL | const S: A = B; - | ^ expected `A`, found `B` + | - ^ expected `A`, found `B` + | | + | expected because of the type of the constant | = note: -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed index 9974ee2d08eb..8d25efbeea00 100644 --- a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed @@ -3,13 +3,10 @@ clippy::let_and_return, clippy::let_unit_value, clippy::unnecessary_lazy_evaluations, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::needless_return )] -const fn identity(x: T) -> T { - x -} - const fn double_it(x: i32) -> i32 { x * 2 } @@ -18,31 +15,42 @@ fn main() { // Expected errors // Basic scenario let option = Some(()); - option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling + option.unwrap_or_else(|| ()); //~ unnecessary_option_map_or_else // Type ascription let option = Some(()); - option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling + option.unwrap_or_else(|| ()); //~ unnecessary_option_map_or_else // Auto-deref let string = String::new(); let option = Some(&string); - let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling + let _: &str = option.map_or_else(|| &string, |x| x); + // This should in theory lint with a smarter check // Temporary variable let option = Some(()); option.unwrap_or_else(|| ()); - // Identity + // Temporary variable with pattern + let option = Some(((), ())); + option.unwrap_or_else(|| ((), ())); + + // std::convert::identity let string = String::new(); let option = Some(&string); - let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling + let _: &str = option.unwrap_or_else(|| &string); //~ unnecessary_option_map_or_else - // Closure bound to a variable - let do_nothing = |x: String| x; - let string = String::new(); - let option = Some(string.clone()); - let _: String = option.unwrap_or_else(|| string); //~ ERROR: unused "map closure" when calling + let x: Option<((), ())> = Some(((), ())); + x.unwrap_or_else(|| ((), ())); + //~^ unnecessary_option_map_or_else + + // Returned temporary variable. + let x: Option<()> = Some(()); + x.unwrap_or_else(|| ()); + + // Returned temporary variable with pattern + let x: Option<((), ())> = Some(((), ())); + x.unwrap_or_else(|| ((), ())); // Correct usages let option = Some(()); diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs index 9b53f3fcd521..42d4ad6ac1f8 100644 --- a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs +++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs @@ -3,13 +3,10 @@ clippy::let_and_return, clippy::let_unit_value, clippy::unnecessary_lazy_evaluations, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::needless_return )] -const fn identity(x: T) -> T { - x -} - const fn double_it(x: i32) -> i32 { x * 2 } @@ -18,21 +15,22 @@ fn main() { // Expected errors // Basic scenario let option = Some(()); - option.map_or_else(|| (), |x| x); //~ ERROR: unused "map closure" when calling + option.map_or_else(|| (), |x| x); //~ unnecessary_option_map_or_else // Type ascription let option = Some(()); - option.map_or_else(|| (), |x: ()| x); //~ ERROR: unused "map closure" when calling + option.map_or_else(|| (), |x: ()| x); //~ unnecessary_option_map_or_else // Auto-deref let string = String::new(); let option = Some(&string); - let _: &str = option.map_or_else(|| &string, |x| x); //~ ERROR: unused "map closure" when calling + let _: &str = option.map_or_else(|| &string, |x| x); + // This should in theory lint with a smarter check // Temporary variable let option = Some(()); option.map_or_else( - //~^ ERROR: unused "map closure" when calling + //~^ unnecessary_option_map_or_else || (), |x| { let tmp = x; @@ -40,16 +38,50 @@ fn main() { }, ); - // Identity + // Temporary variable with pattern + let option = Some(((), ())); + option.map_or_else( + //~^ unnecessary_option_map_or_else + || ((), ()), + |x| { + let tmp = x; + let (a, b) = tmp; + (a, b) + }, + ); + + // std::convert::identity let string = String::new(); let option = Some(&string); - let _: &str = option.map_or_else(|| &string, identity); //~ ERROR: unused "map closure" when calling + let _: &str = option.map_or_else(|| &string, std::convert::identity); //~ unnecessary_option_map_or_else - // Closure bound to a variable - let do_nothing = |x: String| x; - let string = String::new(); - let option = Some(string.clone()); - let _: String = option.map_or_else(|| string, do_nothing); //~ ERROR: unused "map closure" when calling + let x: Option<((), ())> = Some(((), ())); + x.map_or_else(|| ((), ()), |(a, b)| (a, b)); + //~^ unnecessary_option_map_or_else + + // Returned temporary variable. + let x: Option<()> = Some(()); + x.map_or_else( + //~^ unnecessary_option_map_or_else + || (), + |n| { + let tmp = n; + let tmp2 = tmp; + return tmp2; + }, + ); + + // Returned temporary variable with pattern + let x: Option<((), ())> = Some(((), ())); + x.map_or_else( + //~^ unnecessary_option_map_or_else + || ((), ()), + |n| { + let tmp = n; + let (a, b) = tmp; + return (a, b); + }, + ); // Correct usages let option = Some(()); diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr index d90875e4efc7..3b579ebdb289 100644 --- a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr @@ -1,26 +1,31 @@ error: unused "map closure" when calling `Option::map_or_else` value - --> tests/ui/unnecessary_option_map_or_else.rs:21:5 + --> tests/ui/unnecessary_option_map_or_else.rs:18:5 | LL | option.map_or_else(|| (), |x| x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-option-map-or-else` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_option_map_or_else)]` +help: consider using `unwrap_or_else` + | +LL - option.map_or_else(|| (), |x| x); +LL + option.unwrap_or_else(|| ()); + | error: unused "map closure" when calling `Option::map_or_else` value - --> tests/ui/unnecessary_option_map_or_else.rs:25:5 + --> tests/ui/unnecessary_option_map_or_else.rs:22:5 | LL | option.map_or_else(|| (), |x: ()| x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())` - -error: unused "map closure" when calling `Option::map_or_else` value - --> tests/ui/unnecessary_option_map_or_else.rs:30:19 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `unwrap_or_else` + | +LL - option.map_or_else(|| (), |x: ()| x); +LL + option.unwrap_or_else(|| ()); | -LL | let _: &str = option.map_or_else(|| &string, |x| x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)` error: unused "map closure" when calling `Option::map_or_else` value - --> tests/ui/unnecessary_option_map_or_else.rs:34:5 + --> tests/ui/unnecessary_option_map_or_else.rs:32:5 | LL | / option.map_or_else( LL | | @@ -29,19 +34,122 @@ LL | | |x| { ... | LL | | }, LL | | ); - | |_____^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())` + | |_____^ + | +help: consider using `unwrap_or_else` + | +LL - option.map_or_else( +LL - +LL - || (), +LL - |x| { +LL - let tmp = x; +LL - tmp +LL - }, +LL - ); +LL + option.unwrap_or_else(|| ()); + | error: unused "map closure" when calling `Option::map_or_else` value - --> tests/ui/unnecessary_option_map_or_else.rs:46:19 + --> tests/ui/unnecessary_option_map_or_else.rs:43:5 + | +LL | / option.map_or_else( +LL | | +LL | | || ((), ()), +LL | | |x| { +... | +LL | | }, +LL | | ); + | |_____^ + | +help: consider using `unwrap_or_else` + | +LL - option.map_or_else( +LL - +LL - || ((), ()), +LL - |x| { +LL - let tmp = x; +LL - let (a, b) = tmp; +LL - (a, b) +LL - }, +LL - ); +LL + option.unwrap_or_else(|| ((), ())); | -LL | let _: &str = option.map_or_else(|| &string, identity); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)` error: unused "map closure" when calling `Option::map_or_else` value - --> tests/ui/unnecessary_option_map_or_else.rs:52:21 + --> tests/ui/unnecessary_option_map_or_else.rs:56:19 + | +LL | let _: &str = option.map_or_else(|| &string, std::convert::identity); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `unwrap_or_else` + | +LL - let _: &str = option.map_or_else(|| &string, std::convert::identity); +LL + let _: &str = option.unwrap_or_else(|| &string); | -LL | let _: String = option.map_or_else(|| string, do_nothing); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| string)` -error: aborting due to 6 previous errors +error: unused "map closure" when calling `Option::map_or_else` value + --> tests/ui/unnecessary_option_map_or_else.rs:59:5 + | +LL | x.map_or_else(|| ((), ()), |(a, b)| (a, b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else(|| ((), ()), |(a, b)| (a, b)); +LL + x.unwrap_or_else(|| ((), ())); + | + +error: unused "map closure" when calling `Option::map_or_else` value + --> tests/ui/unnecessary_option_map_or_else.rs:64:5 + | +LL | / x.map_or_else( +LL | | +LL | | || (), +LL | | |n| { +... | +LL | | }, +LL | | ); + | |_____^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else( +LL - +LL - || (), +LL - |n| { +LL - let tmp = n; +LL - let tmp2 = tmp; +LL - return tmp2; +LL - }, +LL - ); +LL + x.unwrap_or_else(|| ()); + | + +error: unused "map closure" when calling `Option::map_or_else` value + --> tests/ui/unnecessary_option_map_or_else.rs:76:5 + | +LL | / x.map_or_else( +LL | | +LL | | || ((), ()), +LL | | |n| { +... | +LL | | }, +LL | | ); + | |_____^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else( +LL - +LL - || ((), ()), +LL - |n| { +LL - let tmp = n; +LL - let (a, b) = tmp; +LL - return (a, b); +LL - }, +LL - ); +LL + x.unwrap_or_else(|| ((), ())); + | + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed index 5d7e3fa355fd..55542519bdb7 100644 --- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed @@ -1,5 +1,10 @@ #![warn(clippy::unnecessary_result_map_or_else)] -#![allow(clippy::unnecessary_literal_unwrap, clippy::let_and_return, clippy::let_unit_value)] +#![allow( + clippy::unnecessary_literal_unwrap, + clippy::let_and_return, + clippy::let_unit_value, + clippy::needless_return +)] fn main() { let x: Result<(), ()> = Ok(()); @@ -14,13 +19,17 @@ fn main() { // Auto-deref. let y = String::new(); let x: Result<&String, &String> = Ok(&y); - let y: &str = x.unwrap_or_else(|err| err); - //~^ unnecessary_result_map_or_else + let y: &str = x.map_or_else(|err| err, |n| n); + // This should lint with a smarter check // Temporary variable. let x: Result<(), ()> = Ok(()); x.unwrap_or_else(|err| err); + // Temporary variable with pattern + let x: Result<((), ()), ((), ())> = Ok(((), ())); + x.unwrap_or_else(|err| err); + // Should not warn. let x: Result = Ok(0); x.map_or_else(|err| err, |n| n + 1); @@ -61,4 +70,16 @@ fn main() { y }, ); + + let x: Result<((), ()), ((), ())> = Ok(((), ())); + x.unwrap_or_else(|err| err); + //~^ unnecessary_result_map_or_else + + // Returned temporary variable. + let x: Result<(), ()> = Ok(()); + x.unwrap_or_else(|err| err); + + // Returned temporary variable with pattern + let x: Result<((), ()), ((), ())> = Ok(((), ())); + x.unwrap_or_else(|err| err); } diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs index d2bab0f9d9c1..21a4826911e5 100644 --- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs +++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs @@ -1,5 +1,10 @@ #![warn(clippy::unnecessary_result_map_or_else)] -#![allow(clippy::unnecessary_literal_unwrap, clippy::let_and_return, clippy::let_unit_value)] +#![allow( + clippy::unnecessary_literal_unwrap, + clippy::let_and_return, + clippy::let_unit_value, + clippy::needless_return +)] fn main() { let x: Result<(), ()> = Ok(()); @@ -15,7 +20,7 @@ fn main() { let y = String::new(); let x: Result<&String, &String> = Ok(&y); let y: &str = x.map_or_else(|err| err, |n| n); - //~^ unnecessary_result_map_or_else + // This should lint with a smarter check // Temporary variable. let x: Result<(), ()> = Ok(()); @@ -29,6 +34,18 @@ fn main() { }, ); + // Temporary variable with pattern + let x: Result<((), ()), ((), ())> = Ok(((), ())); + x.map_or_else( + //~^ unnecessary_result_map_or_else + |err| err, + |n| { + let tmp = n; + let (a, b) = tmp; + (a, b) + }, + ); + // Should not warn. let x: Result = Ok(0); x.map_or_else(|err| err, |n| n + 1); @@ -69,4 +86,32 @@ fn main() { y }, ); + + let x: Result<((), ()), ((), ())> = Ok(((), ())); + x.map_or_else(|err| err, |(a, b)| (a, b)); + //~^ unnecessary_result_map_or_else + + // Returned temporary variable. + let x: Result<(), ()> = Ok(()); + x.map_or_else( + //~^ unnecessary_result_map_or_else + |err| err, + |n| { + let tmp = n; + let tmp2 = tmp; + return tmp2; + }, + ); + + // Returned temporary variable with pattern + let x: Result<((), ()), ((), ())> = Ok(((), ())); + x.map_or_else( + //~^ unnecessary_result_map_or_else + |err| err, + |n| { + let tmp = n; + let (a, b) = tmp; + return (a, b); + }, + ); } diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr index e6afa50217cc..f76999127c64 100644 --- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr @@ -1,26 +1,31 @@ -error: unused "map closure" when calling `Result::map_or_else` value - --> tests/ui/unnecessary_result_map_or_else.rs:6:5 - | -LL | x.map_or_else(|err| err, |n| n); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)` - | - = note: `-D clippy::unnecessary-result-map-or-else` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::unnecessary_result_map_or_else)]` - error: unused "map closure" when calling `Result::map_or_else` value --> tests/ui/unnecessary_result_map_or_else.rs:11:5 | -LL | x.map_or_else(|err: ()| err, |n: ()| n); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err: ()| err)` - -error: unused "map closure" when calling `Result::map_or_else` value - --> tests/ui/unnecessary_result_map_or_else.rs:17:19 +LL | x.map_or_else(|err| err, |n| n); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unnecessary-result-map-or-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_result_map_or_else)]` +help: consider using `unwrap_or_else` + | +LL - x.map_or_else(|err| err, |n| n); +LL + x.unwrap_or_else(|err| err); | -LL | let y: &str = x.map_or_else(|err| err, |n| n); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)` error: unused "map closure" when calling `Result::map_or_else` value - --> tests/ui/unnecessary_result_map_or_else.rs:22:5 + --> tests/ui/unnecessary_result_map_or_else.rs:16:5 + | +LL | x.map_or_else(|err: ()| err, |n: ()| n); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else(|err: ()| err, |n: ()| n); +LL + x.unwrap_or_else(|err: ()| err); + | + +error: unused "map closure" when calling `Result::map_or_else` value + --> tests/ui/unnecessary_result_map_or_else.rs:27:5 | LL | / x.map_or_else( LL | | @@ -29,7 +34,111 @@ LL | | |n| { ... | LL | | }, LL | | ); - | |_____^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)` + | |_____^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else( +LL - +LL - |err| err, +LL - |n| { +LL - let tmp = n; +LL - let tmp2 = tmp; +LL - tmp2 +LL - }, +LL - ); +LL + x.unwrap_or_else(|err| err); + | -error: aborting due to 4 previous errors +error: unused "map closure" when calling `Result::map_or_else` value + --> tests/ui/unnecessary_result_map_or_else.rs:39:5 + | +LL | / x.map_or_else( +LL | | +LL | | |err| err, +LL | | |n| { +... | +LL | | }, +LL | | ); + | |_____^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else( +LL - +LL - |err| err, +LL - |n| { +LL - let tmp = n; +LL - let (a, b) = tmp; +LL - (a, b) +LL - }, +LL - ); +LL + x.unwrap_or_else(|err| err); + | + +error: unused "map closure" when calling `Result::map_or_else` value + --> tests/ui/unnecessary_result_map_or_else.rs:91:5 + | +LL | x.map_or_else(|err| err, |(a, b)| (a, b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else(|err| err, |(a, b)| (a, b)); +LL + x.unwrap_or_else(|err| err); + | + +error: unused "map closure" when calling `Result::map_or_else` value + --> tests/ui/unnecessary_result_map_or_else.rs:96:5 + | +LL | / x.map_or_else( +LL | | +LL | | |err| err, +LL | | |n| { +... | +LL | | }, +LL | | ); + | |_____^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else( +LL - +LL - |err| err, +LL - |n| { +LL - let tmp = n; +LL - let tmp2 = tmp; +LL - return tmp2; +LL - }, +LL - ); +LL + x.unwrap_or_else(|err| err); + | + +error: unused "map closure" when calling `Result::map_or_else` value + --> tests/ui/unnecessary_result_map_or_else.rs:108:5 + | +LL | / x.map_or_else( +LL | | +LL | | |err| err, +LL | | |n| { +... | +LL | | }, +LL | | ); + | |_____^ + | +help: consider using `unwrap_or_else` + | +LL - x.map_or_else( +LL - +LL - |err| err, +LL - |n| { +LL - let tmp = n; +LL - let (a, b) = tmp; +LL - return (a, b); +LL - }, +LL - ); +LL + x.unwrap_or_else(|err| err); + | + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs index d82a7b969080..75e8315343d3 100644 --- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs +++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs @@ -100,3 +100,13 @@ pub fn point_to_five() -> *const u8 { } fn main() {} + +mod issue16553 { + //! ``` + //! // SAFETY: All is well. + //! unsafe { + //! foo() + //! } + //! ``` + mod blah {} +} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed index 2c794463457f..852c4ddcfd71 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed @@ -23,6 +23,6 @@ fn main() { //~^ unnested_or_patterns if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} //~^ unnested_or_patterns - if let box box (0 | 2 | 4) = Box::new(Box::new(0)) {} + if let box (box (0 | 2 | 4)) = Box::new(Box::new(0)) {} //~^ unnested_or_patterns } diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr index 3fc8fa174c93..3deef33cf258 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr @@ -93,7 +93,7 @@ LL | if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {} help: nest the patterns | LL - if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {} -LL + if let box box (0 | 2 | 4) = Box::new(Box::new(0)) {} +LL + if let box (box (0 | 2 | 4)) = Box::new(Box::new(0)) {} | error: aborting due to 8 previous errors diff --git a/src/tools/clippy/util/gh-pages/index_template.html b/src/tools/clippy/util/gh-pages/index_template.html index 91a5c1263195..26ca901fcd22 100644 --- a/src/tools/clippy/util/gh-pages/index_template.html +++ b/src/tools/clippy/util/gh-pages/index_template.html @@ -174,13 +174,13 @@ Otherwise, have a great day =^.^=

{# #}
{# #} {{lint.id ~}} - {#+ #} - {# #} + {#+ #} + {# #} 📋 {# #} {# #}
{# #} - {{lint.group}} {#+ #} + {{lint.group}} {#+ #} {{lint.level}} {#+ #} @@ -194,24 +194,20 @@ Otherwise, have a great day =^.^= {# Applicability #}
{# #} Applicability: {#+ #} - {{ lint.applicability_str() }} {# #} + {{ lint.applicability_str() }} {# #} (?) {# #}
{# Clippy version #}
{# #} {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif +%} in: {#+ #} - {{lint.version}} {# #} + {{lint.version}} {# #}
{# Open related issues #} -
{# #} - Related Issues {# #} -
+ Related Issues {# Jump to source #} {% if let Some(id_location) = lint.id_location %} -
{# #} - View Source {# #} -
+ View Source {% endif %} {# #} {# #} diff --git a/src/tools/clippy/util/gh-pages/style.css b/src/tools/clippy/util/gh-pages/style.css index ce478a3e18d0..4f1935ba972f 100644 --- a/src/tools/clippy/util/gh-pages/style.css +++ b/src/tools/clippy/util/gh-pages/style.css @@ -1,5 +1,6 @@ body { --icon-filter: initial; + --label-background: #777; } body.ayu { @@ -230,7 +231,10 @@ button .caret { .panel-title-name { flex: 1; min-width: 400px;} -.panel-title-name .anchor { display: none; } +.panel-title-name .anchor { + display: none; + background-color: var(--label-background); +} article:hover .panel-title-name .anchor { display: inline;} .search-control { @@ -397,10 +401,6 @@ article:hover .panel-title-name .anchor { display: inline;} text-decoration: none; } -.label-default { - background-color: #777; -} - .lint-level { min-width: 4em; } @@ -420,6 +420,7 @@ article:hover .panel-title-name .anchor { display: inline;} .lint-group { min-width: 8em; + background-color: var(--label-background); } .group-deprecated { opacity: 0.5; @@ -459,7 +460,7 @@ article:hover .panel-title-name .anchor { display: inline;} display: flex; flex-flow: column; } - .lint-additional-info > div + div { + .lint-additional-info > * + * { border-top: 1px solid var(--theme-popup-border); } } @@ -468,12 +469,12 @@ article:hover .panel-title-name .anchor { display: inline;} display: flex; flex-flow: row; } - .lint-additional-info > div + div { + .lint-additional-info > * + * { border-left: 1px solid var(--theme-popup-border); } } -.lint-additional-info > div { +.lint-additional-info > * { display: inline-flex; min-width: 200px; flex-grow: 1; diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 54c0f2ec7430..7cac7f5c0494 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -168,6 +168,7 @@ pub enum Sanitizer { Dataflow, Kcfi, KernelAddress, + KernelHwaddress, Leak, Memory, Memtag, @@ -721,9 +722,17 @@ pub struct Config { /// /// This is forwarded from bootstrap's `jobs` configuration. pub jobs: u32, + + /// Number of parallel threads to use for the frontend when building test artifacts. + pub parallel_frontend_threads: u32, + /// Number of times to execute each test. + pub iteration_count: u32, } impl Config { + pub const DEFAULT_PARALLEL_FRONTEND_THREADS: u32 = 1; + pub const DEFAULT_ITERATION_COUNT: u32 = 1; + /// FIXME: this run scheme is... confusing. pub fn run_enabled(&self) -> bool { self.run.unwrap_or_else(|| { @@ -834,6 +843,17 @@ pub fn has_subprocess_support(&self) -> bool { || self.target_cfg().os == "emscripten"; !unsupported_target } + + /// Whether the parallel frontend is enabled, + /// which is the case when `parallel_frontend_threads` is not set to `1`. + /// + /// - `0` means auto-detect: use the number of available hardware threads on the host. + /// But we treat it as the parallel frontend being enabled in this case. + /// - `1` means single-threaded (parallel frontend disabled). + /// - `>1` means an explicitly configured thread count. + pub fn parallel_frontend_enabled(&self) -> bool { + self.parallel_frontend_threads != 1 + } } /// Known widths of `target_has_atomic`. diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 462d9ae626b0..b6a9a5b1b9f5 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -67,7 +67,7 @@ pub(crate) fn from_file_directives( let mut props = EarlyProps::default(); iter_directives( - config.mode, + config, file_directives, // (dummy comment to force args into vertical layout) &mut |ln: &DirectiveLine<'_>| { @@ -362,7 +362,7 @@ fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config let file_directives = FileDirectives::from_file_contents(testfile, &file_contents); iter_directives( - config.mode, + config, &file_directives, // (dummy comment to force args into vertical layout) &mut |ln: &DirectiveLine<'_>| { @@ -574,43 +574,51 @@ fn check_directive<'a>( } fn iter_directives( - mode: TestMode, + config: &Config, file_directives: &FileDirectives<'_>, it: &mut dyn FnMut(&DirectiveLine<'_>), ) { let testfile = file_directives.path; - // Coverage tests in coverage-run mode always have these extra directives, without needing to - // specify them manually in every test file. - // - // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later. - if mode == TestMode::CoverageRun { - let extra_directives: &[&str] = &[ - "//@ needs-profiler-runtime", - // FIXME(pietroalbini): this test currently does not work on cross-compiled targets - // because remote-test is not capable of sending back the *.profraw files generated by - // the LLVM instrumentation. - "//@ ignore-cross-compile", - ]; - // Process the extra implied directives, with a dummy line number of 0. - for directive_str in extra_directives { - let directive_line = line_directive(testfile, LineNumber::ZERO, directive_str) - .unwrap_or_else(|| panic!("bad extra-directive line: {directive_str:?}")); - it(&directive_line); + let extra_directives = match config.mode { + TestMode::CoverageRun => { + // Coverage tests in coverage-run mode always have these extra directives, without needing to + // specify them manually in every test file. + // + // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later. + vec![ + "//@ needs-profiler-runtime", + // FIXME(pietroalbini): this test currently does not work on cross-compiled targets + // because remote-test is not capable of sending back the *.profraw files generated by + // the LLVM instrumentation. + "//@ ignore-cross-compile", + ] + } + TestMode::Codegen if !file_directives.has_explicit_no_std_core_attribute => { + // Note: affects all codegen test suites under test mode `codegen`, e.g. `codegen-llvm`. + // + // Codegen tests automatically receive implied `//@ needs-target-std`, unless + // `#![no_std]`/`#![no_core]` attribute was explicitly seen. The rationale is basically to avoid + // having to manually maintain a bunch of `//@ needs-target-std` directives esp. for targets + // tested/built out-of-tree. + vec!["//@ needs-target-std"] + } + TestMode::Ui if config.parallel_frontend_enabled() => { + // UI tests in parallel-frontend mode always have this extra directive, without needing to + // specify it manually in every test file. + vec!["//@ compare-output-by-lines"] } - } - // Note: affects all codegen test suites under test mode `codegen`, e.g. `codegen-llvm`. - // - // Codegen tests automatically receive implied `//@ needs-target-std`, unless - // `#![no_std]`/`#![no_core]` attribute was explicitly seen. The rationale is basically to avoid - // having to manually maintain a bunch of `//@ needs-target-std` directives esp. for targets - // tested/built out-of-tree. - if mode == TestMode::Codegen && !file_directives.has_explicit_no_std_core_attribute { - let implied_needs_target_std_line = - line_directive(testfile, LineNumber::ZERO, "//@ needs-target-std") - .expect("valid `needs-target-std` directive line"); - it(&implied_needs_target_std_line); + _ => { + // No extra directives for other test modes. + vec![] + } + }; + + for directive_str in extra_directives { + let directive_line = line_directive(testfile, LineNumber::ZERO, directive_str) + .unwrap_or_else(|| panic!("bad extra-directive line: {directive_str:?}")); + it(&directive_line); } for directive_line in &file_directives.lines { @@ -951,55 +959,52 @@ pub(crate) fn make_test_description( let mut should_fail = false; // Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives. - iter_directives( - config.mode, - file_directives, - &mut |ln @ &DirectiveLine { line_number, .. }| { - if !ln.applies_to_test_revision(test_revision) { - return; - } + iter_directives(config, file_directives, &mut |ln @ &DirectiveLine { line_number, .. }| { + if !ln.applies_to_test_revision(test_revision) { + return; + } - // Parse `aux-*` directives, for use by up-to-date checks. - parse_and_update_aux(config, ln, aux_props); + // Parse `aux-*` directives, for use by up-to-date checks. + parse_and_update_aux(config, ln, aux_props); - macro_rules! decision { - ($e:expr) => { - match $e { - IgnoreDecision::Ignore { reason } => { - ignore = true; - ignore_message = Some(reason.into()); - } - IgnoreDecision::Error { message } => { - error!("{path}:{line_number}: {message}"); - *poisoned = true; - return; - } - IgnoreDecision::Continue => {} + macro_rules! decision { + ($e:expr) => { + match $e { + IgnoreDecision::Ignore { reason } => { + ignore = true; + ignore_message = Some(reason.into()); } - }; - } + IgnoreDecision::Error { message } => { + error!("{path}:{line_number}: {message}"); + *poisoned = true; + return; + } + IgnoreDecision::Continue => {} + } + }; + } - decision!(cfg::handle_ignore(&cache.cfg_conditions, ln)); - decision!(cfg::handle_only(&cache.cfg_conditions, ln)); - decision!(needs::handle_needs(&cache.needs, config, ln)); - decision!(ignore_llvm(config, ln)); - decision!(ignore_backends(config, ln)); - decision!(needs_backends(config, ln)); - decision!(ignore_cdb(config, ln)); - decision!(ignore_gdb(config, ln)); - decision!(ignore_lldb(config, ln)); + decision!(cfg::handle_ignore(&cache.cfg_conditions, ln)); + decision!(cfg::handle_only(&cache.cfg_conditions, ln)); + decision!(needs::handle_needs(&cache.needs, config, ln)); + decision!(ignore_llvm(config, ln)); + decision!(ignore_backends(config, ln)); + decision!(needs_backends(config, ln)); + decision!(ignore_cdb(config, ln)); + decision!(ignore_gdb(config, ln)); + decision!(ignore_lldb(config, ln)); + decision!(ignore_parallel_frontend(config, ln)); - if config.target == "wasm32-unknown-unknown" - && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) - { - decision!(IgnoreDecision::Ignore { - reason: "ignored on WASM as the run results cannot be checked there".into(), - }); - } + if config.target == "wasm32-unknown-unknown" + && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) + { + decision!(IgnoreDecision::Ignore { + reason: "ignored on WASM as the run results cannot be checked there".into(), + }); + } - should_fail |= config.parse_name_directive(ln, "should-fail"); - }, - ); + should_fail |= config.parse_name_directive(ln, "should-fail"); + }); // The `should-fail` annotation doesn't apply to pretty tests, // since we run the pretty printer across all tests by default. @@ -1270,6 +1275,17 @@ fn ignore_llvm(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { IgnoreDecision::Continue } +fn ignore_parallel_frontend(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { + if config.parallel_frontend_enabled() + && config.parse_name_directive(line, "ignore-parallel-frontend") + { + return IgnoreDecision::Ignore { + reason: "ignored when the parallel frontend is enabled".into(), + }; + } + IgnoreDecision::Continue +} + enum IgnoreDecision { Ignore { reason: String }, Continue, diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 6431eb6b090b..2587acb7fe10 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -11,6 +11,7 @@ "ignore-backends", "ignore-gdb-version", "ignore-llvm-version", + "ignore-parallel-frontend", "ignore-pass", // tidy-alphabetical-end ]; diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index d2a71a42e076..5421a9720173 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -101,10 +101,12 @@ "ignore-nvptx64", "ignore-nvptx64-nvidia-cuda", "ignore-openbsd", + "ignore-parallel-frontend", "ignore-pass", "ignore-powerpc", "ignore-powerpc64", "ignore-remote", + "ignore-riscv32", "ignore-riscv64", "ignore-rustc-debug-assertions", "ignore-rustc_abi-x86-sse2", @@ -175,7 +177,9 @@ "needs-sanitizer-cfi", "needs-sanitizer-dataflow", "needs-sanitizer-hwaddress", + "needs-sanitizer-kasan", "needs-sanitizer-kcfi", + "needs-sanitizer-khwasan", "needs-sanitizer-leak", "needs-sanitizer-memory", "needs-sanitizer-memtag", @@ -210,6 +214,7 @@ "only-apple", "only-arm", "only-arm64ec", + "only-armv7-unknown-linux-gnueabihf", "only-avr", "only-beta", "only-bpf", diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index 168d5e9eb649..e9f3d6c28d6e 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -46,6 +46,11 @@ pub(super) fn handle_needs( condition: cache.sanitizer_kasan, ignore_reason: "ignored on targets without kernel address sanitizer", }, + Need { + name: "needs-sanitizer-khwasan", + condition: cache.sanitizer_khwasan, + ignore_reason: "ignored on targets without kernel hardware-assisted address sanitizer", + }, Need { name: "needs-sanitizer-leak", condition: cache.sanitizer_leak, @@ -332,6 +337,7 @@ pub(super) struct CachedNeedsConditions { sanitizer_dataflow: bool, sanitizer_kcfi: bool, sanitizer_kasan: bool, + sanitizer_khwasan: bool, sanitizer_leak: bool, sanitizer_memory: bool, sanitizer_thread: bool, @@ -359,6 +365,7 @@ pub(super) fn load(config: &Config) -> Self { sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow), sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi), sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress), + sanitizer_khwasan: sanitizers.contains(&Sanitizer::KernelHwaddress), sanitizer_leak: sanitizers.contains(&Sanitizer::Leak), sanitizer_memory: sanitizers.contains(&Sanitizer::Memory), sanitizer_thread: sanitizers.contains(&Sanitizer::Thread), diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 82e8a0da6b60..6dae2ca0b475 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -219,7 +219,14 @@ fn parse_config(args: Vec) -> Config { "CODEGEN BACKEND [NAME | PATH]", ) .optflag("", "bypass-ignore-backends", "ignore `//@ ignore-backends` directives") - .reqopt("", "jobs", "number of parallel jobs bootstrap was configured with", "JOBS"); + .reqopt("", "jobs", "number of parallel jobs bootstrap was configured with", "JOBS") + .optopt( + "", + "parallel-frontend-threads", + "number of parallel threads to use for the frontend when building test artifacts", + "THREADS_COUNT", + ) + .optopt("", "iteration-count", "number of times to execute each test", "COUNT"); let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { @@ -369,6 +376,20 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { None => panic!("`--jobs` is required"), }; + let parallel_frontend_threads = match matches.opt_str("parallel-frontend-threads") { + Some(threads) => { + threads.parse::().expect("expected `--parallel-frontend-threads` to be an `u32`") + } + None => Config::DEFAULT_PARALLEL_FRONTEND_THREADS, + }; + let iteration_count = match matches.opt_str("iteration-count") { + Some(count) => { + count.parse::().expect("expected `--iteration-count` to be a positive integer") + } + None => Config::DEFAULT_ITERATION_COUNT, + }; + assert!(iteration_count > 0, "`--iteration-count` must be a positive integer"); + Config { bless: matches.opt_present("bless"), fail_fast: matches.opt_present("fail-fast") @@ -489,6 +510,9 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf { bypass_ignore_backends: matches.opt_present("bypass-ignore-backends"), jobs, + + parallel_frontend_threads, + iteration_count, } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index fce3269b149a..da4ec440bb44 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -272,22 +272,26 @@ fn run_revision(&self) { { self.fatal("cannot use should-ice in a test that is not cfail"); } - match self.config.mode { - TestMode::Pretty => self.run_pretty_test(), - TestMode::DebugInfo => self.run_debuginfo_test(), - TestMode::Codegen => self.run_codegen_test(), - TestMode::RustdocHtml => self.run_rustdoc_html_test(), - TestMode::RustdocJson => self.run_rustdoc_json_test(), - TestMode::CodegenUnits => self.run_codegen_units_test(), - TestMode::Incremental => self.run_incremental_test(), - TestMode::RunMake => self.run_rmake_test(), - TestMode::Ui => self.run_ui_test(), - TestMode::MirOpt => self.run_mir_opt_test(), - TestMode::Assembly => self.run_assembly_test(), - TestMode::RustdocJs => self.run_rustdoc_js_test(), - TestMode::CoverageMap => self.run_coverage_map_test(), // see self::coverage - TestMode::CoverageRun => self.run_coverage_run_test(), // see self::coverage - TestMode::Crashes => self.run_crash_test(), + // Run the test multiple times if requested. + // This is useful for catching flaky tests under the parallel frontend. + for _ in 0..self.config.iteration_count { + match self.config.mode { + TestMode::Pretty => self.run_pretty_test(), + TestMode::DebugInfo => self.run_debuginfo_test(), + TestMode::Codegen => self.run_codegen_test(), + TestMode::RustdocHtml => self.run_rustdoc_html_test(), + TestMode::RustdocJson => self.run_rustdoc_json_test(), + TestMode::CodegenUnits => self.run_codegen_units_test(), + TestMode::Incremental => self.run_incremental_test(), + TestMode::RunMake => self.run_rmake_test(), + TestMode::Ui => self.run_ui_test(), + TestMode::MirOpt => self.run_mir_opt_test(), + TestMode::Assembly => self.run_assembly_test(), + TestMode::RustdocJs => self.run_rustdoc_js_test(), + TestMode::CoverageMap => self.run_coverage_map_test(), // see self::coverage + TestMode::CoverageRun => self.run_coverage_run_test(), // see self::coverage + TestMode::Crashes => self.run_crash_test(), + } } } @@ -1752,6 +1756,14 @@ fn make_compile_args( compiler.arg("-Zwrite-long-types-to-disk=no"); // FIXME: use this for other modes too, for perf? compiler.arg("-Cstrip=debuginfo"); + + if self.config.parallel_frontend_enabled() { + // Currently, we only use multiple threads for the UI test suite, + // because UI tests can effectively verify the parallel frontend and + // require minimal modification. The option will later be extended to + // other test suites. + compiler.arg(&format!("-Zthreads={}", self.config.parallel_frontend_threads)); + } } TestMode::MirOpt => { // We check passes under test to minimize the mir-opt test dump @@ -1907,8 +1919,9 @@ fn make_compile_args( compiler.args(&["-A", "unused", "-W", "unused_attributes"]); } - // Allow tests to use internal features. + // Allow tests to use internal and incomplete features. compiler.args(&["-A", "internal_features"]); + compiler.args(&["-A", "incomplete_features"]); // Allow tests to have unused parens and braces. // Add #![deny(unused_parens, unused_braces)] to the test file if you want to @@ -2109,7 +2122,7 @@ fn output_base_name(&self) -> Utf8PathBuf { } /// Prints a message to (captured) stdout if `config.verbose` is true. - /// The message is also logged to `tracing::debug!` regardles of verbosity. + /// The message is also logged to `tracing::debug!` regardless of verbosity. /// /// Use `format_args!` as the argument to perform formatting if required. fn logv(&self, message: impl fmt::Display) { @@ -2718,29 +2731,41 @@ fn compare_output( // Wrapper tools set by `runner` might provide extra output on failure, // for example a WebAssembly runtime might print the stack trace of an // `unreachable` instruction by default. - // + let compare_output_by_lines_subset = self.config.runner.is_some(); + // Also, some tests like `ui/parallel-rustc` have non-deterministic // orders of output, so we need to compare by lines. - let compare_output_by_lines = - self.props.compare_output_by_lines || self.config.runner.is_some(); + let compare_output_by_lines = self.props.compare_output_by_lines; let tmp; - let (expected, actual): (&str, &str) = if compare_output_by_lines { + let (expected, actual): (&str, &str) = if compare_output_by_lines_subset { let actual_lines: HashSet<_> = actual.lines().collect(); let expected_lines: Vec<_> = expected.lines().collect(); let mut used = expected_lines.clone(); used.retain(|line| actual_lines.contains(line)); + // check if `expected` contains a subset of the lines of `actual` if used.len() == expected_lines.len() && (expected.is_empty() == actual.is_empty()) { return CompareOutcome::Same; } if expected_lines.is_empty() { - // if we have no lines to check, force a full overwite + // if we have no lines to check, force a full overwrite ("", actual) } else { + // this prints/blesses the subset, not the actual tmp = (expected_lines.join("\n"), used.join("\n")); (&tmp.0, &tmp.1) } + } else if compare_output_by_lines { + let mut actual_lines: Vec<&str> = actual.lines().collect(); + let mut expected_lines: Vec<&str> = expected.lines().collect(); + actual_lines.sort_unstable(); + expected_lines.sort_unstable(); + if actual_lines == expected_lines { + return CompareOutcome::Same; + } else { + (expected, actual) + } } else { (expected, actual) }; diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 9d6edaddc1b7..8dfac2e3abb2 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -191,7 +191,7 @@ fn run_debuginfo_gdb_test(&self) { let mut stdout = BufReader::new(adb.stdout.take().unwrap()); let mut line = String::new(); loop { - line.truncate(0); + line.clear(); stdout.read_line(&mut line).unwrap(); if line.starts_with("Listening on port 5039") { break; @@ -310,12 +310,7 @@ fn run_debuginfo_gdb_test(&self) { let mut gdb = Command::new(self.config.gdb.as_ref().unwrap()); - // FIXME: we are propagating `PYTHONPATH` from the environment, not a compiletest flag! - let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { - format!("{pp}:{rust_pp_module_abs_path}") - } else { - rust_pp_module_abs_path.to_string() - }; + let pythonpath = with_pythonpath_prepended(&rust_pp_module_abs_path); gdb.args(debugger_opts).env("PYTHONPATH", pythonpath); debugger_run_result = @@ -458,7 +453,8 @@ fn run_lldb( debugger_script: &Utf8Path, ) -> ProcRes { // Path containing `lldb_batchmode.py`, so that the `script` command can import it. - let pythonpath = self.config.src_root.join("src/etc"); + let rust_pp_module_abs_path = self.config.src_root.join("src/etc"); + let pythonpath = with_pythonpath_prepended(&rust_pp_module_abs_path); let mut cmd = Command::new(lldb); cmd.arg("--one-line") @@ -471,3 +467,12 @@ fn run_lldb( self.run_command_to_procres(&mut cmd) } } + +fn with_pythonpath_prepended(some_path: &Utf8Path) -> String { + // FIXME: we are propagating `PYTHONPATH` from the environment, not a compiletest flag! + if let Ok(pp) = std::env::var("PYTHONPATH") { + format!("{pp}:{some_path}") + } else { + some_path.to_string() + } +} diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index 89e9f3168837..d6afb77c2e8d 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -14,6 +14,11 @@ pub(super) fn run_rustdoc_json_test(&self) { }); let proc_res = self.document(&out_dir, DocKind::Json); + + if !self.config.capture { + writeln!(self.stdout, "{}", proc_res.format_info()); + } + if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index f02918ae683b..c71fd714aa66 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -140,5 +140,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { override_codegen_backend: None, bypass_ignore_backends: Default::default(), jobs: Default::default(), + parallel_frontend_threads: Config::DEFAULT_PARALLEL_FRONTEND_THREADS, + iteration_count: Config::DEFAULT_ITERATION_COUNT, } } diff --git a/src/tools/enzyme b/src/tools/enzyme index 0b86a6759e5f..324402444ac4 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit 0b86a6759e5f250d6691a94a4a779a44d846e25b +Subproject commit 324402444ac48874d8ebd3ac767330bdc7cb1c06 diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 4eeba3022892..9129562efe1d 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: env: HOST_TARGET: ${{ matrix.host_target }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: install multiarch if: ${{ matrix.multiarch != '' }} run: | @@ -105,7 +105,7 @@ jobs: name: style checks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: ./.github/workflows/setup - name: rustfmt @@ -121,7 +121,7 @@ jobs: name: bootstrap build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 # Deliberately skipping `./.github/workflows/setup` as we do our own setup - name: Add cache for cargo id: cache @@ -156,7 +156,7 @@ jobs: name: coverage report runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: ./.github/workflows/setup - name: coverage run: ./miri test --coverage @@ -191,7 +191,7 @@ jobs: pull-requests: write if: ${{ github.event_name == 'schedule' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 256 # get a bit more of the history - name: install josh-sync diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 852ea26ab89e..ad8b2b09b6ba 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -171,8 +171,8 @@ MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/pass/v ``` Note that you will only get `info`, `warn` or `error` messages if you use a prebuilt compiler. -In order to get `debug` and `trace` level messages, you need to build miri with a locally built -compiler that has `debug=true` set in `bootstrap.toml`. +In order to get `debug` and `trace` level messages, you need to build miri with a [locally built +compiler](#advanced-topic-building-miri-against-a-locally-compiled-rustc) that has `debug=true` set in `bootstrap.toml`. #### Debugging error messages @@ -320,6 +320,33 @@ You can also directly run Miri on a Rust source file: ./x.py run miri --stage 1 --args src/tools/miri/tests/pass/hello.rs ``` +## Advanced topic: Building Miri against a locally compiled rustc + +Very rarely, it can be necessary to work with an out-of-tree Miri but build it against a rustc that +was locally compiled. (Usually, you should instead work on the Miri that's in the Rust tree, as +described in the previous subsection.) + +This requires a fully bootstrapped build: + +```sh +# Build rustc, then build rustc with that rustc. This can take a while. +./x build library --stage 3 +``` + +You also need to set up a linked toolchain with rustup: + +```sh +rustup toolchain link stage2 build/host/stage2 +``` + +Then in the Miri folder, you can set this as the current toolchain and build against it: + +```sh +rustup override set stage2 +# Prevent `./miri` from reseting the toolchain. +export MIRI_AUTO_OPS=no +``` + ## Advanced topic: Syncing with the rustc repo We use the [`josh-sync`](https://github.com/rust-lang/josh-sync) tool to transmit changes between the diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 2d332ae98dda..630a4b5e3e0f 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -779,9 +779,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libffi" @@ -923,11 +923,12 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.61.2", ] @@ -950,6 +951,7 @@ dependencies = [ "libffi", "libloading", "measureme", + "mio", "nix", "rand", "regex", diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 62387848868d..3255885d95be 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -28,6 +28,7 @@ chrono-tz = "0.10" directories = "6" bitflags = "2.6" serde_json = { version = "1.0", optional = true } +mio = { version = "1.1.1", features = ["os-poll", "net"] } [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index f254eb357a45..f51cd96486b4 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -154,6 +154,18 @@ platform. For example `cargo miri test --target s390x-unknown-linux-gnu` will run your test suite on a big-endian target, which is useful for testing endian-sensitive code. +### Controlling target features + +Controlling target features works similar to regular rustc invocations: +`RUSTFLAGS="-Ctarget-features=+avx512f" cargo miri test` runs the tests with AVX512 enabled. (Miri +only supports very few AVX512 intrinsics at the moment.) `-Ctarget-cpu` also works. If target +features are also relevant for doctests, you have to also set `RUSTDOCFLAGS`. + +Unlike regular rustc, this flag has *two* effects: it builds the code with that target feature +available (which affects `cfg(target_feature)`), and it tells Miri to consider the "virtual CPU" +that the interpreted program runs on as having the feature available (meaning the code is allowed to +invoke the corresponding intrinsics). + ### Testing multiple different executions Certain parts of the execution are picked randomly by Miri, such as the exact base address @@ -421,10 +433,11 @@ to Miri failing to detect cases of undefined behavior in a program. are experimental). Later flags take precedence: borrow tracking can be reactivated by `-Zmiri-tree-borrows`. * `-Zmiri-disable-validation` disables enforcing validity invariants, which are - enforced by default. This is mostly useful to focus on other failures (such - as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs - in your program. However, this can also help to make Miri run faster. Using - this flag is **unsound**. + enforced by default. This only disables these checks for typed copies; using + invalid values in any other operation will still cause an error. This is mostly useful + to focus on other failures (such as out-of-bounds accesses) first. Setting this + flag means Miri can miss bugs in your program. However, this can also help to + make Miri run faster. Using this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. * `-Zmiri-fixed-schedule` disables preemption (like `-Zmiri-preemption-rate=0.0`) and furthermore @@ -463,8 +476,9 @@ to Miri failing to detect cases of undefined behavior in a program. but reports to the program that it did actually write. This is useful when you are not interested in the actual program's output, but only want to see Miri's errors and warnings. -* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking - recurse below references. +* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking recurse + *one level* below references. The in-memory value is treated as-if it was inside a + `MaybeDangling`, i.e., nested references do not even have to be dereferenceable. * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. Note that even without preemption, the schedule is still non-deterministic: @@ -628,6 +642,7 @@ Definite bugs found: * [`winit` registering a global constructor with the wrong ABI on Windows](https://github.com/rust-windowing/winit/issues/4435) * [`VecDeque::splice` confusing physical and logical indices](https://github.com/rust-lang/rust/issues/151758) * [Data race in `oneshot` channel](https://github.com/faern/oneshot/issues/69) +* [Memory leak in serde-yaml-bw](https://github.com/bourumir-wyngs/serde-yaml-bw/issues/197) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock index 45be05fcc7f7..977728f63499 100644 --- a/src/tools/miri/cargo-miri/Cargo.lock +++ b/src/tools/miri/cargo-miri/Cargo.lock @@ -230,9 +230,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b881c015c729b43105bbd3702a9bdecee28fafaa21126d1d62e454ec011a4b7" +checksum = "eec3905e8201688412f6f4b1f6c86d38b3ee6578f59ba85f41330a3af61e8365" dependencies = [ "anyhow", "rustc_version", @@ -339,11 +339,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -392,45 +392,42 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" dependencies = [ "indexmap", - "serde", + "serde_core", "serde_spanned", "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", + "toml_parser", + "toml_writer", "winnow", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_datetime" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" [[package]] name = "unicode-ident" @@ -489,12 +486,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" [[package]] name = "wit-bindgen" diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml index e8da7f2ca8a7..568bb29f49f8 100644 --- a/src/tools/miri/cargo-miri/Cargo.toml +++ b/src/tools/miri/cargo-miri/Cargo.toml @@ -18,7 +18,7 @@ directories = "6" rustc_version = "0.4" serde_json = "1.0.40" cargo_metadata = "0.23" -rustc-build-sysroot = "0.5.10" +rustc-build-sysroot = "0.5.12" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 6c0bceac7731..9bacbbcf4597 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -28,6 +28,7 @@ begingroup "Building Miri" export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--locked" +export CARGO_UNSTABLE_BUILD_DIR_NEW_LAYOUT=true # Determine configuration for installed build (used by test-cargo-miri and `./miri bench`). # We use the default set of features for this. diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 86f6253d4558..d469502c243f 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -80,7 +80,7 @@ fn auto_actions() -> Result<()> { // `toolchain` goes first as it could affect the others if auto_toolchain { - Self::toolchain(vec![])?; + Self::toolchain(None, vec![])?; } if auto_fmt { Self::fmt(vec![])?; @@ -121,15 +121,18 @@ pub fn exec(self) -> Result<()> { Command::Clippy { features, flags } => Self::clippy(features, flags), Command::Bench { target, no_install, save_baseline, load_baseline, benches } => Self::bench(target, no_install, save_baseline, load_baseline, benches), - Command::Toolchain { flags } => Self::toolchain(flags), + Command::Toolchain { commit, flags } => Self::toolchain(commit, flags), Command::Squash => Self::squash(), } } - fn toolchain(flags: Vec) -> Result<()> { + fn toolchain(new_commit: Option, flags: Vec) -> Result<()> { let sh = Shell::new()?; sh.change_dir(miri_dir()?); - let new_commit = sh.read_file("rust-version")?.trim().to_owned(); + let new_commit = match new_commit { + Some(c) => c, + None => sh.read_file("rust-version")?.trim().to_owned(), + }; let current_commit = { let rustc_info = cmd!(sh, "rustc +miri --version -v").read(); if let Ok(rustc_info) = rustc_info { diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index e30701449688..419c128e5b72 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -138,6 +138,9 @@ pub enum Command { /// The `rust-version` file is used to determine the commit that will be intsalled. /// `rustup-toolchain-install-master` must be installed for this to work. Toolchain { + /// Overwrite the commit to install. + #[arg(long)] + commit: Option, /// Flags that are passed through to `rustup-toolchain-install-master`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, @@ -157,8 +160,8 @@ fn add_remainder(&mut self, remainder: Vec) -> Result<()> { | Self::Build { flags, .. } | Self::Check { flags, .. } | Self::Doc { flags, .. } - | Self::Fmt { flags } - | Self::Toolchain { flags } + | Self::Fmt { flags, .. } + | Self::Toolchain { flags, .. } | Self::Clippy { flags, .. } | Self::Run { flags, .. } | Self::Test { flags, .. } => { diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 90a48de0fcb0..85571d95f742 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -d933cf483edf1605142ac6899ff32536c0ad8b22 +116458d0a5ae01cd517cabd2d1aee7f5457018ab diff --git a/src/tools/miri/src/alloc/mod.rs b/src/tools/miri/src/alloc/mod.rs index 35158f50a8ff..bc306b5e8738 100644 --- a/src/tools/miri/src/alloc/mod.rs +++ b/src/tools/miri/src/alloc/mod.rs @@ -1,7 +1,7 @@ mod alloc_bytes; -#[cfg(all(unix, feature = "native-lib"))] +#[cfg(all(feature = "native-lib", unix))] pub mod isolated_alloc; -#[cfg(not(all(unix, feature = "native-lib")))] +#[cfg(not(all(feature = "native-lib", unix)))] pub mod isolated_alloc { use std::alloc::Layout; diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 91559e76e68c..15ad967657de 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -163,7 +163,7 @@ fn addr_from_alloc_id_uncached( this.get_alloc_bytes_unchecked_raw(alloc_id)? } } - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] AllocKind::Function => { if let Some(GlobalAlloc::Function { instance, .. }) = this.tcx.try_get_global_alloc(alloc_id) @@ -186,7 +186,7 @@ fn addr_from_alloc_id_uncached( dummy_alloc(params) } } - #[cfg(not(all(unix, feature = "native-lib")))] + #[cfg(not(all(feature = "native-lib", unix)))] AllocKind::Function => dummy_alloc(params), AllocKind::VTable | AllocKind::VaList => dummy_alloc(params), AllocKind::TypeId | AllocKind::Dead => unreachable!(), diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 3766debb159d..e73c870508bd 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -18,7 +18,6 @@ extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; -extern crate rustc_target; /// See docs in https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc/src/main.rs /// and https://github.com/rust-lang/rust/pull/146627 for why we need this. @@ -42,7 +41,6 @@ use std::process::ExitCode; use std::rc::Rc; use std::str::FromStr; -use std::sync::Once; use std::sync::atomic::{AtomicU32, Ordering}; use miri::{ @@ -66,10 +64,9 @@ use rustc_middle::query::LocalCrate; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::EarlyDiagCtxt; -use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options}; +use rustc_session::config::{CrateType, ErrorOutputType, OptLevel}; +use rustc_session::{EarlyDiagCtxt, Session}; use rustc_span::def_id::DefId; -use rustc_target::spec::Target; use crate::log::setup::{deinit_loggers, init_early_loggers, init_late_loggers}; @@ -174,18 +171,21 @@ fn run_many_seeds( /// Generates the codegen backend for code that Miri will interpret: we basically /// use the dummy backend, except that we put the LLVM backend in charge of /// target features. -fn make_miri_codegen_backend(opts: &Options, target: &Target) -> Box { - let early_dcx = EarlyDiagCtxt::new(opts.error_format); +fn make_miri_codegen_backend(sess: &Session) -> Box { + let early_dcx = EarlyDiagCtxt::new(sess.opts.error_format); // Use the target_config method of the default codegen backend (eg LLVM) to ensure the // calculated target features match said backend by respecting eg -Ctarget-cpu. - let target_config_backend = - rustc_interface::util::get_codegen_backend(&early_dcx, &opts.sysroot, None, target); - let target_config_backend_init = Once::new(); + let target_config_backend = rustc_interface::util::get_codegen_backend( + &early_dcx, + &sess.opts.sysroot, + None, + &sess.target, + ); + target_config_backend.init(sess); Box::new(DummyCodegenBackend { target_config_override: Some(Box::new(move |sess| { - target_config_backend_init.call_once(|| target_config_backend.init(sess)); target_config_backend.target_config(sess) })), }) @@ -382,7 +382,7 @@ fn exit(exit_code: i32) -> ! { // Drop the tracing guard before exiting, so tracing calls are flushed correctly. deinit_loggers(); // Make sure the supervisor knows about the exit code. - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] miri::native_lib::register_retcode_sv(exit_code); // Actually exit. std::process::exit(exit_code); @@ -756,7 +756,7 @@ fn main() -> ExitCode { debug!("crate arguments: {:?}", miri_config.args); if !miri_config.native_lib.is_empty() && miri_config.native_lib_enable_tracing { // SAFETY: No other threads are running - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] if unsafe { miri::native_lib::init_sv() }.is_err() { eprintln!( "warning: The native-lib tracer could not be started. Is this an x86 Linux system, and does Miri have permissions to ptrace?\n\ diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs index 36e574c8e57f..6b7c0adc8afb 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs @@ -37,17 +37,14 @@ fn generate_diagnostic(&self) -> (String, SpanData) { let tag = self.retag.new_tag; if let Some(perm) = self.retag.permission { ( - format!( - "{tag:?} was created by a {:?} retag at offsets {:?}", - perm, self.retag.range, - ), + format!("{tag:?} was created by a {perm:?} retag at offsets {}", self.retag.range), self.span.data(), ) } else { assert!(self.retag.range.size == Size::ZERO); ( format!( - "{tag:?} would have been created here, but this is a zero-size retag ({:?}) so the tag in question does not exist anywhere", + "{tag:?} would have been created here, but this is a zero-size retag ({}) so the tag in question does not exist anywhere", self.retag.range, ), self.span.data(), @@ -79,12 +76,12 @@ fn generate_diagnostic(&self) -> (String, SpanData) { // For a FnEntry retag, our Span points at the caller. // See `DiagnosticCx::log_invalidation`. format!( - "{:?} was later invalidated at offsets {:?} by a {} inside this call", + "{:?} was later invalidated at offsets {} by a {} inside this call", self.tag, self.range, self.cause ) } else { format!( - "{:?} was later invalidated at offsets {:?} by a {}", + "{:?} was later invalidated at offsets {} by a {}", self.tag, self.range, self.cause ) }; @@ -343,7 +340,7 @@ pub fn get_logs_relevant_to( if self.history.root.0.tag() == tag { Some(( format!( - "{tag:?} was created here, as the root tag for {:?}", + "{tag:?} was created here, as the root tag for {}", self.history.id ), self.history.root.1.data(), @@ -383,7 +380,7 @@ pub(super) fn grant_error(&self, stack: &Stack) -> InterpErrorKind<'tcx> { let perm = op.permission.expect("`start_grant` must be called before calling `grant_error`"); let action = format!( - "trying to retag from {:?} for {:?} permission at {:?}[{:#x}]", + "trying to retag from {:?} for {:?} permission at {}[{:#x}]", op.orig_tag, perm, self.history.id, @@ -410,7 +407,7 @@ pub(super) fn access_error(&self, stack: &Stack) -> InterpErrorKind<'tcx> { Operation::Dealloc(_) => return self.dealloc_error(stack), }; let action = format!( - "attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]", + "attempting a {access} using {tag:?} at {alloc_id}[{offset:#x}]", access = op.kind, tag = op.tag, alloc_id = self.history.id, @@ -455,7 +452,7 @@ pub fn dealloc_error(&self, stack: &Stack) -> InterpErrorKind<'tcx> { }; err_sb_ub( format!( - "attempting deallocation using {tag:?} at {alloc_id:?}{cause}", + "attempting deallocation using {tag:?} at {alloc_id}{cause}", tag = op.tag, alloc_id = self.history.id, cause = error_cause(stack, op.tag), @@ -488,7 +485,7 @@ pub fn check_tracked_tag_popped(&self, item: &Item, global: &GlobalStateInner) { } fn operation_summary(operation: &str, alloc_id: AllocId, alloc_range: AllocRange) -> String { - format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}") + format!("this error occurs as part of {operation} at {alloc_id}{alloc_range}") } fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str { diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 617b619a7df9..66e804d972b7 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -917,6 +917,7 @@ fn retag_ptr_inplace( RetagInfo { cause: self.retag_cause, in_field: self.in_field }, )?; self.ecx.write_immediate(*val, place)?; + interp_ok(()) } } @@ -964,6 +965,9 @@ fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // even if field retagging is not enabled. *shrug*) self.walk_value(place)?; } + ty::Adt(adt, _) if adt.is_maybe_dangling() => { + // Skip traversing for everything inside of `MaybeDangling` + } _ => { // Not a reference/pointer/box. Recurse. let in_field = mem::replace(&mut self.in_field, true); // remember and restore old value diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index 055baca8542f..093dada405af 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -157,7 +157,7 @@ fn extend(&mut self, new_history: History, tag_name: &'static str, show_initial_ // to the user. The meaningful one is `access_range`. let access = access_cause.print_as_access(is_foreign); let access_range_text = match access_range { - Some(r) => format!("at offsets {r:?}"), + Some(r) => format!("at offsets {r}"), None => format!("on every location previously accessed by this tag"), }; self.events.push(( @@ -339,7 +339,7 @@ pub fn build<'tcx>(self) -> InterpErrorKind<'tcx> { // all tags through which an access would cause UB. let accessed_is_conflicting = accessed.map(|a| a.tag) == Some(conflicting.tag); let title = format!( - "{cause} through {accessed_str} at {alloc_id:?}[{error_offset:#x}] is forbidden", + "{cause} through {accessed_str} at {alloc_id}[{error_offset:#x}] is forbidden", alloc_id = self.access_info.alloc_id ); let (title, details, conflicting_tag_name) = match self.error_kind { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 1a7c0af2988a..a20550232730 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -523,6 +523,9 @@ fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // even if field retagging is not enabled. *shrug*) self.walk_value(place)?; } + ty::Adt(adt, _) if adt.is_maybe_dangling() => { + // Skip traversing for everything inside of `MaybeDangling` + } _ => { // Not a reference/pointer/box. Recurse. self.walk_value(place)?; diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs index b03635de70ae..a3f7d6176555 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs @@ -50,8 +50,8 @@ pub fn to_relatedness(self) -> Option { } } -/// Caches information about where in the tree exposed nodes with permission to do reads/ rites are -/// located. [`ExposedCache`] stores this information a single location (or rather, a range of +/// Caches information about where in the tree exposed nodes with permission to do reads/writes are +/// located. [`ExposedCache`] stores this information for a single location (or rather, a range of /// homogeneous locations) for all nodes in an allocation. /// /// Nodes not in this map have a default [`ExposedCacheNode`], i.e. they have no exposed children. diff --git a/src/tools/miri/src/concurrency/blocking_io.rs b/src/tools/miri/src/concurrency/blocking_io.rs new file mode 100644 index 000000000000..221d0495cd16 --- /dev/null +++ b/src/tools/miri/src/concurrency/blocking_io.rs @@ -0,0 +1,148 @@ +use std::io; +use std::time::Duration; + +use mio::event::Source; +use mio::{Events, Interest, Poll, Token}; +use rustc_data_structures::fx::FxHashMap; + +use crate::*; + +/// Capacity of the event queue which can be polled at a time. +/// Since we don't expect many simultaneous blocking I/O events +/// this value can be set rather low. +const IO_EVENT_CAPACITY: usize = 16; + +/// Trait for values that contain a mio [`Source`]. +pub trait WithSource { + /// Invoke `f` on the source inside `self`. + fn with_source(&self, f: &mut dyn FnMut(&mut dyn Source) -> io::Result<()>) -> io::Result<()>; +} + +/// Manager for managing blocking host I/O in a non-blocking manner. +/// We use [`Poll`] to poll for new I/O events from the OS for sources +/// registered using this manager. +/// +/// Since blocking host I/O is inherently non-deterministic, no method on this +/// manager should be called when isolation is enabled. The only exception is +/// the [`BlockingIoManager::new`] function to create the manager. Everywhere else, +/// we assert that isolation is disabled! +pub struct BlockingIoManager { + /// Poll instance to monitor I/O events from the OS. + /// This is only [`None`] when Miri is run with isolation enabled. + poll: Option, + /// Buffer used to store the ready I/O events when calling [`Poll::poll`]. + /// This is not part of the state and only stored to avoid allocating a + /// new buffer for every poll. + events: Events, + /// Map between threads which are currently blocked and the + /// underlying I/O source. + sources: FxHashMap>, +} + +impl BlockingIoManager { + /// Create a new blocking I/O manager instance based on the availability + /// of communication with the host. + pub fn new(communicate: bool) -> Result { + let manager = Self { + poll: communicate.then_some(Poll::new()?), + events: Events::with_capacity(IO_EVENT_CAPACITY), + sources: FxHashMap::default(), + }; + Ok(manager) + } + + /// Poll for new I/O events from the OS or wait until the timeout expired. + /// + /// - If the timeout is [`Some`] and contains [`Duration::ZERO`], the poll doesn't block and just + /// reads all events since the last poll. + /// - If the timeout is [`Some`] and contains a non-zero duration, it blocks at most for the + /// specified duration. + /// - If the timeout is [`None`] the poll blocks indefinitely until an event occurs. + /// + /// Returns all threads that are ready because they received an I/O event. + pub fn poll(&mut self, timeout: Option) -> Result, io::Error> { + let poll = + self.poll.as_mut().expect("Blocking I/O should not be called with isolation enabled"); + + // Poll for new I/O events from OS and store them in the events buffer. + poll.poll(&mut self.events, timeout)?; + + let ready = self + .events + .iter() + .map(|event| { + let token = event.token(); + ThreadId::new_unchecked(token.0.try_into().unwrap()) + }) + .collect::>(); + + // Deregister all ready sources as we only want to receive one event per thread. + ready.iter().for_each(|thread_id| self.deregister(*thread_id)); + + Ok(ready) + } + + /// Register a blocking I/O source for a thread together with it's poll interests. + /// + /// The source will be deregistered automatically once an event for it is received. + /// + /// As the OS can always produce spurious wake-ups, it's the callers responsibility to + /// verify the requested I/O interests are really ready and to register again if they're not. + pub fn register(&mut self, source: Box, thread: ThreadId, interests: Interest) { + let poll = + self.poll.as_ref().expect("Blocking I/O should not be called with isolation enabled"); + + let token = Token(thread.to_u32().to_usize()); + + // Treat errors from registering as fatal. On UNIX hosts this can only + // fail due to system resource errors (e.g. ENOMEM or ENOSPC). + source + .with_source(&mut |source| source.register(poll.registry(), token, interests)) + .unwrap(); + self.sources + .try_insert(thread, source) + .unwrap_or_else(|_| panic!("A thread cannot be registered twice at the same time")); + } + + /// Deregister the event source for a thread. Returns the kind of I/O the thread was + /// blocked on. + fn deregister(&mut self, thread: ThreadId) { + let poll = + self.poll.as_ref().expect("Blocking I/O should not be called with isolation enabled"); + + let Some(source) = self.sources.remove(&thread) else { + panic!("Attempt to deregister a token which isn't registered") + }; + + // Treat errors from deregistering as fatal. On UNIX hosts this can only + // fail due to system resource errors (e.g. ENOMEM or ENOSPC). + source.with_source(&mut |source| source.deregister(poll.registry())).unwrap(); + } +} + +impl<'tcx> EvalContextExt<'tcx> for MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { + /// Block the current thread until some interests on an I/O source + /// are fulfilled or the optional timeout exceeded. + /// The callback will be invoked when the thread gets unblocked. + /// + /// There can be spurious wake-ups by the OS and thus it's the callers + /// responsibility to verify that the requested I/O interests are + /// really ready and to block again if they're not. + #[inline] + fn block_thread_for_io( + &mut self, + source: impl WithSource + 'static, + interests: Interest, + timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, + callback: DynUnblockCallback<'tcx>, + ) { + let this = self.eval_context_mut(); + this.machine.blocking_io.register( + Box::new(source), + this.machine.threads.active_thread(), + interests, + ); + this.block_thread(BlockReason::IO, timeout, callback); + } +} diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index 421f24329df0..815ce914db57 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -1,3 +1,4 @@ +pub mod blocking_io; pub mod cpu_affinity; pub mod data_race; mod data_race_handler; diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 9d829bf69e5e..ee74e0681594 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -1,9 +1,9 @@ //! Implements threads. -use std::mem; use std::sync::atomic::Ordering::Relaxed; use std::task::Poll; use std::time::{Duration, SystemTime}; +use std::{io, mem}; use rand::seq::IteratorRandom; use rustc_abi::ExternAbi; @@ -25,10 +25,11 @@ enum SchedulingAction { /// Execute step on the active thread. ExecuteStep, - /// Execute a timeout callback. - ExecuteTimeoutCallback, - /// Wait for a bit, until there is a timeout to be called. - Sleep(Duration), + /// Wait for a bit, but at most as long as the duration specified. + /// We wake up early if an I/O event happened. + /// If the duration is [`None`], we sleep indefinitely. This is + /// only allowed when isolation is disabled and there are threads waiting for I/O! + SleepAndWaitForIo(Option), } /// What to do with TLS allocations from terminated threads @@ -111,6 +112,8 @@ pub enum BlockReason { Eventfd, /// Blocked on unnamed_socket. UnnamedSocket, + /// Blocked on an IO operation. + IO, /// Blocked for any reason related to GenMC, such as `assume` statements (GenMC mode only). /// Will be implicitly unblocked when GenMC schedules this thread again. Genmc, @@ -653,64 +656,10 @@ fn yield_active_thread(&mut self) { // We should only switch stacks between steps. self.yield_active_thread = true; } - - /// Get the wait time for the next timeout, or `None` if no timeout is pending. - fn next_callback_wait_time(&self, clock: &MonotonicClock) -> Option { - self.threads - .iter() - .filter_map(|t| { - match &t.state { - ThreadState::Blocked { timeout: Some(timeout), .. } => - Some(timeout.get_wait_time(clock)), - _ => None, - } - }) - .min() - } } impl<'tcx> EvalContextPrivExt<'tcx> for MiriInterpCx<'tcx> {} trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { - /// Execute a timeout callback on the callback's thread. - #[inline] - fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let mut found_callback = None; - // Find a blocked thread that has timed out. - for (id, thread) in this.machine.threads.threads.iter_enumerated_mut() { - match &thread.state { - ThreadState::Blocked { timeout: Some(timeout), .. } - if timeout.get_wait_time(&this.machine.monotonic_clock) == Duration::ZERO => - { - let old_state = mem::replace(&mut thread.state, ThreadState::Enabled); - let ThreadState::Blocked { callback, .. } = old_state else { unreachable!() }; - found_callback = Some((id, callback)); - // Run the fallback (after the loop because borrow-checking). - break; - } - _ => {} - } - } - if let Some((thread, callback)) = found_callback { - // This back-and-forth with `set_active_thread` is here because of two - // design decisions: - // 1. Make the caller and not the callback responsible for changing - // thread. - // 2. Make the scheduler the only place that can change the active - // thread. - let old_thread = this.machine.threads.set_active_thread_id(thread); - callback.call(this, UnblockKind::TimedOut)?; - this.machine.threads.set_active_thread_id(old_thread); - } - // found_callback can remain None if the computer's clock - // was shifted after calling the scheduler and before the call - // to get_ready_callback (see issue - // https://github.com/rust-lang/miri/issues/1763). In this case, - // just do nothing, which effectively just returns to the - // scheduler. - interp_ok(()) - } - #[inline] fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); @@ -765,9 +714,7 @@ fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { } // We are not in GenMC mode, so we control the scheduling. - let thread_manager = &mut this.machine.threads; - let clock = &this.machine.monotonic_clock; - let rng = this.machine.rng.get_mut(); + let thread_manager = &this.machine.threads; // This thread and the program can keep going. if thread_manager.threads[thread_manager.active_thread].state.is_enabled() && !thread_manager.yield_active_thread @@ -775,16 +722,30 @@ fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { // The currently active thread is still enabled, just continue with it. return interp_ok(SchedulingAction::ExecuteStep); } - // The active thread yielded or got terminated. Let's see if there are any timeouts to take - // care of. We do this *before* running any other thread, to ensure that timeouts "in the - // past" fire before any other thread can take an action. This ensures that for + + // The active thread yielded or got terminated. Let's see if there are any I/O events + // or timeouts to take care of. + + if this.machine.communicate() { + // When isolation is disabled we need to check for events for + // threads which are blocked on host I/O. + // We do this before running any other threads such that the threads + // which received events are available for scheduling afterwards. + + // Perform a non-blocking poll for newly available I/O events from the OS. + this.poll_and_unblock(Some(Duration::ZERO))?; + } + + // We also check timeouts before running any other thread, to ensure that timeouts + // "in the past" fire before any other thread can take an action. This ensures that for // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by // abstime has already been passed at the time of the call". // - let potential_sleep_time = thread_manager.next_callback_wait_time(clock); - if potential_sleep_time == Some(Duration::ZERO) { - return interp_ok(SchedulingAction::ExecuteTimeoutCallback); - } + let potential_sleep_time = this.unblock_expired_timeouts()?; + + let thread_manager = &mut this.machine.threads; + let rng = this.machine.rng.get_mut(); + // No callbacks immediately scheduled, pick a regular thread to execute. // The active thread blocked or yielded. So we go search for another enabled thread. // We build the list of threads by starting with the threads after the current one, followed by @@ -832,11 +793,85 @@ fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { // All threads are currently blocked, but we have unexecuted // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. - interp_ok(SchedulingAction::Sleep(sleep_time)) + interp_ok(SchedulingAction::SleepAndWaitForIo(Some(sleep_time))) + } else if thread_manager + .threads + .iter() + .any(|thread| thread.state.is_blocked_on(BlockReason::IO)) + { + // At least one thread is blocked on host I/O but doesn't + // have a timeout set. Hence, we sleep indefinitely in the + // hope that eventually an I/O event for this thread happens. + interp_ok(SchedulingAction::SleepAndWaitForIo(None)) } else { throw_machine_stop!(TerminationInfo::GlobalDeadlock); } } + + /// Poll for I/O events until either an I/O event happened or the timeout expired. + /// The different timeout values are described in [`BlockingIoManager::poll`]. + fn poll_and_unblock(&mut self, timeout: Option) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let ready = match this.machine.blocking_io.poll(timeout) { + Ok(ready) => ready, + // We can ignore errors originating from interrupts; that's just a spurious wakeup. + Err(e) if e.kind() == io::ErrorKind::Interrupted => return interp_ok(()), + // For other errors we panic. On Linux and BSD hosts this should only be + // reachable when a system resource error (e.g. ENOMEM or ENOSPC) occurred. + Err(e) => panic!("unexpected error while polling: {e}"), + }; + + ready.into_iter().try_for_each(|thread_id| this.unblock_thread(thread_id, BlockReason::IO)) + } + + /// Find all threads with expired timeouts, unblock them and execute their timeout callbacks. + /// + /// This method returns the minimum duration until the next thread timeout expires. + /// If all ready threads have no timeout set, [`None`] is returned. + fn unblock_expired_timeouts(&mut self) -> InterpResult<'tcx, Option> { + let this = self.eval_context_mut(); + let clock = &this.machine.monotonic_clock; + + let mut min_wait_time = Option::::None; + let mut callbacks = Vec::new(); + + for (id, thread) in this.machine.threads.threads.iter_enumerated_mut() { + match &thread.state { + ThreadState::Blocked { timeout: Some(timeout), .. } => { + let wait_time = timeout.get_wait_time(clock); + if wait_time.is_zero() { + // The timeout expired for this thread. + let old_state = mem::replace(&mut thread.state, ThreadState::Enabled); + let ThreadState::Blocked { callback, .. } = old_state else { + unreachable!() + }; + // Add callback to list to be run after this loop because of borrow-checking. + callbacks.push((id, callback)); + } else { + // Update `min_wait_time` to contain the smallest duration until + // the next timeout expires. + min_wait_time = Some(wait_time.min(min_wait_time.unwrap_or(Duration::MAX))); + } + } + _ => {} + } + } + + for (thread, callback) in callbacks { + // This back-and-forth with `set_active_thread` is here because of two + // design decisions: + // 1. Make the caller and not the callback responsible for changing + // thread. + // 2. Make the scheduler the only place that can change the active + // thread. + let old_thread = this.machine.threads.set_active_thread_id(thread); + callback.call(this, UnblockKind::TimedOut)?; + this.machine.threads.set_active_thread_id(old_thread); + } + + interp_ok(min_wait_time) + } } // Public interface to thread management. @@ -1300,11 +1335,19 @@ fn run_threads(&mut self) -> InterpResult<'tcx, !> { } } } - SchedulingAction::ExecuteTimeoutCallback => { - this.run_timeout_callback()?; - } - SchedulingAction::Sleep(duration) => { - this.machine.monotonic_clock.sleep(duration); + SchedulingAction::SleepAndWaitForIo(duration) => { + if this.machine.communicate() { + // When we're running with isolation disabled, instead of + // strictly sleeping the duration we allow waking up + // early for I/O events from the OS. + + this.poll_and_unblock(duration)?; + } else { + let duration = duration.expect( + "Infinite sleep should not be triggered when isolation is enabled", + ); + this.machine.monotonic_clock.sleep(duration); + } } } } diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 367012e56ad9..9d93edcaa344 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -4,7 +4,7 @@ use rustc_abi::{Align, Size}; use rustc_data_structures::fx::{FxBuildHasher, FxHashSet}; -use rustc_errors::{Diag, DiagMessage, Level}; +use rustc_errors::{Diag, Level}; use rustc_span::{DUMMY_SP, Span, SpanData, Symbol}; use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory; @@ -106,16 +106,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -impl MachineStopType for TerminationInfo { - fn diagnostic_message(&self) -> DiagMessage { - self.to_string().into() - } - fn add_args( - self: Box, - _: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagArgValue), - ) { - } -} +impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { @@ -354,16 +345,14 @@ pub fn report_result<'tcx>( (title, helps) } else { let title = match res.kind() { - UndefinedBehavior(ValidationError(validation_err)) - if matches!( - validation_err.kind, - ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer - ) => - { + UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { + ptr_bytes_warning: true, + .. + }) => { ecx.handle_ice(); // print interpreter backtrace (this is outside the eval `catch_unwind`) bug!( "This validation error should be impossible in Miri: {}", - format_interp_error(ecx.tcx.dcx(), res) + format_interp_error(res) ); } UndefinedBehavior(_) => "Undefined Behavior", @@ -380,10 +369,7 @@ pub fn report_result<'tcx>( ) => "post-monomorphization error", _ => { ecx.handle_ice(); // print interpreter backtrace (this is outside the eval `catch_unwind`) - bug!( - "This error should be impossible in Miri: {}", - format_interp_error(ecx.tcx.dcx(), res) - ); + bug!("This error should be impossible in Miri: {}", format_interp_error(res)); } }; #[rustfmt::skip] @@ -411,10 +397,10 @@ pub fn report_result<'tcx>( match info { PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => { if let Some(span) = ecx.machine.allocated_span(*alloc_id) { - helps.push(note_span!(span, "{:?} was allocated here:", alloc_id)); + helps.push(note_span!(span, "{alloc_id} was allocated here:")); } if let Some(span) = ecx.machine.deallocated_span(*alloc_id) { - helps.push(note_span!(span, "{:?} was deallocated here:", alloc_id)); + helps.push(note_span!(span, "{alloc_id} was deallocated here:")); } } AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => { @@ -447,7 +433,7 @@ pub fn report_result<'tcx>( UndefinedBehavior(InvalidUninitBytes(Some((alloc_id, access)))) => { writeln!( extra, - "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:", + "Uninitialized memory occurred at {alloc_id}{range}, in this allocation:", range = access.bad, ) .unwrap(); @@ -460,7 +446,7 @@ pub fn report_result<'tcx>( if let Some(title) = title { write!(primary_msg, "{title}: ").unwrap(); } - write!(primary_msg, "{}", format_interp_error(ecx.tcx.dcx(), res)).unwrap(); + write!(primary_msg, "{}", format_interp_error(res)).unwrap(); if labels.is_empty() { labels.push(format!( @@ -510,7 +496,7 @@ pub fn report_leaks<'tcx>( let mut any_pruned = false; for (id, kind, alloc) in leaks { let mut title = format!( - "memory leaked: {id:?} ({}, size: {:?}, align: {:?})", + "memory leaked: {id:?} ({}, size: {}, align: {})", kind, alloc.size().bytes(), alloc.align.bytes() @@ -665,17 +651,17 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { format!("created {tag:?} with {perm} derived from unknown tag"), CreatedPointerTag(tag, Some(perm), Some((alloc_id, range, orig_tag))) => format!( - "created tag {tag:?} with {perm} at {alloc_id:?}{range:?} derived from {orig_tag:?}" + "created tag {tag:?} with {perm} at {alloc_id}{range} derived from {orig_tag:?}" ), PoppedPointerTag(item, cause) => format!("popped tracked tag for item {item:?}{cause}"), TrackingAlloc(id, size, align) => format!( - "now tracking allocation {id:?} of {size} bytes (alignment {align} bytes)", + "now tracking allocation {id} of {size} bytes (alignment {align} bytes)", size = size.bytes(), align = align.bytes(), ), AccessedAlloc(id, range, access_kind) => - format!("{access_kind} at {id:?}[{}..{}]", range.start.bytes(), range.end().bytes()), + format!("{access_kind} at {id}{range}"), FreedAlloc(id) => format!("freed allocation {id:?}"), RejectedIsolatedOp(op) => format!("{op} was made to return an error due to isolation"), ProgressReport { .. } => @@ -704,7 +690,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { }; format!("GenMC currently does not model the failure ordering for `compare_exchange`. {was_upgraded_msg}. Miri with GenMC might miss bugs related to this memory access.") } - FileInProcOpened => format!("files in `/proc` can bypass the Abstract Machine and might not work properly in Miri") + FileInProcOpened => format!("files in `/proc` can bypass the Abstract Machine and might not work properly in Miri"), }; let notes = match &e { diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index facfade026be..a40ad4b55317 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -5,7 +5,6 @@ use rand::RngCore; use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants}; -use rustc_apfloat::Float; use rustc_data_structures::fx::{FxBuildHasher, FxHashSet}; use rustc_hir::Safety; use rustc_hir::def::{DefKind, Namespace}; @@ -165,50 +164,6 @@ pub fn iter_exported_symbols<'tcx>( interp_ok(()) } -/// Convert a softfloat type to its corresponding hostfloat type. -pub trait ToHost { - type HostFloat; - fn to_host(self) -> Self::HostFloat; -} - -/// Convert a hostfloat type to its corresponding softfloat type. -pub trait ToSoft { - type SoftFloat; - fn to_soft(self) -> Self::SoftFloat; -} - -impl ToHost for rustc_apfloat::ieee::Double { - type HostFloat = f64; - - fn to_host(self) -> Self::HostFloat { - f64::from_bits(self.to_bits().try_into().unwrap()) - } -} - -impl ToSoft for f64 { - type SoftFloat = rustc_apfloat::ieee::Double; - - fn to_soft(self) -> Self::SoftFloat { - Float::from_bits(self.to_bits().into()) - } -} - -impl ToHost for rustc_apfloat::ieee::Single { - type HostFloat = f32; - - fn to_host(self) -> Self::HostFloat { - f32::from_bits(self.to_bits().try_into().unwrap()) - } -} - -impl ToSoft for f32 { - type SoftFloat = rustc_apfloat::ieee::Single; - - fn to_soft(self) -> Self::SoftFloat { - Float::from_bits(self.to_bits().into()) - } -} - impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Checks if the given crate/module exists. @@ -774,19 +729,17 @@ fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option= 1_000_000_000 { - // tv_nsec must not be greater than 999,999,999. - None? - } - Duration::new(seconds, nanoseconds) - }, - ) + interp_ok(try { + // tv_sec must be non-negative. + let seconds: u64 = seconds.try_into().ok()?; + // tv_nsec must be non-negative. + let nanoseconds: u32 = nanoseconds.try_into().ok()?; + if nanoseconds >= 1_000_000_000 { + // tv_nsec must not be greater than 999,999,999. + None? + } + Duration::new(seconds, nanoseconds) + }) } /// Read bytes from a byte slice. diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs index 0cc4342f0d55..fc7101df9ed0 100644 --- a/src/tools/miri/src/intrinsics/math.rs +++ b/src/tools/miri/src/intrinsics/math.rs @@ -1,8 +1,9 @@ +use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, Semantics, SingleS}; use rustc_apfloat::{self, Float, FloatConvert, Round}; use rustc_middle::mir; use rustc_middle::ty::{self, FloatTy}; -use self::helpers::{ToHost, ToSoft}; +use self::math::{HostFloatOperation, HostUnaryFloatOp, IeeeExt, host_unary_float_op}; use super::check_intrinsic_arg_count; use crate::*; @@ -12,12 +13,82 @@ fn sqrt<'tcx, F: Float + FloatConvert + Into>( dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?; - let f: F = f.to_float()?; - // Sqrt is specified to be fully precise. - let res = math::sqrt(f); + math::sqrt_op::(this, f, dest) +} + +/// Determine which float operation on which type this is. +fn is_host_unary_float_op(intrinsic_name: &str) -> Option<(FloatTy, HostUnaryFloatOp)> { + let (op, ty) = intrinsic_name.rsplit_once('f')?; + + let float_ty = match ty { + "16" => FloatTy::F16, + "32" => FloatTy::F32, + "64" => FloatTy::F64, + "128" => FloatTy::F128, + _ => return None, + }; + + let host_float_op = match op { + "sin" => HostUnaryFloatOp::Sin, + "cos" => HostUnaryFloatOp::Cos, + "exp" => HostUnaryFloatOp::Exp, + "exp2" => HostUnaryFloatOp::Exp2, + "log" => HostUnaryFloatOp::Log, + "log10" => HostUnaryFloatOp::Log10, + "log2" => HostUnaryFloatOp::Log2, + _ => return None, + }; + + Some((float_ty, host_float_op)) +} + +fn pow_intrinsic<'tcx, S: Semantics>( + this: &mut MiriInterpCx<'tcx>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx, ()> +where + IeeeFloat: HostFloatOperation + IeeeExt + Float + Into, +{ + let [f1, f2] = check_intrinsic_arg_count(args)?; + let f1: IeeeFloat = this.read_scalar(f1)?.to_float()?; + let f2: IeeeFloat = this.read_scalar(f2)?.to_float()?; + + let res = math::fixed_float_value(this, "pow", &[f1, f2]).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f1.host_powf(f2); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + math::apply_random_float_error_ulp(this, res, 4) + }); + let res = this.adjust_nan(res, &[f1, f2]); + this.write_scalar(res, dest)?; + interp_ok(()) +} +fn powi_intrinsic<'tcx, S: Semantics>( + this: &mut MiriInterpCx<'tcx>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx, ()> +where + IeeeFloat: HostFloatOperation + IeeeExt + Float + Into, +{ + let [f, i] = check_intrinsic_arg_count(args)?; + let f: IeeeFloat = this.read_scalar(f)?.to_float()?; + let i = this.read_scalar(i)?.to_i32()?; + + let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f.host_powi(i); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + math::apply_random_float_error_ulp(this, res, 4) + }); let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest) + this.write_scalar(res, dest)?; + interp_ok(()) } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -108,161 +179,25 @@ fn emulate_math_intrinsic( } // Operations that need host floats. - #[rustfmt::skip] - | "sinf32" - | "cosf32" - | "expf32" - | "exp2f32" - | "logf32" - | "log10f32" - | "log2f32" - => { + _ if let Some((float_ty, op)) = is_host_unary_float_op(intrinsic_name) => { let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - - let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { - // Using host floats (but it's fine, these operations do not have - // guaranteed precision). - let host = f.to_host(); - let res = match intrinsic_name { - "sinf32" => host.sin(), - "cosf32" => host.cos(), - "expf32" => host.exp(), - "exp2f32" => host.exp2(), - "logf32" => host.ln(), - "log10f32" => host.log10(), - "log2f32" => host.log2(), - _ => bug!(), - }; - let res = res.to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp( - this, - res, - 4, - ); - - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - math::clamp_float_value(intrinsic_name, res) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; + match float_ty { + FloatTy::F16 => host_unary_float_op::(this, f, op, dest)?, + FloatTy::F32 => host_unary_float_op::(this, f, op, dest)?, + FloatTy::F64 => host_unary_float_op::(this, f, op, dest)?, + FloatTy::F128 => todo!("f128"), // FIXME(f128) + }; } - #[rustfmt::skip] - | "sinf64" - | "cosf64" - | "expf64" - | "exp2f64" - | "logf64" - | "log10f64" - | "log2f64" - => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; + "powf16" => pow_intrinsic::(this, args, dest)?, + "powf32" => pow_intrinsic::(this, args, dest)?, + "powf64" => pow_intrinsic::(this, args, dest)?, + "powf128" => todo!("f128"), // FIXME(f128) - let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { - // Using host floats (but it's fine, these operations do not have - // guaranteed precision). - let host = f.to_host(); - let res = match intrinsic_name { - "sinf64" => host.sin(), - "cosf64" => host.cos(), - "expf64" => host.exp(), - "exp2f64" => host.exp2(), - "logf64" => host.ln(), - "log10f64" => host.log10(), - "log2f64" => host.log2(), - _ => bug!(), - }; - let res = res.to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp( - this, - res, - 4, - ); - - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - math::clamp_float_value(intrinsic_name, res) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - - "powf32" => { - let [f1, f2] = check_intrinsic_arg_count(args)?; - let f1 = this.read_scalar(f1)?.to_f32()?; - let f2 = this.read_scalar(f2)?.to_f32()?; - - let res = - math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f1.to_host().powf(f2.to_host()).to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - math::apply_random_float_error_ulp(this, res, 4) - }); - let res = this.adjust_nan(res, &[f1, f2]); - this.write_scalar(res, dest)?; - } - "powf64" => { - let [f1, f2] = check_intrinsic_arg_count(args)?; - let f1 = this.read_scalar(f1)?.to_f64()?; - let f2 = this.read_scalar(f2)?.to_f64()?; - - let res = - math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f1.to_host().powf(f2.to_host()).to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - math::apply_random_float_error_ulp(this, res, 4) - }); - let res = this.adjust_nan(res, &[f1, f2]); - this.write_scalar(res, dest)?; - } - - "powif32" => { - let [f, i] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - let i = this.read_scalar(i)?.to_i32()?; - - let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f.to_host().powi(i).to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - math::apply_random_float_error_ulp(this, res, 4) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "powif64" => { - let [f, i] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; - let i = this.read_scalar(i)?.to_i32()?; - - let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f.to_host().powi(i).to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - math::apply_random_float_error_ulp(this, res, 4) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } + "powif16" => powi_intrinsic::(this, args, dest)?, + "powif32" => powi_intrinsic::(this, args, dest)?, + "powif64" => powi_intrinsic::(this, args, dest)?, + "powif128" => todo!("f128"), // FIXME(f128) _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 2b176093cb36..74582bc58900 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -1,8 +1,9 @@ +use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS}; use rustc_middle::ty; use rustc_middle::ty::FloatTy; use super::check_intrinsic_arg_count; -use crate::helpers::{ToHost, ToSoft}; +use crate::math::{HostUnaryFloatOp, host_unary_float_op}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -17,16 +18,8 @@ fn emulate_simd_intrinsic( ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match intrinsic_name { - #[rustfmt::skip] - | "fsqrt" - | "fsin" - | "fcos" - | "fexp" - | "fexp2" - | "flog" - | "flog2" - | "flog10" - => { + // Operations we can do with soft-floats. + "fsqrt" => { let [op] = check_intrinsic_arg_count(args)?; let (op, op_len) = this.project_to_simd(op)?; let (dest, dest_len) = this.project_to_simd(dest)?; @@ -34,51 +27,53 @@ fn emulate_simd_intrinsic( assert_eq!(dest_len, op_len); for i in 0..dest_len { - let op = this.read_immediate(&this.project_index(&op, i)?)?; + let op = this.project_index(&op, i)?; + let dest = this.project_index(&dest, i)?; + let ty::Float(float_ty) = op.layout.ty.kind() else { + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) + }; + match float_ty { + FloatTy::F16 => math::sqrt_op::>(this, &op, &dest)?, + FloatTy::F32 => math::sqrt_op::>(this, &op, &dest)?, + FloatTy::F64 => math::sqrt_op::>(this, &op, &dest)?, + FloatTy::F128 => math::sqrt_op::>(this, &op, &dest)?, + }; + } + } + + // Operations that need host floats. + "fsin" | "fcos" | "fexp" | "fexp2" | "flog" | "flog2" | "flog10" => { + let [op] = check_intrinsic_arg_count(args)?; + let (op, op_len) = this.project_to_simd(op)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + let host_op = match intrinsic_name { + "fsin" => HostUnaryFloatOp::Sin, + "fcos" => HostUnaryFloatOp::Cos, + "fexp" => HostUnaryFloatOp::Exp, + "fexp2" => HostUnaryFloatOp::Exp2, + "flog" => HostUnaryFloatOp::Log, + "flog2" => HostUnaryFloatOp::Log2, + "flog10" => HostUnaryFloatOp::Log10, + _ => bug!(), + }; + + for i in 0..dest_len { + let op = this.project_index(&op, i)?; let dest = this.project_index(&dest, i)?; let ty::Float(float_ty) = op.layout.ty.kind() else { span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; // Using host floats except for sqrt (but it's fine, these operations do not // have guaranteed precision). - let val = match float_ty { - FloatTy::F16 => unimplemented!("f16_f128"), - FloatTy::F32 => { - let f = op.to_scalar().to_f32()?; - let res = match intrinsic_name { - "fsqrt" => math::sqrt(f), - "fsin" => f.to_host().sin().to_soft(), - "fcos" => f.to_host().cos().to_soft(), - "fexp" => f.to_host().exp().to_soft(), - "fexp2" => f.to_host().exp2().to_soft(), - "flog" => f.to_host().ln().to_soft(), - "flog2" => f.to_host().log2().to_soft(), - "flog10" => f.to_host().log10().to_soft(), - _ => bug!(), - }; - let res = this.adjust_nan(res, &[f]); - Scalar::from(res) - } - FloatTy::F64 => { - let f = op.to_scalar().to_f64()?; - let res = match intrinsic_name { - "fsqrt" => math::sqrt(f), - "fsin" => f.to_host().sin().to_soft(), - "fcos" => f.to_host().cos().to_soft(), - "fexp" => f.to_host().exp().to_soft(), - "fexp2" => f.to_host().exp2().to_soft(), - "flog" => f.to_host().ln().to_soft(), - "flog2" => f.to_host().log2().to_soft(), - "flog10" => f.to_host().log10().to_soft(), - _ => bug!(), - }; - let res = this.adjust_nan(res, &[f]); - Scalar::from(res) - } - FloatTy::F128 => unimplemented!("f16_f128"), - }; - - this.write_scalar(val, &dest)?; + match float_ty { + FloatTy::F16 => host_unary_float_op::(this, &op, host_op, &dest)?, + FloatTy::F32 => host_unary_float_op::(this, &op, host_op, &dest)?, + FloatTy::F64 => host_unary_float_op::(this, &op, host_op, &dest)?, + FloatTy::F128 => unimplemented!("f128"), // FIXME(f128) + } } } "expose_provenance" => { diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 244203587950..f41e3c20a7d5 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,21 +1,30 @@ -#![feature(abort_unwind)] +#![cfg_attr(all(feature = "native-lib", unix), feature(iter_advance_by))] +#![cfg_attr( + all( + feature = "native-lib", + target_os = "linux", + target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64") + ), + feature(abort_unwind) +)] #![feature(rustc_private)] +#![feature(f16)] #![feature(float_gamma)] #![feature(float_erf)] #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] #![feature(io_error_more)] +#![feature(io_error_inprogress)] #![feature(variant_count)] #![feature(yeet_expr)] -#![feature(nonzero_ops)] #![feature(pointer_is_aligned_to)] -#![feature(ptr_metadata)] #![feature(unqualified_local_imports)] #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] -#![feature(iter_advance_by)] #![feature(macro_metavar_expr)] +#![feature(uint_carryless_mul)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -41,8 +50,6 @@ clippy::collapsible_match, // We are not implementing queries here so it's fine rustc::potential_query_instability, - // FIXME: Unused features should be removed in the future - unused_features, )] #![warn( rust_2018_idioms, @@ -101,7 +108,7 @@ use rustc_log::tracing::{self, info, trace}; use rustc_middle::{bug, span_bug}; -#[cfg(all(unix, feature = "native-lib"))] +#[cfg(all(feature = "native-lib", unix))] pub mod native_lib { pub use crate::shims::{init_sv, register_retcode_sv}; } @@ -126,6 +133,7 @@ pub mod native_lib { BorTag, BorrowTrackerMethod, EvalContextExt as _, TreeBorrowsParams, }; pub use crate::clock::{Instant, MonotonicClock}; +pub use crate::concurrency::blocking_io::{BlockingIoManager, EvalContextExt as _, WithSource}; pub use crate::concurrency::cpu_affinity::MAX_CPUS; pub use crate::concurrency::data_race::{ AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 000f4ac4ceca..566a775b9010 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -537,6 +537,9 @@ pub struct MiriMachine<'tcx> { /// The set of threads. pub(crate) threads: ThreadManager<'tcx>, + /// Handles blocking I/O and polling for completion. + pub(crate) blocking_io: BlockingIoManager, + /// Stores which thread is eligible to run on which CPUs. /// This has no effect at all, it is just tracked to produce the correct result /// in `sched_getaffinity` @@ -566,7 +569,7 @@ pub struct MiriMachine<'tcx> { pub(crate) user_relevant_crates: Vec, /// Mapping extern static names to their pointer. - extern_statics: FxHashMap, + pub(crate) extern_statics: FxHashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -596,12 +599,12 @@ pub struct MiriMachine<'tcx> { pub(crate) basic_block_count: u64, /// Handle of the optional shared object file for native functions. - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] pub native_lib: Vec<(libloading::Library, std::path::PathBuf)>, - #[cfg(not(all(unix, feature = "native-lib")))] + #[cfg(not(all(feature = "native-lib", unix)))] pub native_lib: Vec, /// A memory location for exchanging the current `ecx` pointer with native code. - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] pub native_lib_ecx_interchange: &'static Cell, /// Run a garbage collector for BorTags every N basic blocks. @@ -732,6 +735,8 @@ pub(crate) fn new( thread_cpu_affinity .insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus)); } + let blocking_io = BlockingIoManager::new(config.isolated_op == IsolatedOp::Allow) + .expect("Couldn't create poll instance"); let alloc_addresses = RefCell::new(alloc_addresses::GlobalStateInner::new(config, stack_addr, tcx)); MiriMachine { @@ -754,6 +759,7 @@ pub(crate) fn new( layouts, threads, thread_cpu_affinity, + blocking_io, static_roots: Vec::new(), profiler, string_cache: Default::default(), @@ -772,7 +778,7 @@ pub(crate) fn new( report_progress: config.report_progress, basic_block_count: 0, monotonic_clock: MonotonicClock::new(config.isolated_op == IsolatedOp::Allow), - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] native_lib: config.native_lib.iter().map(|lib_file_path| { let host_triple = rustc_session::config::host_tuple(); let target_triple = tcx.sess.opts.target_triple.tuple(); @@ -794,9 +800,9 @@ pub(crate) fn new( lib_file_path.clone(), ) }).collect(), - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] native_lib_ecx_interchange: Box::leak(Box::new(Cell::new(0))), - #[cfg(not(all(unix, feature = "native-lib")))] + #[cfg(not(all(feature = "native-lib", unix)))] native_lib: config.native_lib.iter().map(|_| { panic!("calling functions from native libraries via FFI is not supported in this build of Miri") }).collect(), @@ -1010,6 +1016,7 @@ fn visit_provenance(&self, visit: &mut VisitWith<'_>) { data_race, alloc_addresses, fds, + blocking_io:_, epoll_interests:_, tcx: _, isolated_op: _, @@ -1032,7 +1039,7 @@ fn visit_provenance(&self, visit: &mut VisitWith<'_>) { report_progress: _, basic_block_count: _, native_lib: _, - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] native_lib_ecx_interchange: _, gc_interval: _, since_gc: _, diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index f9ff4c84c129..a46d849a18ea 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -1,13 +1,72 @@ use std::ops::Neg; -use std::{f32, f64}; use rand::Rng as _; -use rustc_apfloat::Float; -use rustc_apfloat::ieee::{DoubleS, IeeeFloat, Semantics, SingleS}; +use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, Semantics, SingleS}; +use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::ty::{self, FloatTy, ScalarInt}; use crate::*; +/// Convert a softfloat type to its corresponding hostfloat type. +pub trait ToHost { + type HostFloat; + fn to_host(self) -> Self::HostFloat; +} + +/// Convert a hostfloat type to its corresponding softfloat type. +pub trait ToSoft { + type SoftFloat; + fn to_soft(self) -> Self::SoftFloat; +} + +impl ToHost for rustc_apfloat::ieee::Double { + type HostFloat = f64; + + fn to_host(self) -> Self::HostFloat { + f64::from_bits(self.to_bits().try_into().unwrap()) + } +} + +impl ToSoft for f64 { + type SoftFloat = rustc_apfloat::ieee::Double; + + fn to_soft(self) -> Self::SoftFloat { + Float::from_bits(self.to_bits().into()) + } +} + +impl ToHost for rustc_apfloat::ieee::Single { + type HostFloat = f32; + + fn to_host(self) -> Self::HostFloat { + f32::from_bits(self.to_bits().try_into().unwrap()) + } +} + +impl ToSoft for f32 { + type SoftFloat = rustc_apfloat::ieee::Single; + + fn to_soft(self) -> Self::SoftFloat { + Float::from_bits(self.to_bits().into()) + } +} + +impl ToHost for rustc_apfloat::ieee::Half { + type HostFloat = f16; + + fn to_host(self) -> Self::HostFloat { + f16::from_bits(self.to_bits().try_into().unwrap()) + } +} + +impl ToSoft for f16 { + type SoftFloat = rustc_apfloat::ieee::Half; + + fn to_soft(self) -> Self::SoftFloat { + Float::from_bits(self.to_bits().into()) + } +} + /// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale). pub(crate) fn apply_random_float_error( ecx: &mut crate::MiriInterpCx<'_>, @@ -108,6 +167,21 @@ pub(crate) fn apply_random_float_error_to_imm<'tcx>( interp_ok(ImmTy::from_scalar_int(res, val.layout)) } +/// Remove `f16`/`f32`/`f64`/`f128` suffix, if any. +/// +/// Also strip trailing `f` (indicates "float"), with an exception for "erf" to avoid +/// removing that `f`. +fn strip_float_suffix(intrinsic_name: &str) -> &str { + let name = intrinsic_name + .strip_suffix("f16") + .or_else(|| intrinsic_name.strip_suffix("f32")) + .or_else(|| intrinsic_name.strip_suffix("f64")) + .or_else(|| intrinsic_name.strip_suffix("f128")) + .unwrap_or(intrinsic_name); + + if name == "erf" { name } else { name.strip_suffix("f").unwrap_or(name) } +} + /// Given a floating-point operation and a floating-point value, clamps the result to the output /// range of the given operation according to the C standard, if any. pub(crate) fn clamp_float_value( @@ -123,40 +197,33 @@ pub(crate) fn clamp_float_value( let pi = IeeeFloat::::pi(); let pi_over_2 = (pi / two).value; - match intrinsic_name { + match strip_float_suffix(intrinsic_name) { // sin, cos, tanh: [-1, 1] - #[rustfmt::skip] - | "sinf32" - | "sinf64" - | "cosf32" - | "cosf64" - | "tanhf" - | "tanh" - => val.clamp(one.neg(), one), + "sin" | "cos" | "tanh" => val.clamp(one.neg(), one), // exp: [0, +INF) - "expf32" | "exp2f32" | "expf64" | "exp2f64" => val.maximum(zero), + "exp" | "exp2" => val.maximum(zero), // cosh: [1, +INF) - "coshf" | "cosh" => val.maximum(one), + "cosh" => val.maximum(one), // acos: [0, π] - "acosf" | "acos" => val.clamp(zero, pi), + "acos" => val.clamp(zero, pi), // asin: [-π, +π] - "asinf" | "asin" => val.clamp(pi.neg(), pi), + "asin" => val.clamp(pi.neg(), pi), // atan: (-π/2, +π/2) - "atanf" | "atan" => val.clamp(pi_over_2.neg(), pi_over_2), + "atan" => val.clamp(pi_over_2.neg(), pi_over_2), // erfc: (-1, 1) - "erff" | "erf" => val.clamp(one.neg(), one), + "erf" => val.clamp(one.neg(), one), // erfc: (0, 2) - "erfcf" | "erfc" => val.clamp(zero, two), + "erfc" => val.clamp(zero, two), // atan2(y, x): arctan(y/x) in [−π, +π] - "atan2f" | "atan2" => val.clamp(pi.neg(), pi), + "atan2" => val.clamp(pi.neg(), pi), _ => val, } @@ -210,15 +277,7 @@ pub(crate) fn fixed_float_value( let pi_over_2 = (pi / two).value; let pi_over_4 = (pi_over_2 / two).value; - // Remove `f32`/`f64` suffix, if any. - let name = intrinsic_name - .strip_suffix("f32") - .or_else(|| intrinsic_name.strip_suffix("f64")) - .unwrap_or(intrinsic_name); - // Also strip trailing `f` (indicates "float"), with an exception for "erf" to avoid - // removing that `f`. - let name = if name == "erf" { name } else { name.strip_suffix("f").unwrap_or(name) }; - Some(match (name, args) { + Some(match (strip_float_suffix(intrinsic_name), args) { // cos(±0) and cosh(±0)= 1 ("cos" | "cosh", [input]) if input.is_zero() => one, @@ -400,6 +459,129 @@ pub(crate) fn sqrt(x: F) -> F { } } +pub fn sqrt_op<'tcx, F: Float + FloatConvert + Into>( + this: &mut MiriInterpCx<'tcx>, + f: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx> { + let f: F = this.read_scalar(f)?.to_float()?; + // Sqrt is specified to be fully precise. + let res = math::sqrt(f); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest) +} + +pub trait HostFloatOperation { + fn host_sin(self) -> Self; + fn host_cos(self) -> Self; + fn host_exp(self) -> Self; + fn host_exp2(self) -> Self; + fn host_log(self) -> Self; + fn host_log10(self) -> Self; + fn host_log2(self) -> Self; + fn host_powf(self, y: Self) -> Self; + fn host_powi(self, y: i32) -> Self; +} + +macro_rules! impl_float_host_operations { + ($ty:ty) => { + impl HostFloatOperation for $ty { + fn host_sin(self) -> Self { + self.to_host().sin().to_soft() + } + fn host_cos(self) -> Self { + self.to_host().cos().to_soft() + } + fn host_exp(self) -> Self { + self.to_host().exp().to_soft() + } + fn host_exp2(self) -> Self { + self.to_host().exp2().to_soft() + } + fn host_log(self) -> Self { + self.to_host().ln().to_soft() + } + fn host_log10(self) -> Self { + self.to_host().log10().to_soft() + } + fn host_log2(self) -> Self { + self.to_host().log2().to_soft() + } + fn host_powf(self, y: Self) -> Self { + self.to_host().powf(y.to_host()).to_soft() + } + fn host_powi(self, y: i32) -> Self { + self.to_host().powi(y).to_soft() + } + } + }; +} + +impl_float_host_operations!(IeeeFloat); +impl_float_host_operations!(IeeeFloat); +impl_float_host_operations!(IeeeFloat); + +#[derive(Debug, Clone, Copy)] +pub enum HostUnaryFloatOp { + Sin, + Cos, + Exp, + Exp2, + Log, + Log10, + Log2, +} + +pub fn host_unary_float_op<'tcx, S: Semantics>( + this: &mut MiriInterpCx<'tcx>, + f: &OpTy<'tcx>, + op: HostUnaryFloatOp, + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx> +where + IeeeFloat: HostFloatOperation + IeeeExt + Float + Into, +{ + use HostFloatOperation; + + let f: IeeeFloat = this.read_scalar(f)?.to_float()?; + + // The fixed-value and clamping functions need the name as a string. + let name = match op { + HostUnaryFloatOp::Sin => "sin", + HostUnaryFloatOp::Cos => "cos", + HostUnaryFloatOp::Exp => "exp", + HostUnaryFloatOp::Exp2 => "exp2", + HostUnaryFloatOp::Log => "log", + HostUnaryFloatOp::Log10 => "log10", + HostUnaryFloatOp::Log2 => "log2", + }; + let res = math::fixed_float_value(this, name, &[f]).unwrap_or_else(|| { + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let res = match op { + HostUnaryFloatOp::Sin => f.host_sin(), + HostUnaryFloatOp::Cos => f.host_cos(), + HostUnaryFloatOp::Exp => f.host_exp(), + HostUnaryFloatOp::Exp2 => f.host_exp2(), + HostUnaryFloatOp::Log => f.host_log(), + HostUnaryFloatOp::Log10 => f.host_log10(), + HostUnaryFloatOp::Log2 => f.host_log2(), + }; + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp(this, res, 4); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(name, res) + }); + + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + interp_ok(()) +} + /// Extend functionality of `rustc_apfloat` softfloats for IEEE float types. pub trait IeeeExt: rustc_apfloat::Float { // Some values we use: @@ -433,12 +615,13 @@ impl IeeeExt for IeeeFloat<$semantic> { #[inline] fn pi() -> Self { // We take the value from the standard library as the most reasonable source for an exact π here. - Self::from_bits($float_ty::consts::PI.to_bits().into()) + Self::from_bits(core::$float_ty::consts::PI.to_bits().into()) } } }; } +impl_ieee_pi!(f16, HalfS); impl_ieee_pi!(f32, SingleS); impl_ieee_pi!(f64, DoubleS); diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index 66b0adb3c4eb..f2c750a7577f 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -19,7 +19,7 @@ fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {} )+ } } -no_provenance!(i8 i16 i32 i64 isize u8 u16 u32 u64 usize ThreadId); +no_provenance!(i8 i16 i32 i64 isize u8 u16 u32 u64 usize bool ThreadId); impl VisitProvenance for Option { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs index d06b02a41334..6a914d5cfa68 100644 --- a/src/tools/miri/src/shims/aarch64.rs +++ b/src/tools/miri/src/shims/aarch64.rs @@ -4,6 +4,7 @@ use rustc_span::Symbol; use rustc_target::callconv::FnAbi; +use crate::shims::math::compute_crc32; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -58,6 +59,93 @@ fn emulate_aarch64_intrinsic( this.write_immediate(*res_lane, &dest)?; } } + + // Wrapping pairwise addition. + // + // Concatenates the two input vectors and adds adjacent elements. For input vectors `v` + // and `w` this computes `[v0 + v1, v2 + v3, ..., w0 + w1, w2 + w3, ...]`, using + // wrapping addition for `+`. + // + // Used by `vpadd_{s8, u8, s16, u16, s32, u32}`. + name if name.starts_with("neon.addp.") => { + let [left, right] = + this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(left_len, dest_len); + + assert_eq!(left.layout, right.layout); + assert_eq!(left.layout, dest.layout); + + assert!(dest_len.is_multiple_of(2)); + let half_len = dest_len.strict_div(2); + + for lane_idx in 0..dest_len { + // The left and right vectors are concatenated. + let (src, src_pair_idx) = if lane_idx < half_len { + (&left, lane_idx) + } else { + (&right, lane_idx.strict_sub(half_len)) + }; + // Convert "pair index" into "index of first element of the pair". + let i = src_pair_idx.strict_mul(2); + + let lhs = this.read_immediate(&this.project_index(src, i)?)?; + let rhs = this.read_immediate(&this.project_index(src, i.strict_add(1))?)?; + + // Wrapping addition on the element type. + let sum = this.binary_op(BinOp::Add, &lhs, &rhs)?; + + let dst_lane = this.project_index(&dest, lane_idx)?; + this.write_immediate(*sum, &dst_lane)?; + } + } + + // Widening pairwise addition. + // + // Takes a single input vector, and an output vector with half as many lanes and double + // the element width. Takes adjacent pairs of elements, widens both, and then adds them + // together. + // + // Used by `vpaddl_{u8, u16, u32}` and `vpaddlq_{u8, u16, u32}`. + name if name.starts_with("neon.uaddlp.") => { + let [src] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + let (src, src_len) = this.project_to_simd(src)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + // Operates pairwise, so src has twice as many lanes. + assert_eq!(src_len, dest_len.strict_mul(2)); + + let src_elem_size = src.layout.field(this, 0).size; + let dest_elem_size = dest.layout.field(this, 0).size; + + // Widens, so dest elements must be exactly twice as wide. + assert_eq!(dest_elem_size.bytes(), src_elem_size.bytes().strict_mul(2)); + + for dest_idx in 0..dest_len { + let src_idx = dest_idx.strict_mul(2); + + let a_scalar = this.read_scalar(&this.project_index(&src, src_idx)?)?; + let b_scalar = + this.read_scalar(&this.project_index(&src, src_idx.strict_add(1))?)?; + + let a_val = a_scalar.to_uint(src_elem_size)?; + let b_val = b_scalar.to_uint(src_elem_size)?; + + // Use addition on u128 to simulate widening addition for the destination type. + // This cannot wrap since the element type is at most u64. + let sum = a_val.strict_add(b_val); + + let dst_lane = this.project_index(&dest, dest_idx)?; + this.write_scalar(Scalar::from_uint(sum, dest_elem_size), &dst_lane)?; + } + } + // Vector table lookup: each index selects a byte from the 16-byte table, out-of-range -> 0. // Used to implement vtbl1_u8 function. // LLVM does not have a portable shuffle that takes non-const indices @@ -85,6 +173,47 @@ fn emulate_aarch64_intrinsic( this.write_scalar(val, &this.project_index(&dest, i)?)?; } } + // Used to implement the __crc32{b,h,w,x} and __crc32c{b,h,w,x} functions. + // Polynomial 0x04C11DB7 (standard CRC-32): + // https://developer.arm.com/documentation/ddi0602/latest/Base-Instructions/CRC32B--CRC32H--CRC32W--CRC32X--CRC32-checksum- + // Polynomial 0x1EDC6F41 (CRC-32C / Castagnoli): + // https://developer.arm.com/documentation/ddi0602/latest/Base-Instructions/CRC32CB--CRC32CH--CRC32CW--CRC32CX--CRC32C-checksum- + "crc32b" | "crc32h" | "crc32w" | "crc32x" | "crc32cb" | "crc32ch" | "crc32cw" + | "crc32cx" => { + this.expect_target_feature_for_intrinsic(link_name, "crc")?; + // The polynomial constants below include the leading 1 bit + // (e.g. 0x104C11DB7 instead of 0x04C11DB7) which the ARM docs + // omit but the polynomial division algorithm requires. + let (bit_size, polynomial): (u32, u128) = match unprefixed_name { + "crc32b" => (8, 0x104C11DB7), + "crc32h" => (16, 0x104C11DB7), + "crc32w" => (32, 0x104C11DB7), + "crc32x" => (64, 0x104C11DB7), + "crc32cb" => (8, 0x11EDC6F41), + "crc32ch" => (16, 0x11EDC6F41), + "crc32cw" => (32, 0x11EDC6F41), + "crc32cx" => (64, 0x11EDC6F41), + _ => unreachable!(), + }; + + let [left, right] = + this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let left = this.read_scalar(left)?; + let right = this.read_scalar(right)?; + + // The CRC accumulator is always u32. The data argument is u32 for + // b/h/w variants and u64 for the x variant, per the LLVM intrinsic + // definitions (all b/h/w take i32, only x takes i64). + // https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/IntrinsicsAArch64.td + // If the higher bits are non-zero, `compute_crc32` will panic. We should probably + // raise a proper error instead, but outside stdarch nobody can trigger this anyway. + let crc = left.to_u32()?; + let data = + if bit_size == 64 { right.to_u64()? } else { u64::from(right.to_u32()?) }; + + let result = compute_crc32(crc, data, bit_size, polynomial); + this.write_scalar(Scalar::from_u32(result), dest)?; + } _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 536e77217d83..1c2fdfeea44d 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -255,7 +255,7 @@ fn emulate_foreign_item_inner( let this = self.eval_context_mut(); // First deal with any external C functions in linked .so file. - #[cfg(all(unix, feature = "native-lib"))] + #[cfg(all(feature = "native-lib", unix))] if !this.machine.native_lib.is_empty() { use crate::shims::native_lib::EvalContextExt as _; // An Ok(false) here means that the function being called was not exported diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index 91ae448e2165..bb761980e6c5 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -56,7 +56,7 @@ fn from(value: Scalar) -> Self { } // This mapping should match `decode_error_kind` in -// . +// . const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { use std::io::ErrorKind::*; &[ @@ -94,6 +94,7 @@ fn from(value: Scalar) -> Self { ("ETIMEDOUT", TimedOut), ("ETXTBSY", ExecutableFileBusy), ("EXDEV", CrossesDevices), + ("EINPROGRESS", InProgress), // The following have two valid options. We have both for the forwards mapping; only the // first one will be used for the backwards mapping. ("EPERM", PermissionDenied), @@ -103,7 +104,7 @@ fn from(value: Scalar) -> Self { ] }; // This mapping should match `decode_error_kind` in -// . +// . const WINDOWS_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { use std::io::ErrorKind::*; // It's common for multiple error codes to map to the same io::ErrorKind. We have all for the diff --git a/src/tools/miri/src/shims/math.rs b/src/tools/miri/src/shims/math.rs index 576e76494bcb..1da7fbbdac0c 100644 --- a/src/tools/miri/src/shims/math.rs +++ b/src/tools/miri/src/shims/math.rs @@ -4,7 +4,7 @@ use rustc_span::Symbol; use rustc_target::callconv::FnAbi; -use self::helpers::{ToHost, ToSoft}; +use self::math::{ToHost, ToSoft}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -245,3 +245,51 @@ fn emulate_foreign_item_inner( interp_ok(EmulateItemResult::NeedsReturn) } } + +/// Compute a CRC32 checksum using the given polynomial. +/// +/// `bit_size` is the number of relevant data bits (8, 16, 32, or 64). +/// Only the low `bit_size` bits of `data` are used; higher bits must be zero. +/// `polynomial` includes the leading 1 bit (e.g. `0x11EDC6F41` for CRC32C). +/// +/// Following hardware CRC conventions, `crc` and `data` bits are assumed to be reversed, +/// and output bits will be equally reversed. +pub(crate) fn compute_crc32(crc: u32, data: u64, bit_size: u32, polynomial: u128) -> u32 { + assert!( + bit_size == 64 || data < 1u64.strict_shl(bit_size), + "crc32: `data` is larger than {bit_size} bits" + ); + // Bit-reverse inputs to match hardware CRC conventions. + let crc = u128::from(crc.reverse_bits()); + // Reverse all 64 bits of `data`, then shift right by `64 - bit_size`. This + // discards the (now-reversed) higher bits, leaving only the reversed low + // `bit_size` bits in the lowest positions (with zeros above). + let v = u128::from(data.reverse_bits() >> (64u32.strict_sub(bit_size))); + + // Perform polynomial division modulo 2. + // The algorithm for the division is an adapted version of the + // schoolbook division algorithm used for normal integer or polynomial + // division. In this context, the quotient is not calculated, since + // only the remainder is needed. + // + // The algorithm works as follows: + // 1. Pull down digits until division can be performed. In the context of division + // modulo 2 it means locating the most significant digit of the dividend and shifting + // the divisor such that the position of the divisors most significand digit and the + // dividends most significand digit match. + // 2. Perform a division and determine the remainder. Since it is arithmetic modulo 2, + // this operation is a simple bitwise exclusive or. + // 3. Repeat steps 1. and 2. until the full remainder is calculated. This is the case + // once the degree of the remainder polynomial is smaller than the degree of the + // divisor polynomial. In other words, the number of leading zeros of the remainder + // is larger than the number of leading zeros of the divisor. It is important to + // note that standard arithmetic comparison is not applicable here: + // 0b10011 / 0b11111 = 0b01100 is a valid division, even though the dividend is + // smaller than the divisor. + let mut dividend = (crc << bit_size) ^ (v << 32); + while dividend.leading_zeros() <= polynomial.leading_zeros() { + dividend ^= (polynomial << polynomial.leading_zeros()) >> dividend.leading_zeros(); + } + + u32::try_from(dividend).unwrap().reverse_bits() +} diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 345e16b8da71..281dfc758f4e 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -5,7 +5,7 @@ mod backtrace; mod files; mod math; -#[cfg(all(unix, feature = "native-lib"))] +#[cfg(all(feature = "native-lib", unix))] pub mod native_lib; mod unix; mod windows; @@ -24,7 +24,7 @@ pub mod unwind; pub use self::files::FdTable; -#[cfg(all(unix, feature = "native-lib"))] +#[cfg(all(feature = "native-lib", unix))] pub use self::native_lib::trace::{init_sv, register_retcode_sv}; pub use self::unix::{DirTable, EpollInterestTable}; diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 8a761855c432..b302a07cf0c5 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -245,7 +245,9 @@ fn op_to_ffi_arg(&self, v: &OpTy<'tcx>, tracing: bool) -> InterpResult<'tcx, Own // This should go first so that we emit unsupported before doing a bunch // of extra work for types that aren't supported yet. - let ty = this.ty_to_ffitype(v.layout)?; + let ty = this + .ty_to_ffitype(v.layout) + .map_err(|ty| err_unsup_format!("unsupported argument type for native call: {ty}"))?; // Helper to print a warning when a pointer is shared with the native code. let expose = |prov: Provenance| -> InterpResult<'tcx> { @@ -363,40 +365,41 @@ fn ffi_ret_to_mem(&mut self, v: Box<[u8]>, dest: &MPlaceTy<'tcx>) -> InterpResul /// Parses an ADT to construct the matching libffi type. fn adt_to_ffitype( &self, - orig_ty: Ty<'_>, + orig_ty: Ty<'tcx>, adt_def: ty::AdtDef<'tcx>, args: &'tcx ty::List>, - ) -> InterpResult<'tcx, FfiType> { + ) -> Result> { let this = self.eval_context_ref(); // TODO: unions, etc. if !adt_def.is_struct() { - throw_unsup_format!("passing an enum or union over FFI: {orig_ty}"); + return Err(orig_ty); } // TODO: Certain non-C reprs should be okay also. if !adt_def.repr().c() { - throw_unsup_format!("passing a non-#[repr(C)] {} over FFI: {orig_ty}", adt_def.descr()) + return Err(orig_ty); } let mut fields = vec![]; for field in &adt_def.non_enum_variant().fields { - let layout = this.layout_of(field.ty(*this.tcx, args))?; + let layout = this.layout_of(field.ty(*this.tcx, args)).map_err(|_err| orig_ty)?; fields.push(this.ty_to_ffitype(layout)?); } - interp_ok(FfiType::structure(fields)) + Ok(FfiType::structure(fields)) } /// Gets the matching libffi type for a given Ty. - fn ty_to_ffitype(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, FfiType> { + fn ty_to_ffitype(&self, layout: TyAndLayout<'tcx>) -> Result> { use rustc_abi::{AddressSpace, BackendRepr, Float, Integer, Primitive}; // `BackendRepr::Scalar` is also a signal to pass this type as a scalar in the ABI. This // matches what codegen does. This does mean that we support some types whose ABI is not // stable, but that's fine -- we are anyway quite conservative in native-lib mode. if let BackendRepr::Scalar(s) = layout.backend_repr { - // Simple sanity-check: this cannot be `repr(C)`. - assert!(!layout.ty.ty_adt_def().is_some_and(|adt| adt.repr().c())); - return interp_ok(match s.primitive() { + // Simple sanity-check: this cannot be a `repr(C)` struct or union. (It could be a + // repr(C) enum. Those indeed behave like integers in the ABI.) + assert!(!layout.ty.ty_adt_def().is_some_and(|adt| !adt.is_enum() && adt.repr().c())); + return Ok(match s.primitive() { Primitive::Int(Integer::I8, /* signed */ true) => FfiType::i8(), Primitive::Int(Integer::I16, /* signed */ true) => FfiType::i16(), Primitive::Int(Integer::I32, /* signed */ true) => FfiType::i32(), @@ -408,17 +411,15 @@ fn ty_to_ffitype(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, FfiType Primitive::Float(Float::F32) => FfiType::f32(), Primitive::Float(Float::F64) => FfiType::f64(), Primitive::Pointer(AddressSpace::ZERO) => FfiType::pointer(), - _ => throw_unsup_format!("unsupported scalar type for native call: {}", layout.ty), + _ => return Err(layout.ty), }); } - interp_ok(match layout.ty.kind() { + Ok(match layout.ty.kind() { // Scalar types have already been handled above. ty::Adt(adt_def, args) => self.adt_to_ffitype(layout.ty, *adt_def, args)?, // Rust uses `()` as return type for `void` function, which becomes `Tuple([])`. ty::Tuple(t_list) if t_list.len() == 0 => FfiType::void(), - _ => { - throw_unsup_format!("unsupported type for native call: {}", layout.ty) - } + _ => return Err(layout.ty), }) } } @@ -427,6 +428,7 @@ fn ty_to_ffitype(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, FfiType /// native code. struct LibffiClosureData<'tcx> { ecx_interchange: &'static Cell, + unsupported: bool, marker: PhantomData>, } @@ -441,22 +443,32 @@ pub fn build_libffi_closure<'tcx, 'this>( fn_sig: rustc_middle::ty::FnSig<'tcx>, ) -> InterpResult<'tcx, unsafe extern "C" fn()> { // Compute argument and return types in libffi representation. - let mut args = Vec::new(); - for input in fn_sig.inputs().iter() { - let layout = this.layout_of(*input)?; - let ty = this.ty_to_ffitype(layout)?; - args.push(ty); - } - let res_type = fn_sig.output(); - let res_type = { - let layout = this.layout_of(res_type)?; - this.ty_to_ffitype(layout)? + let closure_builder = try { + let mut closure_builder = libffi::middle::Builder::new(); + for &input in fn_sig.inputs().iter() { + let layout = this.layout_of(input).map_err(|_| input)?; + let ty = this.ty_to_ffitype(layout)?; + closure_builder = closure_builder.arg(ty); + } + let res_type = fn_sig.output(); + let res_type = { + let layout = this.layout_of(res_type).map_err(|_| res_type)?; + this.ty_to_ffitype(layout)? + }; + closure_builder.res(res_type) }; + let mut unsupported = false; + let closure_builder = closure_builder.unwrap_or_else(|_| { + unsupported = true; + // We hope that a closure which aborts execution is works correctly even if we don't + // set its signature. + libffi::middle::Builder::new() + }); // Build the actual closure. - let closure_builder = libffi::middle::Builder::new().args(args).res(res_type); let data = LibffiClosureData { ecx_interchange: this.machine.native_lib_ecx_interchange, + unsupported, marker: PhantomData, }; let data = Box::leak(Box::new(data)); @@ -486,7 +498,13 @@ pub fn build_libffi_closure<'tcx, 'this>( .as_mut() .expect("libffi closure called while no FFI call is active") }; - let err = err_unsup_format!("calling a function pointer through the FFI boundary"); + let err = if data.unsupported { + err_unsup_format!( + "calling a function pointer with unsupported argument/return type through the FFI boundary" + ) + } else { + err_unsup_format!("calling a function pointer through the FFI boundary") + }; crate::diagnostics::report_result(ecx, err.into()); // We abort the execution at this point as we cannot return the @@ -524,7 +542,9 @@ fn call_native_fn( for arg in args.iter() { libffi_args.push(this.op_to_ffi_arg(arg, tracing)?); } - let ret_ty = this.ty_to_ffitype(dest.layout)?; + let ret_ty = this + .ty_to_ffitype(dest.layout) + .map_err(|ty| err_unsup_format!("unsupported return type for native call: {ty}"))?; // Prepare all exposed memory (both previously exposed, and just newly exposed since a // pointer was passed as argument). Uninitialised memory is left as-is, but any data diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 41bf70c34634..488d82f2109a 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -272,6 +272,53 @@ fn unix_gettid(&mut self, link_name: &str) -> InterpResult<'tcx, Scalar> { interp_ok(Scalar::from_u32(this.get_current_tid())) } + /// `fields_size`, if present, says how large each field of the struct is. + fn uname( + &mut self, + uname: &OpTy<'tcx>, + fields_size: Option<&OpTy<'tcx>>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("uname"); + + let uname_ptr = this.read_pointer(uname)?; + let fields_size = match fields_size { + None => None, + Some(size) => Some(this.read_scalar(size)?.to_i32()?), + }; + + if this.ptr_is_null(uname_ptr)? { + return this.set_last_error_and_return_i32(LibcError("EFAULT")); + } + + let uname = this.deref_pointer_as(uname, this.libc_ty_layout("utsname"))?; + let arch = this.machine.tcx.sess.target.arch.desc_symbol(); + // Values required by POSIX. + let mut values = vec![ + ("sysname", "Miri"), + ("nodename", "Miri"), + ("release", env!("CARGO_PKG_VERSION")), + ("version", concat!("Miri ", env!("CARGO_PKG_VERSION"))), + ("machine", arch.as_str()), + ]; + if matches!(this.machine.tcx.sess.target.os, Os::Linux | Os::Android) { + values.push(("domainname", "(none)")); + } + + for (name, value) in values { + let field = this.project_field_named(&uname, name)?; + let size = field.layout().layout.size().bytes(); + if fields_size.is_some_and(|fields_size| u64::try_from(fields_size) != Ok(size)) { + throw_unsup_format!( + "the fields size passed to `uname` does not match the type in the libc crate" + ); + } + let (written, _) = this.write_c_str(value.as_bytes(), field.ptr(), size)?; + assert!(written); // All values should fit. + } + interp_ok(Scalar::from_i32(0)) + } + /// The Apple-specific `int pthread_threadid_np(pthread_t thread, uint64_t *thread_id)`, which /// allows querying the ID for arbitrary threads, identified by their pthread_t. /// diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 130643ec680d..3651bc171adc 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -174,6 +174,21 @@ fn emulate_foreign_item_inner( let result = this.getpid()?; this.write_scalar(result, dest)?; } + "uname" => { + // Not all Unixes have the `uname` symbol, e.g. FreeBSD does not. + this.check_target_os( + &[Os::Linux, Os::Android, Os::MacOs, Os::Solaris, Os::Illumos], + link_name, + )?; + let [uname] = this.check_shim_sig( + shim_sig!(extern "C" fn(*mut _) -> i32), + link_name, + abi, + args, + )?; + let result = this.uname(uname, None)?; + this.write_scalar(result, dest)?; + } "sysconf" => { let [val] = this.check_shim_sig( shim_sig!(extern "C" fn(i32) -> isize), @@ -550,6 +565,84 @@ fn emulate_foreign_item_inner( let result = this.socket(domain, type_, protocol)?; this.write_scalar(result, dest)?; } + "bind" => { + let [socket, address, address_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32), + link_name, + abi, + args, + )?; + let result = this.bind(socket, address, address_len)?; + this.write_scalar(result, dest)?; + } + "listen" => { + let [socket, backlog] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, i32) -> i32), + link_name, + abi, + args, + )?; + let result = this.listen(socket, backlog)?; + this.write_scalar(result, dest)?; + } + "accept" => { + let [socket, address, address_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32), + link_name, + abi, + args, + )?; + this.accept4(socket, address, address_len, /* flags */ None, dest)?; + } + "accept4" => { + let [socket, address, address_len, flags] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _, *mut _, i32) -> i32), + link_name, + abi, + args, + )?; + this.accept4(socket, address, address_len, Some(flags), dest)?; + } + "connect" => { + let [socket, address, address_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32), + link_name, + abi, + args, + )?; + this.connect(socket, address, address_len, dest)?; + } + "setsockopt" => { + let [socket, level, option_name, option_value, option_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, i32, i32, *const _, libc::socklen_t) -> i32), + link_name, + abi, + args, + )?; + let result = + this.setsockopt(socket, level, option_name, option_value, option_len)?; + this.write_scalar(result, dest)?; + } + "getsockname" => { + let [socket, address, address_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32), + link_name, + abi, + args, + )?; + let result = this.getsockname(socket, address, address_len)?; + this.write_scalar(result, dest)?; + } + "getpeername" => { + let [socket, address, address_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32), + link_name, + abi, + args, + )?; + let result = this.getpeername(socket, address, address_len)?; + this.write_scalar(result, dest)?; + } // Time "gettimeofday" => { @@ -644,11 +737,14 @@ fn emulate_foreign_item_inner( this.read_target_usize(handle)?; let symbol = this.read_pointer(symbol)?; let name = this.read_c_str(symbol)?; - if let Ok(name) = str::from_utf8(name) - && is_dyn_sym(name, &this.tcx.sess.target.os) - { + let Ok(name) = str::from_utf8(name) else { + throw_unsup_format!("dlsym: non UTF-8 symbol name not supported") + }; + if is_dyn_sym(name, &this.tcx.sess.target.os) { let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name))); this.write_pointer(ptr, dest)?; + } else if let Some(&ptr) = this.machine.extern_statics.get(&Symbol::intern(name)) { + this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index f64ee3b16220..de08f4c6afe4 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -165,6 +165,19 @@ fn emulate_foreign_item_inner( let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } + "__xuname" => { + // FreeBSD uses __xuname under the hood to implement uname, see: + // https://github.com/freebsd/freebsd-src/blob/3542d60fb8042474f66fbf2d779ed8c5a80d0f78/sys/sys/utsname.h#L64 + // https://github.com/freebsd/freebsd-src/blob/3542d60fb8042474f66fbf2d779ed8c5a80d0f78/lib/libc/gen/uname.c#L44 + let [size, uname] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _) -> i32), + link_name, + abi, + args, + )?; + let result = this.uname(uname, Some(size))?; + this.write_scalar(result, dest)?; + } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs index 8cf446438963..7c46dd549bc0 100644 --- a/src/tools/miri/src/shims/unix/freebsd/sync.rs +++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs @@ -215,8 +215,17 @@ fn read_umtx_time(&mut self, ut: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option( @@ -26,6 +27,7 @@ pub fn syscall<'tcx>( let sys_futex = ecx.eval_libc("SYS_futex").to_target_usize(ecx)?; let sys_eventfd2 = ecx.eval_libc("SYS_eventfd2").to_target_usize(ecx)?; let sys_gettid = ecx.eval_libc("SYS_gettid").to_target_usize(ecx)?; + let sys_accept4 = ecx.eval_libc("SYS_accept4").to_target_usize(ecx)?; match ecx.read_target_usize(op)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` @@ -59,6 +61,12 @@ pub fn syscall<'tcx>( let result = ecx.unix_gettid("SYS_gettid")?; ecx.write_int(result.to_u32()?, dest)?; } + num if num == sys_accept4 => { + // Used on Android. + let [socket, address, address_len, flags] = + check_min_vararg_count("syscall(SYS_accept4, ...)", varargs)?; + ecx.accept4(socket, address, address_len, Some(flags), dest)?; + } num => { throw_unsup_format!("syscall: unsupported syscall number {num}"); } diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index 66fe5d8a44a4..8f2ab69261ce 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -1,11 +1,16 @@ -use std::cell::Cell; -use std::net::{TcpListener, TcpStream}; +use std::cell::{Cell, RefCell}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::{io, iter}; +use mio::Interest; +use mio::event::Source; +use mio::net::{TcpListener, TcpStream}; +use rustc_abi::Size; use rustc_const_eval::interpret::{InterpResult, interp_ok}; use rustc_middle::throw_unsup_format; use rustc_target::spec::Os; -use crate::shims::files::{FdId, FileDescription}; +use crate::shims::files::{FdId, FileDescription, FileDescriptionRef}; use crate::{OpTy, Scalar, *}; #[derive(Debug, PartialEq)] @@ -16,28 +21,104 @@ enum SocketFamily { IPv6, } -#[derive(Debug)] -enum SocketType { - /// Reliable full-duplex communication, based on connections. - Stream, +enum SocketIoError { + /// The socket is not yet ready. Either EINPROGRESS or ENOTCONNECTED occurred. + NotReady, + /// Any other kind of I/O error. + Other(io::Error), } -#[allow(unused)] -#[derive(Debug)] -enum SocketKind { - TcpListener(TcpListener), - TcpStream(TcpStream), +impl From for SocketIoError { + fn from(value: io::Error) -> Self { + match value.kind() { + io::ErrorKind::InProgress | io::ErrorKind::NotConnected => Self::NotReady, + _ => Self::Other(value), + } + } +} + +#[derive(Debug)] +enum SocketState { + /// No syscall after `socket` has been made. + Initial, + /// The `bind` syscall has been called on the socket. + /// This is only reachable from the [`SocketState::Initial`] state. + Bound(SocketAddr), + /// The `listen` syscall has been called on the socket. + /// This is only reachable from the [`SocketState::Bound`] state. + Listening(TcpListener), + /// The `connect` syscall has been called and we weren't yet able + /// to ensure the connection is established. This is only reachable + /// from the [`SocketState::Initial`] state. + Connecting(TcpStream), + /// The `connect` syscall has been called on the socket and + /// we ensured that the connection is established, or + /// the socket was created by the `accept` syscall. + /// For a socket created using the `connect` syscall, this is + /// only reachable from the [`SocketState::Connecting`] state. + Connected(TcpStream), +} + +impl SocketState { + /// If the socket is currently in [`SocketState::Connecting`], try to ensure + /// that the connection is established by first checking that [`TcpStream::take_error`] + /// doesn't return an error and then by checking that [`TcpStream::peer_addr`] + /// returns the address of the connected peer. + /// + /// If the connection is established or the socket is in any other state, + /// [`Ok`] is returned. + /// + /// **Important**: On Windows hosts this function can only be used to ensure a socket is connected + /// _after_ a [`Interest::WRITABLE`] event was received. + pub fn try_set_connected(&mut self) -> Result<(), SocketIoError> { + // Further explanation of the limitation on Windows hosts: + // Windows treats sockets which are connecting as connected until either the connection timeout hits + // or an error occurs. Thus, the [`TcpStream::peer_addr`] method returns [`Ok`] with the provided peer + // address even when the connection might not yet be established. + + let SocketState::Connecting(stream) = self else { return Ok(()) }; + + if let Ok(Some(e)) = stream.take_error() { + // There was an error whilst connecting. + let e = SocketIoError::from(e); + // We won't get EINPROGRESS or ENOTCONNECTED here + // so we need to reset the state. + assert!(matches!(e, SocketIoError::Other(_))); + // Go back to initial state as the only way of getting into the + // `Connecting` state is from the `Initial` state. + *self = SocketState::Initial; + return Err(e); + } + + if let Err(e) = stream.peer_addr() { + let e = SocketIoError::from(e); + if let SocketIoError::Other(_) = &e { + // All other errors are fatal for a socket and thus the state needs to be reset. + *self = SocketState::Initial; + } + return Err(e); + }; + + // We just read the peer address without an error so we can be + // sure that the connection is established. + + // Temporarily use dummy state to take ownership of the stream. + let SocketState::Connecting(stream) = std::mem::replace(self, SocketState::Initial) else { + // At the start of the function we ensured that we're currently connecting. + unreachable!() + }; + *self = SocketState::Connected(stream); + Ok(()) + } } -#[allow(unused)] #[derive(Debug)] struct Socket { /// Family of the socket, used to ensure socket only binds/connects to address of /// same family. family: SocketFamily, - /// Type of the socket, either datagram or stream. - /// Only stream is supported at the moment! - socket_type: SocketType, + /// Current state of the inner socket. + state: RefCell, /// Whether this fd is non-blocking or not. is_non_block: Cell, } @@ -97,16 +178,19 @@ fn socket( // Reject if isolation is enabled if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`socket`", reject_with)?; - this.set_last_error(LibcError("EACCES"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EACCES")); } let mut is_sock_nonblock = false; // Interpret the flag. Every flag we recognize is "subtracted" from `flags`, so // if there is anything left at the end, that's an unsupported flag. - if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android | Os::FreeBsd) { - // SOCK_NONBLOCK and SOCK_CLOEXEC only exist on Linux, Android and FreeBSD. + if matches!( + this.tcx.sess.target.os, + Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos + ) { + // SOCK_NONBLOCK and SOCK_CLOEXEC only exist on Linux, Android, FreeBSD, + // Solaris, and Illumos targets let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK"); let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC"); if flags & sock_nonblock == sock_nonblock { @@ -126,7 +210,7 @@ fn socket( } else { throw_unsup_format!( "socket: domain {:#x} is unsupported, only AF_INET and \ - AF_INET6 are allowed.", + AF_INET6 are allowed.", domain ); }; @@ -134,24 +218,841 @@ fn socket( if flags != this.eval_libc_i32("SOCK_STREAM") { throw_unsup_format!( "socket: type {:#x} is unsupported, only SOCK_STREAM, \ - SOCK_CLOEXEC and SOCK_NONBLOCK are allowed", + SOCK_CLOEXEC and SOCK_NONBLOCK are allowed", flags ); } if protocol != 0 { throw_unsup_format!( "socket: socket protocol {protocol} is unsupported, \ - only 0 is allowed" + only 0 is allowed" ); } let fds = &mut this.machine.fds; let fd = fds.new_ref(Socket { family, + state: RefCell::new(SocketState::Initial), is_non_block: Cell::new(is_sock_nonblock), - socket_type: SocketType::Stream, }); interp_ok(Scalar::from_i32(fds.insert(fd))) } + + fn bind( + &mut self, + socket: &OpTy<'tcx>, + address: &OpTy<'tcx>, + address_len: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let socket = this.read_scalar(socket)?.to_i32()?; + let address = match this.socket_address(address, address_len, "bind")? { + Ok(addr) => addr, + Err(e) => return this.set_last_error_and_return_i32(e), + }; + + // Get the file handle + let Some(fd) = this.machine.fds.get(socket) else { + return this.set_last_error_and_return_i32(LibcError("EBADF")); + }; + + let Some(socket) = fd.downcast::() else { + // Man page specifies to return ENOTSOCK if `fd` is not a socket. + return this.set_last_error_and_return_i32(LibcError("ENOTSOCK")); + }; + + assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!"); + + let mut state = socket.state.borrow_mut(); + + match *state { + SocketState::Initial => { + let address_family = match &address { + SocketAddr::V4(_) => SocketFamily::IPv4, + SocketAddr::V6(_) => SocketFamily::IPv6, + }; + + if socket.family != address_family { + // Attempted to bind an address from a family that doesn't match + // the family of the socket. + let err = if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android) { + // Linux man page states that `EINVAL` is used when there is an address family mismatch. + // See + LibcError("EINVAL") + } else { + // POSIX man page states that `EAFNOSUPPORT` should be used when there is an address + // family mismatch. + // See + LibcError("EAFNOSUPPORT") + }; + return this.set_last_error_and_return_i32(err); + } + + *state = SocketState::Bound(address); + } + SocketState::Connecting(_) | SocketState::Connected(_) => + throw_unsup_format!( + "bind: socket is already connected and binding a + connected socket is unsupported" + ), + SocketState::Bound(_) | SocketState::Listening(_) => + throw_unsup_format!( + "bind: socket is already bound and binding a socket \ + multiple times is unsupported" + ), + } + + interp_ok(Scalar::from_i32(0)) + } + + fn listen(&mut self, socket: &OpTy<'tcx>, backlog: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let socket = this.read_scalar(socket)?.to_i32()?; + // Since the backlog value is just a performance hint we can ignore it. + let _backlog = this.read_scalar(backlog)?.to_i32()?; + + // Get the file handle + let Some(fd) = this.machine.fds.get(socket) else { + return this.set_last_error_and_return_i32(LibcError("EBADF")); + }; + + let Some(socket) = fd.downcast::() else { + // Man page specifies to return ENOTSOCK if `fd` is not a socket. + return this.set_last_error_and_return_i32(LibcError("ENOTSOCK")); + }; + + assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!"); + + let mut state = socket.state.borrow_mut(); + + match *state { + SocketState::Bound(socket_addr) => + match TcpListener::bind(socket_addr) { + Ok(listener) => *state = SocketState::Listening(listener), + Err(e) => return this.set_last_error_and_return_i32(e), + }, + SocketState::Initial => { + throw_unsup_format!( + "listen: listening on a socket which isn't bound is unsupported" + ) + } + SocketState::Listening(_) => { + throw_unsup_format!("listen: listening on a socket multiple times is unsupported") + } + SocketState::Connecting(_) | SocketState::Connected(_) => { + throw_unsup_format!("listen: listening on a connected socket is unsupported") + } + } + + interp_ok(Scalar::from_i32(0)) + } + + /// For more information on the arguments see the accept manpage: + /// + fn accept4( + &mut self, + socket: &OpTy<'tcx>, + address: &OpTy<'tcx>, + address_len: &OpTy<'tcx>, + flags: Option<&OpTy<'tcx>>, + // Location where the output scalar is written to. + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let socket = this.read_scalar(socket)?.to_i32()?; + let address_ptr = this.read_pointer(address)?; + let address_len_ptr = this.read_pointer(address_len)?; + let mut flags = + if let Some(flags) = flags { this.read_scalar(flags)?.to_i32()? } else { 0 }; + + // Get the file handle + let Some(fd) = this.machine.fds.get(socket) else { + return this.set_last_error_and_return(LibcError("EBADF"), dest); + }; + + let Some(socket) = fd.downcast::() else { + // Man page specifies to return ENOTSOCK if `fd` is not a socket. + return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest); + }; + + assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!"); + + if !matches!(*socket.state.borrow(), SocketState::Listening(_)) { + throw_unsup_format!( + "accept4: accepting incoming connections is only allowed when socket is listening" + ) + }; + + let mut is_client_sock_nonblock = false; + + // Interpret the flag. Every flag we recognize is "subtracted" from `flags`, so + // if there is anything left at the end, that's an unsupported flag. + if matches!( + this.tcx.sess.target.os, + Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos + ) { + // SOCK_NONBLOCK and SOCK_CLOEXEC only exist on Linux, Android, FreeBSD, + // Solaris, and Illumos targets + let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK"); + let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC"); + if flags & sock_nonblock == sock_nonblock { + is_client_sock_nonblock = true; + flags &= !sock_nonblock; + } + if flags & sock_cloexec == sock_cloexec { + // We don't support `exec` so we can ignore this. + flags &= !sock_cloexec; + } + } + + if flags != 0 { + throw_unsup_format!( + "accept4: flag {flags:#x} is unsupported, only SOCK_CLOEXEC \ + and SOCK_NONBLOCK are allowed", + ); + } + + if socket.is_non_block.get() { + throw_unsup_format!("accept4: non-blocking accept is unsupported") + } + + // The socket is in blocking mode and thus the accept call should block + // until an incoming connection is ready. + this.block_for_accept( + address_ptr, + address_len_ptr, + is_client_sock_nonblock, + socket, + dest.clone(), + ); + interp_ok(()) + } + + fn connect( + &mut self, + socket: &OpTy<'tcx>, + address: &OpTy<'tcx>, + address_len: &OpTy<'tcx>, + // Location where the output scalar is written to. + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let socket = this.read_scalar(socket)?.to_i32()?; + let address = match this.socket_address(address, address_len, "connect")? { + Ok(address) => address, + Err(e) => return this.set_last_error_and_return(e, dest), + }; + + // Get the file handle + let Some(fd) = this.machine.fds.get(socket) else { + return this.set_last_error_and_return(LibcError("EBADF"), dest); + }; + + let Some(socket) = fd.downcast::() else { + // Man page specifies to return ENOTSOCK if `fd` is not a socket + return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest); + }; + + assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!"); + + match &*socket.state.borrow() { + SocketState::Initial => { /* fall-through to below */ } + // The socket is already in a connecting state. + SocketState::Connecting(_) => + return this.set_last_error_and_return(LibcError("EALREADY"), dest), + // We don't return EISCONN for already connected sockets, for which we're + // sure that the connection is established, since TCP sockets are usually + // allowed to be connected multiple times. + _ => + throw_unsup_format!( + "connect: connecting is only supported for sockets which are neither \ + bound, listening nor already connected" + ), + } + + // Mio returns a potentially unconnected stream. + // We can be ensured that the connection is established when + // [`TcpStream::take_err`] and [`TcpStream::peer_addr`] both + // don't return errors. + // For non-blocking sockets we need to check that for every + // [`Interest::WRITEABLE`] event on the stream. + match TcpStream::connect(address) { + Ok(stream) => *socket.state.borrow_mut() = SocketState::Connecting(stream), + Err(e) => return this.set_last_error_and_return(e, dest), + }; + + if socket.is_non_block.get() { + throw_unsup_format!("connect: non-blocking connect is unsupported"); + } + + // The socket is in blocking mode and thus the connect call should block + // until the connection with the server is established. + this.block_for_connect(socket, dest.clone()); + interp_ok(()) + } + + fn setsockopt( + &mut self, + socket: &OpTy<'tcx>, + level: &OpTy<'tcx>, + option_name: &OpTy<'tcx>, + option_value: &OpTy<'tcx>, + option_len: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let socket = this.read_scalar(socket)?.to_i32()?; + let level = this.read_scalar(level)?.to_i32()?; + let option_name = this.read_scalar(option_name)?.to_i32()?; + let socklen_layout = this.libc_ty_layout("socklen_t"); + let option_len = this.read_scalar(option_len)?.to_int(socklen_layout.size)?; + + // Get the file handle + let Some(fd) = this.machine.fds.get(socket) else { + return this.set_last_error_and_return_i32(LibcError("EBADF")); + }; + + let Some(_socket) = fd.downcast::() else { + // Man page specifies to return ENOTSOCK if `fd` is not a socket. + return this.set_last_error_and_return_i32(LibcError("ENOTSOCK")); + }; + + if level == this.eval_libc_i32("SOL_SOCKET") { + let opt_so_reuseaddr = this.eval_libc_i32("SO_REUSEADDR"); + + if matches!(this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd | Os::NetBsd) { + // SO_NOSIGPIPE only exists on MacOS, FreeBSD, and NetBSD. + let opt_so_nosigpipe = this.eval_libc_i32("SO_NOSIGPIPE"); + + if option_name == opt_so_nosigpipe { + if option_len != 4 { + // Option value should be C-int which is usually 4 bytes. + return this.set_last_error_and_return_i32(LibcError("EINVAL")); + } + let option_value = + this.deref_pointer_as(option_value, this.machine.layouts.i32)?; + let _val = this.read_scalar(&option_value)?.to_i32()?; + // We entirely ignore this value since we do not support signals anyway. + + return interp_ok(Scalar::from_i32(0)); + } + } + + if option_name == opt_so_reuseaddr { + if option_len != 4 { + // Option value should be C-int which is usually 4 bytes. + return this.set_last_error_and_return_i32(LibcError("EINVAL")); + } + let option_value = this.deref_pointer_as(option_value, this.machine.layouts.i32)?; + let _val = this.read_scalar(&option_value)?.to_i32()?; + // We entirely ignore this: std always sets REUSEADDR for us, and in the end it's more of a + // hint to bypass some arbitrary timeout anyway. + return interp_ok(Scalar::from_i32(0)); + } else { + throw_unsup_format!( + "setsockopt: option {option_name:#x} is unsupported for level SOL_SOCKET", + ); + } + } + + throw_unsup_format!( + "setsockopt: level {level:#x} is unsupported, only SOL_SOCKET is allowed" + ); + } + + fn getsockname( + &mut self, + socket: &OpTy<'tcx>, + address: &OpTy<'tcx>, + address_len: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let socket = this.read_scalar(socket)?.to_i32()?; + let address_ptr = this.read_pointer(address)?; + let address_len_ptr = this.read_pointer(address_len)?; + + // Get the file handle + let Some(fd) = this.machine.fds.get(socket) else { + return this.set_last_error_and_return_i32(LibcError("EBADF")); + }; + + let Some(socket) = fd.downcast::() else { + // Man page specifies to return ENOTSOCK if `fd` is not a socket. + return this.set_last_error_and_return_i32(LibcError("ENOTSOCK")); + }; + + assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!"); + + let state = socket.state.borrow(); + + let address = match &*state { + SocketState::Bound(address) => { + if address.port() == 0 { + // The socket is bound to a zero-port which means it gets assigned a random + // port. Since we don't yet have an underlying socket, we don't know what this + // random port will be and thus this is unsupported. + throw_unsup_format!( + "getsockname: when the port is 0, getting the socket address before \ + calling `listen` or `connect` is unsupported" + ) + } + + *address + } + SocketState::Listening(listener) => + match listener.local_addr() { + Ok(address) => address, + Err(e) => return this.set_last_error_and_return_i32(e), + }, + // For non-bound sockets the POSIX manual says the returned address is unspecified. + // Often this is 0.0.0.0:0 and thus we set it to this value. + _ => SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0)), + }; + + match this.write_socket_address(&address, address_ptr, address_len_ptr, "getsockname")? { + Ok(_) => interp_ok(Scalar::from_i32(0)), + Err(e) => this.set_last_error_and_return_i32(e), + } + } + + fn getpeername( + &mut self, + socket: &OpTy<'tcx>, + address: &OpTy<'tcx>, + address_len: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let socket = this.read_scalar(socket)?.to_i32()?; + let address_ptr = this.read_pointer(address)?; + let address_len_ptr = this.read_pointer(address_len)?; + + // Get the file handle + let Some(fd) = this.machine.fds.get(socket) else { + return this.set_last_error_and_return_i32(LibcError("EBADF")); + }; + + let Some(socket) = fd.downcast::() else { + // Man page specifies to return ENOTSOCK if `fd` is not a socket. + return this.set_last_error_and_return_i32(LibcError("ENOTSOCK")); + }; + + assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!"); + + let state = socket.state.borrow(); + + let SocketState::Connected(stream) = &*state else { + // We can only read the peer address of connected sockets. + return this.set_last_error_and_return_i32(LibcError("ENOTCONN")); + }; + + let address = match stream.peer_addr() { + Ok(address) => address, + Err(e) => return this.set_last_error_and_return_i32(e), + }; + + match this.write_socket_address(&address, address_ptr, address_len_ptr, "getpeername")? { + Ok(_) => interp_ok(Scalar::from_i32(0)), + Err(e) => this.set_last_error_and_return_i32(e), + } + } +} + +impl<'tcx> EvalContextPrivExt<'tcx> for crate::MiriInterpCx<'tcx> {} +trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Attempt to turn an address and length operand into a standard library socket address. + /// + /// Returns an IO error should the address length not match the address family length. + fn socket_address( + &self, + address: &OpTy<'tcx>, + address_len: &OpTy<'tcx>, + foreign_name: &'static str, + ) -> InterpResult<'tcx, Result> { + let this = self.eval_context_ref(); + + let socklen_layout = this.libc_ty_layout("socklen_t"); + // We only support address lengths which can be stored in a u64 since the + // size of a layout is also stored in a u64. + let address_len: u64 = + this.read_scalar(address_len)?.to_int(socklen_layout.size)?.try_into().unwrap(); + + // Initially, treat address as generic sockaddr just to extract the family field. + let sockaddr_layout = this.libc_ty_layout("sockaddr"); + if address_len < sockaddr_layout.size.bytes() { + // Address length should be at least as big as the generic sockaddr + return interp_ok(Err(LibcError("EINVAL"))); + } + let address = this.deref_pointer_as(address, sockaddr_layout)?; + + let family_field = this.project_field_named(&address, "sa_family")?; + let family_layout = this.libc_ty_layout("sa_family_t"); + let family = this.read_scalar(&family_field)?.to_int(family_layout.size)?; + + // Depending on the family, decide whether it's IPv4 or IPv6 and use specialized layout + // to extract address and port. + let socket_addr = if family == this.eval_libc_i32("AF_INET").into() { + let sockaddr_in_layout = this.libc_ty_layout("sockaddr_in"); + if address_len != sockaddr_in_layout.size.bytes() { + // Address length should be exactly the length of an IPv4 address. + return interp_ok(Err(LibcError("EINVAL"))); + } + let address = address.transmute(sockaddr_in_layout, this)?; + + let port_field = this.project_field_named(&address, "sin_port")?; + // Read bytes and treat them as big endian since port is stored in network byte order. + let port_bytes: [u8; 2] = this + .read_bytes_ptr_strip_provenance(port_field.ptr(), Size::from_bytes(2))? + .try_into() + .unwrap(); + let port = u16::from_be_bytes(port_bytes); + + let addr_field = this.project_field_named(&address, "sin_addr")?; + let s_addr_field = this.project_field_named(&addr_field, "s_addr")?; + // Read bytes and treat them as big endian since address is stored in network byte order. + let addr_bytes: [u8; 4] = this + .read_bytes_ptr_strip_provenance(s_addr_field.ptr(), Size::from_bytes(4))? + .try_into() + .unwrap(); + let addr_bits = u32::from_be_bytes(addr_bytes); + + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_bits(addr_bits), port)) + } else if family == this.eval_libc_i32("AF_INET6").into() { + let sockaddr_in6_layout = this.libc_ty_layout("sockaddr_in6"); + if address_len != sockaddr_in6_layout.size.bytes() { + // Address length should be exactly the length of an IPv6 address. + return interp_ok(Err(LibcError("EINVAL"))); + } + // We cannot transmute since the `sockaddr_in6` layout is bigger than the `sockaddr` layout. + let address = address.offset(Size::ZERO, sockaddr_in6_layout, this)?; + + let port_field = this.project_field_named(&address, "sin6_port")?; + // Read bytes and treat them as big endian since port is stored in network byte order. + let port_bytes: [u8; 2] = this + .read_bytes_ptr_strip_provenance(port_field.ptr(), Size::from_bytes(2))? + .try_into() + .unwrap(); + let port = u16::from_be_bytes(port_bytes); + + let addr_field = this.project_field_named(&address, "sin6_addr")?; + let s_addr_field = this + .project_field_named(&addr_field, "s6_addr")? + .transmute(this.machine.layouts.u128, this)?; + // Read bytes and treat them as big endian since address is stored in network byte order. + let addr_bytes: [u8; 16] = this + .read_bytes_ptr_strip_provenance(s_addr_field.ptr(), Size::from_bytes(16))? + .try_into() + .unwrap(); + let addr_bits = u128::from_be_bytes(addr_bytes); + + let flowinfo_field = this.project_field_named(&address, "sin6_flowinfo")?; + // flowinfo doesn't get the big endian treatment as this field is stored in native byte order + // and not in network byte order. + let flowinfo = this.read_scalar(&flowinfo_field)?.to_u32()?; + + let scope_id_field = this.project_field_named(&address, "sin6_scope_id")?; + // scope_id doesn't get the big endian treatment as this field is stored in native byte order + // and not in network byte order. + let scope_id = this.read_scalar(&scope_id_field)?.to_u32()?; + + SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::from_bits(addr_bits), + port, + flowinfo, + scope_id, + )) + } else { + // Socket of other types shouldn't be created in a first place and + // thus also no address family of another type should be supported. + throw_unsup_format!( + "{foreign_name}: address family {family:#x} is unsupported, \ + only AF_INET and AF_INET6 are allowed" + ); + }; + + interp_ok(Ok(socket_addr)) + } + + /// Attempt to write a standard library socket address into a pointer. + /// + /// The `address_len_ptr` parameter serves both as input and output parameter. + /// On input, it points to the size of the buffer `address_ptr` points to, and + /// on output it points to the non-truncated size of the written address in the + /// buffer pointed to by `address_ptr`. + /// + /// If the address buffer doesn't fit the whole address, the address is truncated to not + /// overflow the buffer. + fn write_socket_address( + &mut self, + address: &SocketAddr, + address_ptr: Pointer, + address_len_ptr: Pointer, + foreign_name: &'static str, + ) -> InterpResult<'tcx, Result<(), IoError>> { + let this = self.eval_context_mut(); + + if address_ptr == Pointer::null() || address_len_ptr == Pointer::null() { + // The POSIX man page doesn't account for the cases where the `address_ptr` or + // `address_len_ptr` could be null pointers. Thus, this behavior is undefined! + throw_ub_format!( + "{foreign_name}: writing a socket address but the address or the length pointer is a null pointer" + ) + } + + let socklen_layout = this.libc_ty_layout("socklen_t"); + let address_buffer_len_place = this.ptr_to_mplace(address_len_ptr, socklen_layout); + // We only support buffer lengths which can be stored in a u64 since the + // size of a layout in bytes is also stored in a u64. + let address_buffer_len: u64 = this + .read_scalar(&address_buffer_len_place)? + .to_int(socklen_layout.size)? + .try_into() + .unwrap(); + + let (address_buffer, address_layout) = match address { + SocketAddr::V4(address) => { + // IPv4 address bytes; already stored in network byte order. + let address_bytes = address.ip().octets(); + // Port needs to be manually turned into network byte order. + let port = address.port().to_be(); + + let sockaddr_in_layout = this.libc_ty_layout("sockaddr_in"); + // Allocate new buffer on the stack with the `sockaddr_in` layout. + // We need a temporary buffer as `address_ptr` might not point to a large enough + // buffer, in which case we have to truncate. + let address_buffer = this.allocate(sockaddr_in_layout, MemoryKind::Stack)?; + // Zero the whole buffer as some libc targets have additional fields which we fill + // with zero bytes (just like the standard library does it). + this.write_bytes_ptr( + address_buffer.ptr(), + iter::repeat_n(0, address_buffer.layout.size.bytes_usize()), + )?; + + let sin_family_field = this.project_field_named(&address_buffer, "sin_family")?; + // We cannot simply write the `AF_INET` scalar into the `sin_family_field` because on most + // systems the field has a layout of 16-bit whilst the scalar has a size of 32-bit. + // Since the `AF_INET` constant is chosen such that it can safely be converted into + // a 16-bit integer, we use the following logic to get a scalar of the right size. + let af_inet = this.eval_libc("AF_INET"); + let address_family = + Scalar::from_int(af_inet.to_int(af_inet.size())?, sin_family_field.layout.size); + this.write_scalar(address_family, &sin_family_field)?; + + let sin_port_field = this.project_field_named(&address_buffer, "sin_port")?; + // Write the port in target native endianness bytes as we already converted it + // to big endian above. + this.write_bytes_ptr(sin_port_field.ptr(), port.to_ne_bytes())?; + + let sin_addr_field = this.project_field_named(&address_buffer, "sin_addr")?; + let s_addr_field = this.project_field_named(&sin_addr_field, "s_addr")?; + this.write_bytes_ptr(s_addr_field.ptr(), address_bytes)?; + + (address_buffer, sockaddr_in_layout) + } + SocketAddr::V6(address) => { + // IPv6 address bytes; already stored in network byte order. + let address_bytes = address.ip().octets(); + // Port needs to be manually turned into network byte order. + let port = address.port().to_be(); + // Flowinfo is stored in native byte order. + let flowinfo = address.flowinfo(); + // Scope id is stored in native byte order. + let scope_id = address.scope_id(); + + let sockaddr_in6_layout = this.libc_ty_layout("sockaddr_in6"); + // Allocate new buffer on the stack with the `sockaddr_in6` layout. + // We need a temporary buffer as `address_ptr` might not point to a large enough + // buffer, in which case we have to truncate. + let address_buffer = this.allocate(sockaddr_in6_layout, MemoryKind::Stack)?; + // Zero the whole buffer as some libc targets have additional fields which we fill + // with zero bytes (just like the standard library does it). + this.write_bytes_ptr( + address_buffer.ptr(), + iter::repeat_n(0, address_buffer.layout.size.bytes_usize()), + )?; + + let sin6_family_field = this.project_field_named(&address_buffer, "sin6_family")?; + // We cannot simply write the `AF_INET6` scalar into the `sin6_family_field` because on most + // systems the field has a layout of 16-bit whilst the scalar has a size of 32-bit. + // Since the `AF_INET6` constant is chosen such that it can safely be converted into + // a 16-bit integer, we use the following logic to get a scalar of the right size. + let af_inet6 = this.eval_libc("AF_INET6"); + let address_family = Scalar::from_int( + af_inet6.to_int(af_inet6.size())?, + sin6_family_field.layout.size, + ); + this.write_scalar(address_family, &sin6_family_field)?; + + let sin6_port_field = this.project_field_named(&address_buffer, "sin6_port")?; + // Write the port in target native endianness bytes as we already converted it + // to big endian above. + this.write_bytes_ptr(sin6_port_field.ptr(), port.to_ne_bytes())?; + + let sin6_flowinfo_field = + this.project_field_named(&address_buffer, "sin6_flowinfo")?; + this.write_scalar(Scalar::from_u32(flowinfo), &sin6_flowinfo_field)?; + + let sin6_scope_id_field = + this.project_field_named(&address_buffer, "sin6_scope_id")?; + this.write_scalar(Scalar::from_u32(scope_id), &sin6_scope_id_field)?; + + let sin6_addr_field = this.project_field_named(&address_buffer, "sin6_addr")?; + let s6_addr_field = this.project_field_named(&sin6_addr_field, "s6_addr")?; + this.write_bytes_ptr(s6_addr_field.ptr(), address_bytes)?; + + (address_buffer, sockaddr_in6_layout) + } + }; + + // Copy the truncated address into the pointer pointed to by `address_ptr`. + this.mem_copy( + address_buffer.ptr(), + address_ptr, + // Truncate the address to fit the provided buffer. + address_layout.size.min(Size::from_bytes(address_buffer_len)), + // The buffers are guaranteed to not overlap since the `address_buffer` + // was just newly allocated on the stack. + true, + )?; + // Deallocate the address buffer as it was only needed to construct the address and + // copy it into the buffer pointed to by `address_ptr`. + this.deallocate_ptr(address_buffer.ptr(), None, MemoryKind::Stack)?; + // Size of the non-truncated address. + let address_len = address_layout.size.bytes(); + + this.write_scalar( + Scalar::from_uint(address_len, socklen_layout.size), + &address_buffer_len_place, + )?; + + interp_ok(Ok(())) + } + + /// Block the thread until there's an incoming connection or an error occurred. + /// + /// This recursively calls itself should the operation still block for some reason. + fn block_for_accept( + &mut self, + address_ptr: Pointer, + address_len_ptr: Pointer, + is_client_sock_nonblock: bool, + socket: FileDescriptionRef, + dest: MPlaceTy<'tcx>, + ) { + let this = self.eval_context_mut(); + this.block_thread_for_io( + socket.clone(), + Interest::READABLE, + None, + callback!(@capture<'tcx> { + address_ptr: Pointer, + address_len_ptr: Pointer, + is_client_sock_nonblock: bool, + socket: FileDescriptionRef, + dest: MPlaceTy<'tcx>, + } |this, kind: UnblockKind| { + assert_eq!(kind, UnblockKind::Ready); + + let state = socket.state.borrow(); + + let SocketState::Listening(listener) = &*state else { + // We checked that the socket is in listening state before blocking + // and since there is no outgoing transition from that state this + // should be unreachable. + unreachable!() + }; + + let (stream, addr) = match listener.accept() { + Ok(peer) => peer, + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + // We need to block the thread again as it would still block. + drop(state); + this.block_for_accept(address_ptr, address_len_ptr, is_client_sock_nonblock, socket, dest); + return interp_ok(()) + }, + Err(e) => return this.set_last_error_and_return(e, &dest), + }; + + let family = match addr { + SocketAddr::V4(_) => SocketFamily::IPv4, + SocketAddr::V6(_) => SocketFamily::IPv6, + }; + + if address_ptr != Pointer::null() { + // We only attempt a write if the address pointer is not a null pointer. + // If the address pointer is a null pointer the user isn't interested in the + // address and we don't need to write anything. + if let Err(e) = this.write_socket_address(&addr, address_ptr, address_len_ptr, "accept4")? { + return this.set_last_error_and_return(e, &dest); + }; + } + + let fd = this.machine.fds.new_ref(Socket { + family, + state: RefCell::new(SocketState::Connected(stream)), + is_non_block: Cell::new(is_client_sock_nonblock), + }); + let sockfd = this.machine.fds.insert(fd); + // We need to create the scalar using the destination size since + // `syscall(SYS_accept4, ...)` returns a long which doesn't match + // the int returned from the `accept`/`accept4` syscalls. + // See . + this.write_scalar(Scalar::from_int(sockfd, dest.layout.size), &dest) + }), + ); + } + + /// Block the thread until the stream is connected or an error occurred. + fn block_for_connect(&mut self, socket: FileDescriptionRef, dest: MPlaceTy<'tcx>) { + let this = self.eval_context_mut(); + this.block_thread_for_io( + socket.clone(), + Interest::WRITABLE, + None, + callback!(@capture<'tcx> { + socket: FileDescriptionRef, + dest: MPlaceTy<'tcx>, + } |this, kind: UnblockKind| { + assert_eq!(kind, UnblockKind::Ready); + + let mut state = socket.state.borrow_mut(); + + // We received a "writable" event so `try_set_connected` is safe to call. + match state.try_set_connected() { + Ok(_) => this.write_scalar(Scalar::from_i32(0), &dest), + Err(SocketIoError::NotReady) => { + // We need to block the thread again as the connection is still not yet ready. + drop(state); + this.block_for_connect(socket, dest); + return interp_ok(()) + }, + Err(SocketIoError::Other(e)) => return this.set_last_error_and_return(e, &dest) + } + }), + ); + } +} + +impl VisitProvenance for FileDescriptionRef { + // A socket doesn't contain any references to machine memory + // and thus we don't need to propagate the visit. + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {} +} + +impl WithSource for FileDescriptionRef { + fn with_source(&self, f: &mut dyn FnMut(&mut dyn Source) -> io::Result<()>) -> io::Result<()> { + let mut state = self.state.borrow_mut(); + match &mut *state { + SocketState::Listening(listener) => f(listener), + SocketState::Connecting(stream) | SocketState::Connected(stream) => f(stream), + // We never try adding a socket which is not backed by a real socket to the poll registry. + _ => unreachable!(), + } + } } diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index 723e7bae4cdf..d4ebdeab86f1 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -111,6 +111,38 @@ fn emulate_foreign_item_inner( this.write_scalar(result, dest)?; } + // Network sockets + "__xnet_socket" | "__xnet7_socket" => { + let [domain, type_, protocol] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, i32, i32) -> i32), + link_name, + abi, + args, + )?; + let result = this.socket(domain, type_, protocol)?; + this.write_scalar(result, dest)?; + } + + "__xnet_bind" => { + let [socket, address, address_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32), + link_name, + abi, + args, + )?; + let result = this.bind(socket, address, address_len)?; + this.write_scalar(result, dest)?; + } + "__xnet_connect" => { + let [socket, address, address_len] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32), + link_name, + abi, + args, + )?; + this.connect(socket, address, address_len, dest)?; + } + // Miscellaneous "___errno" => { let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 2d1a153d9262..16e269c68880 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -451,6 +451,16 @@ fn emulate_foreign_item_inner( this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?; this.write_scalar(res, dest)?; } + "MoveFileExW" => { + let [existing_name, new_name, flags] = this.check_shim_sig( + shim_sig!(extern "system" fn(*const _, *const _, u32) -> winapi::BOOL), + link_name, + abi, + args, + )?; + let res = this.MoveFileExW(existing_name, new_name, flags)?; + this.write_scalar(res, dest)?; + } // Allocation "HeapAlloc" => { diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs index e5a98e86d645..1ee93cf911c5 100644 --- a/src/tools/miri/src/shims/windows/fs.rs +++ b/src/tools/miri/src/shims/windows/fs.rs @@ -490,6 +490,36 @@ fn FlushFileBuffers( } } + fn MoveFileExW( + &mut self, + existing_name: &OpTy<'tcx>, + new_name: &OpTy<'tcx>, + flags: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let existing_name = this.read_path_from_wide_str(this.read_pointer(existing_name)?)?; + let new_name = this.read_path_from_wide_str(this.read_pointer(new_name)?)?; + + let flags = this.read_scalar(flags)?.to_u32()?; + + // Flag to indicate whether we should replace an existing file. + // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexw + let movefile_replace_existing = this.eval_windows_u32("c", "MOVEFILE_REPLACE_EXISTING"); + + if flags != movefile_replace_existing { + throw_unsup_format!("MoveFileExW: Unsupported `dwFlags` value {}", flags); + } + + match std::fs::rename(existing_name, new_name) { + Ok(_) => interp_ok(this.eval_windows("c", "TRUE")), + Err(e) => { + this.set_last_error(e)?; + interp_ok(this.eval_windows("c", "FALSE")) + } + } + } + fn DeleteFileW( &mut self, file_name: &OpTy<'tcx>, // LPCWSTR diff --git a/src/tools/miri/src/shims/x86/avx512.rs b/src/tools/miri/src/shims/x86/avx512.rs index 23538f0dea96..8e1d22d723e7 100644 --- a/src/tools/miri/src/shims/x86/avx512.rs +++ b/src/tools/miri/src/shims/x86/avx512.rs @@ -191,9 +191,9 @@ fn vpdpbusd<'tcx>( // fn vpdpbusd(src: i32x16, a: u8x64, b: i8x64) -> i32x16; // fn vpdpbusd256(src: i32x8, a: u8x32, b: i8x32) -> i32x8; // fn vpdpbusd128(src: i32x4, a: u8x16, b: i8x16) -> i32x4; - assert_eq!(dest_len, src_len); - assert_eq!(dest_len * 4, a_len); - assert_eq!(a_len, b_len); + assert_eq!(src_len, dest_len); + assert_eq!(a_len, dest_len.strict_mul(4)); + assert_eq!(b_len, a_len); for i in 0..dest_len { let src = ecx.read_scalar(&ecx.project_index(&src, i)?)?.to_i32()?; diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index dc0d8d48ac9b..ce6538c8ca27 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1178,21 +1178,7 @@ fn pclmulqdq<'tcx>( let index = if (imm8 & 0x10) == 0 { lo } else { hi }; let right = ecx.read_scalar(&ecx.project_index(&right, index)?)?.to_u64()?; - // Perform carry-less multiplication. - // - // This operation is like long multiplication, but ignores all carries. - // That idea corresponds to the xor operator, which is used in the implementation. - // - // Wikipedia has an example https://en.wikipedia.org/wiki/Carry-less_product#Example - let mut result: u128 = 0; - - for i in 0..64 { - // if the i-th bit in right is set - if (right & (1 << i)) != 0 { - // xor result with `left` shifted to the left by i positions - result ^= u128::from(left) << i; - } - } + let result = left.widening_carryless_mul(right); let dest = ecx.project_index(&dest, i)?; ecx.write_scalar(Scalar::from_u128(result), &dest)?; diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 7c0f9c570e2e..6b0e6726e8f7 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -5,6 +5,7 @@ use rustc_target::callconv::FnAbi; use rustc_target::spec::Arch; +use crate::shims::math::compute_crc32; use crate::*; /// A bitmask constant for scrutinizing the immediate byte provided @@ -445,46 +446,19 @@ fn emulate_x86_sse42_intrinsic( // The 64-bit version will only consider the lower 32 bits, // while the upper 32 bits get discarded. #[expect(clippy::as_conversions)] - u128::from((left.to_u64()? as u32).reverse_bits()) + (left.to_u64()? as u32) } else { - u128::from(left.to_u32()?.reverse_bits()) + left.to_u32()? }; - let v = match bit_size { - 8 => u128::from(right.to_u8()?.reverse_bits()), - 16 => u128::from(right.to_u16()?.reverse_bits()), - 32 => u128::from(right.to_u32()?.reverse_bits()), - 64 => u128::from(right.to_u64()?.reverse_bits()), + let data = match bit_size { + 8 => u64::from(right.to_u8()?), + 16 => u64::from(right.to_u16()?), + 32 => u64::from(right.to_u32()?), + 64 => right.to_u64()?, _ => unreachable!(), }; - // Perform polynomial division modulo 2. - // The algorithm for the division is an adapted version of the - // schoolbook division algorithm used for normal integer or polynomial - // division. In this context, the quotient is not calculated, since - // only the remainder is needed. - // - // The algorithm works as follows: - // 1. Pull down digits until division can be performed. In the context of division - // modulo 2 it means locating the most significant digit of the dividend and shifting - // the divisor such that the position of the divisors most significand digit and the - // dividends most significand digit match. - // 2. Perform a division and determine the remainder. Since it is arithmetic modulo 2, - // this operation is a simple bitwise exclusive or. - // 3. Repeat steps 1. and 2. until the full remainder is calculated. This is the case - // once the degree of the remainder polynomial is smaller than the degree of the - // divisor polynomial. In other words, the number of leading zeros of the remainder - // is larger than the number of leading zeros of the divisor. It is important to - // note that standard arithmetic comparison is not applicable here: - // 0b10011 / 0b11111 = 0b01100 is a valid division, even though the dividend is - // smaller than the divisor. - let mut dividend = (crc << bit_size) ^ (v << 32); - const POLYNOMIAL: u128 = 0x11EDC6F41; - while dividend.leading_zeros() <= POLYNOMIAL.leading_zeros() { - dividend ^= - (POLYNOMIAL << POLYNOMIAL.leading_zeros()) >> dividend.leading_zeros(); - } - - let result = u32::try_from(dividend).unwrap().reverse_bits(); + let result = compute_crc32(crc, data, bit_size, 0x11EDC6F41); let result = if bit_size == 64 { Scalar::from_u64(u64::from(result)) } else { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs index 6fec6500cc96..024537633383 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs @@ -5,6 +5,7 @@ use std::{mem, ptr}; extern "C" fn thread_start() -> *mut libc::c_void { + //~^ERROR: calling a function with more arguments than it expected panic!() } @@ -16,7 +17,6 @@ fn main() { mem::transmute(thread_start); assert_eq!( libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), - //~^ERROR: calling a function with more arguments than it expected 0 ); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr index 979a1a8337b5..e3509a2a6ee8 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr @@ -1,14 +1,17 @@ error: Undefined Behavior: calling a function with more arguments than it expected --> tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs:LL:CC | -LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code +LL | extern "C" fn thread_start() -> *mut libc::c_void { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: this is on thread `unnamed-ID` - = note: this error occurred while pushing a call frame onto an empty stack - = note: the span indicates which code caused the function to be called, but may not be the literal call site +note: the current function got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs:LL:CC + | +LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs index cb55b0f92ee6..28fdb1d01384 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs @@ -5,6 +5,7 @@ use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { + //~^ERROR: calling a function with fewer arguments than it requires panic!() } @@ -16,7 +17,6 @@ fn main() { mem::transmute(thread_start); assert_eq!( libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), - //~^ERROR: calling a function with fewer arguments than it requires 0 ); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr index e8ad65a74ac8..d6504f6b9787 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr @@ -1,14 +1,17 @@ error: Undefined Behavior: calling a function with fewer arguments than it requires --> tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs:LL:CC | -LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code +LL | extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { + | ^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: this is on thread `unnamed-ID` - = note: this error occurred while pushing a call frame onto an empty stack - = note: the span indicates which code caused the function to be called, but may not be the literal call site +note: the current function got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs:LL:CC + | +LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs index 5c80f6425eaa..b1929e3f27ed 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs @@ -7,7 +7,7 @@ fn main() { let t = thread::spawn(|| unsafe { // Access the environment in another thread without taking the env lock. // This represents some C code that queries the environment. - libc::getenv(b"TZ\0".as_ptr().cast()); //~ERROR: Data race detected + libc::getenv(c"TZ".as_ptr()); //~ERROR: Data race detected }); // Meanwhile, the main thread uses the "safe" Rust env accessor. env::set_var("MY_RUST_VAR", "Ferris"); diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr index 635091cc0173..b4cd31b4ddab 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic read on thread `unnamed-ID` at ALLOC --> tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC | -LL | libc::getenv(b"TZ/0".as_ptr().cast()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (2) just happened here +LL | libc::getenv(c"TZ".as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (2) just happened here | help: and (1) occurred earlier here --> tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC @@ -19,7 +19,7 @@ LL | let t = thread::spawn(|| unsafe { | _____________^ LL | | // Access the environment in another thread without taking the env lock. LL | | // This represents some C code that queries the environment. -LL | | libc::getenv(b"TZ/0".as_ptr().cast()); +LL | | libc::getenv(c"TZ".as_ptr()); LL | | }); | |______^ diff --git a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs index 2c676f12b4f0..abdafe2b0fb3 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs @@ -6,6 +6,6 @@ fn main() { } fn test_mkstemp_immutable_arg() { - let s: *mut libc::c_char = b"fooXXXXXX\0" as *const _ as *mut _; + let s: *mut libc::c_char = c"fooXXXXXX".as_ptr().cast_mut(); let _fd = unsafe { libc::mkstemp(s) }; //~ ERROR: Undefined Behavior: writing to alloc1 which is read-only } diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs index 457f32e55446..29548c17443a 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs @@ -6,7 +6,6 @@ fn main() { } fn test_file_open_missing_needed_mode() { - let name = b"missing_arg.txt\0"; - let name_ptr = name.as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: not enough variadic arguments + let name = c"missing_arg.txt".as_ptr(); + let _fd = unsafe { libc::open(name, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: not enough variadic arguments } diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr index a85fae9c7dd2..186ca4ccdd40 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not enough variadic arguments for `open(pathname, O_CREAT, ...)`: got 0, expected at least 1 --> tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC | -LL | let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | let _fd = unsafe { libc::open(name, libc::O_CREAT) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr index 9d5e119d1c37..214b626f4f69 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [3]: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value of type [u8; 4]: at [3], encountered uninitialized memory, but expected an integer --> tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs:LL:CC | LL | buf.assume_init(); diff --git a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs index 7147813c4b6c..b4259161df55 100644 --- a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs +++ b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs @@ -14,7 +14,7 @@ fn main() { // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { transmute::<_, &str>( - //~^ ERROR: constructing invalid value: encountered a dangling reference + //~^ ERROR: encountered a dangling reference !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) diff --git a/src/tools/miri/tests/fail/branchless-select-i128-pointer.stderr b/src/tools/miri/tests/fail/branchless-select-i128-pointer.stderr index abcaf90a1ec3..83dc2ddf2904 100644 --- a/src/tools/miri/tests/fail/branchless-select-i128-pointer.stderr +++ b/src/tools/miri/tests/fail/branchless-select-i128-pointer.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) +error: Undefined Behavior: constructing invalid value of type &str: encountered a dangling reference ($HEX[noalloc] has no provenance) --> tests/fail/branchless-select-i128-pointer.rs:LL:CC | LL | / transmute::<_, &str>( diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr index afc2cb214842..4f06a1afa50f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr @@ -2,7 +2,7 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this p --> tests/fail/dangling_pointers/dangling_primitive.rs:LL:CC | LL | dbg!(*ptr); - | ^^^^^^^^^^ Undefined Behavior occurred here + | ^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr index 0ae38c3b326f..64671315fbec 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling box (0x18[noalloc] has no provenance) +error: Undefined Behavior: constructing invalid value of type std::boxed::Box: encountered a dangling box (0x18[noalloc] has no provenance) --> tests/fail/dangling_pointers/deref_dangling_box.rs:LL:CC | LL | let _val = unsafe { addr_of_mut!(**outer) }; diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr index c10dc19f3626..552094780ad1 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference (0x18[noalloc] has no provenance) +error: Undefined Behavior: constructing invalid value of type &mut i32: encountered a dangling reference (0x18[noalloc] has no provenance) --> tests/fail/dangling_pointers/deref_dangling_ref.rs:LL:CC | LL | let _val = unsafe { addr_of_mut!(**outer) }; diff --git a/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr b/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr index 74102f7e1b5e..df82e089ccfb 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error: Undefined Behavior: constructing invalid value of type &SliceWithHead: encountered a dangling reference (going beyond the bounds of its allocation) --> tests/fail/dangling_pointers/dyn_size.rs:LL:CC | LL | let _ptr = unsafe { &*ptr }; diff --git a/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr index 65ad97f4911b..86a695f62fc0 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr +++ b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display` +error: Undefined Behavior: constructing invalid value of type *const dyn std::fmt::Debug + std::marker::Send + std::marker::Sync: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display` --> tests/fail/dyn-upcast-nop-wrong-trait.rs:LL:CC | LL | let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; diff --git a/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.rs b/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.rs index bd02e7f5fb44..2bea47e32dd9 100644 --- a/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.rs +++ b/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.rs @@ -20,8 +20,8 @@ fn main() { assert!(Foo::Var1 == mem::transmute(2u8)); assert!(Foo::Var3 == mem::transmute(4u8)); - let invalid: Foo = mem::transmute(3u8); - assert!(matches!(invalid, Foo::Var2(_))); + let invalid: *const Foo = mem::transmute(&3u8); + assert!(matches!(*invalid, Foo::Var2(_))); //~^ ERROR: invalid tag } } diff --git a/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.stderr b/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.stderr index e019a350ba17..b0862cf94b9a 100644 --- a/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.stderr +++ b/src/tools/miri/tests/fail/enum-untagged-variant-invalid-encoding.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: enum value has invalid tag: 0x03 --> tests/fail/enum-untagged-variant-invalid-encoding.rs:LL:CC | -LL | assert!(matches!(invalid, Foo::Var2(_))); - | ^^^^^^^ Undefined Behavior occurred here +LL | assert!(matches!(*invalid, Foo::Var2(_))); + | ^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs index b6cda6007536..1fb597fdc02a 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs @@ -21,8 +21,6 @@ fn main() { // This specifically uses a type with scalar representation to tempt Miri to use the // efficient way of storing local variables (outside adressable memory). Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) - //~[stack]^ ERROR: not granting access - //~[tree]| ERROR: /read access .* forbidden/ } after_call = { Return() @@ -32,6 +30,8 @@ fn main() { #[expect(unused_variables, unused_assignments)] fn callee(x: S, mut y: S) { + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /read access .* forbidden/ // With the setup above, if `x` and `y` are both moved, // then writing to `y` will change the value stored in `x`! y.0 = 0; diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr index a86c68cebd23..14df4ebd11f5 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(x: S, mut y: S) { + | ^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -14,8 +14,13 @@ LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a help: is this argument --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | y.0 = 0; - | ^^^^^^^ +LL | fn callee(x: S, mut y: S) { + | ^ + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_locals_alias.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/fail/function_calls/arg_inplace_locals_alias.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr index d62adeeb8420..7012c4f8aead 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: read access through (root of the allocation) at ALLOC[0x0] is forbidden --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(x: S, mut y: S) { + | ^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information @@ -17,14 +17,19 @@ LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | y.0 = 0; - | ^^^^^^^ +LL | fn callee(x: S, mut y: S) { + | ^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | y.0 = 0; - | ^^^^^^^ +LL | fn callee(x: S, mut y: S) { + | ^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_locals_alias.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/fail/function_calls/arg_inplace_locals_alias_ret.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs index 3cb8ee2b407c..b3d43ca63cb0 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs @@ -20,8 +20,6 @@ fn main() { // This specifically uses a type with scalar representation to tempt Miri to use the // efficient way of storing local variables (outside adressable memory). Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) - //~[stack]^ ERROR: not granting access - //~[tree]| ERROR: /reborrow .* forbidden/ } after_call = { Return() @@ -30,5 +28,7 @@ fn main() { } fn callee(x: S) -> S { + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /reborrow .* forbidden/ x } diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr index 491d01cf4284..21fcfb96fd17 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(x: S) -> S { + | ^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -14,8 +14,13 @@ LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), help: is this argument --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | x - | ^ +LL | fn callee(x: S) -> S { + | ^ + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_locals_alias_ret.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/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr index 3c1038d364bb..e4d4e87625a9 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: reborrow through (root of the allocation) at ALLOC[0x0] is forbidden --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(x: S) -> S { + | ^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information @@ -17,14 +17,19 @@ LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | x - | ^ +LL | fn callee(x: S) -> S { + | ^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | x - | ^ +LL | fn callee(x: S) -> S { + | ^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_locals_alias_ret.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/fail/function_calls/arg_inplace_mutate.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr index 952f2272f3bf..c754acdd5ea1 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: is this argument --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | -LL | unsafe { ptr.write(S(0)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn callee(x: S, ptr: *mut S) { + | ^ = note: stack backtrace: 0: callee at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index 095dc7e1a1fb..c210d5c00524 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | -LL | unsafe { ptr.write(S(0)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn callee(x: S, ptr: *mut S) { + | ^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | -LL | unsafe { ptr.write(S(0)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn callee(x: S, ptr: *mut S) { + | ^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: callee diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr index d625d1d1d034..b7eb3c5e9cab 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: is this argument --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | -LL | x.0 = 0; - | ^^^^^^^ +LL | fn change_arg(mut x: S, ptr: *mut S) { + | ^^^^^ = note: stack backtrace: 0: change_arg at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index a01c040fe6f8..e79cf08b15bf 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | -LL | x.0 = 0; - | ^^^^^^^ +LL | fn change_arg(mut x: S, ptr: *mut S) { + | ^^^^^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | -LL | x.0 = 0; - | ^^^^^^^ +LL | fn change_arg(mut x: S, ptr: *mut S) { + | ^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: change_arg diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.rs index a108944c5e43..81fa672d5229 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.rs @@ -1,9 +1,9 @@ #[no_mangle] -fn foo() {} +fn foo() {} //~ ERROR: calling a function with more arguments than it expected fn main() { extern "Rust" { fn foo(_: i32); } - unsafe { foo(1) } //~ ERROR: calling a function with more arguments than it expected + unsafe { foo(1) } } diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr index 75c060ea51d4..4c481e8d3cb9 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -1,11 +1,16 @@ error: Undefined Behavior: calling a function with more arguments than it expected --> tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC | -LL | unsafe { foo(1) } - | ^^^^^^ Undefined Behavior occurred here +LL | fn foo() {} + | ^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: foo + at tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC + 1: main + at tests/fail/function_calls/exported_symbol_wrong_arguments.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/fail/function_calls/return_pointer_aliasing_read.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr index 73c562c94e95..5cf0fd40b58c 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | unsafe { ptr.read() }; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = note: stack backtrace: 0: myfun at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index 0dc137843c91..cc5f4a812eeb 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | unsafe { ptr.read() }; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | unsafe { ptr.read() }; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: myfun diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr index 6654ddc12c29..133aa8ca35a1 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = note: stack backtrace: 0: myfun at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index 6472dfd4f995..fb87eea63102 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: myfun diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr index 79f4d2c69f3c..07ed6d128215 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | become myfun2(ptr) - | ^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = note: stack backtrace: 0: myfun2 at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index 82b898df45b2..e3c5d6baf89f 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun2(ptr: *mut i32) -> i32 { + | ^^^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun2(ptr: *mut i32) -> i32 { + | ^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: myfun2 diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr index 364a4b4a7441..88d5694c4736 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr @@ -7,7 +7,7 @@ error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is unin --> tests/fail/function_calls/return_pointer_on_unwind.rs:LL:CC | LL | dbg!(x.0); - | ^^^^^^^^^ Undefined Behavior occurred here + | ^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs index 26f2e73dd752..beb0f726568f 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs @@ -12,10 +12,10 @@ struct S( type A = [i32; 4]; fn main() { - fn f(_: S) {} + fn f(_: S) {} //~ ERROR: type S passing argument of type [i32; 4] // These two types have the same size but are still not compatible. let g = unsafe { std::mem::transmute::(f) }; - g(Default::default()) //~ ERROR: type S passing argument of type [i32; 4] + g(Default::default()) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr index 56e69e846696..62ba807d7a95 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type S passing argument of type [i32; 4] --> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC | -LL | g(Default::default()) - | ^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(_: S) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_array_vs_struct.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/fail/function_pointers/abi_mismatch_int_vs_float.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs index 0cca4a132333..a40e5b44660d 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs @@ -1,7 +1,7 @@ fn main() { - fn f(_: f32) {} + fn f(_: f32) {} //~ ERROR: type f32 passing argument of type i32 let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR: type f32 passing argument of type i32 + g(42) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr index cbef9d27cdf9..8147d009ff85 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type f32 passing argument of type i32 --> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC | -LL | g(42) - | ^^^^^ Undefined Behavior occurred here +LL | fn f(_: f32) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_int_vs_float.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/fail/function_pointers/abi_mismatch_raw_pointer.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs index 053a4a5f2845..8c2d0648cbf1 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs @@ -1,7 +1,7 @@ fn main() { - fn f(_: *const [i32]) {} + fn f(_: *const [i32]) {} //~ ERROR: type *const [i32] passing argument of type *const i32 let g = unsafe { std::mem::transmute::(f) }; - g(&42 as *const i32) //~ ERROR: type *const [i32] passing argument of type *const i32 + g(&42 as *const i32) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr index cd14ea156a47..f9195a869798 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type *const [i32] passing argument of type *const i32 --> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC | -LL | g(&42 as *const i32) - | ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(_: *const [i32]) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_raw_pointer.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/fail/function_pointers/abi_mismatch_repr_C.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs index f3dffcc4e867..79485a27ee13 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs @@ -7,10 +7,10 @@ struct S2(i32); fn callee(_s: S2) {} +//~^ ERROR: type S2 passing argument of type S1 fn main() { let fnptr: fn(S2) = callee; let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) }; fnptr(S1(NonZero::new(1).unwrap())); - //~^ ERROR: type S2 passing argument of type S1 } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr index 0e52dc02884c..3e4be1e39fd9 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type S2 passing argument of type S1 --> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC | -LL | fnptr(S1(NonZero::new(1).unwrap())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(_s: S2) {} + | ^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: callee + at tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_repr_C.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/fail/function_pointers/abi_mismatch_return_type.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs index 05b645cf75af..3f9c42a78223 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs @@ -1,9 +1,10 @@ fn main() { fn f() -> u32 { + //~^ERROR: type u32 passing return place of type () 42 } let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; - g() //~ ERROR: type u32 passing return place of type () + g() } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr index ba940902c8ce..9f206189b6e0 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function with return type u32 passing return place of type () --> tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC | -LL | g() - | ^^^ Undefined Behavior occurred here +LL | fn f() -> u32 { + | ^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_return_type.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/fail/function_pointers/abi_mismatch_simple.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs index ca43c06008fd..0b06496b2bfd 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs @@ -1,7 +1,7 @@ fn main() { - fn f(_: (i32, i32)) {} + fn f(_: (i32, i32)) {} //~ ERROR: type (i32, i32) passing argument of type i32 let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR: type (i32, i32) passing argument of type i32 + g(42) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr index ab9c0e720304..b85ac39faa8f 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type (i32, i32) passing argument of type i32 --> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC | -LL | g(42) - | ^^^^^ Undefined Behavior occurred here +LL | fn f(_: (i32, i32)) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_simple.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/fail/function_pointers/abi_mismatch_too_few_args.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.rs index 920fb51abb64..fc9a107f0c73 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.rs @@ -1,7 +1,7 @@ fn main() { - fn f(_: (i32, i32)) {} + fn f(_: (i32, i32)) {} //~ ERROR: calling a function with fewer arguments than it requires let g = unsafe { std::mem::transmute::(f) }; - g() //~ ERROR: calling a function with fewer arguments than it requires + g() } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr index 06e6ccbd7bf2..271ec64475ee 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr @@ -1,11 +1,16 @@ error: Undefined Behavior: calling a function with fewer arguments than it requires --> tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC | -LL | g() - | ^^^ Undefined Behavior occurred here +LL | fn f(_: (i32, i32)) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_too_few_args.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/fail/function_pointers/abi_mismatch_too_many_args.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.rs index c0e96a43cc52..744c5289e018 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.rs @@ -1,7 +1,7 @@ fn main() { - fn f() {} + fn f() {} //~ ERROR: calling a function with more arguments than it expected let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR: calling a function with more arguments than it expected + g(42) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr index d343eb8f2599..1721f0f9428c 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr @@ -1,11 +1,16 @@ error: Undefined Behavior: calling a function with more arguments than it expected --> tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC | -LL | g(42) - | ^^^^^ Undefined Behavior occurred here +LL | fn f() {} + | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_too_many_args.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/fail/function_pointers/abi_mismatch_vector.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs index dedcaac61427..ed5b4696dd0f 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs @@ -2,10 +2,10 @@ use std::simd; fn main() { - fn f(_: simd::u32x8) {} + fn f(_: simd::u32x8) {} //~ ERROR: type std::simd::Simd passing argument of type std::simd::Simd // These two vector types have the same size but are still not compatible. let g = unsafe { std::mem::transmute::(f) }; - g(Default::default()) //~ ERROR: type std::simd::Simd passing argument of type std::simd::Simd + g(Default::default()) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr index 1176589a5f4a..59823fad522b 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type std::simd::Simd passing argument of type std::simd::Simd --> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC | -LL | g(Default::default()) - | ^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(_: simd::u32x8) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_vector.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/fail/intrinsics/typed-swap-invalid-array.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr index 6cdcd114d5cf..e366aa96a30a 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [0]: encountered 0x02, but expected a boolean +error: Undefined Behavior: constructing invalid value of type [bool; 100]: at [0], encountered 0x02, but expected a boolean --> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC | LL | typed_swap_nonoverlapping(a, b); diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr index 223f7430b60a..58e20306ed1d 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean +error: Undefined Behavior: constructing invalid value of type bool: encountered 0x02, but expected a boolean --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC | LL | typed_swap_nonoverlapping(a, b); diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr index 59e392085001..b5bf8d7256bf 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered 0x03, but expected a boolean +error: Undefined Behavior: constructing invalid value of type bool: encountered 0x03, but expected a boolean --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC | LL | typed_swap_nonoverlapping(a, b); diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index d0f7cc1eacc2..47acb43ec0e9 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a value of the never type `!` +error: Undefined Behavior: constructing invalid value of type !: encountered a value of the never type `!` --> tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC | LL | let _ = unsafe { std::mem::uninitialized::() }; diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index 1646721e2eba..ab6f91399af5 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a null function pointer +error: Undefined Behavior: constructing invalid value of type fn(): encountered a null function pointer --> tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC | LL | let _ = unsafe { std::mem::zeroed::() }; diff --git a/src/tools/miri/tests/fail/issue-miri-1112.stderr b/src/tools/miri/tests/fail/issue-miri-1112.stderr index 0c5c6a94baf2..9873591c7d61 100644 --- a/src/tools/miri/tests/fail/issue-miri-1112.stderr +++ b/src/tools/miri/tests/fail/issue-miri-1112.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer +error: Undefined Behavior: constructing invalid value of type *mut FunnyPointer: encountered $HEX[ALLOC], but expected a vtable pointer --> tests/fail/issue-miri-1112.rs:LL:CC | LL | let obj = std::mem::transmute::(obj); diff --git a/src/tools/miri/tests/fail/match/closures/deref-in-pattern.stderr b/src/tools/miri/tests/fail/match/closures/deref-in-pattern.stderr index cbb74df5de77..9bbbc1b2d215 100644 --- a/src/tools/miri/tests/fail/match/closures/deref-in-pattern.stderr +++ b/src/tools/miri/tests/fail/match/closures/deref-in-pattern.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) +error: Undefined Behavior: constructing invalid value of type &u32: encountered a dangling reference (use-after-free) --> tests/fail/match/closures/deref-in-pattern.rs:LL:CC | LL | let _ = || { diff --git a/src/tools/miri/tests/fail/match/closures/partial-pattern.stderr b/src/tools/miri/tests/fail/match/closures/partial-pattern.stderr index b8ca04559e23..ab50f9bb53c2 100644 --- a/src/tools/miri/tests/fail/match/closures/partial-pattern.stderr +++ b/src/tools/miri/tests/fail/match/closures/partial-pattern.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) +error: Undefined Behavior: constructing invalid value of type &u32: encountered a dangling reference (use-after-free) --> tests/fail/match/closures/partial-pattern.rs:LL:CC | LL | let _ = || { diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.stderr index 6f097c336d2c..8a3448f048af 100644 --- a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.stderr +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance0.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) +error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference ($HEX[noalloc] has no provenance) --> tests/fail/provenance/int_copy_looses_provenance0.rs:LL:CC | LL | let _val = unsafe { *ptr.read() }; diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.stderr index f3d1d8c13dec..d4fb5b54fba3 100644 --- a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.stderr +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) +error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference ($HEX[noalloc] has no provenance) --> tests/fail/provenance/int_copy_looses_provenance1.rs:LL:CC | LL | let _val = unsafe { *ptr.read() }; diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.stderr index 837423292daa..bdeb8a4ef810 100644 --- a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.stderr +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance2.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance) +error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference ($HEX[noalloc] has no provenance) --> tests/fail/provenance/int_copy_looses_provenance2.rs:LL:CC | LL | let _val = unsafe { *ptr.read() }; diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs index 3629e4387e7f..1e10f682e71e 100644 --- a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs +++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs @@ -1,4 +1,5 @@ unsafe extern "C" fn ctor() -> i32 { + //~^ERROR: calling a function with return type i32 passing return place of type () 0 } @@ -30,7 +31,6 @@ macro_rules! ctor { )] #[used] static $ident: unsafe extern "C" fn() -> i32 = $ctor; - //~^ERROR: calling a function with return type i32 passing return place of type () }; } diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr index 1b4cd23e41a8..4e474dbadcb6 100644 --- a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr +++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr @@ -1,18 +1,21 @@ error: Undefined Behavior: calling a function with return type i32 passing return place of type () --> tests/fail/shims/ctor_wrong_ret_type.rs:LL:CC | -LL | static $ident: unsafe extern "C" fn() -> i32 = $ctor; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code -... -LL | ctor! { CTOR = ctor } - | --------------------- in this macro invocation +LL | unsafe extern "C" fn ctor() -> i32 { + | ^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri - = note: this error occurred while pushing a call frame onto an empty stack - = note: the span indicates which code caused the function to be called, but may not be the literal call site +note: the current function got called indirectly due to this code + --> tests/fail/shims/ctor_wrong_ret_type.rs:LL:CC + | +LL | static $ident: unsafe extern "C" fn() -> i32 = $ctor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | ctor! { CTOR = ctor } + | --------------------- in this macro invocation = note: this error originates in the macro `ctor` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/src/tools/miri/tests/fail/stacked_borrows/transmute-is-no-escape.rs index 233b927dfc7e..03b716cda500 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -2,7 +2,7 @@ // (i.e, no EscapeToRaw happened). // We could, in principle, do EscapeToRaw lazily to allow this code, but that // would no alleviate the need for EscapeToRaw (see `ref_raw_int_raw` in -// `run-pass/stacked-borrows.rs`), and thus increase overall complexity. +// `pass/both_borrows/int-to-ptr.rs`), and thus increase overall complexity. use std::mem; fn main() { diff --git a/src/tools/miri/tests/fail/storage-live-resets-var.stderr b/src/tools/miri/tests/fail/storage-live-resets-var.stderr index b3dd4ea0e848..418e5f5eec5b 100644 --- a/src/tools/miri/tests/fail/storage-live-resets-var.stderr +++ b/src/tools/miri/tests/fail/storage-live-resets-var.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value of type i32: encountered uninitialized memory, but expected an integer --> tests/fail/storage-live-resets-var.rs:LL:CC | LL | _val2 = val; diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs index 36bd1e99cfbc..e747bfdbf520 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs @@ -2,16 +2,14 @@ #![allow(incomplete_features)] fn main() { - // FIXME(explicit_tail_calls): - // the error should point to `become g(x)`, - // but tail calls mess up the backtrace it seems like... f(0); - //~^ error: type i32 passing argument of type u32 } fn f(x: u32) { let g = unsafe { std::mem::transmute::(g) }; - become g(x); + become g(x); // FIXME ideally this should also be involved in the error somehow, + // but by the time we pass the argument, `f`'s stackframe has already been popped. } fn g(_: i32) {} +//~^ error: type i32 passing argument of type u32 diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr index f5eccaeba666..9c10db8e5fe4 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32 --> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC | -LL | f(0); - | ^^^^ Undefined Behavior occurred here +LL | fn g(_: i32) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: g + at tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC + 1: main + at tests/fail/tail_calls/signature-mismatch-arg.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/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr index 2b98a2f99cf9..ea4b495926c5 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) +error: Undefined Behavior: constructing invalid value of type &mut PartialDrop: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> RUSTLIB/core/src/ptr/mod.rs:LL:CC | LL | / pub const unsafe fn drop_in_place(to_drop: *mut T) diff --git a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr index 0be5ef9ccf1b..7c85a3be5a26 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) +error: Undefined Behavior: constructing invalid value of type &dyn std::fmt::Debug: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> tests/fail/unaligned_pointers/dyn_alignment.rs:LL:CC | LL | let _ptr = &*ptr; diff --git a/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.rs b/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.rs new file mode 100644 index 000000000000..38ec7a7c3f54 --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.rs @@ -0,0 +1,15 @@ +// Test that an unaligned `MaybeDangling<&u8>` is still detected as UB. +// +//@compile-flags: -Zmiri-disable-stacked-borrows +#![feature(maybe_dangling)] + +use std::mem::{MaybeDangling, transmute}; + +fn main() { + let a = [1u16, 0u16]; + unsafe { + let unaligned = MaybeDangling::new(a.as_ptr().byte_add(1)); + transmute::, MaybeDangling<&u16>>(unaligned) + //~^ ERROR: encountered an unaligned reference + }; +} diff --git a/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr new file mode 100644 index 000000000000..190976c4f046 --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u16>: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) + --> tests/fail/unaligned_pointers/maybe_dangling_unalighed.rs:LL:CC + | +LL | transmute::, MaybeDangling<&u16>>(unaligned) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr index 2f3079383d12..d8252e51ae84 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) +error: Undefined Behavior: constructing invalid value of type &i32: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC | LL | mem::transmute(x) diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr index dfd6c143dfe4..85273177b2ae 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) +error: Undefined Behavior: constructing invalid value of type &u32: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs:LL:CC | LL | let _x = unsafe { &*x }; diff --git a/src/tools/miri/tests/fail/uninit/padding-struct-in-union.stderr b/src/tools/miri/tests/fail/uninit/padding-struct-in-union.stderr index 2b0dbd38e6ed..cf22b56e40b2 100644 --- a/src/tools/miri/tests/fail/uninit/padding-struct-in-union.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-struct-in-union.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .bytes[2]: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value of type Bar: at .bytes[2], encountered uninitialized memory, but expected an integer --> tests/fail/uninit/padding-struct-in-union.rs:LL:CC | LL | let _val = unsafe { (foobar.foo, foobar.bar) }; diff --git a/src/tools/miri/tests/fail/uninit/padding-union.stderr b/src/tools/miri/tests/fail/uninit/padding-union.stderr index 30d0862df39a..7851bb60781d 100644 --- a/src/tools/miri/tests/fail/uninit/padding-union.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-union.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value of type [u8; 4]: at [1], encountered uninitialized memory, but expected an integer --> tests/fail/uninit/padding-union.rs:LL:CC | LL | let _val = *c; diff --git a/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr b/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr index e8deb5732a70..d4048bbaa176 100644 --- a/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value of type [u8; 4]: at [1], encountered uninitialized memory, but expected an integer --> tests/fail/uninit/uninit-after-aggregate-assign.rs:LL:CC | LL | _val = *sptr2; // should hence be UB diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr index b470e79232d5..3de7f6cf9913 100644 --- a/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr +++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling box (0x4[noalloc] has no provenance) +error: Undefined Behavior: constructing invalid value of type std::boxed::Box: encountered a dangling box (0x4[noalloc] has no provenance) --> tests/fail/validity/box-custom-alloc-dangling-ptr.rs:LL:CC | LL | std::mem::transmute(b) diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr index d7594ab53b5d..f2fa738cb6d3 100644 --- a/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr +++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .1.my_alloc_field1: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value of type std::boxed::Box: at .1.my_alloc_field1, encountered uninitialized memory, but expected an integer --> tests/fail/validity/box-custom-alloc-invalid-alloc.rs:LL:CC | LL | std::mem::transmute(b) diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs index 6ab73569c634..8657e3ad679d 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs @@ -5,9 +5,9 @@ fn main() { // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. fn f(_x: &i32) {} + //~^ ERROR: encountered a null reference let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; g(0usize as *const i32) - //~^ ERROR: encountered a null reference } diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr index 02e0ebe8abe6..1859ec5bcb2f 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr @@ -1,11 +1,16 @@ -error: Undefined Behavior: constructing invalid value: encountered a null reference +error: Undefined Behavior: constructing invalid value of type &i32: encountered a null reference --> tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs:LL:CC | -LL | g(0usize as *const i32) - | ^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(_x: &i32) {} + | ^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::f + at tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs:LL:CC + 1: main + at tests/fail/validity/cast_fn_ptr_invalid_callee_arg.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/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr index 6fc1bc01655c..26db49e49f70 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value of type std::num::NonZero: at .0.0, encountered 0, but expected something greater or equal to 1 --> tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs index 7ca26bffc14f..0635fdd14920 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -6,6 +6,7 @@ use std::ptr; fn f(c: u32) { + //~^ERROR: expected something greater or equal to 1 println!("{c}"); } @@ -20,7 +21,7 @@ fn call(f: fn(NonZero)) { let tmp = ptr::addr_of!(c); let ptr = tmp as *const NonZero; // The call site now is a `NonZero` to `u32` transmute. - Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) //~ERROR: expected something greater or equal to 1 + Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) } retblock = { Return() diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr index 3b23a6cc4e85..fa67150184c6 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -1,15 +1,17 @@ -error: Undefined Behavior: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value of type std::num::NonZero: at .0.0, encountered 0, but expected something greater or equal to 1 --> tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC | -LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(c: u32) { + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: stack backtrace: - 0: call + 0: f at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC - 1: main + 1: call + at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + 2: main at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.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/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr index 03d6637cdb61..d92253293a9c 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a null reference +error: Undefined Behavior: constructing invalid value of type &i32: encountered a null reference --> tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs:LL:CC | LL | let _x = g(); diff --git a/src/tools/miri/tests/fail/validity/dangling_ref1.stderr b/src/tools/miri/tests/fail/validity/dangling_ref1.stderr index 05467c483f63..0020c641274e 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref1.stderr +++ b/src/tools/miri/tests/fail/validity/dangling_ref1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference (0x10[noalloc] has no provenance) +error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference (0x10[noalloc] has no provenance) --> tests/fail/validity/dangling_ref1.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; diff --git a/src/tools/miri/tests/fail/validity/dangling_ref2.stderr b/src/tools/miri/tests/fail/validity/dangling_ref2.stderr index eb1b6e2c5804..a1c8de2a2324 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref2.stderr +++ b/src/tools/miri/tests/fail/validity/dangling_ref2.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference (going beyond the bounds of its allocation) --> tests/fail/validity/dangling_ref2.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; diff --git a/src/tools/miri/tests/fail/validity/dangling_ref3.stderr b/src/tools/miri/tests/fail/validity/dangling_ref3.stderr index ec2238c8618f..0bf25982833f 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref3.stderr +++ b/src/tools/miri/tests/fail/validity/dangling_ref3.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) +error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference (use-after-free) --> tests/fail/validity/dangling_ref3.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; diff --git a/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.stderr b/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.stderr index 383c13cc2ab7..9df01f0d4d18 100644 --- a/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.stderr +++ b/src/tools/miri/tests/fail/validity/dyn-transmute-inner-binder.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait fn(&'a ())>`, but encountered `Trait` +error: Undefined Behavior: constructing invalid value of type &dyn Trait fn(&'a ())>: wrong trait in wide pointer vtable: expected `Trait fn(&'a ())>`, but encountered `Trait` --> tests/fail/validity/dyn-transmute-inner-binder.rs:LL:CC | LL | let y: &dyn Trait fn(&'a ())> = unsafe { std::mem::transmute(x) }; diff --git a/src/tools/miri/tests/fail/validity/invalid_bool.stderr b/src/tools/miri/tests/fail/validity/invalid_bool.stderr index b667449add68..a403c8dc9411 100644 --- a/src/tools/miri/tests/fail/validity/invalid_bool.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_bool.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean +error: Undefined Behavior: constructing invalid value of type bool: encountered 0x02, but expected a boolean --> tests/fail/validity/invalid_bool.rs:LL:CC | LL | let _b = unsafe { std::mem::transmute::(2) }; diff --git a/src/tools/miri/tests/fail/validity/invalid_bool_uninit.stderr b/src/tools/miri/tests/fail/validity/invalid_bool_uninit.stderr index 800bc4fc3163..86767c6eef0b 100644 --- a/src/tools/miri/tests/fail/validity/invalid_bool_uninit.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_bool_uninit.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean +error: Undefined Behavior: constructing invalid value of type [bool; 1]: at [0], encountered uninitialized memory, but expected a boolean --> tests/fail/validity/invalid_bool_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; diff --git a/src/tools/miri/tests/fail/validity/invalid_char.stderr b/src/tools/miri/tests/fail/validity/invalid_char.stderr index 7f579882bea0..cb81038f8bd9 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) +error: Undefined Behavior: constructing invalid value of type char: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) --> tests/fail/validity/invalid_char.rs:LL:CC | LL | let _val = match unsafe { std::mem::transmute::(-1) } { diff --git a/src/tools/miri/tests/fail/validity/invalid_char_uninit.stderr b/src/tools/miri/tests/fail/validity/invalid_char_uninit.stderr index de8c1f39f248..78acda63d745 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_uninit.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_uninit.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value +error: Undefined Behavior: constructing invalid value of type [char; 1]: at [0], encountered uninitialized memory, but expected a unicode scalar value --> tests/fail/validity/invalid_char_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.rs b/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.rs new file mode 100644 index 000000000000..3d1ae64b5782 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.rs @@ -0,0 +1,27 @@ +// Make sure we find these even with many checks disabled. +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +#![feature(never_type)] + +enum Never {} + +// An enum with 4 variants of which only some are uninhabited -- so the uninhabited variants *do* +// have a discriminant. +#[allow(unused)] +enum UninhDiscriminant { + A, + B(!), + C, + D(Never), +} + +fn main() { + unsafe { + let x = 3u8; + let x_ptr: *const u8 = &x; + let cast_ptr = x_ptr as *const UninhDiscriminant; + // Reading the discriminant should fail since the tag value is not in the valid + // range for the tag field. + let _val = matches!(*cast_ptr, UninhDiscriminant::A); + //~^ ERROR: invalid tag + } +} diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.stderr new file mode 100644 index 000000000000..2e2ad81a0451 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op_discr_uninhabited.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: enum value has invalid tag: 0x03 + --> tests/fail/validity/invalid_enum_op_discr_uninhabited.rs:LL:CC + | +LL | let _val = matches!(*cast_ptr, UninhDiscriminant::A); + | ^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.rs b/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.rs new file mode 100644 index 000000000000..51237c360f1c --- /dev/null +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.rs @@ -0,0 +1,14 @@ +// Make sure we find these even with many checks disabled. +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + +fn main() { + unsafe { + let x = 12u8; + let x_ptr: *const u8 = &x; + let cast_ptr = x_ptr as *const Option; + // Reading the discriminant should fail since the tag value is not in the valid + // range for the tag field. + let _val = matches!(*cast_ptr, None); + //~^ ERROR: invalid tag + } +} diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.stderr new file mode 100644 index 000000000000..65fcddbb43da --- /dev/null +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op_niche_out_of_range.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: enum value has invalid tag: 0x0c + --> tests/fail/validity/invalid_enum_op_niche_out_of_range.rs:LL:CC + | +LL | let _val = matches!(*cast_ptr, None); + | ^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_tag.rs b/src/tools/miri/tests/fail/validity/invalid_enum_tag.rs index fa115e1e78e4..9ef4a30e0d61 100644 --- a/src/tools/miri/tests/fail/validity/invalid_enum_tag.rs +++ b/src/tools/miri/tests/fail/validity/invalid_enum_tag.rs @@ -7,5 +7,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR: constructing invalid value at .: encountered 0x0000002a, but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR: constructing invalid value of type Foo: at ., encountered 0x0000002a, but expected a valid enum tag } diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_tag.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_tag.stderr index d7f299105205..bd182df5c1eb 100644 --- a/src/tools/miri/tests/fail/validity/invalid_enum_tag.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_enum_tag.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .: encountered $HEX, but expected a valid enum tag +error: Undefined Behavior: constructing invalid value of type Foo: at ., encountered $HEX, but expected a valid enum tag --> tests/fail/validity/invalid_enum_tag.rs:LL:CC | LL | let _f = unsafe { std::mem::transmute::(42) }; diff --git a/src/tools/miri/tests/fail/validity/invalid_fnptr_null.stderr b/src/tools/miri/tests/fail/validity/invalid_fnptr_null.stderr index 20b2234e2ab2..6750dcb5b2bf 100644 --- a/src/tools/miri/tests/fail/validity/invalid_fnptr_null.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_fnptr_null.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a null function pointer +error: Undefined Behavior: constructing invalid value of type fn(): encountered a null function pointer --> tests/fail/validity/invalid_fnptr_null.rs:LL:CC | LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; diff --git a/src/tools/miri/tests/fail/validity/invalid_fnptr_uninit.stderr b/src/tools/miri/tests/fail/validity/invalid_fnptr_uninit.stderr index 513b90b5d85e..60994e2c6d14 100644 --- a/src/tools/miri/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer +error: Undefined Behavior: constructing invalid value of type [fn(); 1]: at [0], encountered uninitialized memory, but expected a function pointer --> tests/fail/validity/invalid_fnptr_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; diff --git a/src/tools/miri/tests/fail/validity/invalid_wide_raw.stderr b/src/tools/miri/tests/fail/validity/invalid_wide_raw.stderr index a3c7815cf282..cb3c09816981 100644 --- a/src/tools/miri/tests/fail/validity/invalid_wide_raw.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_wide_raw.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered null pointer, but expected a vtable pointer +error: Undefined Behavior: constructing invalid value of type *mut dyn main::T: encountered null pointer, but expected a vtable pointer --> tests/fail/validity/invalid_wide_raw.rs:LL:CC | LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); diff --git a/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr b/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr index 0ca8bc9f9bae..c905f3a65b62 100644 --- a/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr +++ b/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a value of uninhabited type `main::Void` +error: Undefined Behavior: constructing invalid value of type main::Void: encountered a value of uninhabited type `main::Void` --> tests/fail/validity/match_binder_checks_validity1.rs:LL:CC | LL | _x => println!("hi from the void!"), diff --git a/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr b/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr index 281314e68d51..02caf64eae51 100644 --- a/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr +++ b/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered 0x03, but expected a boolean +error: Undefined Behavior: constructing invalid value of type bool: encountered 0x03, but expected a boolean --> tests/fail/validity/match_binder_checks_validity2.rs:LL:CC | LL | _x => println!("hi from the void!"), diff --git a/src/tools/miri/tests/fail/validity/maybe_dangling_null.rs b/src/tools/miri/tests/fail/validity/maybe_dangling_null.rs new file mode 100644 index 000000000000..9b3c80b97542 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/maybe_dangling_null.rs @@ -0,0 +1,13 @@ +// Test that a null `MaybeDangling<&u8>` is still detected as UB. +// +//@compile-flags: -Zmiri-disable-stacked-borrows +#![feature(maybe_dangling)] + +use std::mem::{MaybeDangling, transmute}; +use std::ptr::null; + +fn main() { + let null = MaybeDangling::new(null()); + unsafe { transmute::, MaybeDangling<&u8>>(null) }; + //~^ ERROR: encountered a null reference +} diff --git a/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr b/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr new file mode 100644 index 000000000000..041a6b1b96e0 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u8>: encountered a null reference + --> tests/fail/validity/maybe_dangling_null.rs:LL:CC + | +LL | unsafe { transmute::, MaybeDangling<&u8>>(null) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/nonzero.stderr b/src/tools/miri/tests/fail/validity/nonzero.stderr index e5fcdadb0d2c..2b352400b6e8 100644 --- a/src/tools/miri/tests/fail/validity/nonzero.stderr +++ b/src/tools/miri/tests/fail/validity/nonzero.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value of type NonZero: encountered 0, but expected something greater or equal to 1 --> tests/fail/validity/nonzero.rs:LL:CC | LL | let _x = Some(unsafe { NonZero(0) }); diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-box-bool.stderr b/src/tools/miri/tests/fail/validity/recursive-validity-box-bool.stderr index d658909efd93..9cb64307ccb1 100644 --- a/src/tools/miri/tests/fail/validity/recursive-validity-box-bool.stderr +++ b/src/tools/miri/tests/fail/validity/recursive-validity-box-bool.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .: encountered 0x03, but expected a boolean +error: Undefined Behavior: constructing invalid value of type std::boxed::Box: at ., encountered 0x03, but expected a boolean --> tests/fail/validity/recursive-validity-box-bool.rs:LL:CC | LL | let xref_wrong_type: Box = unsafe { std::mem::transmute(xref) }; diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr index 112072679ea5..933e48a19d65 100644 --- a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr +++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .: encountered 0x03, but expected a boolean +error: Undefined Behavior: constructing invalid value of type &bool: at ., encountered 0x03, but expected a boolean --> tests/fail/validity/recursive-validity-ref-bool.rs:LL:CC | LL | let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; diff --git a/src/tools/miri/tests/fail/validity/ref_to_uninhabited1.stderr b/src/tools/miri/tests/fail/validity/ref_to_uninhabited1.stderr index f1a059175566..645a9789207a 100644 --- a/src/tools/miri/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/src/tools/miri/tests/fail/validity/ref_to_uninhabited1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a box pointing to uninhabited type ! +error: Undefined Behavior: constructing invalid value of type std::boxed::Box: encountered a box pointing to uninhabited type ! --> tests/fail/validity/ref_to_uninhabited1.rs:LL:CC | LL | let x: Box = transmute(&mut 42); diff --git a/src/tools/miri/tests/fail/validity/ref_to_uninhabited2.stderr b/src/tools/miri/tests/fail/validity/ref_to_uninhabited2.stderr index 4d25de46ade8..37b265a771bc 100644 --- a/src/tools/miri/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/src/tools/miri/tests/fail/validity/ref_to_uninhabited2.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered a reference pointing to uninhabited type (i32, Void) +error: Undefined Behavior: constructing invalid value of type &(i32, Void): encountered a reference pointing to uninhabited type (i32, Void) --> tests/fail/validity/ref_to_uninhabited2.rs:LL:CC | LL | let _x: &(i32, Void) = transmute(&42); diff --git a/src/tools/miri/tests/fail/validity/too-big-slice.stderr b/src/tools/miri/tests/fail/validity/too-big-slice.stderr index 9d4c34748660..7377d207ffed 100644 --- a/src/tools/miri/tests/fail/validity/too-big-slice.stderr +++ b/src/tools/miri/tests/fail/validity/too-big-slice.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error: Undefined Behavior: constructing invalid value of type &[u8]: encountered invalid reference metadata: slice is bigger than largest supported object --> tests/fail/validity/too-big-slice.rs:LL:CC | LL | ... let _x: &[u8] = mem::transmute((ptr, usize::MAX)); diff --git a/src/tools/miri/tests/fail/validity/too-big-unsized.stderr b/src/tools/miri/tests/fail/validity/too-big-unsized.stderr index 6c07308d08ca..0fc63395c601 100644 --- a/src/tools/miri/tests/fail/validity/too-big-unsized.stderr +++ b/src/tools/miri/tests/fail/validity/too-big-unsized.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered invalid reference metadata: total size is bigger than largest supported object +error: Undefined Behavior: constructing invalid value of type &MySlice: encountered invalid reference metadata: total size is bigger than largest supported object --> tests/fail/validity/too-big-unsized.rs:LL:CC | LL | ... let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); diff --git a/src/tools/miri/tests/fail/validity/transmute_through_ptr.rs b/src/tools/miri/tests/fail/validity/transmute_through_ptr.rs index 60b3bdd6cd69..b49c7745f28e 100644 --- a/src/tools/miri/tests/fail/validity/transmute_through_ptr.rs +++ b/src/tools/miri/tests/fail/validity/transmute_through_ptr.rs @@ -14,6 +14,6 @@ fn main() { let mut x = Bool::True; evil(&mut x); let y = x; // reading this ought to be enough to trigger validation - //~^ ERROR: constructing invalid value at .: encountered 0x0000002c, but expected a valid enum tag + //~^ ERROR: constructing invalid value of type Bool: at ., encountered 0x0000002c, but expected a valid enum tag println!("{:?}", y); // make sure it is used (and not optimized away) } diff --git a/src/tools/miri/tests/fail/validity/transmute_through_ptr.stderr b/src/tools/miri/tests/fail/validity/transmute_through_ptr.stderr index 998ff79d3afe..d531df63dc20 100644 --- a/src/tools/miri/tests/fail/validity/transmute_through_ptr.stderr +++ b/src/tools/miri/tests/fail/validity/transmute_through_ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .: encountered $HEX, but expected a valid enum tag +error: Undefined Behavior: constructing invalid value of type Bool: at ., encountered $HEX, but expected a valid enum tag --> tests/fail/validity/transmute_through_ptr.rs:LL:CC | LL | let y = x; // reading this ought to be enough to trigger validation diff --git a/src/tools/miri/tests/fail/validity/uninhabited_variant.stderr b/src/tools/miri/tests/fail/validity/uninhabited_variant.stderr index 76ee25009b6e..8f120cb399e4 100644 --- a/src/tools/miri/tests/fail/validity/uninhabited_variant.stderr +++ b/src/tools/miri/tests/fail/validity/uninhabited_variant.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .: encountered an uninhabited enum variant +error: Undefined Behavior: constructing invalid value of type E: at ., encountered an uninhabited enum variant --> tests/fail/validity/uninhabited_variant.rs:LL:CC | LL | std::mem::transmute::(1); diff --git a/src/tools/miri/tests/fail/validity/uninit_float.stderr b/src/tools/miri/tests/fail/validity/uninit_float.stderr index 7f3c94a87874..82e0b2064d6e 100644 --- a/src/tools/miri/tests/fail/validity/uninit_float.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_float.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a floating point number +error: Undefined Behavior: constructing invalid value of type [f32; 1]: at [0], encountered uninitialized memory, but expected a floating point number --> tests/fail/validity/uninit_float.rs:LL:CC | LL | let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; diff --git a/src/tools/miri/tests/fail/validity/uninit_integer.stderr b/src/tools/miri/tests/fail/validity/uninit_integer.stderr index a80396f7f1ce..038ffde63c45 100644 --- a/src/tools/miri/tests/fail/validity/uninit_integer.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_integer.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value of type [usize; 1]: at [0], encountered uninitialized memory, but expected an integer --> tests/fail/validity/uninit_integer.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; diff --git a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr index 946d74d35484..ecfca66984cc 100644 --- a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr +++ b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a raw pointer +error: Undefined Behavior: constructing invalid value of type [*const u8; 1]: at [0], encountered uninitialized memory, but expected a raw pointer --> tests/fail/validity/uninit_raw_ptr.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr index ea77d11f1e83..74d8a4697ca4 100644 --- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` +error: Undefined Behavior: constructing invalid value of type std::boxed::Box>: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` --> tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC | LL | let v: Box> = unsafe { std::mem::transmute(v) }; diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr index f9e2f15d98f9..9273e398a2ad 100644 --- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` +error: Undefined Behavior: constructing invalid value of type *const dyn Trait: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` --> tests/fail/validity/wrong-dyn-trait-generic.rs:LL:CC | LL | let _y: *const dyn Trait = unsafe { mem::transmute(x) }; diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr index 47efd0b0428c..6ca55c24c3be 100644 --- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send` +error: Undefined Behavior: constructing invalid value of type *const dyn std::fmt::Debug: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send` --> tests/fail/validity/wrong-dyn-trait.rs:LL:CC | LL | let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) }; diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs index 8be29c0c121a..061e5134c80e 100644 --- a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs @@ -16,7 +16,16 @@ extern "C" fn id(x: T) -> T { x } + fn pass_via_id_fn_ptr(x: T) -> T { + let f = id:: as extern "C" fn(T) -> T; + f(x) + } + unsafe { + // As long as we keep the function pointer on the Rust side, this is all fine. + let closure = || (); + pass_via_id_fn_ptr(closure)(); + // When we pass it to FFI, we get the expected error. call_fn_ptr(id::); //~ ERROR: unsupported operation: calling a function pointer through the FFI boundary } } diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_unsupported.notrace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_unsupported.notrace.stderr new file mode 100644 index 000000000000..a3e98a162ea2 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_unsupported.notrace.stderr @@ -0,0 +1,31 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + | +LL | call_fn_ptr(std::mem::transmute(f)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory + = help: in particular, Miri assumes that the native call initializes all memory it has access to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + +error: unsupported operation: calling a function pointer with unsupported argument/return type through the FFI boundary + --> tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + | +LL | call_fn_ptr(std::mem::transmute(f)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_unsupported.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/native-lib/fail/call_fn_ptr_with_unsupported.rs b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_unsupported.rs new file mode 100644 index 000000000000..a079651b3fd8 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_unsupported.rs @@ -0,0 +1,32 @@ +//@revisions: trace notrace +//@[trace] only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu +//@[trace] compile-flags: -Zmiri-native-lib-enable-tracing +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + pass_fn_ptr() +} + +fn pass_fn_ptr() { + extern "C" { + fn call_fn_ptr(s: extern "C" fn(i32) -> i32); + } + + extern "C" fn id(x: T) -> T { + x + } + + fn make_fn_ptr_for_type(_x: &T) -> extern "C" fn(T) -> T { + id:: as extern "C" fn(T) -> T + } + + unsafe { + let closure = || (); + let f = make_fn_ptr_for_type(&closure); + // Transmute the type around so C can invoke this -- with the entirely wrong signature. + // Wht we're hoping for is that Miri just ignores all the arguments and aborts + // with a reasonable error instead. + call_fn_ptr(std::mem::transmute(f)); + //~^ ERROR: unsupported operation: calling a function pointer with unsupported argument/return type + } +} diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_unsupported.trace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_unsupported.trace.stderr new file mode 100644 index 000000000000..72448b2ab0ff --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_unsupported.trace.stderr @@ -0,0 +1,32 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + | +LL | call_fn_ptr(std::mem::transmute(f)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis + = help: in particular, Miri assumes that the native call initializes all memory it has written to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + +error: unsupported operation: calling a function pointer with unsupported argument/return type through the FFI boundary + --> tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + | +LL | call_fn_ptr(std::mem::transmute(f)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_unsupported.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_unsupported.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/native-lib/fail/invalid_retval.rs b/src/tools/miri/tests/native-lib/fail/invalid_retval.rs index 4967866b7e7f..e4bcbeb10926 100644 --- a/src/tools/miri/tests/native-lib/fail/invalid_retval.rs +++ b/src/tools/miri/tests/native-lib/fail/invalid_retval.rs @@ -9,6 +9,6 @@ fn main() { unsafe { - u8_id(2); //~ ERROR: invalid value: encountered 0x02, but expected a boolean + u8_id(2); //~ ERROR: encountered 0x02, but expected a boolean } } diff --git a/src/tools/miri/tests/native-lib/fail/invalid_retval.stderr b/src/tools/miri/tests/native-lib/fail/invalid_retval.stderr index 9db29822d4f5..b3b99cc56e7b 100644 --- a/src/tools/miri/tests/native-lib/fail/invalid_retval.stderr +++ b/src/tools/miri/tests/native-lib/fail/invalid_retval.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean +error: Undefined Behavior: constructing invalid value of type bool: encountered 0x02, but expected a boolean --> tests/native-lib/fail/invalid_retval.rs:LL:CC | LL | u8_id(2); diff --git a/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs index cf8315e0fd9d..27ae6c477a84 100644 --- a/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs +++ b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs @@ -15,5 +15,5 @@ pub struct PassMe { fn main() { let pass_me = PassMe { value: 42, other_value: 1337 }; - unsafe { pass_struct(pass_me) }; //~ ERROR: unsupported operation: passing a non-#[repr(C)] struct over FFI + unsafe { pass_struct(pass_me) }; //~ ERROR: unsupported operation: unsupported argument type for native call } diff --git a/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr index a9158a0c6bac..fd701e0e302e 100644 --- a/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr +++ b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr @@ -1,4 +1,4 @@ -error: unsupported operation: passing a non-#[repr(C)] struct over FFI: PassMe +error: unsupported operation: unsupported argument type for native call: PassMe --> tests/native-lib/fail/struct_not_extern_c.rs:LL:CC | LL | unsafe { pass_struct(pass_me) }; diff --git a/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr b/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr index 9833b65b91b3..83e81703d8ad 100644 --- a/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr +++ b/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value at .part_1.high: encountered uninitialized memory, but expected an integer +error: Undefined Behavior: constructing invalid value of type ComplexStruct: at .part_1.high, encountered uninitialized memory, but expected an integer --> tests/native-lib/fail/uninit_struct.rs:LL:CC | LL | unsafe { pass_struct_complex(*arg.as_ptr(), 0, 0, 0) }; diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs index 57def78b0ab1..03f14dcc3cc9 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs @@ -176,7 +176,7 @@ struct Triple { } extern "C" { - fn swap_ptr_triple_dangling(t_ptr: *const Triple); + fn swap_ptr_triple_dangling(t_ptr: *mut Triple); } let x = 101; @@ -184,9 +184,9 @@ struct Triple { let ptr = Box::as_ptr(&b); drop(b); let z = 121; - let triple = Triple { ptr0: &raw const x, ptr1: ptr, ptr2: &raw const z }; + let mut triple = Triple { ptr0: &raw const x, ptr1: ptr, ptr2: &raw const z }; - unsafe { swap_ptr_triple_dangling(&triple) } + unsafe { swap_ptr_triple_dangling(&mut triple) } assert_eq!(unsafe { *triple.ptr2 }, x); } diff --git a/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs b/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs index 231df67bb5b8..07584ba236b9 100644 --- a/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs +++ b/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs @@ -1,3 +1,10 @@ +#[allow(unused)] +#[repr(C)] +enum CEnum { + A, + B, +} + extern "C" { fn add_one_int(x: i32) -> i32; fn add_int16(x: i16) -> i16; @@ -19,6 +26,7 @@ fn test_stack_spill( fn get_unsigned_int() -> u32; fn add_float(x: f32) -> f32; fn printer(); + fn scalar_enum(e: CEnum) -> u8; } fn main() { @@ -43,5 +51,8 @@ fn main() { // test void function that prints from C printer(); + + // test passing enums with scalar layout + assert_eq!(scalar_enum(CEnum::B), 1); } } diff --git a/src/tools/miri/tests/native-lib/scalar_arguments.c b/src/tools/miri/tests/native-lib/scalar_arguments.c index 720f1982178c..19ca940204a0 100644 --- a/src/tools/miri/tests/native-lib/scalar_arguments.c +++ b/src/tools/miri/tests/native-lib/scalar_arguments.c @@ -4,6 +4,11 @@ // See comments in build_native_lib() #define EXPORT __attribute__((visibility("default"))) +enum cenum { + cenum_a, + cenum_b, +}; + EXPORT int32_t add_one_int(int32_t x) { return 2 + x; } @@ -38,6 +43,10 @@ EXPORT uint8_t u8_id(uint8_t x) { return x; } +EXPORT uint8_t scalar_enum(enum cenum e) { + return (uint8_t)e; +} + // To test that functions not marked with EXPORT cannot be called by Miri. int32_t not_exported(void) { return 0; diff --git a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs index 91cf24a944ad..44e969578989 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs @@ -8,7 +8,7 @@ fn main() { unsafe { thread::spawn(|| { // Access the environment in another thread without taking the env lock - let s = libc::getenv("MIRI_ENV_VAR_TEST\0".as_ptr().cast()); + let s = libc::getenv(c"MIRI_ENV_VAR_TEST".as_ptr()); if s.is_null() { panic!("null"); } diff --git a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs index 9e5627c75a97..70fa6c183c84 100644 --- a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs +++ b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs @@ -7,8 +7,8 @@ type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; fn main() { - let name = "getentropy\0"; - let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize }; + let name = c"getentropy"; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize }; // If the GC does not account for the extra_fn_ptr entry that this dlsym just added, this GC // run will delete our entry for the base addr of the function pointer we will transmute to, // and the call through the function pointer will report UB. diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index f5e9a56d7d03..9dc1af1be299 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -54,29 +54,23 @@ fn main() { fn test_file_open_unix_allow_two_args() { let path = utils::prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY) }; + let _fd = unsafe { libc::open(name.as_ptr(), libc::O_RDONLY) }; } fn test_file_open_unix_needs_three_args() { let path = utils::prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT, 0o666) }; + let _fd = unsafe { libc::open(name.as_ptr(), libc::O_CREAT, 0o666) }; } fn test_file_open_unix_extra_third_arg() { let path = utils::prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 42) }; + let _fd = unsafe { libc::open(name.as_ptr(), libc::O_RDONLY, 42) }; } fn test_dup_stdout_stderr() { @@ -92,12 +86,10 @@ fn test_dup_stdout_stderr() { fn test_dup() { let bytes = b"dup and dup2"; let path = utils::prepare_with_content("miri_test_libc_dup.txt", bytes); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); unsafe { - let fd = libc::open(name_ptr, libc::O_RDONLY); + let fd = libc::open(name.as_ptr(), libc::O_RDONLY); let new_fd = libc::dup(fd); let new_fd2 = libc::dup2(fd, 8); @@ -519,7 +511,7 @@ fn test_read_and_uninit() { { // We test that libc::read initializes its buffer. let path = utils::prepare_with_content("pass-libc-read-and-uninit.txt", &[1u8, 2, 3]); - let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap(); + let cpath = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); unsafe { let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY); assert_ne!(fd, -1); @@ -528,8 +520,8 @@ fn test_read_and_uninit() { let buf = buf.assume_init(); assert_eq!(buf, 1); assert_eq!(libc::close(fd), 0); + assert_eq!(libc::unlink(cpath.as_ptr()), 0); } - remove_file(&path).unwrap(); } { // We test that if we requested to read 4 bytes, but actually read 3 bytes, then @@ -567,17 +559,15 @@ fn test_nofollow_not_symlink() { #[cfg(target_os = "macos")] fn test_ioctl() { let path = utils::prepare_with_content("miri_test_libc_ioctl.txt", &[]); + let name = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); - let mut name = path.into_os_string(); - name.push("\0"); - let name_ptr = name.as_bytes().as_ptr().cast::(); unsafe { // 100 surely is an invalid FD. assert_eq!(libc::ioctl(100, libc::FIOCLEX), -1); let errno = std::io::Error::last_os_error().raw_os_error().unwrap(); assert_eq!(errno, libc::EBADF); - let fd = libc::open(name_ptr, libc::O_RDONLY); + let fd = libc::open(name.as_ptr(), libc::O_RDONLY); assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0); } } diff --git a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs index d1c0085b024a..36ed470b353f 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs @@ -63,15 +63,22 @@ fn test_sigrt() { } fn test_dlsym() { - let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"notasymbol\0".as_ptr().cast()) }; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"notasymbol".as_ptr()) }; assert!(addr as usize == 0); - let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"isatty\0".as_ptr().cast()) }; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"isatty".as_ptr()) }; assert!(addr as usize != 0); let isatty: extern "C" fn(i32) -> i32 = unsafe { transmute(addr) }; assert_eq!(isatty(999), 0); let errno = std::io::Error::last_os_error().raw_os_error().unwrap(); assert_eq!(errno, libc::EBADF); + + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"environ".as_ptr()) }; + assert!(addr as usize != 0); + extern "C" { + static mut environ: *const *const u8; + } + assert!(addr as usize == &raw const environ as usize); } fn test_getuid() { diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs index ce4df4de72b6..0826db7e94a1 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs @@ -1,6 +1,4 @@ //@ignore-target: windows # No libc socket on Windows -//@ignore-target: solaris # Socket is a macro for __xnet7_socket which has no shim -//@ignore-target: illumos # Socket is a macro for __xnet7_socket which has no shim //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace use std::io::ErrorKind; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket.rs b/src/tools/miri/tests/pass-dep/libc/libc-socket.rs index ac9f13367642..8dd00e60200a 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socket.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket.rs @@ -1,14 +1,46 @@ //@ignore-target: windows # No libc socket on Windows -//@ignore-target: solaris # Does socket is a macro for __xnet7_socket which has no shim -//@ignore-target: illumos # Does socket is a macro for __xnet7_socket which has no shim //@compile-flags: -Zmiri-disable-isolation +#![feature(io_error_inprogress)] + #[path = "../../utils/libc.rs"] mod libc_utils; +use std::io::{self, ErrorKind}; +use std::time::Duration; +#[allow(unused)] +use std::{mem::MaybeUninit, thread}; + use libc_utils::*; fn main() { test_socket_close(); + test_bind_ipv4(); + test_bind_ipv4_reuseaddr(); + test_set_reuseaddr_invalid_len(); + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly" + ))] + { + test_bind_ipv4_nosigpipe(); + test_set_nosigpipe_invalid_len(); + } + test_bind_ipv4_invalid_addr_len(); + test_bind_ipv6(); + + test_listen(); + + test_accept_connect(); + + test_getsockname_ipv4(); + test_getsockname_ipv4_random_port(); + test_getsockname_ipv4_unbound(); + test_getsockname_ipv6(); + + test_getpeername_ipv4(); + test_getpeername_ipv6(); } fn test_socket_close() { @@ -17,3 +49,522 @@ fn test_socket_close() { errno_check(libc::close(sockfd)); } } + +fn test_bind_ipv4() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } +} + +/// Tests binding after the `SO_REUSEADDR` socket option has been set on the newly created socket. +fn test_bind_ipv4_reuseaddr() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + setsockopt(sockfd, libc::SOL_SOCKET, libc::SO_REUSEADDR, 1 as libc::c_int).unwrap(); + unsafe { + errno_check(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } +} + +/// Tests setting the `SO_REUSEADDR` socket option but with an invalid length. +fn test_set_reuseaddr_invalid_len() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + // Value should be of type `libc::c_int` which has size 4 bytes. + // By providing a u64 of size 8 bytes we trigger an invalid length error. + let err = setsockopt(sockfd, libc::SOL_SOCKET, libc::SO_REUSEADDR, 1u64).unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + // check that it is the right kind of `InvalidInput` + assert_eq!(err.raw_os_error(), Some(libc::EINVAL)); +} + +#[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly" +))] +/// Tests binding after the `SO_NOSIGPIPE` socket option has been set on the newly created socket. +/// That flag only exists on BSD-like OSes. +fn test_bind_ipv4_nosigpipe() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + setsockopt(sockfd, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1 as libc::c_int).unwrap(); + unsafe { + errno_check(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } +} + +#[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly" +))] +/// Tests setting the `SO_NOSIGPIPE` socket option but with an invalid length. +fn test_set_nosigpipe_invalid_len() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + // Value should be of type `libc::c_int` which has size 4 bytes. + // By providing a u64 of size 8 bytes we trigger an invalid length error. + let err = setsockopt(sockfd, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1u64).unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + // Check that it is the right kind of `InvalidInput`. + assert_eq!(err.raw_os_error(), Some(libc::EINVAL)); +} + +/// Tests binding an IPv4 socket with an IPv4 address but the addrlen argument +/// has the wrong size. +fn test_bind_ipv4_invalid_addr_len() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + let err = unsafe { + errno_result(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + // Add 1 to the address to make the size invalid. + (size_of::() + 1) as libc::socklen_t, + )) + .unwrap_err() + }; + assert_eq!(err.kind(), ErrorKind::InvalidInput); + // Check that it is the right kind of `InvalidInput`. + assert_eq!(err.raw_os_error(), Some(libc::EINVAL)); +} + +fn test_bind_ipv6() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET6, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv6_sock_addr(net::IPV6_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in6).cast::(), + size_of::() as libc::socklen_t, + )); + } +} + +fn test_listen() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(sockfd, 16)); + } +} + +/// Test accepting connections by running a server in a separate thread and connecting clients +/// from the main thread. +/// This function tests both +/// - Connecting when the server is already accepting +/// - Accepting when there is already an incoming connection +fn test_accept_connect() { + let server_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let client_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + server_sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(server_sockfd, 16)); + } + + // Retrieve actual listener address because we used a randomized port. + let (_, server_addr) = + sockname(|storage, len| unsafe { libc::getsockname(server_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V4(addr) = server_addr else { + // We bound an IPv4 address so we also expect + // an IPv4 address to be returned. + panic!() + }; + + // Spawn the server thread. + let server_thread = thread::spawn(move || { + let (_peerfd, _peer_addr) = + sockname(|storage, len| unsafe { libc::accept(server_sockfd, storage, len) }).unwrap(); + + // Yield back to the client thread to test whether calling `connect` first also + // works. + thread::sleep(Duration::from_millis(10)); + + let (_peerfd, _peer_addr) = + sockname(|storage, len| unsafe { libc::accept(server_sockfd, storage, len) }).unwrap(); + }); + + // Yield to server thread to ensure `accept` is called before we try + // to connect. + thread::sleep(Duration::from_millis(10)); + + // Test connecting to an already accepting server. + unsafe { + errno_check(libc::connect( + client_sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + // Server thread should now be in its `sleep`. + // Test connecting when there is no actively ongoing `accept`. + // We need a new client socket since we cannot connect a socket multiple times. + let client_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + + unsafe { + errno_check(libc::connect( + client_sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + server_thread.join().unwrap(); +} + +/// Test the `getsockname` syscall on an IPv4 socket which is bound. +/// The `getsockname` syscall should return the same address as to +/// which the socket was bound to. +fn test_getsockname_ipv4() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 6789); + unsafe { + errno_check(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(sockfd, 16)); + } + + let (_, sock_addr) = + sockname(|storage, len| unsafe { libc::getsockname(sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V4(sock_addr) = sock_addr else { + // We bound an IPv4 address so we also expect + // an IPv4 address to be returned. + panic!() + }; + + assert_eq!(addr.sin_family, sock_addr.sin_family); + assert_eq!(addr.sin_port, sock_addr.sin_port); + assert_eq!(addr.sin_addr.s_addr, sock_addr.sin_addr.s_addr); +} + +/// Test the `getsockname` syscall on an IPv4 socket which is bound +/// but the port was zero. +/// The `getsockname` syscall should return the same address as to +/// which the socket was bound to but the port should be non-zero. +fn test_getsockname_ipv4_random_port() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + // Use zero-port to let the OS choose a free port to bind to. + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(sockfd, 16)); + } + + let (_, sock_addr) = + sockname(|storage, len| unsafe { libc::getsockname(sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V4(sock_addr) = sock_addr else { + // We bound an IPv4 address so we also expect + // an IPv4 address to be returned. + panic!() + }; + assert_eq!(addr.sin_family, sock_addr.sin_family); + // The bound port must not be the zero port. + assert!(sock_addr.sin_port > 0); + assert_eq!(addr.sin_addr.s_addr, sock_addr.sin_addr.s_addr); +} + +/// Test the `getsockname` syscall on an IPv4 socket which is not bound. +/// The `getsockname` syscall should return 0.0.0.0:0 +fn test_getsockname_ipv4_unbound() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + + let (_, sock_addr) = + sockname(|storage, len| unsafe { libc::getsockname(sockfd, storage, len) }).unwrap(); + + // Libc representation of an unspecified IPv4 address with zero port. + let addr = net::ipv4_sock_addr([0, 0, 0, 0], 0); + let LibcSocketAddr::V4(sock_addr) = sock_addr else { + // We bound an IPv4 address so we also expect + // an IPv4 address to be returned. + panic!() + }; + + assert_eq!(addr.sin_family, sock_addr.sin_family); + assert_eq!(addr.sin_port, sock_addr.sin_port); + assert_eq!(addr.sin_addr.s_addr, sock_addr.sin_addr.s_addr); +} + +/// Test the `getsockname` syscall on an IPv6 socket which is bound. +/// The `getsockname` syscall should return the same address as to +/// which the socket was bound to. +fn test_getsockname_ipv6() { + let sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET6, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv6_sock_addr(net::IPV6_LOCALHOST, 1234); + unsafe { + errno_check(libc::bind( + sockfd, + (&addr as *const libc::sockaddr_in6).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(sockfd, 16)); + } + + let (_, sock_addr) = + sockname(|storage, len| unsafe { libc::getsockname(sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V6(sock_addr) = sock_addr else { + // We bound an IPv6 address so we also expect + // an IPv6 address to be returned. + panic!() + }; + + assert_eq!(addr.sin6_family, sock_addr.sin6_family); + assert_eq!(addr.sin6_port, sock_addr.sin6_port); + assert_eq!(addr.sin6_flowinfo, sock_addr.sin6_flowinfo); + assert_eq!(addr.sin6_scope_id, sock_addr.sin6_scope_id); + assert_eq!(addr.sin6_addr.s6_addr, sock_addr.sin6_addr.s6_addr); +} + +/// Test the `getpeername` syscall on an IPv4 socket. +/// For a connected socket, the `getpeername` syscall should +/// return the same address as the socket was connected to. +fn test_getpeername_ipv4() { + let server_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let client_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv4_sock_addr(net::IPV4_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + server_sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(server_sockfd, 16)); + } + + // Retrieve actual listener address because we used a randomized port. + let (_, server_addr) = + sockname(|storage, len| unsafe { libc::getsockname(server_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V4(addr) = server_addr else { + // We bound an IPv4 address so we also expect + // an IPv4 address to be returned. + panic!() + }; + + // Spawn the server thread. + let server_thread = thread::spawn(move || { + let (_peerfd, _peer_addr) = + sockname(|storage, len| unsafe { libc::accept(server_sockfd, storage, len) }).unwrap(); + }); + + // Test connecting to an already accepting server. + unsafe { + errno_check(libc::connect( + client_sockfd, + (&addr as *const libc::sockaddr_in).cast::(), + size_of::() as libc::socklen_t, + )); + } + + let (_, peer_addr) = + sockname(|storage, len| unsafe { libc::getpeername(client_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V4(peer_addr) = peer_addr else { + // We connected to an IPv4 address so we also expect + // an IPv4 address to be returned. + panic!() + }; + + assert_eq!(addr.sin_family, peer_addr.sin_family); + assert_eq!(addr.sin_port, peer_addr.sin_port); + assert_eq!(addr.sin_addr.s_addr, peer_addr.sin_addr.s_addr); + + server_thread.join().unwrap(); +} + +/// Test the `getpeername` syscall on an IPv6 socket. +/// For a connected socket, the `getpeername` syscall should +/// return the same address as the socket was connected to. +fn test_getpeername_ipv6() { + let server_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET6, libc::SOCK_STREAM, 0)).unwrap() }; + let client_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET6, libc::SOCK_STREAM, 0)).unwrap() }; + let addr = net::ipv6_sock_addr(net::IPV6_LOCALHOST, 0); + unsafe { + errno_check(libc::bind( + server_sockfd, + (&addr as *const libc::sockaddr_in6).cast::(), + size_of::() as libc::socklen_t, + )); + } + + unsafe { + errno_check(libc::listen(server_sockfd, 16)); + } + + // Retrieve actual listener address because we used a randomized port. + let (_, server_addr) = + sockname(|storage, len| unsafe { libc::getsockname(server_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V6(addr) = server_addr else { + // We bound an IPv6 address so we also expect + // an IPv6 address to be returned. + panic!() + }; + + // Spawn the server thread. + let server_thread = thread::spawn(move || { + let (_peerfd, _peer_addr) = + sockname(|storage, len| unsafe { libc::accept(server_sockfd, storage, len) }).unwrap(); + }); + + // Test connecting to an already accepting server. + unsafe { + errno_check(libc::connect( + client_sockfd, + (&addr as *const libc::sockaddr_in6).cast::(), + size_of::() as libc::socklen_t, + )); + } + + let (_, peer_addr) = + sockname(|storage, len| unsafe { libc::getpeername(client_sockfd, storage, len) }).unwrap(); + + let LibcSocketAddr::V6(peer_addr) = peer_addr else { + // We connected to an IPv6 address so we also expect + // an IPv6 address to be returned. + panic!() + }; + + assert_eq!(addr.sin6_family, peer_addr.sin6_family); + assert_eq!(addr.sin6_port, peer_addr.sin6_port); + assert_eq!(addr.sin6_flowinfo, peer_addr.sin6_flowinfo); + assert_eq!(addr.sin6_scope_id, peer_addr.sin6_scope_id); + assert_eq!(addr.sin6_addr.s6_addr, peer_addr.sin6_addr.s6_addr); + + server_thread.join().unwrap(); +} + +/// Set a socket option. It's the caller's responsibility to ensure that `T` is +/// associated with the given socket option. +/// +/// This function is directly copied from the standard library implementation +/// for sockets on UNIX targets. +fn setsockopt( + sockfd: i32, + level: libc::c_int, + option_name: libc::c_int, + option_value: T, +) -> io::Result<()> { + let option_len = size_of::() as libc::socklen_t; + + errno_result(unsafe { + libc::setsockopt( + sockfd, + level, + option_name, + (&raw const option_value) as *const _, + option_len, + ) + })?; + Ok(()) +} + +enum LibcSocketAddr { + V4(libc::sockaddr_in), + V6(libc::sockaddr_in6), +} + +/// Wraps a call to a platform function that returns a socket address. +/// This is very much the same as the function with the same name in the +/// standard library implementation. +/// Returns a tuple containing the actual return value of the performed +/// syscall and the written address of it. +fn sockname(f: F) -> io::Result<(libc::c_int, LibcSocketAddr)> +where + F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, +{ + let mut storage = MaybeUninit::::zeroed(); + let mut len = size_of::() as libc::socklen_t; + let value = errno_result(f(storage.as_mut_ptr().cast(), &mut len))?; + // SAFETY: + // The caller guarantees that the storage has been successfully initialized + // and its size written to `len` if `f` returns a success. + let address = unsafe { + match (*storage.as_ptr()).ss_family as libc::c_int { + libc::AF_INET => { + assert!(len as usize >= size_of::()); + LibcSocketAddr::V4(*(storage.as_ptr() as *const _ as *const libc::sockaddr_in)) + } + libc::AF_INET6 => { + assert!(len as usize >= size_of::()); + LibcSocketAddr::V6(*(storage.as_ptr() as *const _ as *const libc::sockaddr_in6)) + } + _ => return Err(io::Error::new(ErrorKind::InvalidInput, "invalid argument")), + } + }; + + Ok((value, address)) +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index b80fb0025530..141e0009101a 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -3,6 +3,7 @@ #[path = "../../utils/libc.rs"] mod libc_utils; + use std::time::{Duration, Instant}; use std::{env, mem, ptr}; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-uname.rs b/src/tools/miri/tests/pass-dep/libc/libc-uname.rs new file mode 100644 index 000000000000..b071e0522582 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-uname.rs @@ -0,0 +1,40 @@ +//@ignore-target: windows # No libc + +#[path = "../../utils/libc.rs"] +mod libc_utils; + +use std::ffi::CStr; +use std::{io, ptr}; + +use libc_utils::*; + +fn main() { + test_ok(); + test_null_ptr(); +} + +fn test_ok() { + // SAFETY: all zeros for `utsname` is valid. + let mut uname: libc::utsname = unsafe { std::mem::zeroed() }; + errno_check(unsafe { libc::uname(&mut uname) }); + + assert_eq!(unsafe { CStr::from_ptr(&uname.sysname as *const _) }, c"Miri"); + assert_eq!(unsafe { CStr::from_ptr(&uname.nodename as *const _) }, c"Miri"); + assert_eq!( + unsafe { CStr::from_ptr(&uname.release as *const _) }.to_str().unwrap(), + env!("CARGO_PKG_VERSION") + ); + assert_eq!(unsafe { CStr::from_ptr(&uname.version as *const _) }, c"Miri 0.1.0"); + assert_eq!( + unsafe { CStr::from_ptr(&uname.machine as *const _) }.to_str().unwrap(), + std::env::consts::ARCH + ); + #[cfg(any(target_os = "linux", target_os = "android"))] + assert_eq!(unsafe { CStr::from_ptr(&uname.domainname as *const _) }, c"(none)"); +} + +fn test_null_ptr() { + let err = errno_result(unsafe { libc::uname(ptr::null_mut()) }).unwrap_err(); + assert_eq!(err.raw_os_error(), Some(libc::EFAULT)); + assert_eq!(io::Error::last_os_error().raw_os_error(), Some(libc::EFAULT)); +} diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs index 91639c502325..79cb551386a1 100644 --- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs +++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs @@ -22,7 +22,7 @@ FILE_ALLOCATION_INFO, FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, FILE_CURRENT, FILE_END_OF_FILE_INFO, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, FileAllocationInfo, FileEndOfFileInfo, - FlushFileBuffers, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, + FlushFileBuffers, GetFileInformationByHandle, MoveFileExW, OPEN_ALWAYS, OPEN_EXISTING, SetFileInformationByHandle, SetFilePointerEx, }; use windows_sys::Win32::System::IO::IO_STATUS_BLOCK; @@ -42,6 +42,7 @@ fn main() { test_set_file_info(); test_dup_handle(); test_flush_buffers(); + test_move_file(); } } @@ -376,6 +377,23 @@ unsafe fn test_flush_buffers() { } } +unsafe fn test_move_file() { + let tmp_dir = utils::tmp(); + + let temp = tmp_dir.join("test_move_file.txt"); + let temp_new = tmp_dir.join("test_move_file_new.txt"); + let mut file = fs::File::options().create(true).write(true).open(&temp).unwrap(); + file.write_all(b"Hello, World!\n").unwrap(); + + let from = to_wide_cstr(&temp); + let to = to_wide_cstr(&temp_new); + if MoveFileExW(from.as_ptr(), to.as_ptr(), 1) == 0 { + panic!("Failed to rename file from {} to {}", temp.display(), temp_new.display()); + } + + assert_eq!(fs::read_to_string(temp_new).unwrap(), "Hello, World!\n"); +} + fn to_wide_cstr(path: &Path) -> Vec { let mut raw_path = path.as_os_str().encode_wide().collect::>(); raw_path.extend([0, 0]); diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.stderr b/src/tools/miri/tests/pass/alloc-access-tracking.stderr index f1c9241beded..6c780e78e91b 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.stderr +++ b/src/tools/miri/tests/pass/alloc-access-tracking.stderr @@ -4,13 +4,13 @@ note: now tracking allocation ALLOC of 123 bytes (alignment ALIGN bytes) LL | utils::miri_track_alloc(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here -note: write access at ALLOC[0..1] +note: write access at ALLOC[0x0..0x1] --> tests/pass/alloc-access-tracking.rs:LL:CC | LL | *ptr = 42; // Crucially, only a write is printed here, no read! | ^^^^^^^^^ tracking was triggered here -note: read access at ALLOC[0..1] +note: read access at ALLOC[0x0..0x1] --> tests/pass/alloc-access-tracking.rs:LL:CC | LL | assert_eq!(*ptr, 42); diff --git a/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs b/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs new file mode 100644 index 000000000000..fe2b526d94b1 --- /dev/null +++ b/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs @@ -0,0 +1,59 @@ +// Check that `MaybeDangling` actually prevents UB when it wraps dangling +// boxes and references +// +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows +#![feature(maybe_dangling)] + +use std::mem::{self, MaybeDangling}; +use std::ptr::drop_in_place; + +fn main() { + boxy(); + reference(); + write_through_shared_ref(); +} + +fn boxy() { + let mut x = MaybeDangling::new(Box::new(1)); + + // make the box dangle + unsafe { drop_in_place(x.as_mut()) }; + + // move the dangling box (without `MaybeDangling` this causes UB) + let x: MaybeDangling> = x; + + mem::forget(x); +} + +fn reference() { + let x = { + let local = 0; + + // erase the lifetime to make a dangling reference + unsafe { + mem::transmute::, MaybeDangling<&u32>>(MaybeDangling::new(&local)) + } + }; + + // move the dangling reference (without `MaybeDangling` this causes UB) + let _x: MaybeDangling<&u32> = x; +} + +fn write_through_shared_ref() { + // Under the current models, we do not forbid writing through + // `MaybeDangling<&i32>`. That's not yet finally decided, but meanwhile + // ensure we document this and notice when it changes. + + unsafe { + let mutref = &mut 0; + write_through_shr(mem::transmute(mutref)); + } + + fn write_through_shr(x: MaybeDangling<&i32>) { + unsafe { + let y: *mut i32 = mem::transmute(x); + y.write(1); + } + } +} diff --git a/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs b/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs new file mode 100644 index 000000000000..b41e1b0f076a --- /dev/null +++ b/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs @@ -0,0 +1,21 @@ +//@ ignore-target: windows # does not ignore ZST arguments +//@ ignore-target: powerpc # does not ignore ZST arguments +//@ ignore-target: s390x # does not ignore ZST arguments +//@ ignore-target: sparc # does not ignore ZST arguments +#![feature(c_variadic)] + +// Some platforms ignore ZSTs, meaning that the argument is not passed, even though it is part +// of the callee's ABI. Test that this doesn't trip any asserts. +// +// NOTE: this test only succeeds when the `()` argument uses `Passmode::Ignore`. For some targets, +// notably msvc, such arguments are not ignored, which would cause UB when attempting to read the +// second `i32` argument while the next item in the variable argument list is `()`. + +fn main() { + unsafe extern "C" fn variadic(mut ap: ...) { + ap.arg::(); + ap.arg::(); + } + + unsafe { variadic(0i32, (), 1i32) } +} diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 052c83d1aa31..e5454905bb52 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -7,21 +7,25 @@ #![allow(arithmetic_overflow)] #![allow(internal_features)] #![allow(unnecessary_transmutes)] +#![deny(deprecated_in_future)] + +use std::any::type_name; +use std::cmp::min; +use std::f16::consts as f16_consts; +use std::f32::consts as f32_consts; +use std::f64::consts as f64_consts; +use std::f128::consts as f128_consts; +use std::fmt::{Debug, Display, LowerHex}; +use std::hint::black_box; #[path = "../utils/mod.rs"] mod utils; -use std::any::type_name; -use std::cmp::min; -use std::fmt::{Debug, Display, LowerHex}; -use std::hint::black_box; -use std::{f32, f64}; - use utils::check_nondet; /// Compare the two floats, allowing for $ulp many ULPs of error. /// /// ULP means "Units in the Last Place" or "Units of Least Precision". -/// The ULP of a float `a`` is the smallest possible change at `a`, so the ULP difference represents how +/// The ULP of a float `a` is the smallest possible change at `a`, so the ULP difference represents how /// many discrete floating-point steps are needed to reach the actual value from the expected value. /// /// Essentially ULP can be seen as a distance metric of floating-point numbers, but with @@ -70,7 +74,6 @@ fn main() { test_fast(); test_algebraic(); test_fmuladd(); - test_min_max_nondet(); test_non_determinism(); } @@ -1014,14 +1017,20 @@ fn rounding() { } fn mul_add() { - // FIXME(f16_f128): add when supported - + assert_eq!(3.0f16.mul_add(2.0f16, 5.0f16), 11.0); assert_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0); - assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E); - assert_eq!(3.0f64.mul_add(2.0, 5.0), 11.0); - assert_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); + assert_eq!(3.0f64.mul_add(2.0f64, 5.0f64), 11.0); + assert_eq!(3.0f128.mul_add(2.0f128, 5.0f128), 11.0); + + assert_eq!(0.0f16.mul_add(-2.0f16, f16_consts::E), f16_consts::E); + assert_eq!(0.0f32.mul_add(-2.0f32, f32_consts::E), f32_consts::E); + assert_eq!(0.0f64.mul_add(-2.0f64, f64_consts::E), f64_consts::E); + assert_eq!(0.0f128.mul_add(-2.0f128, f128_consts::E), f128_consts::E); + + assert_eq!((-3.2f16).mul_add(2.4, f16::NEG_INFINITY), f16::NEG_INFINITY); assert_eq!((-3.2f32).mul_add(2.4, f32::NEG_INFINITY), f32::NEG_INFINITY); assert_eq!((-3.2f64).mul_add(2.4, f64::NEG_INFINITY), f64::NEG_INFINITY); + assert_eq!((-3.2f128).mul_add(2.4, f128::NEG_INFINITY), f128::NEG_INFINITY); let f = f32::mul_add( -0.000000000000000000000000000000000000014728589, @@ -1039,9 +1048,11 @@ fn ldexp(a: f64, b: i32) -> f64 { unsafe { ldexp(a, b) } } + assert_approx_eq!(25f16.powi(-2), 0.0016f16); assert_approx_eq!(25f32.powi(-2), 0.0016f32); assert_approx_eq!(23.2f64.powi(2), 538.24f64); + assert_approx_eq!(25f16.powf(-2f16), 0.0016f16); assert_approx_eq!(25f32.powf(-2f32), 0.0016f32); assert_approx_eq!(400f64.powf(0.5f64), 20f64); @@ -1049,83 +1060,113 @@ fn ldexp(a: f64, b: i32) -> f64 { // and thus must be exactly equal to that value. // C standard says: // 1^y = 1 for any y, even a NaN. + assert_eq!(1f16.powf(10.0), 1.0); assert_eq!(1f32.powf(10.0), 1.0); assert_eq!(1f64.powf(100.0), 1.0); + assert_eq!(1f16.powf(f16::INFINITY), 1.0); assert_eq!(1f32.powf(f32::INFINITY), 1.0); assert_eq!(1f64.powf(f64::INFINITY), 1.0); + assert_eq!(1f16.powf(f16::NAN), 1.0); assert_eq!(1f32.powf(f32::NAN), 1.0); assert_eq!(1f64.powf(f64::NAN), 1.0); // f*::NAN is a quiet NAN and should return 1 as well. + assert_eq!(f16::NAN.powf(0.0), 1.0); assert_eq!(f32::NAN.powf(0.0), 1.0); assert_eq!(f64::NAN.powf(0.0), 1.0); + assert_eq!(42f16.powf(0.0), 1.0); assert_eq!(42f32.powf(0.0), 1.0); assert_eq!(42f64.powf(0.0), 1.0); + assert_eq!(f16::INFINITY.powf(0.0), 1.0); assert_eq!(f32::INFINITY.powf(0.0), 1.0); assert_eq!(f64::INFINITY.powf(0.0), 1.0); + assert_eq!(f16::NEG_INFINITY.powi(3), f16::NEG_INFINITY); assert_eq!(f32::NEG_INFINITY.powi(3), f32::NEG_INFINITY); assert_eq!(f32::NEG_INFINITY.powi(2), f32::INFINITY); + assert_eq!(f16::INFINITY.powi(3), f16::INFINITY); assert_eq!(f64::INFINITY.powi(3), f64::INFINITY); assert_eq!(f64::INFINITY.powi(2), f64::INFINITY); // f*::NAN is a quiet NAN and should return 1 as well. + assert_eq!(f16::NAN.powi(0), 1.0); assert_eq!(f32::NAN.powi(0), 1.0); assert_eq!(f64::NAN.powi(0), 1.0); + assert_eq!(10.0f16.powi(0), 1.0); assert_eq!(10.0f32.powi(0), 1.0); assert_eq!(10.0f64.powi(0), 1.0); + assert_eq!(f16::INFINITY.powi(0), 1.0); assert_eq!(f32::INFINITY.powi(0), 1.0); assert_eq!(f64::INFINITY.powi(0), 1.0); + assert_eq!((-1f16).powf(f16::INFINITY), 1.0); assert_eq!((-1f32).powf(f32::INFINITY), 1.0); assert_eq!((-1f64).powf(f64::INFINITY), 1.0); + assert_eq!((-1f16).powf(f16::NEG_INFINITY), 1.0); assert_eq!((-1f32).powf(f32::NEG_INFINITY), 1.0); assert_eq!((-1f64).powf(f64::NEG_INFINITY), 1.0); + assert_eq!(0f16.powi(10), 0.0); assert_eq!(0f32.powi(10), 0.0); assert_eq!(0f64.powi(100), 0.0); + assert_eq!(0f16.powi(9), 0.0); assert_eq!(0f32.powi(9), 0.0); assert_eq!(0f64.powi(99), 0.0); + assert_biteq((-0f16).powf(10.0), 0.0, "-0^x = +0 where x is positive"); assert_biteq((-0f32).powf(10.0), 0.0, "-0^x = +0 where x is positive"); assert_biteq((-0f64).powf(100.0), 0.0, "-0^x = +0 where x is positive"); + assert_biteq((-0f16).powf(9.0), -0.0, "-0^x = -0 where x is negative"); assert_biteq((-0f32).powf(9.0), -0.0, "-0^x = -0 where x is negative"); assert_biteq((-0f64).powf(99.0), -0.0, "-0^x = -0 where x is negative"); + assert_biteq((-0f16).powi(10), 0.0, "-0^x = +0 where x is positive"); assert_biteq((-0f32).powi(10), 0.0, "-0^x = +0 where x is positive"); assert_biteq((-0f64).powi(100), 0.0, "-0^x = +0 where x is positive"); + assert_biteq((-0f16).powi(9), -0.0, "-0^x = -0 where x is negative"); assert_biteq((-0f32).powi(9), -0.0, "-0^x = -0 where x is negative"); assert_biteq((-0f64).powi(99), -0.0, "-0^x = -0 where x is negative"); - assert_approx_eq!(1f32.exp(), f32::consts::E); - assert_approx_eq!(1f64.exp(), f64::consts::E); + assert_approx_eq!(1f16.exp(), f16_consts::E); + assert_approx_eq!(1f32.exp(), f32_consts::E); + assert_approx_eq!(1f64.exp(), f64_consts::E); + assert_eq!(0f16.exp(), 1.0); assert_eq!(0f32.exp(), 1.0); assert_eq!(0f64.exp(), 1.0); - assert_approx_eq!(1f32.exp_m1(), f32::consts::E - 1.0); - assert_approx_eq!(1f64.exp_m1(), f64::consts::E - 1.0); + assert_approx_eq!(1f16.exp_m1(), f16_consts::E - 1.0); + assert_approx_eq!(1f32.exp_m1(), f32_consts::E - 1.0); + assert_approx_eq!(1f64.exp_m1(), f64_consts::E - 1.0); + assert_approx_eq!(f16::NEG_INFINITY.exp_m1(), -1.0); assert_approx_eq!(f32::NEG_INFINITY.exp_m1(), -1.0); assert_approx_eq!(f64::NEG_INFINITY.exp_m1(), -1.0); + assert_approx_eq!(10f16.exp2(), 1024f16); assert_approx_eq!(10f32.exp2(), 1024f32); assert_approx_eq!(50f64.exp2(), 1125899906842624f64); + assert_eq!(0f16.exp2(), 1.0); assert_eq!(0f32.exp2(), 1.0); assert_eq!(0f64.exp2(), 1.0); - assert_approx_eq!(f32::consts::E.ln(), 1f32); - assert_approx_eq!(f64::consts::E.ln(), 1f64); + assert_approx_eq!(f16_consts::E.ln(), 1f16); + assert_approx_eq!(f32_consts::E.ln(), 1f32); + assert_approx_eq!(f64_consts::E.ln(), 1f64); + assert_eq!(1f16.ln(), 0.0); assert_eq!(1f32.ln(), 0.0); assert_eq!(1f64.ln(), 0.0); + assert_approx_eq!(0f16.ln_1p(), 0f16); assert_approx_eq!(0f32.ln_1p(), 0f32); assert_approx_eq!(0f64.ln_1p(), 0f64); + assert_approx_eq!(10f16.log10(), 1f16); assert_approx_eq!(10f32.log10(), 1f32); - assert_approx_eq!(f64::consts::E.log10(), f64::consts::LOG10_E); + assert_approx_eq!(f64_consts::E.log10(), f64_consts::LOG10_E); + assert_approx_eq!(8f16.log2(), 3f16); assert_approx_eq!(8f32.log2(), 3f32); - assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E); + assert_approx_eq!(f64_consts::E.log2(), f64_consts::LOG2_E); #[allow(deprecated)] { @@ -1133,9 +1174,11 @@ fn ldexp(a: f64, b: i32) -> f64 { assert_approx_eq!(3.0f64.abs_sub(5.0), 0.0); } + assert_approx_eq!(27.0f16.cbrt(), 3.0f16); assert_approx_eq!(27.0f32.cbrt(), 3.0f32); assert_approx_eq!(27.0f64.cbrt(), 3.0f64); + assert_approx_eq!(3.0f16.hypot(4.0f16), 5.0f16); assert_approx_eq!(3.0f32.hypot(4.0f32), 5.0f32); assert_approx_eq!(3.0f64.hypot(4.0f64), 5.0f64); @@ -1146,70 +1189,94 @@ fn ldexp(a: f64, b: i32) -> f64 { // Trigonometric functions. + assert_eq!(0f16.sin(), 0f16); assert_eq!(0f32.sin(), 0f32); assert_eq!(0f64.sin(), 0f64); - assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); - assert_approx_eq!(f32::consts::FRAC_PI_6.sin(), 0.5); - assert_approx_eq!(f64::consts::FRAC_PI_6.sin(), 0.5); + assert_approx_eq!(f16_consts::FRAC_PI_6.sin(), 0.5); + assert_approx_eq!(f32_consts::FRAC_PI_6.sin(), 0.5); + assert_approx_eq!(f64_consts::FRAC_PI_6.sin(), 0.5); // Increase error tolerance to 16ULP because of the extra operation. - assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4, 16); - assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4, 16); + assert_approx_eq!(f16_consts::FRAC_PI_4.sin().asin(), f16_consts::FRAC_PI_4, 16); + assert_approx_eq!(f32_consts::FRAC_PI_4.sin().asin(), f32_consts::FRAC_PI_4, 16); + assert_approx_eq!(f64_consts::FRAC_PI_4.sin().asin(), f64_consts::FRAC_PI_4, 16); + assert_biteq(0.0f16.asin(), 0.0f16, "asin(+0) = +0"); + assert_biteq((-0.0f16).asin(), -0.0, "asin(-0) = -0"); assert_biteq(0.0f32.asin(), 0.0f32, "asin(+0) = +0"); assert_biteq((-0.0f32).asin(), -0.0, "asin(-0) = -0"); assert_biteq(0.0f64.asin(), 0.0, "asin(+0) = +0"); assert_biteq((-0.0f64).asin(), -0.0, "asin(-0) = -0"); + assert_approx_eq!(1.0f16.sinh(), 1.1752012f16); assert_approx_eq!(1.0f32.sinh(), 1.1752012f32); assert_approx_eq!(1.0f64.sinh(), 1.1752011936438014f64); + assert_approx_eq!(2.0f16.asinh(), 1.443635475178810342493276740273105f16); assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); // Ensure `sin` always returns something that is a valid input for `asin`, and same for // `cos` and `acos`. - let halve_pi_f32 = std::f32::consts::FRAC_PI_2; - let halve_pi_f64 = std::f64::consts::FRAC_PI_2; - let pi_f32 = std::f32::consts::PI; - let pi_f64 = std::f64::consts::PI; + let halve_pi_f16 = f16_consts::FRAC_PI_2; + let halve_pi_f32 = f32_consts::FRAC_PI_2; + let halve_pi_f64 = f64_consts::FRAC_PI_2; + let pi_f16 = f16_consts::PI; + let pi_f32 = f32_consts::PI; + let pi_f64 = f64_consts::PI; for _ in 0..64 { // sin() should be clamped to [-1, 1] so asin() can never return NaN + assert!(!halve_pi_f16.sin().asin().is_nan()); assert!(!halve_pi_f32.sin().asin().is_nan()); assert!(!halve_pi_f64.sin().asin().is_nan()); // cos() should be clamped to [-1, 1] so acos() can never return NaN + assert!(!pi_f16.cos().acos().is_nan()); assert!(!pi_f32.cos().acos().is_nan()); assert!(!pi_f64.cos().acos().is_nan()); } + assert_eq!(0f16.cos(), 1f16); assert_eq!(0f32.cos(), 1f32); assert_eq!(0f64.cos(), 1f64); - assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); - assert_approx_eq!(f32::consts::FRAC_PI_3.cos(), 0.5); - assert_approx_eq!(f64::consts::FRAC_PI_3.cos(), 0.5); + assert_approx_eq!(f16_consts::FRAC_PI_3.cos(), 0.5); + assert_approx_eq!(f32_consts::FRAC_PI_3.cos(), 0.5); + assert_approx_eq!(f64_consts::FRAC_PI_3.cos(), 0.5); // Increase error tolerance to 16ULP because of the extra operation. - assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4, 16); - assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4, 16); + assert_approx_eq!(f16_consts::FRAC_PI_4.cos().acos(), f16_consts::FRAC_PI_4, 16); + assert_approx_eq!(f32_consts::FRAC_PI_4.cos().acos(), f32_consts::FRAC_PI_4, 16); + assert_approx_eq!(f64_consts::FRAC_PI_4.cos().acos(), f64_consts::FRAC_PI_4, 16); + assert_biteq(1.0f16.acos(), 0.0, "acos(1) = 0"); assert_biteq(1.0f32.acos(), 0.0, "acos(1) = 0"); assert_biteq(1.0f64.acos(), 0.0, "acos(1) = 0"); + assert_approx_eq!(1.0f16.cosh(), 1.5430806f16); assert_approx_eq!(1.0f32.cosh(), 1.5430806f32); assert_approx_eq!(1.0f64.cosh(), 1.5430806348152437f64); + assert_eq!(0.0f16.cosh(), 1.0); assert_eq!(0.0f32.cosh(), 1.0); assert_eq!(0.0f64.cosh(), 1.0); + assert_eq!((-0.0f16).cosh(), 1.0); assert_eq!((-0.0f32).cosh(), 1.0); assert_eq!((-0.0f64).cosh(), 1.0); + assert_approx_eq!(2.0f16.acosh(), 1.31695789692481670862504634730796844f16); assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); + assert_approx_eq!(1.0f16.tan(), 1.557408f16); assert_approx_eq!(1.0f32.tan(), 1.557408f32); assert_approx_eq!(1.0f64.tan(), 1.5574077246549023f64); + assert_approx_eq!(1.0_f16, 1.0_f16.tan().atan()); assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan()); assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan()); + assert_approx_eq!(1.0f16.atan2(2.0f16), 0.46364761f16); assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); // C standard defines a bunch of fixed outputs for atan2 macro_rules! fixed_atan2_cases{ ($float_type:ident) => {{ use std::$float_type::consts::{PI, FRAC_PI_2, FRAC_PI_4}; - use $float_type::{INFINITY, NEG_INFINITY}; + + // The core::$float_type::INFINITY constant is deprecated, and not available for f16. + // Associated items cannot be brought into scope with a `use`, hence the `const`s. + const INFINITY: $float_type = <$float_type>::INFINITY; + const NEG_INFINITY: $float_type = <$float_type>::NEG_INFINITY; // atan2(±0,−0) = ±π. assert_eq!($float_type::atan2(0.0, -0.0), PI, "atan2(0,−0) = π"); @@ -1244,48 +1311,67 @@ macro_rules! fixed_atan2_cases{ assert_eq!($float_type::atan2(NEG_INFINITY, INFINITY), -FRAC_PI_4, "atan2(-∞, +∞) = -π/4"); }} } + fixed_atan2_cases!(f16); fixed_atan2_cases!(f32); fixed_atan2_cases!(f64); + assert_approx_eq!( + 1.0f16.tanh(), + (1.0 - f16_consts::E.powi(-2)) / (1.0 + f16_consts::E.powi(-2)) + ); assert_approx_eq!( 1.0f32.tanh(), - (1.0 - f32::consts::E.powi(-2)) / (1.0 + f32::consts::E.powi(-2)) + (1.0 - f32_consts::E.powi(-2)) / (1.0 + f32_consts::E.powi(-2)) ); assert_approx_eq!( 1.0f64.tanh(), - (1.0 - f64::consts::E.powi(-2)) / (1.0 + f64::consts::E.powi(-2)) + (1.0 - f64_consts::E.powi(-2)) / (1.0 + f64_consts::E.powi(-2)) ); + assert_eq!(f16::INFINITY.tanh(), 1.0); + assert_eq!(f16::NEG_INFINITY.tanh(), -1.0); assert_eq!(f32::INFINITY.tanh(), 1.0); assert_eq!(f32::NEG_INFINITY.tanh(), -1.0); assert_eq!(f64::INFINITY.tanh(), 1.0); assert_eq!(f64::NEG_INFINITY.tanh(), -1.0); + assert_approx_eq!(0.5f16.atanh(), 0.54930614433405484569762261846126285f16); assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); + assert_approx_eq!(5.0f16.gamma(), 24.0); assert_approx_eq!(5.0f32.gamma(), 24.0); assert_approx_eq!(5.0f64.gamma(), 24.0); - assert_approx_eq!((-0.5f32).gamma(), (-2.0) * f32::consts::PI.sqrt()); - assert_approx_eq!((-0.5f64).gamma(), (-2.0) * f64::consts::PI.sqrt()); + assert_approx_eq!((-0.5f16).gamma(), (-2.0) * f16_consts::PI.sqrt()); + assert_approx_eq!((-0.5f32).gamma(), (-2.0) * f32_consts::PI.sqrt()); + assert_approx_eq!((-0.5f64).gamma(), (-2.0) * f64_consts::PI.sqrt()); + assert_eq!(2.0f16.ln_gamma(), (0.0, 1)); assert_eq!(2.0f32.ln_gamma(), (0.0, 1)); assert_eq!(2.0f64.ln_gamma(), (0.0, 1)); // Gamma(-0.5) = -2*sqrt(π) + let (val, sign) = (-0.5f16).ln_gamma(); + assert_approx_eq!(val, (2.0 * f16_consts::PI.sqrt()).ln()); + assert_eq!(sign, -1); let (val, sign) = (-0.5f32).ln_gamma(); - assert_approx_eq!(val, (2.0 * f32::consts::PI.sqrt()).ln()); + assert_approx_eq!(val, (2.0 * f32_consts::PI.sqrt()).ln()); assert_eq!(sign, -1); let (val, sign) = (-0.5f64).ln_gamma(); - assert_approx_eq!(val, (2.0 * f64::consts::PI.sqrt()).ln()); + assert_approx_eq!(val, (2.0 * f64_consts::PI.sqrt()).ln()); assert_eq!(sign, -1); + assert_approx_eq!(1.0f16.erf(), 0.84270079294971486934122063508260926f16); assert_approx_eq!(1.0f32.erf(), 0.84270079294971486934122063508260926f32); assert_approx_eq!(1.0f64.erf(), 0.84270079294971486934122063508260926f64); + assert_eq!(f16::INFINITY.erf(), 1.0); assert_eq!(f32::INFINITY.erf(), 1.0); assert_eq!(f64::INFINITY.erf(), 1.0); + assert_approx_eq!(1.0f16.erfc(), 0.15729920705028513065877936491739074f16); assert_approx_eq!(1.0f32.erfc(), 0.15729920705028513065877936491739074f32); assert_approx_eq!(1.0f64.erfc(), 0.15729920705028513065877936491739074f64); + assert_eq!(f16::NEG_INFINITY.erfc(), 2.0); assert_eq!(f32::NEG_INFINITY.erfc(), 2.0); assert_eq!(f64::NEG_INFINITY.erfc(), 2.0); + assert_eq!(f16::INFINITY.erfc(), 0.0); assert_eq!(f32::INFINITY.erfc(), 0.0); assert_eq!(f64::INFINITY.erfc(), 0.0); } @@ -1407,9 +1493,14 @@ fn test_operations_f128(a: f128, b: f128) { } fn test_fmuladd() { - use std::intrinsics::{fmuladdf32, fmuladdf64}; + use std::intrinsics::{fmuladdf16, fmuladdf32, fmuladdf64}; - // FIXME(f16_f128): add when supported + // FIXME(f128): add when supported + + #[inline(never)] + fn test_operations_f16(a: f16, b: f16, c: f16) { + assert_approx_eq!(fmuladdf16(a, b, c), a * b + c); + } #[inline(never)] fn test_operations_f32(a: f32, b: f32, c: f32) { @@ -1421,23 +1512,18 @@ fn test_operations_f64(a: f64, b: f64, c: f64) { assert_approx_eq!(fmuladdf64(a, b, c), a * b + c); } + test_operations_f16(0.1, 0.2, 0.3); test_operations_f32(0.1, 0.2, 0.3); test_operations_f64(1.1, 1.2, 1.3); } -/// `min` and `max` on equal arguments are non-deterministic. -fn test_min_max_nondet() { - check_nondet(|| f16::min(0.0, -0.0).is_sign_positive()); - check_nondet(|| f16::max(0.0, -0.0).is_sign_positive()); - check_nondet(|| f32::min(0.0, -0.0).is_sign_positive()); - check_nondet(|| f32::max(0.0, -0.0).is_sign_positive()); - check_nondet(|| f64::min(0.0, -0.0).is_sign_positive()); - check_nondet(|| f64::max(0.0, -0.0).is_sign_positive()); - check_nondet(|| f128::min(0.0, -0.0).is_sign_positive()); - check_nondet(|| f128::max(0.0, -0.0).is_sign_positive()); -} - fn test_non_determinism() { + if cfg!(force_intrinsic_fallback) { + // Skip this test when we use the fallback bodies, as that one is deterministic. + // (CI sets `--cfg force_intrinsic_fallback` together with `-Zmiri-force-intrinsic-fallback`.) + return; + } + use std::intrinsics::{ fadd_algebraic, fadd_fast, fdiv_algebraic, fdiv_fast, fmul_algebraic, fmul_fast, frem_algebraic, frem_fast, fsub_algebraic, fsub_fast, @@ -1464,6 +1550,39 @@ macro_rules! test_operations_f { fn test_operations_f16(a: f16, b: f16) { test_operations_f!(a, b); + check_nondet(|| a.powf(b)); + check_nondet(|| a.powi(2)); + check_nondet(|| a.log(b)); + check_nondet(|| a.exp()); + check_nondet(|| 10f16.exp2()); + check_nondet(|| f16_consts::E.ln()); + check_nondet(|| 10f16.log10()); + check_nondet(|| 8f16.log2()); + check_nondet(|| 1f16.sin()); + check_nondet(|| 1f16.cos()); + + // these functions are implemented by calling the `f32` version, which means the little + // rounding errors Miri introduces are discarded by the cast down to `f16`. + // Just skip the test for them. + // + // check_nondet(|| 1f16.ln_1p()); + // check_nondet(|| 27.0f16.cbrt()); + // check_nondet(|| 3.0f16.hypot(4.0f16)); + // check_nondet(|| 1.0f16.tan()); + // check_nondet(|| 1.0f16.asin()); + // check_nondet(|| 5.0f16.acos()); + // check_nondet(|| 1.0f16.atan()); + // check_nondet(|| 1.0f16.atan2(2.0f16)); + // check_nondet(|| 1.0f16.sinh()); + // check_nondet(|| 1.0f16.cosh()); + // check_nondet(|| 1.0f16.tanh()); + // check_nondet(|| 1.0f16.asinh()); + // check_nondet(|| 2.0f16.acosh()); + // check_nondet(|| 0.5f16.atanh()); + // check_nondet(|| 5.0f16.gamma()); + // check_nondet(|| 5.0f16.ln_gamma()); + // check_nondet(|| 5.0f16.erf()); + // check_nondet(|| 5.0f16.erfc()); } fn test_operations_f32(a: f32, b: f32) { test_operations_f!(a, b); @@ -1472,7 +1591,7 @@ fn test_operations_f32(a: f32, b: f32) { check_nondet(|| a.log(b)); check_nondet(|| a.exp()); check_nondet(|| 10f32.exp2()); - check_nondet(|| f32::consts::E.ln()); + check_nondet(|| f32_consts::E.ln()); check_nondet(|| 10f32.log10()); check_nondet(|| 8f32.log2()); check_nondet(|| 1f32.ln_1p()); @@ -1509,8 +1628,8 @@ fn test_operations_f64(a: f64, b: f64) { check_nondet(|| a.exp()); check_nondet(|| 50f64.exp2()); check_nondet(|| 3f64.ln()); - check_nondet(|| f64::consts::E.log10()); - check_nondet(|| f64::consts::E.log2()); + check_nondet(|| f64_consts::E.log10()); + check_nondet(|| f64_consts::E.log2()); check_nondet(|| 1f64.ln_1p()); check_nondet(|| 27.0f64.cbrt()); check_nondet(|| 3.0f64.hypot(4.0f64)); @@ -1536,11 +1655,21 @@ fn test_operations_f128(a: f128, b: f128) { test_operations_f!(a, b); } - test_operations_f16(5., 7.); + test_operations_f16(3., 5.); test_operations_f32(12., 5.); test_operations_f64(19., 11.); test_operations_f128(25., 18.); + // min/max signed zero nondet + check_nondet(|| f16::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f16::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f32::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f32::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f64::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f64::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f128::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f128::max(0.0, -0.0).is_sign_positive()); + // SNaN^0 = (1 | NaN) check_nondet(|| f32::powf(F32_SNAN, 0.0).is_nan()); check_nondet(|| f64::powf(F64_SNAN, 0.0).is_nan()); diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index c07ffdf9740c..4ec5a7e9c209 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -513,10 +513,10 @@ fn test_simd() { F32::from(unsafe { simd_div(f32x4::splat(0.0), f32x4::splat(0.0)) }[0]) }); check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { - F32::from(unsafe { simd_fmin(f32x4::splat(nan), f32x4::splat(nan)) }[0]) + F32::from(unsafe { simd_minimum_number_nsz(f32x4::splat(nan), f32x4::splat(nan)) }[0]) }); check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { - F32::from(unsafe { simd_fmax(f32x4::splat(nan), f32x4::splat(nan)) }[0]) + F32::from(unsafe { simd_maximum_number_nsz(f32x4::splat(nan), f32x4::splat(nan)) }[0]) }); check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { F32::from(unsafe { simd_fma(f32x4::splat(nan), f32x4::splat(nan), f32x4::splat(nan)) }[0]) @@ -541,6 +541,12 @@ fn test_simd() { } fn main() { + if cfg!(force_intrinsic_fallback) { + // Skip this test when we use the fallback bodies, as that one is deterministic. + // (CI sets `--cfg force_intrinsic_fallback` together with `-Zmiri-force-intrinsic-fallback`.) + return; + } + // Check our constants against std, just to be sure. // We add 1 since our numbers are the number of bits stored // to represent the value, and std has the precision of the value, diff --git a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs index 913c3cde272d..c6ccadf03188 100644 --- a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs +++ b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs @@ -5,6 +5,10 @@ use std::intrinsics; use std::mem::{discriminant, size_of, size_of_val, size_of_val_raw}; +#[path = "../../utils/mod.rs"] +mod utils; +use utils::check_nondet; + struct Bomb; impl Drop for Bomb { @@ -36,20 +40,7 @@ fn main() { // Skip this test when we use the fallback bodies, as that one is deterministic. // (CI sets `--cfg force_intrinsic_fallback` together with `-Zmiri-force-intrinsic-fallback`.) if !cfg!(force_intrinsic_fallback) { - let mut saw_true = false; - let mut saw_false = false; - - for _ in 0..50 { - if intrinsics::is_val_statically_known(0) { - saw_true = true; - } else { - saw_false = true; - } - } - assert!( - saw_true && saw_false, - "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!" - ); + check_nondet(|| intrinsics::is_val_statically_known(0)); } intrinsics::forget(Bomb); diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index 6c5e06518f56..f81f62e17602 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -17,6 +17,7 @@ use std::simd::StdFloat; use std::simd::prelude::*; +// The `portable_simd` crate currently does not support f16 or f128 vectors, so we define our own. #[repr(simd, packed)] #[derive(Copy)] struct PackedSimd([T; N]); @@ -41,6 +42,7 @@ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { type f16x2 = PackedSimd; type f16x4 = PackedSimd; +type f16x8 = PackedSimd; type f128x2 = PackedSimd; type f128x4 = PackedSimd; @@ -88,11 +90,11 @@ macro_rules! assert_eq { assert_eq!(simd_rem(a, b), f16x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(simd_fabs(b), f16x4::from_array([1.0, 2.0, 3.0, 4.0])); assert_eq!( - simd_fmax(a, simd_mul(b, f16x4::splat(4.0))), + simd_maximum_number_nsz(a, simd_mul(b, f16x4::splat(4.0))), f16x4::from_array([10.0, 10.0, 12.0, 10.0]) ); assert_eq!( - simd_fmin(a, simd_mul(b, f16x4::splat(4.0))), + simd_minimum_number_nsz(a, simd_mul(b, f16x4::splat(4.0))), f16x4::from_array([4.0, 8.0, 10.0, -16.0]) ); @@ -112,6 +114,9 @@ macro_rules! assert_eq { f16x4::splat(f16::NEG_INFINITY) ); + assert_eq!(simd_fsqrt(simd_mul(a, a)), a); + assert_eq!(simd_fsqrt(simd_mul(b, b)), simd_fabs(b)); + assert_eq!(simd_eq(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([0, !0, 0, 0])); assert_eq!(simd_ne(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([!0, 0, !0, !0])); assert_eq!(simd_le(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([0, !0, !0, 0])); @@ -129,13 +134,19 @@ macro_rules! assert_eq { assert_eq!(simd_reduce_min(b), -4.0f16); assert_eq!( - simd_fmax(f16x2::from_array([0.0, f16::NAN]), f16x2::from_array([f16::NAN, 0.0])), + simd_maximum_number_nsz( + f16x2::from_array([0.0, f16::NAN]), + f16x2::from_array([f16::NAN, 0.0]) + ), f16x2::from_array([0.0, 0.0]) ); assert_eq!(simd_reduce_max(f16x2::from_array([0.0, f16::NAN])), 0.0f16); assert_eq!(simd_reduce_max(f16x2::from_array([f16::NAN, 0.0])), 0.0f16); assert_eq!( - simd_fmin(f16x2::from_array([0.0, f16::NAN]), f16x2::from_array([f16::NAN, 0.0])), + simd_minimum_number_nsz( + f16x2::from_array([0.0, f16::NAN]), + f16x2::from_array([f16::NAN, 0.0]) + ), f16x2::from_array([0.0, 0.0]) ); assert_eq!(simd_reduce_min(f16x2::from_array([0.0, f16::NAN])), 0.0f16); @@ -299,11 +310,11 @@ macro_rules! assert_eq { assert_eq!(simd_rem(a, b), f128x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(simd_fabs(b), f128x4::from_array([1.0, 2.0, 3.0, 4.0])); assert_eq!( - simd_fmax(a, simd_mul(b, f128x4::splat(4.0))), + simd_maximum_number_nsz(a, simd_mul(b, f128x4::splat(4.0))), f128x4::from_array([10.0, 10.0, 12.0, 10.0]) ); assert_eq!( - simd_fmin(a, simd_mul(b, f128x4::splat(4.0))), + simd_minimum_number_nsz(a, simd_mul(b, f128x4::splat(4.0))), f128x4::from_array([4.0, 8.0, 10.0, -16.0]) ); @@ -323,6 +334,9 @@ macro_rules! assert_eq { f128x4::splat(f128::NEG_INFINITY) ); + assert_eq!(simd_fsqrt(simd_mul(a, a)), a); + assert_eq!(simd_fsqrt(simd_mul(b, b)), simd_fabs(b)); + assert_eq!(simd_eq(a, simd_mul(f128x4::splat(5.0), b)), i32x4::from_array([0, !0, 0, 0])); assert_eq!(simd_ne(a, simd_mul(f128x4::splat(5.0), b)), i32x4::from_array([!0, 0, !0, !0])); assert_eq!(simd_le(a, simd_mul(f128x4::splat(5.0), b)), i32x4::from_array([0, !0, !0, 0])); @@ -340,13 +354,19 @@ macro_rules! assert_eq { assert_eq!(simd_reduce_min(b), -4.0f128); assert_eq!( - simd_fmax(f128x2::from_array([0.0, f128::NAN]), f128x2::from_array([f128::NAN, 0.0])), + simd_maximum_number_nsz( + f128x2::from_array([0.0, f128::NAN]), + f128x2::from_array([f128::NAN, 0.0]) + ), f128x2::from_array([0.0, 0.0]) ); assert_eq!(simd_reduce_max(f128x2::from_array([0.0, f128::NAN])), 0.0f128); assert_eq!(simd_reduce_max(f128x2::from_array([f128::NAN, 0.0])), 0.0f128); assert_eq!( - simd_fmin(f128x2::from_array([0.0, f128::NAN]), f128x2::from_array([f128::NAN, 0.0])), + simd_minimum_number_nsz( + f128x2::from_array([0.0, f128::NAN]), + f128x2::from_array([f128::NAN, 0.0]) + ), f128x2::from_array([0.0, 0.0]) ); assert_eq!(simd_reduce_min(f128x2::from_array([0.0, f128::NAN])), 0.0f128); @@ -934,6 +954,18 @@ fn simd_float_intrinsics() { use intrinsics::*; // These are just smoke tests to ensure the intrinsics can be called. + unsafe { + let a = f16x8::splat(10.0); + simd_fsqrt(a); + simd_fsin(a); + simd_fcos(a); + simd_fexp(a); + simd_fexp2(a); + simd_flog(a); + simd_flog2(a); + simd_flog10(a); + } + unsafe { let a = f32x4::splat(10.0); simd_fsqrt(a); @@ -945,6 +977,23 @@ fn simd_float_intrinsics() { simd_flog2(a); simd_flog10(a); } + + unsafe { + let a = f64x2::splat(10.0); + simd_fsqrt(a); + simd_fsin(a); + simd_fcos(a); + simd_fexp(a); + simd_fexp2(a); + simd_flog(a); + simd_flog2(a); + simd_flog10(a); + } + + unsafe { + let a = f128x2::splat(10.0); + simd_fsqrt(a); + } } fn simd_masked_loadstore() { diff --git a/src/tools/miri/tests/pass/no_std_miri_start.rs b/src/tools/miri/tests/pass/miri_start_no_std.rs similarity index 100% rename from src/tools/miri/tests/pass/no_std_miri_start.rs rename to src/tools/miri/tests/pass/miri_start_no_std.rs diff --git a/src/tools/miri/tests/pass/no_std_miri_start.stdout b/src/tools/miri/tests/pass/miri_start_no_std.stdout similarity index 100% rename from src/tools/miri/tests/pass/no_std_miri_start.stdout rename to src/tools/miri/tests/pass/miri_start_no_std.stdout diff --git a/src/tools/miri/tests/pass/miri_start_with_std.rs b/src/tools/miri/tests/pass/miri_start_with_std.rs new file mode 100644 index 000000000000..510b9d419622 --- /dev/null +++ b/src/tools/miri/tests/pass/miri_start_with_std.rs @@ -0,0 +1,8 @@ +#![no_main] + +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _b = Box::new(0); + println!("hello, world!"); + 0 +} diff --git a/src/tools/miri/tests/pass/miri_start_with_std.stdout b/src/tools/miri/tests/pass/miri_start_with_std.stdout new file mode 100644 index 000000000000..270c611ee72c --- /dev/null +++ b/src/tools/miri/tests/pass/miri_start_with_std.stdout @@ -0,0 +1 @@ +hello, world! diff --git a/src/tools/miri/tests/pass/packed-struct-dyn-trait.rs b/src/tools/miri/tests/pass/packed-struct-dyn-trait.rs index bb73c26c18a0..2e61e77a221e 100644 --- a/src/tools/miri/tests/pass/packed-struct-dyn-trait.rs +++ b/src/tools/miri/tests/pass/packed-struct-dyn-trait.rs @@ -1,4 +1,3 @@ -// run-pass use std::ptr::addr_of; // When the unsized tail is a `dyn Trait`, its alignments is only dynamically known. This means the diff --git a/src/tools/miri/tests/pass/pointers.rs b/src/tools/miri/tests/pass/pointers.rs index 280a815abc43..388b3e99b726 100644 --- a/src/tools/miri/tests/pass/pointers.rs +++ b/src/tools/miri/tests/pass/pointers.rs @@ -137,6 +137,8 @@ fn main() { let addr = &13 as *const i32; let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); assert_eq!(addr.guaranteed_eq(addr2 as *const _), Some(true)); + // Technically, this assertion could fail as the promoted may truly end up at address 0x100; + // here we rely on knowing how Miri assigns memory addresses. assert_eq!(addr.guaranteed_ne(0x100 as *const _), Some(true)); wide_ptr_ops(); diff --git a/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-crc32.rs b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-crc32.rs new file mode 100644 index 000000000000..849f99ee36cc --- /dev/null +++ b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-crc32.rs @@ -0,0 +1,61 @@ +// We're testing aarch64 CRC32 target specific features +//@only-target: aarch64 +//@compile-flags: -C target-feature=+crc + +use std::arch::aarch64::*; +use std::arch::is_aarch64_feature_detected; + +fn main() { + assert!(is_aarch64_feature_detected!("crc")); + + unsafe { + test_crc32_standard(); + test_crc32c_castagnoli(); + } +} + +#[target_feature(enable = "crc")] +unsafe fn test_crc32_standard() { + // __crc32b: 8-bit input + assert_eq!(__crc32b(0x00000000, 0x01), 0x77073096); + assert_eq!(__crc32b(0xffffffff, 0x61), 0x174841bc); + assert_eq!(__crc32b(0x2aa1e72b, 0x2a), 0x772d9171); + + // __crc32h: 16-bit input + assert_eq!(__crc32h(0x00000000, 0x0001), 0x191b3141); + assert_eq!(__crc32h(0xffffffff, 0x1234), 0xf6b56fbf); + assert_eq!(__crc32h(0x8ecec3b5, 0x022b), 0x03a1db7c); + + // __crc32w: 32-bit input + assert_eq!(__crc32w(0x00000000, 0x00000001), 0xb8bc6765); + assert_eq!(__crc32w(0xffffffff, 0x12345678), 0x5092782d); + assert_eq!(__crc32w(0xae2912c8, 0x00845fed), 0xc5690dd4); + + // __crc32d: 64-bit input + assert_eq!(__crc32d(0x00000000, 0x0000000000000001), 0xccaa009e); + assert_eq!(__crc32d(0xffffffff, 0x123456789abcdef0), 0xe6ddf8b5); + assert_eq!(__crc32d(0x0badeafe, 0xc0febeefdadafefe), 0x61a45fba); +} + +#[target_feature(enable = "crc")] +unsafe fn test_crc32c_castagnoli() { + // __crc32cb: 8-bit input + assert_eq!(__crc32cb(0x00000000, 0x01), 0xf26b8303); + assert_eq!(__crc32cb(0xffffffff, 0x61), 0x3e2fbccf); + assert_eq!(__crc32cb(0x2aa1e72b, 0x2a), 0xf24122e4); + + // __crc32ch: 16-bit input + assert_eq!(__crc32ch(0x00000000, 0x0001), 0x13a29877); + assert_eq!(__crc32ch(0xffffffff, 0x1234), 0xf13f4cea); + assert_eq!(__crc32ch(0x8ecec3b5, 0x022b), 0x013bb2fb); + + // __crc32cw: 32-bit input + assert_eq!(__crc32cw(0x00000000, 0x00000001), 0xdd45aab8); + assert_eq!(__crc32cw(0xffffffff, 0x12345678), 0x4dece20c); + assert_eq!(__crc32cw(0xae2912c8, 0x00845fed), 0xffae2ed1); + + // __crc32cd: 64-bit input + assert_eq!(__crc32cd(0x00000000, 0x0000000000000001), 0x493c7d27); + assert_eq!(__crc32cd(0xffffffff, 0x123456789abcdef0), 0xd95b664b); + assert_eq!(__crc32cd(0x0badeafe, 0xc0febeefdadafefe), 0x5b44f54f); +} diff --git a/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs index 6d3f153e194f..884f8eff41bd 100644 --- a/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs +++ b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-neon.rs @@ -12,6 +12,8 @@ fn main() { unsafe { test_vpmaxq_u8(); test_tbl1_v16i8_basic(); + test_vpadd(); + test_vpaddl(); } } @@ -65,3 +67,93 @@ fn test_tbl1_v16i8_basic() { assert_eq!(&got2_arr[3..16], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12][..]); } } +#[target_feature(enable = "neon")] +unsafe fn test_vpadd() { + let a = vld1_s8([1, 2, 3, 4, 5, 6, 7, 8].as_ptr()); + let b = vld1_s8([9, 10, -1, 2, i8::MIN, i8::MIN, i8::MAX, i8::MAX].as_ptr()); + let e = + [3i8, 7, 11, 15, 19, -1 + 2, i8::MIN.wrapping_add(i8::MIN), i8::MAX.wrapping_add(i8::MAX)]; + let mut r = [0i8; 8]; + vst1_s8(r.as_mut_ptr(), vpadd_s8(a, b)); + assert_eq!(r, e); + + let a = vld1_s16([1, 2, 3, 4].as_ptr()); + let b = vld1_s16([-1, 2, i16::MAX, i16::MAX].as_ptr()); + let e = [3i16, 7, -1 + 2, i16::MAX.wrapping_add(i16::MAX)]; + let mut r = [0i16; 4]; + vst1_s16(r.as_mut_ptr(), vpadd_s16(a, b)); + assert_eq!(r, e); + + let a = vld1_s32([1, 2].as_ptr()); + let b = vld1_s32([i32::MAX, i32::MAX].as_ptr()); + let e = [3i32, i32::MAX.wrapping_add(i32::MAX)]; + let mut r = [0i32; 2]; + vst1_s32(r.as_mut_ptr(), vpadd_s32(a, b)); + assert_eq!(r, e); + + let a = vld1_u8([1, 2, 3, 4, 5, 6, 7, 8].as_ptr()); + let b = vld1_u8([9, 10, 11, 12, 13, 14, u8::MAX, u8::MAX].as_ptr()); + let e = [3u8, 7, 11, 15, 19, 23, 27, 254]; + let mut r = [0u8; 8]; + vst1_u8(r.as_mut_ptr(), vpadd_u8(a, b)); + assert_eq!(r, e); + + let a = vld1_u16([1, 2, 3, 4].as_ptr()); + let b = vld1_u16([5, 6, u16::MAX, u16::MAX].as_ptr()); + let e = [3u16, 7, 11, 65534]; + let mut r = [0u16; 4]; + vst1_u16(r.as_mut_ptr(), vpadd_u16(a, b)); + assert_eq!(r, e); + + let a = vld1_u32([1, 2].as_ptr()); + let b = vld1_u32([u32::MAX, u32::MAX].as_ptr()); + let e = [3u32, u32::MAX.wrapping_add(u32::MAX)]; + let mut r = [0u32; 2]; + vst1_u32(r.as_mut_ptr(), vpadd_u32(a, b)); + assert_eq!(r, e); +} + +#[target_feature(enable = "neon")] +unsafe fn test_vpaddl() { + let a = vld1_u8([1, 2, 3, 4, 5, 6, u8::MAX, u8::MAX].as_ptr()); + let e = [3u16, 7, 11, 510]; + let mut r = [0u16; 4]; + vst1_u16(r.as_mut_ptr(), vpaddl_u8(a)); + assert_eq!(r, e); + + let a = vld1q_u8([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, u8::MAX, u8::MAX].as_ptr()); + let e = [3u16, 7, 11, 15, 19, 23, 27, 510]; + let mut r = [0u16; 8]; + vst1q_u16(r.as_mut_ptr(), vpaddlq_u8(a)); + assert_eq!(r, e); + + let a = vld1_u16([1, 2, u16::MAX, u16::MAX].as_ptr()); + let e = [3u32, 131070]; + let mut r = [0u32; 2]; + vst1_u32(r.as_mut_ptr(), vpaddl_u16(a)); + assert_eq!(r, e); + + let a = vld1q_u16([1, 2, 3, 4, 5, 6, u16::MAX, u16::MAX].as_ptr()); + let e = [3u32, 7, 11, 131070]; + let mut r = [0u32; 4]; + vst1q_u32(r.as_mut_ptr(), vpaddlq_u16(a)); + assert_eq!(r, e); + + let a = vld1_u32([1, 2].as_ptr()); + let e = [3u64]; + let mut r = [0u64; 1]; + vst1_u64(r.as_mut_ptr(), vpaddl_u32(a)); + assert_eq!(r, e); + + let a = vld1_u32([u32::MAX, u32::MAX].as_ptr()); + let e = [8589934590]; + let mut r = [0u64; 1]; + vst1_u64(r.as_mut_ptr(), vpaddl_u32(a)); + assert_eq!(r, e); + + let a = vld1q_u32([1, 2, u32::MAX, u32::MAX].as_ptr()); + let e = [3u64, 8589934590]; + let mut r = [0u64; 2]; + vst1q_u64(r.as_mut_ptr(), vpaddlq_u32(a)); + assert_eq!(r, e); +} diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 50b5dbfba1cd..e6c15c81d9fd 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -30,9 +30,9 @@ fn main() { test_file_clone(); test_file_set_len(); test_file_sync(); + test_rename(); // Windows file handling is very incomplete. if cfg!(not(windows)) { - test_rename(); test_directory(); test_canonicalize(); #[cfg(unix)] diff --git a/src/tools/miri/tests/pass/shims/socket.rs b/src/tools/miri/tests/pass/shims/socket.rs new file mode 100644 index 000000000000..852397a35691 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/socket.rs @@ -0,0 +1,56 @@ +//@ignore-target: windows # No libc socket on Windows +//@compile-flags: -Zmiri-disable-isolation + +use std::net::{TcpListener, TcpStream}; +use std::thread; + +fn main() { + test_create_ipv4_listener(); + test_create_ipv6_listener(); + test_accept_and_connect(); + test_peer_addr(); +} + +fn test_create_ipv4_listener() { + let _listener_ipv4 = TcpListener::bind("127.0.0.1:0").unwrap(); +} + +fn test_create_ipv6_listener() { + let _listener_ipv6 = TcpListener::bind("[::1]:0").unwrap(); +} + +/// Try to connect to a TCP listener running in a separate thread and +/// accepting connections. +fn test_accept_and_connect() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + // Get local address with randomized port to know where + // we need to connect to. + let address = listener.local_addr().unwrap(); + + let handle = thread::spawn(move || { + let (_stream, _addr) = listener.accept().unwrap(); + }); + + let _stream = TcpStream::connect(address).unwrap(); + + handle.join().unwrap(); +} + +/// Test whether the [`TcpStream::peer_addr`] of a connected socket +/// is the same address as the one the stream was connected to. +fn test_peer_addr() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + // Get local address with randomized port to know where + // we need to connect to. + let address = listener.local_addr().unwrap(); + + let handle = thread::spawn(move || { + let (_stream, _addr) = listener.accept().unwrap(); + }); + + let stream = TcpStream::connect(address).unwrap(); + let peer_addr = stream.peer_addr().unwrap(); + assert_eq!(address, peer_addr); + + handle.join().unwrap(); +} diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs index be3f961e10ff..9136b5eda387 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs @@ -6,9 +6,10 @@ use std::arch::x86::*; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; -use std::f32::NAN; use std::mem::transmute; +const NAN: f32 = f32::NAN; + fn main() { assert!(is_x86_feature_detected!("sse")); diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs index 242aa0e89f63..570da30f0b62 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs @@ -6,9 +6,10 @@ use std::arch::x86::*; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; -use std::f64::NAN; use std::mem::transmute; +const NAN: f64 = f64::NAN; + fn main() { assert!(is_x86_feature_detected!("sse2")); diff --git a/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout index de7da309271d..296339e73845 100644 --- a/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout +++ b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout @@ -1,6 +1,6 @@ 0..1: [ SharedReadWrite ] 0..1: [ SharedReadWrite ] 0..1: [ SharedReadWrite ] -0..1: [ SharedReadWrite Unique Unique Unique Unique Unique Unique Unique Unique Unique Unique Unique ] -0..1: [ SharedReadWrite Disabled Disabled Disabled Disabled Disabled Disabled Disabled Disabled Disabled Disabled Disabled SharedReadOnly ] +0..1: [ SharedReadWrite Unique Unique Unique Unique Unique Unique Unique ] +0..1: [ SharedReadWrite Disabled Disabled Disabled Disabled Disabled Disabled Disabled SharedReadOnly ] 0..1: [ unknown-bottom(..) ] diff --git a/src/tools/miri/tests/utils/libc.rs b/src/tools/miri/tests/utils/libc.rs index 0cc6ad0334c0..ef22d3af5425 100644 --- a/src/tools/miri/tests/utils/libc.rs +++ b/src/tools/miri/tests/utils/libc.rs @@ -157,3 +157,51 @@ pub fn check_epoll_wait_noblock(epfd: i32, expected: &[Ev]) { check_epoll_wait::(epfd, expected, 0); } } + +pub mod net { + /// IPv4 localhost address bytes + pub const IPV4_LOCALHOST: [u8; 4] = [127, 0, 0, 1]; + /// IPv6 localhost address bytes + pub const IPV6_LOCALHOST: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; + + /// Create a libc representation of an IPv4 address given the address bytes and a port. + pub fn ipv4_sock_addr(addr_bytes: [u8; 4], port: u16) -> libc::sockaddr_in { + libc::sockaddr_in { + sin_family: libc::AF_INET as libc::sa_family_t, + sin_port: port.to_be(), + // `addr_bytes` is already in big-endian and that's the format `sin_addr` expects. + #[expect(unnecessary_transmutes)] + sin_addr: libc::in_addr { + s_addr: unsafe { std::mem::transmute::<[u8; 4], u32>(addr_bytes) }, + }, + ..unsafe { core::mem::zeroed() } + } + } + + /// Create a libc representation of an IPv6 address given the address bytes and a port. + /// + /// This method sets `flowinfo` and `scope_id` to 0. + pub fn ipv6_sock_addr(addr_bytes: [u8; 16], port: u16) -> libc::sockaddr_in6 { + ipv6_sock_addr_full(addr_bytes, port, 0, 0) + } + + /// Create a libc representation of a full IPv6 address given the address bytes, a port + /// as well as a flowinfo and scope id. + pub fn ipv6_sock_addr_full( + addr_bytes: [u8; 16], + port: u16, + flowinfo: u32, + scope_id: u32, + ) -> libc::sockaddr_in6 { + #[allow(clippy::needless_update)] + libc::sockaddr_in6 { + sin6_family: libc::AF_INET6 as libc::sa_family_t, + sin6_port: port.to_be(), + sin6_addr: libc::in6_addr { s6_addr: addr_bytes }, + sin6_flowinfo: flowinfo, + sin6_scope_id: scope_id, + // This is only needed on some targets where an additional `sin6_len` field exists. + ..unsafe { core::mem::zeroed() } + } + } +} diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index b6547eff007b..9b54f62da9bd 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -10,10 +10,10 @@ log = "0.4" anyhow = "1" humantime = "2" humansize = "2" -sysinfo = { version = "0.38.2", default-features = false, features = ["disk"] } +sysinfo = { version = "0.38.4", default-features = false, features = ["disk"] } fs_extra = "1" camino = "1" -tar = "0.4" +tar = "0.4.45" xz = { version = "0.1", package = "xz2" } serde_json = "1" glob = "0.3" diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index c0820e4a6854..cc8edfcdac61 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -123,6 +123,8 @@ fn main() { let listener = bind_socket(config.bind); let (work, tmp): (PathBuf, PathBuf) = if cfg!(target_os = "android") { ("/data/local/tmp/work".into(), "/data/local/tmp/work/tmp".into()) + } else if cfg!(target_os = "uefi") { + ("tmp\\work".into(), "tmp\\work\\tmp".into()) } else { let mut work_dir = env::temp_dir(); work_dir.push("work"); @@ -209,12 +211,12 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf let mut args = Vec::new(); while t!(reader.read_until(0, &mut arg)) > 1 { args.push(t!(str::from_utf8(&arg[..arg.len() - 1])).to_string()); - arg.truncate(0); + arg.clear(); } // Next we'll get a bunch of env vars in pairs delimited by 0s as well let mut env = Vec::new(); - arg.truncate(0); + arg.clear(); while t!(reader.read_until(0, &mut arg)) > 1 { let key_len = arg.len() - 1; let val_len = t!(reader.read_until(0, &mut arg)) - 1; @@ -225,7 +227,7 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf let val = t!(str::from_utf8(val)).to_string(); env.push((key, val)); } - arg.truncate(0); + arg.clear(); } // The section of code from here down to where we drop the lock is going to @@ -274,6 +276,8 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf } else if cfg!(target_vendor = "apple") { // On Apple platforms, the environment variable is named differently. "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "uefi") { + "path" } else { "LD_LIBRARY_PATH" }; diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index f4a09f9faae8..0216ae7a30dd 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -6,7 +6,7 @@ use build_helper::drop_bomb::DropBomb; -use crate::util::handle_failed_output; +use crate::util::{handle_failed_output, verbose_print_command}; use crate::{ assert_contains, assert_contains_regex, assert_equals, assert_not_contains, assert_not_contains_regex, @@ -156,7 +156,7 @@ pub fn args(&mut self, args: V) -> &mut Self /// Inspect what the underlying [`std::process::Command`] is up to the /// current construction. - pub fn inspect(&mut self, inspector: I) -> &mut Self + pub fn inspect(&self, inspector: I) -> &Self where I: FnOnce(&StdCommand), { @@ -233,6 +233,8 @@ pub fn run(&mut self) -> CompletedProcess { let output = self.command_output(); if !output.status().success() { handle_failed_output(&self, output, panic::Location::caller().line()); + } else { + verbose_print_command(self, &output); } output } @@ -245,6 +247,8 @@ pub fn run_fail(&mut self) -> CompletedProcess { let output = self.command_output(); if output.status().success() { handle_failed_output(&self, output, panic::Location::caller().line()); + } else { + verbose_print_command(self, &output); } output } diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index b95f3a5cfe5a..43f0473ddf4a 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -1,9 +1,8 @@ +use std::env; use std::ffi::{OsStr, OsString}; use std::path::PathBuf; -use std::{env, panic}; use crate::command::{Command, CompletedProcess}; -use crate::util::handle_failed_output; use crate::{cwd, env_var}; #[track_caller] @@ -59,43 +58,26 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command { }); cmd.env("LC_ALL", "C"); // force english locale + cmd.inspect(|std_cmd| eprintln!("running: {std_cmd:?}")); cmd } /// Run a built binary and make sure it succeeds. #[track_caller] pub fn run(name: &str) -> CompletedProcess { - let caller = panic::Location::caller(); - let mut cmd = run_common(name, None); - let output = cmd.run(); - if !output.status().success() { - handle_failed_output(&cmd, output, caller.line()); - } - output + run_common(name, None).run() } /// Run a built binary with one or more argument(s) and make sure it succeeds. #[track_caller] pub fn run_with_args(name: &str, args: &[&str]) -> CompletedProcess { - let caller = panic::Location::caller(); - let mut cmd = run_common(name, Some(args)); - let output = cmd.run(); - if !output.status().success() { - handle_failed_output(&cmd, output, caller.line()); - } - output + run_common(name, Some(args)).run() } /// Run a built binary and make sure it fails. #[track_caller] pub fn run_fail(name: &str) -> CompletedProcess { - let caller = panic::Location::caller(); - let mut cmd = run_common(name, None); - let output = cmd.run_fail(); - if output.status().success() { - handle_failed_output(&cmd, output, caller.line()); - } - output + run_common(name, None).run_fail() } /// Create a new custom [`Command`]. This should be preferred to creating [`std::process::Command`] diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index 6288f5f7c59d..bbc36889b1a4 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -2,7 +2,6 @@ use crate::command::Command; use crate::env_var; -use crate::util::handle_failed_output; /// `TARGET` #[must_use] @@ -81,11 +80,5 @@ pub fn llvm_components_contain(component: &str) -> bool { #[track_caller] #[must_use] pub fn uname() -> String { - let caller = panic::Location::caller(); - let mut uname = Command::new("uname"); - let output = uname.run(); - if !output.status().success() { - handle_failed_output(&uname, output, caller.line()); - } - output.stdout_utf8() + Command::new("uname").run().stdout_utf8() } diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs index 7908dc1f7b3d..f44b3861d11d 100644 --- a/src/tools/run-make-support/src/util.rs +++ b/src/tools/run-make-support/src/util.rs @@ -4,6 +4,18 @@ use crate::env::env_var; use crate::path_helpers::cwd; +pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) { + cmd.inspect(|std_cmd| { + eprintln!("{std_cmd:?}"); + }); + eprintln!("output status: `{}`", output.status()); + eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); + eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); + if !cmd.get_context().is_empty() { + eprintln!("Context:\n{}", cmd.get_context()); + } +} + /// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the /// executed command, failure location, output status and stdout/stderr, and abort the process with /// exit code `1`. @@ -17,13 +29,7 @@ pub(crate) fn handle_failed_output( } else { eprintln!("command failed at line {caller_line_number}"); } - eprintln!("{cmd:?}"); - eprintln!("output status: `{}`", output.status()); - eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); - eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); - if !cmd.get_context().is_empty() { - eprintln!("Context:\n{}", cmd.get_context()); - } + verbose_print_command(cmd, &output); std::process::exit(1) } diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml index 6e2be7fd3da5..abb9b521f1a5 100644 --- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml +++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 04de6d11e3eb..c27d84fb0bc0 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -30,8 +30,8 @@ jobs: outputs: typescript: ${{ steps.filter.outputs.typescript }} steps: - - uses: actions/checkout@v4 - - uses: dorny/paths-filter@1441771bbfdd59dcd748680ee64ebd8faab1a242 + - uses: actions/checkout@v6 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 id: filter with: filters: | @@ -45,7 +45,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} @@ -88,7 +88,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} @@ -136,7 +136,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -164,7 +164,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -180,7 +180,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 # Note that clippy output is currently dependent on whether rust-src is installed, # https://github.com/rust-lang/rust-clippy/issues/14625 @@ -202,7 +202,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -226,12 +226,7 @@ jobs: strategy: matrix: - target: - [ - powerpc-unknown-linux-gnu, - x86_64-unknown-linux-musl, - wasm32-unknown-unknown, - ] + target: [powerpc-unknown-linux-gnu, x86_64-unknown-linux-musl, wasm32-unknown-unknown] include: # The rust-analyzer binary is not expected to compile on WASM, but the IDE # crate should @@ -240,7 +235,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -268,10 +263,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Nodejs - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 @@ -327,7 +322,7 @@ jobs: run: curl -LsSf https://github.com/crate-ci/typos/releases/download/$TYPOS_VERSION/typos-$TYPOS_VERSION-x86_64-unknown-linux-musl.tar.gz | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} diff --git a/src/tools/rust-analyzer/.github/workflows/coverage.yaml b/src/tools/rust-analyzer/.github/workflows/coverage.yaml index bd4edba747ca..9460c6a3c77a 100644 --- a/src/tools/rust-analyzer/.github/workflows/coverage.yaml +++ b/src/tools/rust-analyzer/.github/workflows/coverage.yaml @@ -13,7 +13,7 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -34,9 +34,9 @@ jobs: - name: Generate code coverage run: cargo llvm-cov --workspace --lcov --output-path lcov.info - + - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: files: lcov.info fail_ci_if_error: false diff --git a/src/tools/rust-analyzer/.github/workflows/fuzz.yml b/src/tools/rust-analyzer/.github/workflows/fuzz.yml index 7acfcbe351fe..af0e03598ecf 100644 --- a/src/tools/rust-analyzer/.github/workflows/fuzz.yml +++ b/src/tools/rust-analyzer/.github/workflows/fuzz.yml @@ -2,10 +2,10 @@ name: Fuzz on: schedule: # Once a week - - cron: '0 0 * * 0' + - cron: "0 0 * * 0" push: paths: - - '.github/workflows/fuzz.yml' + - ".github/workflows/fuzz.yml" # Allow manual trigger workflow_dispatch: @@ -27,7 +27,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 1 diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml index 860837dd7fd4..a482235105c0 100644 --- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml +++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml @@ -23,7 +23,7 @@ jobs: rustup component add --toolchain beta rust-src - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Cache cargo uses: actions/cache@v4 @@ -45,7 +45,7 @@ jobs: key: ${{ runner.os }}-target-${{ github.sha }} - name: Upload build metrics - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: build-${{ github.sha }} path: target/build.json @@ -66,7 +66,7 @@ jobs: rustup component add --toolchain beta rust-src - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Restore target cache uses: actions/cache@v4 @@ -78,7 +78,7 @@ jobs: run: cargo xtask metrics "${{ matrix.names }}" - name: Upload metrics - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.names }}-${{ github.sha }} path: target/${{ matrix.names }}.json @@ -89,35 +89,35 @@ jobs: needs: [build_metrics, other_metrics] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download build metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: build-${{ github.sha }} - name: Download self metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: self-${{ github.sha }} - name: Download ripgrep-13.0.0 metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: ripgrep-13.0.0-${{ github.sha }} - name: Download webrender-2022 metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: webrender-2022-${{ github.sha }} - name: Download diesel-1.4.8 metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: diesel-1.4.8-${{ github.sha }} - name: Download hyper-0.14.18 metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: hyper-0.14.18-${{ github.sha }} diff --git a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml index f2c8b6365b66..762b7bda871c 100644 --- a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml +++ b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index 28914118de94..b35614f91b2d 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -70,12 +70,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: ${{ env.FETCH_DEPTH }} - name: Install Node.js toolchain - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 @@ -143,7 +143,7 @@ jobs: run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps --no-sysroot --no-test $(rustc --print sysroot)/lib/rustlib/src/rust/library/std -q - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: dist-${{ matrix.target }} path: ./dist @@ -166,7 +166,7 @@ jobs: run: apk add --no-cache git clang lld musl-dev nodejs npm - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: ${{ env.FETCH_DEPTH }} @@ -189,7 +189,7 @@ jobs: - run: rm -rf editors/code/server - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: dist-x86_64-unknown-linux-musl path: ./dist @@ -201,7 +201,7 @@ jobs: needs: ["dist", "dist-x86_64-unknown-linux-musl"] steps: - name: Install Nodejs - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 @@ -212,46 +212,46 @@ jobs: - run: 'echo "TAG: $TAG"' - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: ${{ env.FETCH_DEPTH }} - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV - run: 'echo "HEAD_SHA: $HEAD_SHA"' - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-aarch64-apple-darwin path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-x86_64-apple-darwin path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-x86_64-unknown-linux-gnu path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-x86_64-unknown-linux-musl path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-aarch64-unknown-linux-gnu path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-arm-unknown-linux-gnueabihf path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-x86_64-pc-windows-msvc path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-i686-pc-windows-msvc path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-aarch64-pc-windows-msvc path: dist diff --git a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml index 0cc7ce77ddb6..03fd08317501 100644 --- a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml +++ b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml @@ -1,8 +1,8 @@ name: rustdoc on: push: - branches: - - master + branches: + - master env: CARGO_INCREMENTAL: 0 @@ -10,6 +10,7 @@ env: RUSTFLAGS: "-D warnings -W unreachable-pub" RUSTDOCFLAGS: "-D warnings" RUSTUP_MAX_RETRIES: 10 + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true jobs: rustdoc: @@ -17,19 +18,19 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v6 - - name: Install Rust toolchain - run: rustup update --no-self-update stable + - name: Install Rust toolchain + run: rustup update --no-self-update stable - - name: Build Documentation - run: cargo doc --all --no-deps --document-private-items + - name: Build Documentation + run: cargo doc --all --no-deps --document-private-items - - name: Deploy Docs - uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: gh-pages - publish_dir: ./target/doc - force_orphan: true + - name: Deploy Docs + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: ./target/doc + force_orphan: true diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index f31dda4a107b..5370127ddc8e 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2315,6 +2315,7 @@ dependencies = [ "ide-db", "ide-ssr", "indexmap", + "intern", "itertools 0.14.0", "load-cargo", "lsp-server 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/rust-analyzer/README.md b/src/tools/rust-analyzer/README.md index 6d2a67328685..06d63a2d23a7 100644 --- a/src/tools/rust-analyzer/README.md +++ b/src/tools/rust-analyzer/README.md @@ -20,6 +20,8 @@ analyzing Rust code. See [Architecture](https://rust-analyzer.github.io/book/contributing/architecture.html) in the manual. +[![codecov](https://codecov.io/github/rust-lang/rust-analyzer/graph/badge.svg)](https://app.codecov.io/github/rust-lang/rust-analyzer/tree/master) + ## Quick Start https://rust-analyzer.github.io/book/installation.html diff --git a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs index 13fb05d56547..8721f3a0ff3b 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs @@ -1,305 +1,46 @@ //! Defines [`EditionedFileId`], an interned wrapper around [`span::EditionedFileId`] that -//! is interned (so queries can take it) and remembers its crate. +//! is interned (so queries can take it) and stores only the underlying `span::EditionedFileId`. -use core::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; +use salsa::Database; use span::Edition; use vfs::FileId; -use crate::{Crate, RootQueryDb}; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct EditionedFileId( - salsa::Id, - std::marker::PhantomData<&'static salsa::plumbing::interned::Value>, -); - -const _: () = { - use salsa::plumbing as zalsa_; - use zalsa_::interned as zalsa_struct_; - type Configuration_ = EditionedFileId; - - #[derive(Debug, Clone, PartialEq, Eq)] - pub struct EditionedFileIdData { - editioned_file_id: span::EditionedFileId, - krate: Crate, - } - - // FIXME: This poses an invalidation problem, if one constructs an `EditionedFileId` with a - // different crate then whatever the input of a memo used, it will invalidate the memo causing - // it to recompute even if the crate is not really used. - /// We like to include the origin crate in an `EditionedFileId` (for use in the item tree), - /// but this poses us a problem. - /// - /// Spans contain `EditionedFileId`s, and we don't want to make them store the crate too - /// because that will increase their size, which will increase memory usage significantly. - /// Furthermore, things using spans do not generally need the crate: they are using the - /// file id for queries like `ast_id_map` or `parse`, which do not care about the crate. - /// - /// To solve this, we hash **only the `span::EditionedFileId`**, but on still compare - /// the crate in equality check. This preserves the invariant of `Hash` and `Eq` - - /// although same hashes can be used for different items, same file ids used for multiple - /// crates is a rare thing, and different items always have different hashes. Then, - /// when we only have a `span::EditionedFileId`, we use the `intern()` method to - /// reuse existing file ids, and create new one only if needed. See [`from_span_guess_origin`]. - /// - /// See this for more info: https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Letting.20EditionedFileId.20know.20its.20crate/near/530189401 - /// - /// [`from_span_guess_origin`]: EditionedFileId::from_span_guess_origin - #[derive(Hash, PartialEq, Eq)] - struct WithoutCrate { - editioned_file_id: span::EditionedFileId, - } - - impl Hash for EditionedFileIdData { - #[inline] - fn hash(&self, state: &mut H) { - let EditionedFileIdData { editioned_file_id, krate: _ } = *self; - editioned_file_id.hash(state); - } - } - - impl zalsa_struct_::HashEqLike for EditionedFileIdData { - #[inline] - fn hash(&self, state: &mut H) { - Hash::hash(self, state); - } - - #[inline] - fn eq(&self, data: &WithoutCrate) -> bool { - let EditionedFileIdData { editioned_file_id, krate: _ } = *self; - editioned_file_id == data.editioned_file_id - } - } - - impl zalsa_::HasJar for EditionedFileId { - type Jar = zalsa_struct_::JarImpl; - const KIND: zalsa_::JarKind = zalsa_::JarKind::Struct; - } - - zalsa_::register_jar! { - zalsa_::ErasedJar::erase::() - } - - impl zalsa_struct_::Configuration for EditionedFileId { - const LOCATION: salsa::plumbing::Location = - salsa::plumbing::Location { file: file!(), line: line!() }; - const DEBUG_NAME: &'static str = "EditionedFileId"; - const REVISIONS: std::num::NonZeroUsize = std::num::NonZeroUsize::MAX; - const PERSIST: bool = false; - - type Fields<'a> = EditionedFileIdData; - type Struct<'db> = EditionedFileId; - - fn serialize(_: &Self::Fields<'_>, _: S) -> Result - where - S: zalsa_::serde::Serializer, - { - unimplemented!("attempted to serialize value that set `PERSIST` to false") - } - - fn deserialize<'de, D>(_: D) -> Result, D::Error> - where - D: zalsa_::serde::Deserializer<'de>, - { - unimplemented!("attempted to deserialize value that cannot set `PERSIST` to false"); - } - } - - impl Configuration_ { - pub fn ingredient(zalsa: &zalsa_::Zalsa) -> &zalsa_struct_::IngredientImpl { - static CACHE: zalsa_::IngredientCache> = - zalsa_::IngredientCache::new(); - - // SAFETY: `lookup_jar_by_type` returns a valid ingredient index, and the only - // ingredient created by our jar is the struct ingredient. - unsafe { - CACHE.get_or_create(zalsa, || { - zalsa.lookup_jar_by_type::>() - }) - } - } - } - - impl zalsa_::AsId for EditionedFileId { - fn as_id(&self) -> salsa::Id { - self.0.as_id() - } - } - impl zalsa_::FromId for EditionedFileId { - fn from_id(id: salsa::Id) -> Self { - Self(::from_id(id), std::marker::PhantomData) - } - } - - unsafe impl Send for EditionedFileId {} - unsafe impl Sync for EditionedFileId {} - - impl std::fmt::Debug for EditionedFileId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Self::default_debug_fmt(*self, f) - } - } - - impl zalsa_::SalsaStructInDb for EditionedFileId { - type MemoIngredientMap = salsa::plumbing::MemoIngredientSingletonIndex; - - fn lookup_ingredient_index(aux: &zalsa_::Zalsa) -> salsa::plumbing::IngredientIndices { - aux.lookup_jar_by_type::>().into() - } - - fn entries(zalsa: &zalsa_::Zalsa) -> impl Iterator + '_ { - let _ingredient_index = - zalsa.lookup_jar_by_type::>(); - ::ingredient(zalsa).entries(zalsa).map(|entry| entry.key()) - } - - #[inline] - fn cast(id: salsa::Id, type_id: std::any::TypeId) -> Option { - if type_id == std::any::TypeId::of::() { - Some(::from_id(id)) - } else { - None - } - } - - #[inline] - unsafe fn memo_table( - zalsa: &zalsa_::Zalsa, - id: zalsa_::Id, - current_revision: zalsa_::Revision, - ) -> zalsa_::MemoTableWithTypes<'_> { - // SAFETY: Guaranteed by caller. - unsafe { - zalsa.table().memos::>(id, current_revision) - } - } - } - - unsafe impl zalsa_::Update for EditionedFileId { - unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { - if unsafe { *old_pointer } != new_value { - unsafe { *old_pointer = new_value }; - true - } else { - false - } - } - } - - impl EditionedFileId { - pub fn from_span( - db: &(impl salsa::Database + ?Sized), - editioned_file_id: span::EditionedFileId, - krate: Crate, - ) -> Self { - let (zalsa, zalsa_local) = db.zalsas(); - Configuration_::ingredient(zalsa).intern( - zalsa, - zalsa_local, - EditionedFileIdData { editioned_file_id, krate }, - |_, data| data, - ) - } - - /// Guesses the crate for the file. - /// - /// Only use this if you cannot precisely determine the origin. This can happen in one of two cases: - /// - /// 1. The file is not in the module tree. - /// 2. You are latency sensitive and cannot afford calling the def map to precisely compute the origin - /// (e.g. on enter feature, folding, etc.). - pub fn from_span_guess_origin( - db: &dyn RootQueryDb, - editioned_file_id: span::EditionedFileId, - ) -> Self { - let (zalsa, zalsa_local) = db.zalsas(); - Configuration_::ingredient(zalsa).intern( - zalsa, - zalsa_local, - WithoutCrate { editioned_file_id }, - |_, _| { - // FileId not in the database. - let krate = db - .relevant_crates(editioned_file_id.file_id()) - .first() - .copied() - .or_else(|| db.all_crates().first().copied()) - .unwrap_or_else(|| { - // What we're doing here is a bit fishy. We rely on the fact that we only need - // the crate in the item tree, and we should not create an `EditionedFileId` - // without a crate except in cases where it does not matter. The chances that - // `all_crates()` will be empty are also very slim, but it can occur during startup. - // In the very unlikely case that there is a bug and we'll use this crate, Salsa - // will panic. - - // SAFETY: 0 is less than `Id::MAX_U32`. - salsa::plumbing::FromId::from_id(unsafe { salsa::Id::from_index(0) }) - }); - EditionedFileIdData { editioned_file_id, krate } - }, - ) - } - - pub fn editioned_file_id(self, db: &dyn salsa::Database) -> span::EditionedFileId { - let zalsa = db.zalsa(); - let fields = Configuration_::ingredient(zalsa).fields(zalsa, self); - fields.editioned_file_id - } - - pub fn krate(self, db: &dyn salsa::Database) -> Crate { - let zalsa = db.zalsa(); - let fields = Configuration_::ingredient(zalsa).fields(zalsa, self); - fields.krate - } - - /// Default debug formatting for this struct (may be useful if you define your own `Debug` impl) - pub fn default_debug_fmt(this: Self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - zalsa_::with_attached_database(|db| { - let zalsa = db.zalsa(); - let fields = Configuration_::ingredient(zalsa).fields(zalsa, this); - fmt::Debug::fmt(fields, f) - }) - .unwrap_or_else(|| { - f.debug_tuple("EditionedFileId").field(&zalsa_::AsId::as_id(&this)).finish() - }) - } - } -}; +#[salsa::interned(debug, constructor = from_span_file_id, no_lifetime)] +#[derive(PartialOrd, Ord)] +pub struct EditionedFileId { + field: span::EditionedFileId, +} impl EditionedFileId { #[inline] - pub fn new(db: &dyn salsa::Database, file_id: FileId, edition: Edition, krate: Crate) -> Self { - EditionedFileId::from_span(db, span::EditionedFileId::new(file_id, edition), krate) - } - - /// Attaches the current edition and guesses the crate for the file. - /// - /// Only use this if you cannot precisely determine the origin. This can happen in one of two cases: - /// - /// 1. The file is not in the module tree. - /// 2. You are latency sensitive and cannot afford calling the def map to precisely compute the origin - /// (e.g. on enter feature, folding, etc.). - #[inline] - pub fn current_edition_guess_origin(db: &dyn RootQueryDb, file_id: FileId) -> Self { - Self::from_span_guess_origin(db, span::EditionedFileId::current_edition(file_id)) + pub fn new(db: &dyn Database, file_id: FileId, edition: Edition) -> Self { + Self::from_span_file_id(db, span::EditionedFileId::new(file_id, edition)) } #[inline] - pub fn file_id(self, db: &dyn salsa::Database) -> vfs::FileId { - let id = self.editioned_file_id(db); - id.file_id() + pub fn current_edition(db: &dyn Database, file_id: FileId) -> Self { + Self::from_span_file_id(db, span::EditionedFileId::current_edition(file_id)) } #[inline] - pub fn unpack(self, db: &dyn salsa::Database) -> (vfs::FileId, span::Edition) { - let id = self.editioned_file_id(db); - (id.file_id(), id.edition()) + pub fn file_id(self, db: &dyn Database) -> vfs::FileId { + self.field(db).file_id() } #[inline] - pub fn edition(self, db: &dyn salsa::Database) -> Edition { - self.editioned_file_id(db).edition() + pub fn span_file_id(self, db: &dyn Database) -> span::EditionedFileId { + self.field(db) + } + + #[inline] + pub fn unpack(self, db: &dyn Database) -> (vfs::FileId, span::Edition) { + self.field(db).unpack() + } + + #[inline] + pub fn edition(self, db: &dyn Database) -> Edition { + self.field(db).edition() } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 151aba82a203..246c57edc2df 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -870,7 +870,7 @@ pub fn shrink_to_fit(&mut self) { impl Crate { pub fn root_file_id(self, db: &dyn salsa::Database) -> EditionedFileId { let data = self.data(db); - EditionedFileId::new(db, data.root_file_id, data.edition, self) + EditionedFileId::new(db, data.root_file_id, data.edition) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs index 0b8f65687218..e3e1aac7090a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs @@ -894,7 +894,7 @@ pub fn query_generic_params( def: GenericDefId, ) -> &(ArenaMap, ArenaMap) { - let generic_params = GenericParams::new(db, def); + let generic_params = GenericParams::of(db, def); let params_count_excluding_self = generic_params.len() - usize::from(generic_params.trait_self_param().is_some()); if params_count_excluding_self == 0 { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index ccd4bc9be84a..5d5d43539822 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -4,28 +4,18 @@ EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind, db::ExpandDatabase, }; -use la_arena::ArenaMap; use triomphe::Arc; use crate::{ - AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, - EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, - FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, - MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, - ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, - TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, + AnonConstId, AnonConstLoc, AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, + EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, + ExternCrateLoc, FunctionId, FunctionLoc, ImplId, ImplLoc, Macro2Id, Macro2Loc, MacroExpander, + MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, + StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, + UnionLoc, UseId, UseLoc, attrs::AttrFlags, - expr_store::{ - Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes, - }, - hir::generics::GenericParams, - import_map::ImportMap, item_tree::{ItemTree, file_item_tree_query}, nameres::crate_def_map, - signatures::{ - ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, - StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, - }, visibility::{self, Visibility}, }; @@ -61,6 +51,9 @@ pub trait InternDatabase: RootQueryDb { #[salsa::interned] fn intern_static(&self, loc: StaticLoc) -> StaticId; + #[salsa::interned] + fn intern_anon_const(&self, loc: AnonConstLoc) -> AnonConstId; + #[salsa::interned] fn intern_trait(&self, loc: TraitLoc) -> TraitId; @@ -96,151 +89,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { /// Computes an [`ItemTree`] for the given file or macro expansion. #[salsa::invoke(file_item_tree_query)] #[salsa::transparent] - fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree; + fn file_item_tree(&self, file_id: HirFileId, krate: Crate) -> &ItemTree; /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution. #[salsa::invoke(macro_def)] fn macro_def(&self, m: MacroId) -> MacroDefId; - // region:data - - #[salsa::tracked] - fn trait_signature(&self, trait_: TraitId) -> Arc { - self.trait_signature_with_source_map(trait_).0 - } - - #[salsa::tracked] - fn impl_signature(&self, impl_: ImplId) -> Arc { - self.impl_signature_with_source_map(impl_).0 - } - - #[salsa::tracked] - fn struct_signature(&self, struct_: StructId) -> Arc { - self.struct_signature_with_source_map(struct_).0 - } - - #[salsa::tracked] - fn union_signature(&self, union_: UnionId) -> Arc { - self.union_signature_with_source_map(union_).0 - } - - #[salsa::tracked] - fn enum_signature(&self, e: EnumId) -> Arc { - self.enum_signature_with_source_map(e).0 - } - - #[salsa::tracked] - fn const_signature(&self, e: ConstId) -> Arc { - self.const_signature_with_source_map(e).0 - } - - #[salsa::tracked] - fn static_signature(&self, e: StaticId) -> Arc { - self.static_signature_with_source_map(e).0 - } - - #[salsa::tracked] - fn function_signature(&self, e: FunctionId) -> Arc { - self.function_signature_with_source_map(e).0 - } - - #[salsa::tracked] - fn type_alias_signature(&self, e: TypeAliasId) -> Arc { - self.type_alias_signature_with_source_map(e).0 - } - - #[salsa::invoke(TraitSignature::query)] - fn trait_signature_with_source_map( - &self, - trait_: TraitId, - ) -> (Arc, Arc); - - #[salsa::invoke(ImplSignature::query)] - fn impl_signature_with_source_map( - &self, - impl_: ImplId, - ) -> (Arc, Arc); - - #[salsa::invoke(StructSignature::query)] - fn struct_signature_with_source_map( - &self, - struct_: StructId, - ) -> (Arc, Arc); - - #[salsa::invoke(UnionSignature::query)] - fn union_signature_with_source_map( - &self, - union_: UnionId, - ) -> (Arc, Arc); - - #[salsa::invoke(EnumSignature::query)] - fn enum_signature_with_source_map( - &self, - e: EnumId, - ) -> (Arc, Arc); - - #[salsa::invoke(ConstSignature::query)] - fn const_signature_with_source_map( - &self, - e: ConstId, - ) -> (Arc, Arc); - - #[salsa::invoke(StaticSignature::query)] - fn static_signature_with_source_map( - &self, - e: StaticId, - ) -> (Arc, Arc); - - #[salsa::invoke(FunctionSignature::query)] - fn function_signature_with_source_map( - &self, - e: FunctionId, - ) -> (Arc, Arc); - - #[salsa::invoke(TypeAliasSignature::query)] - fn type_alias_signature_with_source_map( - &self, - e: TypeAliasId, - ) -> (Arc, Arc); - - // endregion:data - - #[salsa::invoke(Body::body_with_source_map_query)] - #[salsa::lru(512)] - fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc, Arc); - - #[salsa::invoke(Body::body_query)] - fn body(&self, def: DefWithBodyId) -> Arc; - - #[salsa::invoke(ExprScopes::expr_scopes_query)] - fn expr_scopes(&self, def: DefWithBodyId) -> Arc; - - #[salsa::transparent] - #[salsa::invoke(GenericParams::new)] - fn generic_params(&self, def: GenericDefId) -> Arc; - - #[salsa::transparent] - #[salsa::invoke(GenericParams::generic_params_and_store)] - fn generic_params_and_store( - &self, - def: GenericDefId, - ) -> (Arc, Arc); - - #[salsa::transparent] - #[salsa::invoke(GenericParams::generic_params_and_store_and_source_map)] - fn generic_params_and_store_and_source_map( - &self, - def: GenericDefId, - ) -> (Arc, Arc, Arc); - - #[salsa::invoke(ImportMap::import_map_query)] - fn import_map(&self, krate: Crate) -> Arc; - // region:visibilities - #[salsa::invoke(visibility::field_visibilities_query)] - fn field_visibilities(&self, var: VariantId) -> Arc>; - #[salsa::invoke(visibility::assoc_visibility_query)] fn assoc_visibility(&self, def: AssocItemId) -> Visibility; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index 1ce4c881e7ea..ca523622ec84 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -9,10 +9,7 @@ #[cfg(test)] mod tests; -use std::{ - ops::{Deref, Index}, - sync::LazyLock, -}; +use std::ops::{Deref, Index}; use cfg::{CfgExpr, CfgOptions}; use either::Either; @@ -23,11 +20,10 @@ use span::{Edition, SyntaxContext}; use syntax::{AstPtr, SyntaxNodePtr, ast}; use thin_vec::ThinVec; -use triomphe::Arc; use tt::TextRange; use crate::{ - BlockId, SyntheticSyntax, + AdtId, BlockId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, db::DefDatabase, expr_store::path::Path, hir::{ @@ -35,6 +31,7 @@ PatId, RecordFieldPat, RecordSpread, Statement, }, nameres::{DefMap, block_def_map}, + signatures::VariantFields, type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId}, }; @@ -94,9 +91,26 @@ pub(crate) fn is_root(self) -> bool { pub type LifetimePtr = AstPtr; pub type LifetimeSource = InFile; +/// Describes where a const expression originated from. +/// +/// Used by signature/body inference to determine the expected type for each +/// const expression root. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum RootExprOrigin { + /// Array length expression: `[T; ]` — expected type is `usize`. + ArrayLength, + /// Const parameter default value: `const N: usize = `. + ConstParam(crate::hir::generics::LocalTypeOrConstParamId), + /// Const generic argument in a path: `SomeType::<{ }>` or `some_fn::<{ }>()`. + /// Determining the expected type requires path resolution, so it is deferred. + GenericArgsPath, + /// The root expression of a body. + BodyRoot, +} + // We split the store into types-only and expressions, because most stores (e.g. generics) // don't store any expressions and this saves memory. Same thing for the source map. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] struct ExpressionOnlyStore { exprs: Arena, pats: Arena, @@ -113,9 +127,12 @@ struct ExpressionOnlyStore { /// Expressions (and destructuing patterns) that can be recorded here are single segment path, although not all single segments path refer /// to variables and have hygiene (some refer to items, we don't know at this stage). ident_hygiene: FxHashMap, + + /// Maps expression roots to their origin. + expr_roots: SmallVec<[(ExprId, RootExprOrigin); 1]>, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ExpressionStore { expr_only: Option>, pub types: Arena, @@ -226,6 +243,7 @@ pub struct ExpressionStoreBuilder { pub types: Arena, block_scopes: Vec, ident_hygiene: FxHashMap, + pub inference_roots: Option>, // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected). @@ -297,6 +315,7 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { mut bindings, mut binding_owners, mut ident_hygiene, + inference_roots: mut expr_roots, mut types, mut lifetimes, @@ -356,6 +375,9 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { let store = { let expr_only = if has_exprs { + if let Some(const_expr_origins) = &mut expr_roots { + const_expr_origins.shrink_to_fit(); + } Some(Box::new(ExpressionOnlyStore { exprs, pats, @@ -364,6 +386,7 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { binding_owners, block_scopes: block_scopes.into_boxed_slice(), ident_hygiene, + expr_roots: expr_roots.unwrap_or_default(), })) } else { None @@ -404,13 +427,108 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { } impl ExpressionStore { - pub fn empty_singleton() -> (Arc, Arc) { - static EMPTY: LazyLock<(Arc, Arc)> = - LazyLock::new(|| { - let (store, source_map) = ExpressionStoreBuilder::default().finish(); - (Arc::new(store), Arc::new(source_map)) - }); - EMPTY.clone() + pub fn of(db: &dyn DefDatabase, def: ExpressionStoreOwnerId) -> &ExpressionStore { + match def { + ExpressionStoreOwnerId::Signature(def) => { + use crate::signatures::{ + ConstSignature, EnumSignature, FunctionSignature, ImplSignature, + StaticSignature, StructSignature, TraitSignature, TypeAliasSignature, + UnionSignature, + }; + match def { + GenericDefId::AdtId(AdtId::EnumId(id)) => &EnumSignature::of(db, id).store, + GenericDefId::AdtId(AdtId::StructId(id)) => &StructSignature::of(db, id).store, + GenericDefId::AdtId(AdtId::UnionId(id)) => &UnionSignature::of(db, id).store, + GenericDefId::ConstId(id) => &ConstSignature::of(db, id).store, + GenericDefId::FunctionId(id) => &FunctionSignature::of(db, id).store, + GenericDefId::ImplId(id) => &ImplSignature::of(db, id).store, + GenericDefId::StaticId(id) => &StaticSignature::of(db, id).store, + GenericDefId::TraitId(id) => &TraitSignature::of(db, id).store, + GenericDefId::TypeAliasId(id) => &TypeAliasSignature::of(db, id).store, + } + } + ExpressionStoreOwnerId::Body(body) => &Body::of(db, body).store, + ExpressionStoreOwnerId::VariantFields(variant_id) => { + &VariantFields::of(db, variant_id).store + } + } + } + + pub fn with_source_map( + db: &dyn DefDatabase, + def: ExpressionStoreOwnerId, + ) -> (&ExpressionStore, &ExpressionStoreSourceMap) { + match def { + ExpressionStoreOwnerId::Signature(def) => { + use crate::signatures::{ + ConstSignature, EnumSignature, FunctionSignature, ImplSignature, + StaticSignature, StructSignature, TraitSignature, TypeAliasSignature, + UnionSignature, + }; + match def { + GenericDefId::AdtId(AdtId::EnumId(id)) => { + let sig = EnumSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::AdtId(AdtId::StructId(id)) => { + let sig = StructSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::AdtId(AdtId::UnionId(id)) => { + let sig = UnionSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::ConstId(id) => { + let sig = ConstSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::FunctionId(id) => { + let sig = FunctionSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::ImplId(id) => { + let sig = ImplSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::StaticId(id) => { + let sig = StaticSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::TraitId(id) => { + let sig = TraitSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::TypeAliasId(id) => { + let sig = TypeAliasSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + } + } + ExpressionStoreOwnerId::Body(body) => { + let (store, sm) = Body::with_source_map(db, body); + (&store.store, &sm.store) + } + ExpressionStoreOwnerId::VariantFields(variant_id) => { + let (store, sm) = VariantFields::with_source_map(db, variant_id); + (&store.store, sm) + } + } + } + + /// Returns all expression root `ExprId`s found in this store. + pub fn expr_roots(&self) -> impl Iterator { + self.const_expr_origins().iter().map(|&(id, _)| id) + } + + /// Like [`Self::signature_const_expr_roots`], but also returns the origin + /// of each expression. + pub fn expr_roots_with_origins(&self) -> impl Iterator { + self.const_expr_origins().iter().map(|&(id, origin)| (id, origin)) + } + + /// Returns the map of const expression roots to their origins. + pub fn const_expr_origins(&self) -> &[(ExprId, RootExprOrigin)] { + self.expr_only.as_ref().map_or(&[], |it| &it.expr_roots) } /// Returns an iterator over all block expressions in this store that define inner items. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs index c955393b9cf2..0c8320369f66 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs @@ -29,8 +29,6 @@ pub struct Body { /// empty. pub params: Box<[PatId]>, pub self_param: Option, - /// The `ExprId` of the actual body expression. - pub body_expr: ExprId, } impl ops::Deref for Body { @@ -68,11 +66,10 @@ fn deref(&self) -> &Self::Target { } } +#[salsa::tracked] impl Body { - pub(crate) fn body_with_source_map_query( - db: &dyn DefDatabase, - def: DefWithBodyId, - ) -> (Arc, Arc) { + #[salsa::tracked(lru = 512, returns(ref))] + pub fn with_source_map(db: &dyn DefDatabase, def: DefWithBodyId) -> (Arc, BodySourceMap) { let _p = tracing::info_span!("body_with_source_map_query").entered(); let mut params = None; @@ -99,18 +96,25 @@ pub(crate) fn body_with_source_map_query( DefWithBodyId::VariantId(v) => { let s = v.lookup(db); let src = s.source(db); - src.map(|it| it.expr()) + src.map(|it| it.const_arg()?.expr()) } } }; let module = def.module(db); let (body, source_map) = lower_body(db, def, file_id, module, params, body, is_async_fn); - (Arc::new(body), Arc::new(source_map)) + (Arc::new(body), source_map) } - pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { - db.body_with_source_map(def).0 + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { + Self::with_source_map(db, def).0.clone() + } +} + +impl Body { + pub fn root_expr(&self) -> ExprId { + self.store.expr_roots().next().unwrap() } pub fn pretty_print( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index d34ec9bbc182..2fffa02c1314 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -14,7 +14,6 @@ use span::{AstIdMap, SyntaxContext}; use syntax::ast::HasAttrs; use syntax::{AstNode, Parse, ast}; -use triomphe::Arc; use tt::TextRange; use crate::{ @@ -23,21 +22,21 @@ }; #[derive(Debug)] -pub(super) struct Expander { +pub(super) struct Expander<'db> { span_map: SpanMap, current_file_id: HirFileId, - ast_id_map: Arc, + ast_id_map: &'db AstIdMap, /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached. recursion_depth: u32, recursion_limit: usize, } -impl Expander { +impl<'db> Expander<'db> { pub(super) fn new( - db: &dyn DefDatabase, + db: &'db dyn DefDatabase, current_file_id: HirFileId, - def_map: &DefMap, - ) -> Expander { + def_map: &'db DefMap, + ) -> Expander<'db> { let recursion_limit = def_map.recursion_limit() as usize; let recursion_limit = if cfg!(test) { // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug @@ -77,12 +76,12 @@ pub(super) fn is_cfg_enabled( pub(super) fn enter_expand( &mut self, - db: &dyn DefDatabase, + db: &'db dyn DefDatabase, macro_call: ast::MacroCall, krate: Crate, resolver: impl Fn(&ModPath) -> Option, eager_callback: EagerCallBackFn<'_>, - ) -> Result>)>>, UnresolvedMacro> { + ) -> Result, Option>)>>, UnresolvedMacro> { // FIXME: within_limit should support this, instead of us having to extract the error let mut unresolved_macro_err = None; @@ -130,13 +129,13 @@ pub(super) fn enter_expand( pub(super) fn enter_expand_id( &mut self, - db: &dyn DefDatabase, + db: &'db dyn DefDatabase, call_id: MacroCallId, - ) -> ExpandResult>)>> { + ) -> ExpandResult, Option>)>> { self.within_limit(db, |_this| ExpandResult::ok(Some(call_id))) } - pub(super) fn exit(&mut self, Mark { file_id, span_map, ast_id_map, mut bomb }: Mark) { + pub(super) fn exit(&mut self, Mark { file_id, span_map, ast_id_map, mut bomb }: Mark<'db>) { self.span_map = span_map; self.current_file_id = file_id; self.ast_id_map = ast_id_map; @@ -162,9 +161,9 @@ pub(super) fn current_file_id(&self) -> HirFileId { fn within_limit( &mut self, - db: &dyn DefDatabase, + db: &'db dyn DefDatabase, op: F, - ) -> ExpandResult>)>> + ) -> ExpandResult, Option>)>> where F: FnOnce(&mut Self) -> ExpandResult>, { @@ -219,7 +218,7 @@ fn within_limit( #[inline] pub(super) fn ast_id_map(&self) -> &AstIdMap { - &self.ast_id_map + self.ast_id_map } #[inline] @@ -229,9 +228,9 @@ pub(super) fn span_map(&self) -> SpanMapRef<'_> { } #[derive(Debug)] -pub(super) struct Mark { +pub(super) struct Mark<'db> { file_id: HirFileId, span_map: SpanMap, - ast_id_map: Arc, + ast_id_map: &'db AstIdMap, bomb: DropBomb, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 1cecd1976b40..74006c603703 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -18,6 +18,7 @@ }; use intern::{Symbol, sym}; use rustc_hash::FxHashMap; +use smallvec::smallvec; use stdx::never; use syntax::{ AstNode, AstPtr, SyntaxNodePtr, @@ -28,7 +29,6 @@ }, }; use thin_vec::ThinVec; -use triomphe::Arc; use tt::TextRange; use crate::{ @@ -39,7 +39,7 @@ expr_store::{ Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr, - PatPtr, TypePtr, + PatPtr, RootExprOrigin, TypePtr, expander::Expander, lower::generics::ImplTraitLowerFn, path::{AssociatedTypeBinding, GenericArg, GenericArgs, GenericArgsParentheses, Path}, @@ -53,6 +53,7 @@ item_tree::FieldsShape, lang_item::{LangItemTarget, LangItems}, nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map}, + signatures::StructSignature, type_ref::{ ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef, @@ -79,7 +80,7 @@ pub(super) fn lower_body( let mut self_param = None; let mut source_map_self_param = None; let mut params = vec![]; - let mut collector = ExprCollector::new(db, module, current_file_id); + let mut collector = ExprCollector::body(db, module, current_file_id); let skip_body = AttrFlags::query( db, @@ -117,9 +118,10 @@ pub(super) fn lower_body( params = (0..count).map(|_| collector.missing_pat()).collect(); }; let body_expr = collector.missing_expr(); + collector.store.inference_roots = Some(smallvec![(body_expr, RootExprOrigin::BodyRoot)]); let (store, source_map) = collector.store.finish(); return ( - Body { store, params: params.into_boxed_slice(), self_param, body_expr }, + Body { store, params: params.into_boxed_slice(), self_param }, BodySourceMap { self_param: source_map_self_param, store: source_map }, ); } @@ -173,10 +175,11 @@ pub(super) fn lower_body( } }, ); + collector.store.inference_roots = Some(smallvec![(body_expr, RootExprOrigin::BodyRoot)]); let (store, source_map) = collector.store.finish(); ( - Body { store, params: params.into_boxed_slice(), self_param, body_expr }, + Body { store, params: params.into_boxed_slice(), self_param }, BodySourceMap { self_param: source_map_self_param, store: source_map }, ) } @@ -186,7 +189,7 @@ pub(crate) fn lower_type_ref( module: ModuleId, type_ref: InFile>, ) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) { - let mut expr_collector = ExprCollector::new(db, module, type_ref.file_id); + let mut expr_collector = ExprCollector::signature(db, module, type_ref.file_id); let type_ref = expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator); let (store, source_map) = expr_collector.store.finish(); @@ -200,13 +203,13 @@ pub(crate) fn lower_generic_params( file_id: HirFileId, param_list: Option, where_clause: Option, -) -> (Arc, Arc, ExpressionStoreSourceMap) { - let mut expr_collector = ExprCollector::new(db, module, file_id); +) -> (ExpressionStore, GenericParams, ExpressionStoreSourceMap) { + let mut expr_collector = ExprCollector::signature(db, module, file_id); let mut collector = generics::GenericParamsCollector::new(def); collector.lower(&mut expr_collector, param_list, where_clause); let params = collector.finish(); let (store, source_map) = expr_collector.store.finish(); - (Arc::new(store), params, source_map) + (store, params, source_map) } pub(crate) fn lower_impl( @@ -214,8 +217,8 @@ pub(crate) fn lower_impl( module: ModuleId, impl_syntax: InFile, impl_id: ImplId, -) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option, Arc) { - let mut expr_collector = ExprCollector::new(db, module, impl_syntax.file_id); +) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option, GenericParams) { + let mut expr_collector = ExprCollector::signature(db, module, impl_syntax.file_id); let self_ty = expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty()); let trait_ = impl_syntax.value.trait_().and_then(|it| match &it { @@ -242,8 +245,8 @@ pub(crate) fn lower_trait( module: ModuleId, trait_syntax: InFile, trait_id: TraitId, -) -> (ExpressionStore, ExpressionStoreSourceMap, Arc) { - let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id); +) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams) { + let mut expr_collector = ExprCollector::signature(db, module, trait_syntax.file_id); let mut collector = generics::GenericParamsCollector::with_self_param( &mut expr_collector, trait_id.into(), @@ -264,14 +267,9 @@ pub(crate) fn lower_type_alias( module: ModuleId, alias: InFile, type_alias_id: TypeAliasId, -) -> ( - ExpressionStore, - ExpressionStoreSourceMap, - Arc, - Box<[TypeBound]>, - Option, -) { - let mut expr_collector = ExprCollector::new(db, module, alias.file_id); +) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams, Box<[TypeBound]>, Option) +{ + let mut expr_collector = ExprCollector::signature(db, module, alias.file_id); let bounds = alias .value .type_bound_list() @@ -307,13 +305,13 @@ pub(crate) fn lower_function( ) -> ( ExpressionStore, ExpressionStoreSourceMap, - Arc, + GenericParams, Box<[TypeRefId]>, Option, bool, bool, ) { - let mut expr_collector = ExprCollector::new(db, module, fn_.file_id); + let mut expr_collector = ExprCollector::signature(db, module, fn_.file_id); let mut collector = generics::GenericParamsCollector::new(function_id.into()); collector.lower(&mut expr_collector, fn_.value.generic_param_list(), fn_.value.where_clause()); let mut params = vec![]; @@ -419,7 +417,7 @@ pub(crate) fn lower_function( pub struct ExprCollector<'db> { db: &'db dyn DefDatabase, cfg_options: &'db CfgOptions, - expander: Expander, + expander: Expander<'db>, def_map: &'db DefMap, local_def_map: &'db LocalDefMap, module: ModuleId, @@ -532,7 +530,20 @@ fn check_is_used(&mut self, ec: &mut ExprCollector<'_>, id: BindingId) { } impl<'db> ExprCollector<'db> { - pub fn new( + /// Creates a collector for a signature store, this will populate `const_expr_origins` to any + /// top level const arg roots. + pub fn signature( + db: &dyn DefDatabase, + module: ModuleId, + current_file_id: HirFileId, + ) -> ExprCollector<'_> { + let mut this = Self::body(db, module, current_file_id); + this.store.inference_roots = Some(Default::default()); + this + } + + /// Creates a collector for a bidy store. + pub fn body( db: &dyn DefDatabase, module: ModuleId, current_file_id: HirFileId, @@ -577,7 +588,10 @@ pub(crate) fn span_map(&self) -> SpanMapRef<'_> { self.expander.span_map() } - pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId { + pub(in crate::expr_store) fn lower_lifetime_ref( + &mut self, + lifetime: ast::Lifetime, + ) -> LifetimeRefId { // FIXME: Keyword check? let lifetime_ref = match &*lifetime.text() { "" | "'" => LifetimeRef::Error, @@ -588,7 +602,10 @@ pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId { self.alloc_lifetime_ref(lifetime_ref, AstPtr::new(&lifetime)) } - pub fn lower_lifetime_ref_opt(&mut self, lifetime: Option) -> LifetimeRefId { + pub(in crate::expr_store) fn lower_lifetime_ref_opt( + &mut self, + lifetime: Option, + ) -> LifetimeRefId { match lifetime { Some(lifetime) => self.lower_lifetime_ref(lifetime), None => self.alloc_lifetime_ref_desugared(LifetimeRef::Placeholder), @@ -596,7 +613,7 @@ pub fn lower_lifetime_ref_opt(&mut self, lifetime: Option) -> Lif } /// Converts an `ast::TypeRef` to a `hir::TypeRef`. - pub fn lower_type_ref( + pub(in crate::expr_store) fn lower_type_ref( &mut self, node: ast::Type, impl_trait_lower_fn: ImplTraitLowerFn<'_>, @@ -621,6 +638,9 @@ pub fn lower_type_ref( } ast::Type::ArrayType(inner) => { let len = self.lower_const_arg_opt(inner.const_arg()); + if let Some(const_expr_origins) = &mut self.store.inference_roots { + const_expr_origins.push((len.expr, RootExprOrigin::ArrayLength)); + } TypeRef::Array(ArrayType { ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn), len, @@ -810,7 +830,7 @@ fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId { /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). - pub fn lower_generic_args_from_fn_path( + pub(in crate::expr_store) fn lower_generic_args_from_fn_path( &mut self, args: Option, ret_type: Option, @@ -905,6 +925,9 @@ pub(super) fn lower_generic_args( } ast::GenericArg::ConstArg(arg) => { let arg = self.lower_const_arg(arg); + if let Some(const_expr_origins) = &mut self.store.inference_roots { + const_expr_origins.push((arg.expr, RootExprOrigin::GenericArgsPath)); + } args.push(GenericArg::Const(arg)) } } @@ -1045,17 +1068,30 @@ fn lower_type_bound( } fn lower_const_arg_opt(&mut self, arg: Option) -> ConstRef { - ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) } + let const_expr_origins = self.store.inference_roots.take(); + let r = ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) }; + self.store.inference_roots = const_expr_origins; + r } - fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef { - ConstRef { expr: self.collect_expr_opt(arg.expr()) } + pub fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef { + let const_expr_origins = self.store.inference_roots.take(); + let r = ConstRef { expr: self.collect_expr_opt(arg.expr()) }; + self.store.inference_roots = const_expr_origins; + r } fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr()) } + pub(in crate::expr_store) fn collect_expr_opt(&mut self, expr: Option) -> ExprId { + match expr { + Some(expr) => self.collect_expr(expr), + None => self.missing_expr(), + } + } + /// Returns `None` if and only if the expression is `#[cfg]`d out. fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option { let syntax_ptr = AstPtr::new(&expr); @@ -2065,13 +2101,6 @@ fn collect_macro_call( } } - pub fn collect_expr_opt(&mut self, expr: Option) -> ExprId { - match expr { - Some(expr) => self.collect_expr(expr), - None => self.missing_expr(), - } - } - fn collect_macro_as_stmt( &mut self, statements: &mut Vec, @@ -2332,7 +2361,7 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI } Some(ModuleDefId::AdtId(AdtId::StructId(s))) // FIXME: This can cause a cycle if the user is writing invalid code - if self.db.struct_signature(s).shape != FieldsShape::Record => + if StructSignature::of(self.db, s).shape != FieldsShape::Record => { (None, Pat::Path(name.into())) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs index c570df42b2f6..5ffc4f5851d3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs @@ -3,15 +3,12 @@ //! generic parameters. See also the `Generics` type and the `generics_of` query //! in rustc. -use std::sync::LazyLock; - use either::Either; use hir_expand::name::{AsName, Name}; use intern::sym; use la_arena::Arena; use syntax::ast::{self, HasName, HasTypeBounds}; use thin_vec::ThinVec; -use triomphe::Arc; use crate::{ GenericDefId, TypeOrConstParamId, TypeParamId, @@ -84,28 +81,16 @@ pub(crate) fn collect_impl_trait( ) } - pub(crate) fn finish(self) -> Arc { - let Self { mut lifetimes, mut type_or_consts, mut where_predicates, parent: _ } = self; - - if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() { - static EMPTY: LazyLock> = LazyLock::new(|| { - Arc::new(GenericParams { - lifetimes: Arena::new(), - type_or_consts: Arena::new(), - where_predicates: Box::default(), - }) - }); - return Arc::clone(&EMPTY); - } + pub(crate) fn finish(self) -> GenericParams { + let Self { mut lifetimes, mut type_or_consts, where_predicates, parent: _ } = self; lifetimes.shrink_to_fit(); type_or_consts.shrink_to_fit(); - where_predicates.shrink_to_fit(); - Arc::new(GenericParams { + GenericParams { type_or_consts, lifetimes, where_predicates: where_predicates.into_boxed_slice(), - }) + } } fn lower_param_list(&mut self, ec: &mut ExprCollector<'_>, params: ast::GenericParamList) { @@ -141,12 +126,17 @@ fn lower_param_list(&mut self, ec: &mut ExprCollector<'_>, params: ast::GenericP const_param.ty(), &mut ExprCollector::impl_trait_error_allocator, ); - let param = ConstParamData { - name, - ty, - default: const_param.default_val().map(|it| ec.lower_const_arg(it)), - }; - let _idx = self.type_or_consts.alloc(param.into()); + let default = const_param.default_val().map(|it| ec.lower_const_arg(it)); + let param = ConstParamData { name, ty, default }; + let idx = self.type_or_consts.alloc(param.into()); + if let Some(default) = default + && let Some(const_expr_origins) = &mut ec.store.inference_roots + { + const_expr_origins.push(( + default.expr, + crate::expr_store::RootExprOrigin::ConstParam(idx), + )); + } } ast::GenericParam::LifetimeParam(lifetime_param) => { let lifetime = ec.lower_lifetime_ref_opt(lifetime_param.lifetime()); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs index f507841a91bf..6819eb3deb57 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs @@ -21,7 +21,7 @@ fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option) { let (db, file_id) = TestDB::with_single_file(""); let krate = db.fetch_test_crate(); let mut ctx = - ExprCollector::new(&db, crate_def_map(&db, krate).root_module_id(), file_id.into()); + ExprCollector::signature(&db, crate_def_map(&db, krate).root_module_id(), file_id.into()); let lowered_path = ctx.lower_path(path, &mut ExprCollector::impl_trait_allocator); let (store, _) = ctx.store.finish(); (db, store, lowered_path) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index 35f3cd114e36..9c9c4db3b208 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -105,7 +105,7 @@ pub fn print_body_hir( p.buf.push(')'); p.buf.push(' '); } - p.print_expr(body.body_expr); + p.print_expr(body.root_expr()); if matches!(owner, DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_)) { p.buf.push(';'); } @@ -168,8 +168,8 @@ pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Editi match owner { GenericDefId::AdtId(id) => match id { AdtId::StructId(id) => { - let signature = db.struct_signature(id); - print_struct(db, id, &signature, edition) + let signature = StructSignature::of(db, id); + print_struct(db, id, signature, edition) } AdtId::UnionId(id) => { format!("unimplemented {id:?}") @@ -180,8 +180,8 @@ pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Editi }, GenericDefId::ConstId(id) => format!("unimplemented {id:?}"), GenericDefId::FunctionId(id) => { - let signature = db.function_signature(id); - print_function(db, id, &signature, edition) + let signature = FunctionSignature::of(db, id); + print_function(db, id, signature, edition) } GenericDefId::ImplId(id) => format!("unimplemented {id:?}"), GenericDefId::StaticId(id) => format!("unimplemented {id:?}"), @@ -1212,7 +1212,7 @@ pub(crate) fn print_generic_arg(&mut self, arg: &GenericArg) { } pub(crate) fn print_type_param(&mut self, param: TypeParamId) { - let generic_params = self.db.generic_params(param.parent()); + let generic_params = GenericParams::of(self.db, param.parent()); match generic_params[param.local_id()].name() { Some(name) => w!(self, "{}", name.display(self.db, self.edition)), @@ -1221,7 +1221,7 @@ pub(crate) fn print_type_param(&mut self, param: TypeParamId) { } pub(crate) fn print_lifetime_param(&mut self, param: LifetimeParamId) { - let generic_params = self.db.generic_params(param.parent); + let generic_params = GenericParams::of(self.db, param.parent); w!(self, "{}", generic_params[param.local_id].name.display(self.db, self.edition)) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs index 1952dae9d71a..40ae0b7de462 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs @@ -1,13 +1,16 @@ //! Name resolution for expressions. use hir_expand::{MacroDefId, name::Name}; use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx}; -use triomphe::Arc; use crate::{ - BlockId, DefWithBodyId, + BlockId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, VariantId, db::DefDatabase, expr_store::{Body, ExpressionStore, HygieneId}, - hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement}, + hir::{ + Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement, + generics::GenericParams, + }, + signatures::VariantFields, }; pub type ScopeId = Idx; @@ -50,12 +53,45 @@ pub struct ScopeData { entries: IdxRange, } +#[salsa::tracked] impl ExprScopes { - pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { - let body = db.body(def); - let mut scopes = ExprScopes::new_body(&body); + #[salsa::tracked(returns(ref))] + pub fn body_expr_scopes(db: &dyn DefDatabase, def: DefWithBodyId) -> ExprScopes { + let body = Body::of(db, def); + let mut scopes = ExprScopes::new_body(body); scopes.shrink_to_fit(); - Arc::new(scopes) + scopes + } + + #[salsa::tracked(returns(ref))] + pub fn sig_expr_scopes(db: &dyn DefDatabase, def: GenericDefId) -> ExprScopes { + let (_, store) = GenericParams::with_store(db, def); + let roots = store.expr_roots(); + let mut scopes = ExprScopes::new_store(store, roots); + scopes.shrink_to_fit(); + scopes + } + + #[salsa::tracked(returns(ref))] + pub fn variant_scopes(db: &dyn DefDatabase, def: VariantId) -> ExprScopes { + let fields = VariantFields::of(db, def); + let roots = fields.store.expr_roots(); + let mut scopes = ExprScopes::new_store(&fields.store, roots); + scopes.shrink_to_fit(); + scopes + } +} + +impl ExprScopes { + #[inline] + pub fn of(db: &dyn DefDatabase, def: impl Into) -> &ExprScopes { + match def.into() { + ExpressionStoreOwnerId::Body(def) => Self::body_expr_scopes(db, def), + ExpressionStoreOwnerId::Signature(def) => Self::sig_expr_scopes(db, def), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + Self::variant_scopes(db, variant_id) + } + } } pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { @@ -115,7 +151,23 @@ fn new_body(body: &Body) -> ExprScopes { scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param)); } scopes.add_params_bindings(body, root, &body.params); - compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); + compute_expr_scopes(body.root_expr(), body, &mut scopes, &mut root); + scopes + } + + fn new_store(store: &ExpressionStore, roots: impl IntoIterator) -> ExprScopes { + let mut scopes = ExprScopes { + scopes: Arena::default(), + scope_entries: Arena::default(), + scope_by_expr: ArenaMap::with_capacity( + store.expr_only.as_ref().map_or(0, |it| it.exprs.len()), + ), + }; + let root = scopes.root_scope(); + for root_expr in roots { + let mut scope = scopes.new_scope(root); + compute_expr_scopes(root_expr, store, &mut scopes, &mut scope); + } scopes } @@ -327,7 +379,10 @@ mod tests { use test_utils::{assert_eq_text, extract_offset}; use crate::{ - FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, test_db::TestDB, + DefWithBodyId, FunctionId, ModuleDefId, + expr_store::{Body, scope::ExprScopes}, + nameres::crate_def_map, + test_db::TestDB, }; fn find_function(db: &TestDB, file_id: FileId) -> FunctionId { @@ -363,8 +418,8 @@ fn do_check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &[&str]) let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap(); let function = find_function(&db, file_id); - let scopes = db.expr_scopes(function.into()); - let (_body, source_map) = db.body_with_source_map(function.into()); + let scopes = ExprScopes::of(&db, DefWithBodyId::from(function)); + let (_body, source_map) = Body::with_source_map(&db, function.into()); let expr_id = source_map .node_expr(InFile { file_id: editioned_file_id.into(), value: &marker.into() }) @@ -522,8 +577,8 @@ fn do_check_local_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected let function = find_function(&db, file_id); - let scopes = db.expr_scopes(function.into()); - let (_, source_map) = db.body_with_source_map(function.into()); + let scopes = ExprScopes::body_expr_scopes(&db, DefWithBodyId::from(function)); + let (_, source_map) = Body::with_source_map(&db, function.into()); let expr_scope = { let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs index 8f857aeeff95..985cd9666267 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs @@ -4,11 +4,10 @@ use expect_test::{Expect, expect}; use la_arena::RawIdx; use test_fixture::WithFixture; -use triomphe::Arc; use super::super::*; -fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc, DefWithBodyId) { +fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, DefWithBodyId) { let db = TestDB::with_files(ra_fixture); let krate = db.fetch_test_crate(); @@ -24,8 +23,27 @@ fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc, } let fn_def = fn_def.unwrap().into(); - let body = db.body(fn_def); - (db, body, fn_def) + Body::of(&db, fn_def); + (db, fn_def) +} + +fn pretty_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { + let db = TestDB::with_files(ra_fixture); + + let krate = db.fetch_test_crate(); + let def_map = crate_def_map(&db, krate); + let mut fn_def = None; + 'outer: for (_, module) in def_map.modules() { + for decl in module.scope.declarations() { + if let ModuleDefId::FunctionId(it) = decl { + fn_def = Some(it); + break 'outer; + } + } + } + let fn_def = fn_def.unwrap().into(); + + expect.assert_eq(&Body::of(&db, fn_def).pretty_print(&db, fn_def, Edition::CURRENT)); } fn def_map_at(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { @@ -144,7 +162,7 @@ fn outer() { #[test] fn desugar_for_loop() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: iterator fn main() { @@ -154,9 +172,7 @@ fn main() { } } "#, - ); - - expect![[r#" + expect![[r#" fn main() { match builtin#lang(into_iter)( 0..10, @@ -173,13 +189,13 @@ fn main() { } }, } - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ); } #[test] fn desugar_builtin_format_args_before_1_89_0() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: fmt_before_1_89_0 fn main() { @@ -188,9 +204,7 @@ fn main() { builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); } "#, - ); - - expect![[r#" + expect![[r#" fn main() { let are = "are"; let count = 10; @@ -256,13 +270,13 @@ fn main() { } }, ); - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn desugar_builtin_format_args_before_1_93_0() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: fmt_before_1_93_0 fn main() { @@ -271,9 +285,7 @@ fn main() { builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); } "#, - ); - - expect![[r#" + expect![[r#" fn main() { let are = "are"; let count = 10; @@ -339,13 +351,13 @@ fn main() { ) } }; - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn desugar_builtin_format_args() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: fmt fn main() { @@ -356,9 +368,7 @@ fn main() { builtin#format_args("hello world", orphan = ()); } "#, - ); - - expect![[r#" + expect![[r#" fn main() { let are = "are"; let count = 10; @@ -392,13 +402,13 @@ fn main() { "hello world", ) }; - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn test_macro_hygiene() { - let (db, body, def) = lower( + pretty_print( r##" //- minicore: fmt, from //- /main.rs @@ -428,10 +438,7 @@ pub(crate) fn new(message: impl Into) -> SsrError { } } "##, - ); - - assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]); - expect![[r#" + expect![[r#" fn main() { _ = ra_test_fixture::error::SsrError::new( { @@ -449,13 +456,13 @@ fn main() { } }, ); - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn regression_10300() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: concat, panic, fmt_before_1_89_0 mod private { @@ -472,16 +479,7 @@ fn f(a: i32, b: u32) -> String { m!(); } "#, - ); - - let (_, source_map) = db.body_with_source_map(def); - assert_eq!(source_map.diagnostics(), &[]); - - for (_, def_map) in body.blocks(&db) { - assert_eq!(def_map.diagnostics(), &[]); - } - - expect![[r#" + expect![[r#" fn f(a, b) { { core::panicking::panic_fmt( @@ -497,8 +495,8 @@ fn f(a, b) { ), ); }; - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] @@ -507,7 +505,7 @@ fn destructuring_assignment_tuple_macro() { // but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring // assignments start their lives as expressions. So we have to do the same. - let (db, body, def) = lower( + pretty_print( r#" struct Bar(); @@ -519,25 +517,16 @@ fn foo() { m!()() = Bar(); } "#, - ); - - let (_, source_map) = db.body_with_source_map(def); - assert_eq!(source_map.diagnostics(), &[]); - - for (_, def_map) in body.blocks(&db) { - assert_eq!(def_map.diagnostics(), &[]); - } - - expect![[r#" + expect![[r#" fn foo() { Bar() = Bar(); - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn shadowing_record_variant() { - let (_, body, _) = lower( + let (db, def) = lower( r#" enum A { B { field: i32 }, @@ -550,6 +539,7 @@ fn f() { } "#, ); + let body = Body::of(&db, def); assert_eq!(body.assert_expr_only().bindings.len(), 1, "should have a binding for `B`"); assert_eq!( body[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(), @@ -560,39 +550,35 @@ fn f() { #[test] fn regression_pretty_print_bind_pat() { - let (db, body, owner) = lower( + pretty_print( r#" fn foo() { let v @ u = 123; } "#, - ); - let printed = body.pretty_print(&db, owner, Edition::CURRENT); - - expect![[r#" + expect![[r#" fn foo() { let v @ u = 123; - }"#]] - .assert_eq(&printed); + }"#]], + ); } #[test] fn skip_skips_body() { - let (db, body, owner) = lower( + pretty_print( r#" #[rust_analyzer::skip] async fn foo(a: (), b: i32) -> u32 { 0 + 1 + b() } "#, + expect!["fn foo(�, �) �"], ); - let printed = body.pretty_print(&db, owner, Edition::CURRENT); - expect!["fn foo(�, �) �"].assert_eq(&printed); } #[test] fn range_bounds_are_hir_exprs() { - let (_, body, _) = lower( + let (db, body) = lower( r#" pub const L: i32 = 6; mod x { @@ -607,6 +593,7 @@ const fn f(x: i32) -> i32 { }"#, ); + let body = Body::of(&db, body); let mtch_arms = body .assert_expr_only() .exprs @@ -635,7 +622,7 @@ const fn f(x: i32) -> i32 { #[test] fn print_hir_precedences() { - let (db, body, def) = lower( + pretty_print( r#" fn main() { _ = &(1 - (2 - 3) + 4 * 5 * (6 + 7)); @@ -646,9 +633,7 @@ fn main() { let _ = &mut (*r as i32) } "#, - ); - - expect![[r#" + expect![[r#" fn main() { _ = &((1 - (2 - 3)) + (4 * 5) * (6 + 7)); _ = 1 + 2 < 3 && true && 4 < 5 && (a || b || c) || d && e; @@ -656,24 +641,22 @@ fn main() { break a && b || (return) || (return 2); let r = &2; let _ = &mut (*r as i32); - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn async_fn_weird_param_patterns() { - let (db, body, def) = lower( + pretty_print( r#" async fn main(&self, param1: i32, ref mut param2: i32, _: i32, param4 @ _: i32, 123: i32) {} "#, - ); - - expect![[r#" + expect![[r#" fn main(self, param1, mut param2, mut 0, param4 @ _, mut 1) async { let ref mut param2 = param2; let _ = 0; let 123 = 1; {} - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs index d457a4ca7a3b..83594ee02169 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs @@ -196,7 +196,7 @@ fn f() { ), block: Some( BlockId( - 4401, + 4801, ), ), }"#]], diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs index f1db00cf6a67..5e0184dfad82 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs @@ -2,6 +2,7 @@ GenericDefId, ModuleDefId, expr_store::pretty::{print_function, print_struct}, nameres::crate_def_map, + signatures::{FunctionSignature, StructSignature}, test_db::TestDB, }; use expect_test::{Expect, expect}; @@ -41,7 +42,7 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe out += &print_struct( &db, struct_id, - &db.struct_signature(struct_id), + StructSignature::of(&db, struct_id), Edition::CURRENT, ); } @@ -53,7 +54,7 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe out += &print_function( &db, function_id, - &db.function_signature(function_id), + FunctionSignature::of(&db, function_id), Edition::CURRENT, ) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index 5d1cac8e93c4..830820369336 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -14,6 +14,7 @@ use crate::{ FindPathConfig, ModuleDefId, ModuleId, db::DefDatabase, + import_map::ImportMap, item_scope::ItemInNs, nameres::DefMap, visibility::{Visibility, VisibilityExplicitness}, @@ -426,7 +427,7 @@ fn find_in_dep( best_choice: &mut Option, dep: Crate, ) { - let import_map = ctx.db.import_map(dep); + let import_map = ImportMap::of(ctx.db, dep); let Some(import_info_for) = import_map.import_info_for(item) else { return; }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index 022f8adfdb06..43dd7d1c54cd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -5,12 +5,15 @@ use la_arena::{Arena, Idx, RawIdx}; use stdx::impl_from; use thin_vec::ThinVec; -use triomphe::Arc; use crate::{ AdtId, ConstParamId, GenericDefId, LifetimeParamId, TypeOrConstParamId, TypeParamId, db::DefDatabase, expr_store::{ExpressionStore, ExpressionStoreSourceMap}, + signatures::{ + ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, + StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, + }, type_ref::{ConstRef, LifetimeRefId, TypeBound, TypeRefId}, }; @@ -142,7 +145,7 @@ pub enum GenericParamDataRef<'a> { } /// Data about the generic parameters of a function, struct, impl, etc. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(PartialEq, Eq, Debug, Hash, Default)] pub struct GenericParams { pub(crate) type_or_consts: Arena, pub(crate) lifetimes: Arena, @@ -174,12 +177,10 @@ pub enum WherePredicate { ForLifetime { lifetimes: ThinVec, target: TypeRefId, bound: TypeBound }, } -static EMPTY: LazyLock> = LazyLock::new(|| { - Arc::new(GenericParams { - type_or_consts: Arena::default(), - lifetimes: Arena::default(), - where_predicates: Box::default(), - }) +static EMPTY: LazyLock = LazyLock::new(|| GenericParams { + type_or_consts: Arena::default(), + lifetimes: Arena::default(), + where_predicates: Box::default(), }); impl GenericParams { @@ -187,112 +188,94 @@ impl GenericParams { pub const SELF_PARAM_ID_IN_SELF: la_arena::Idx = LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); - pub fn new(db: &dyn DefDatabase, def: GenericDefId) -> Arc { + pub fn of(db: &dyn DefDatabase, def: GenericDefId) -> &GenericParams { + Self::with_store(db, def).0 + } + + pub fn with_store( + db: &dyn DefDatabase, + def: GenericDefId, + ) -> (&GenericParams, &ExpressionStore) { match def { - GenericDefId::AdtId(AdtId::EnumId(it)) => db.enum_signature(it).generic_params.clone(), - GenericDefId::AdtId(AdtId::StructId(it)) => { - db.struct_signature(it).generic_params.clone() + GenericDefId::AdtId(AdtId::EnumId(id)) => { + let sig = EnumSignature::of(db, id); + (&sig.generic_params, &sig.store) } - GenericDefId::AdtId(AdtId::UnionId(it)) => { - db.union_signature(it).generic_params.clone() + GenericDefId::AdtId(AdtId::StructId(id)) => { + let sig = StructSignature::of(db, id); + (&sig.generic_params, &sig.store) } - GenericDefId::ConstId(_) => EMPTY.clone(), - GenericDefId::FunctionId(function_id) => { - db.function_signature(function_id).generic_params.clone() + GenericDefId::AdtId(AdtId::UnionId(id)) => { + let sig = UnionSignature::of(db, id); + (&sig.generic_params, &sig.store) } - GenericDefId::ImplId(impl_id) => db.impl_signature(impl_id).generic_params.clone(), - GenericDefId::StaticId(_) => EMPTY.clone(), - GenericDefId::TraitId(trait_id) => db.trait_signature(trait_id).generic_params.clone(), - GenericDefId::TypeAliasId(type_alias_id) => { - db.type_alias_signature(type_alias_id).generic_params.clone() + GenericDefId::ConstId(id) => { + let sig = ConstSignature::of(db, id); + (&EMPTY, &sig.store) + } + GenericDefId::FunctionId(id) => { + let sig = FunctionSignature::of(db, id); + (&sig.generic_params, &sig.store) + } + GenericDefId::ImplId(id) => { + let sig = ImplSignature::of(db, id); + (&sig.generic_params, &sig.store) + } + GenericDefId::StaticId(id) => { + let sig = StaticSignature::of(db, id); + (&EMPTY, &sig.store) + } + GenericDefId::TraitId(id) => { + let sig = TraitSignature::of(db, id); + (&sig.generic_params, &sig.store) + } + GenericDefId::TypeAliasId(id) => { + let sig = TypeAliasSignature::of(db, id); + (&sig.generic_params, &sig.store) } } } - pub fn generic_params_and_store( + pub fn with_source_map( db: &dyn DefDatabase, def: GenericDefId, - ) -> (Arc, Arc) { + ) -> (&GenericParams, &ExpressionStore, &ExpressionStoreSourceMap) { match def { GenericDefId::AdtId(AdtId::EnumId(id)) => { - let sig = db.enum_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = EnumSignature::with_source_map(db, id); + (&sig.generic_params, &sig.store, sm) } GenericDefId::AdtId(AdtId::StructId(id)) => { - let sig = db.struct_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = StructSignature::with_source_map(db, id); + (&sig.generic_params, &sig.store, sm) } GenericDefId::AdtId(AdtId::UnionId(id)) => { - let sig = db.union_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = UnionSignature::with_source_map(db, id); + (&sig.generic_params, &sig.store, sm) } GenericDefId::ConstId(id) => { - let sig = db.const_signature(id); - (EMPTY.clone(), sig.store.clone()) + let (sig, sm) = ConstSignature::with_source_map(db, id); + (&EMPTY, &sig.store, sm) } GenericDefId::FunctionId(id) => { - let sig = db.function_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = FunctionSignature::with_source_map(db, id); + (&sig.generic_params, &sig.store, sm) } GenericDefId::ImplId(id) => { - let sig = db.impl_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = ImplSignature::with_source_map(db, id); + (&sig.generic_params, &sig.store, sm) } GenericDefId::StaticId(id) => { - let sig = db.static_signature(id); - (EMPTY.clone(), sig.store.clone()) + let (sig, sm) = StaticSignature::with_source_map(db, id); + (&EMPTY, &sig.store, sm) } GenericDefId::TraitId(id) => { - let sig = db.trait_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = TraitSignature::with_source_map(db, id); + (&sig.generic_params, &sig.store, sm) } GenericDefId::TypeAliasId(id) => { - let sig = db.type_alias_signature(id); - (sig.generic_params.clone(), sig.store.clone()) - } - } - } - - pub fn generic_params_and_store_and_source_map( - db: &dyn DefDatabase, - def: GenericDefId, - ) -> (Arc, Arc, Arc) { - match def { - GenericDefId::AdtId(AdtId::EnumId(id)) => { - let (sig, sm) = db.enum_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::AdtId(AdtId::StructId(id)) => { - let (sig, sm) = db.struct_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::AdtId(AdtId::UnionId(id)) => { - let (sig, sm) = db.union_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::ConstId(id) => { - let (sig, sm) = db.const_signature_with_source_map(id); - (EMPTY.clone(), sig.store.clone(), sm) - } - GenericDefId::FunctionId(id) => { - let (sig, sm) = db.function_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::ImplId(id) => { - let (sig, sm) = db.impl_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::StaticId(id) => { - let (sig, sm) = db.static_signature_with_source_map(id); - (EMPTY.clone(), sig.store.clone(), sm) - } - GenericDefId::TraitId(id) => { - let (sig, sm) = db.trait_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::TypeAliasId(id) => { - let (sig, sm) = db.type_alias_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) + let (sig, sm) = TypeAliasSignature::with_source_map(db, id); + (&sig.generic_params, &sig.store, sm) } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index 6c5d226cac1b..0014e1af5c0d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -10,7 +10,6 @@ use smallvec::SmallVec; use span::Edition; use stdx::format_to; -use triomphe::Arc; use crate::{ AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId, @@ -63,6 +62,14 @@ enum IsTraitAssocItem { type ImportMapIndex = FxIndexMap, IsTraitAssocItem)>; +#[salsa::tracked] +impl ImportMap { + #[salsa::tracked(returns(ref))] + pub fn of(db: &dyn DefDatabase, krate: Crate) -> Self { + Self::import_map_query_impl(db, krate) + } +} + impl ImportMap { pub fn dump(&self, db: &dyn DefDatabase) -> String { let mut out = String::new(); @@ -76,7 +83,7 @@ pub fn dump(&self, db: &dyn DefDatabase) -> String { out } - pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: Crate) -> Arc { + fn import_map_query_impl(db: &dyn DefDatabase, krate: Crate) -> Self { let _p = tracing::info_span!("import_map_query").entered(); let map = Self::collect_import_map(db, krate); @@ -120,7 +127,7 @@ pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: Crate) -> Arc } let importables = importables.into_iter().map(|(item, _, idx)| (item, idx)).collect(); - Arc::new(ImportMap { item_to_info_map: map, fst: builder.into_map(), importables }) + ImportMap { item_to_info_map: map, fst: builder.into_map(), importables } } pub fn import_info_for(&self, item: ItemInNs) -> Option<&[ImportInfo]> { @@ -424,7 +431,7 @@ pub fn search_dependencies( let _p = tracing::info_span!("search_dependencies", ?query).entered(); let import_maps: Vec<_> = - krate.data(db).dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); + krate.data(db).dependencies.iter().map(|dep| ImportMap::of(db, dep.crate_id)).collect(); let mut op = fst::map::OpBuilder::new(); @@ -458,7 +465,7 @@ pub fn search_dependencies( fn search_maps( _db: &dyn DefDatabase, - import_maps: &[Arc], + import_maps: &[&ImportMap], mut stream: fst::map::Union<'_>, query: &Query, ) -> FxHashSet<(ItemInNs, Complete)> { @@ -467,7 +474,7 @@ fn search_maps( for &IndexedValue { index: import_map_idx, value } in indexed_values { let end = (value & 0xFFFF_FFFF) as usize; let start = (value >> 32) as usize; - let ImportMap { item_to_info_map, importables, .. } = &*import_maps[import_map_idx]; + let ImportMap { item_to_info_map, importables, .. } = import_maps[import_map_idx]; let importables = &importables[start..end]; let iter = importables @@ -546,9 +553,9 @@ fn check_search( .into_iter() .filter_map(|(dependency, _)| { let dependency_krate = dependency.krate(&db)?; - let dependency_imports = db.import_map(dependency_krate); + let dependency_imports = ImportMap::of(&db, dependency_krate); - let (path, mark) = match assoc_item_path(&db, &dependency_imports, dependency) { + let (path, mark) = match assoc_item_path(&db, dependency_imports, dependency) { Some(assoc_item_path) => (assoc_item_path, "a"), None => ( render_path(&db, &dependency_imports.import_info_for(dependency)?[0]), @@ -618,7 +625,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let cdata = &krate.extra_data(&db); let name = cdata.display_name.as_ref()?; - let map = db.import_map(krate); + let map = ImportMap::of(&db, krate); Some(format!("{name}:\n{}\n", map.fmt_for_test(&db))) }) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index a1707f17beb0..e7ab2b390f26 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -44,6 +44,7 @@ }; use ast::{AstNode, StructKind}; +use base_db::Crate; use cfg::CfgOptions; use hir_expand::{ ExpandTo, HirFileId, @@ -121,21 +122,23 @@ fn span_for(&self, range: TextRange) -> Span { } #[salsa_macros::tracked(returns(deref))] -pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { +pub(crate) fn file_item_tree_query( + db: &dyn DefDatabase, + file_id: HirFileId, + krate: Crate, +) -> Arc { let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); static EMPTY: OnceLock> = OnceLock::new(); - let ctx = lower::Ctx::new(db, file_id); + let ctx = lower::Ctx::new(db, file_id, krate); let syntax = db.parse_or_expand(file_id); let mut item_tree = match_ast! { match syntax { ast::SourceFile(file) => { - let krate = file_id.krate(db); let root_file_id = krate.root_file_id(db); let extra_top_attrs = (file_id == root_file_id).then(|| { parse_extra_crate_attrs(db, krate).map(|crate_attrs| { - let file_id = root_file_id.editioned_file_id(db); - lower_extra_crate_attrs(db, crate_attrs, file_id, &|| ctx.cfg_options()) + lower_extra_crate_attrs(db, crate_attrs, root_file_id.span_file_id(db), &|| ctx.cfg_options()) }) }).flatten(); let top_attrs = match extra_top_attrs { @@ -189,41 +192,22 @@ pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> } } -#[salsa_macros::tracked(returns(deref))] -pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc { +#[salsa_macros::tracked(returns(ref))] +pub(crate) fn block_item_tree_query( + db: &dyn DefDatabase, + block: BlockId, + krate: Crate, +) -> ItemTree { let _p = tracing::info_span!("block_item_tree_query", ?block).entered(); - static EMPTY: OnceLock> = OnceLock::new(); - let loc = block.lookup(db); let block = loc.ast_id.to_node(db); - let ctx = lower::Ctx::new(db, loc.ast_id.file_id); + let ctx = lower::Ctx::new(db, loc.ast_id.file_id, krate); let mut item_tree = ctx.lower_block(&block); - let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree; - if small_data.is_empty() - && big_data.is_empty() - && top_level.is_empty() - && attrs.is_empty() - && top_attrs.is_empty() - && vis.arena.is_empty() - { - EMPTY - .get_or_init(|| { - Arc::new(ItemTree { - top_level: Box::new([]), - attrs: FxHashMap::default(), - small_data: FxHashMap::default(), - big_data: FxHashMap::default(), - top_attrs: AttrsOrCfg::empty(), - vis: ItemVisibilities { arena: ThinVec::new() }, - }) - }) - .clone() - } else { - item_tree.shrink_to_fit(); - Arc::new(item_tree) - } + item_tree.shrink_to_fit(); + item_tree } + /// The item tree of a source file. #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { @@ -356,10 +340,10 @@ pub(crate) fn new(file: HirFileId, block: Option) -> Self { Self { file, block } } - pub(crate) fn item_tree<'db>(&self, db: &'db dyn DefDatabase) -> &'db ItemTree { + pub(crate) fn item_tree<'db>(&self, db: &'db dyn DefDatabase, krate: Crate) -> &'db ItemTree { match self.block { - Some(block) => block_item_tree_query(db, block), - None => file_item_tree_query(db, self.file), + Some(block) => block_item_tree_query(db, block, krate), + None => file_item_tree_query(db, self.file, krate), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 3f19e001548e..31e409d86e49 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -2,7 +2,7 @@ use std::cell::OnceCell; -use base_db::FxIndexSet; +use base_db::{Crate, FxIndexSet}; use cfg::CfgOptions; use hir_expand::{ HirFileId, @@ -16,7 +16,6 @@ AstNode, ast::{self, HasModuleItem, HasName}, }; -use triomphe::Arc; use crate::{ db::DefDatabase, @@ -29,19 +28,20 @@ }, }; -pub(super) struct Ctx<'a> { - pub(super) db: &'a dyn DefDatabase, +pub(super) struct Ctx<'db> { + pub(super) db: &'db dyn DefDatabase, tree: ItemTree, - source_ast_id_map: Arc, + source_ast_id_map: &'db AstIdMap, span_map: OnceCell, file: HirFileId, - cfg_options: OnceCell<&'a CfgOptions>, + cfg_options: OnceCell<&'db CfgOptions>, + krate: Crate, top_level: Vec, visibilities: FxIndexSet, } -impl<'a> Ctx<'a> { - pub(super) fn new(db: &'a dyn DefDatabase, file: HirFileId) -> Self { +impl<'db> Ctx<'db> { + pub(super) fn new(db: &'db dyn DefDatabase, file: HirFileId, krate: Crate) -> Self { Self { db, tree: ItemTree::default(), @@ -51,12 +51,13 @@ pub(super) fn new(db: &'a dyn DefDatabase, file: HirFileId) -> Self { span_map: OnceCell::new(), visibilities: FxIndexSet::default(), top_level: Vec::new(), + krate, } } #[inline] - pub(super) fn cfg_options(&self) -> &'a CfgOptions { - self.cfg_options.get_or_init(|| self.file.krate(self.db).cfg_options(self.db)) + pub(super) fn cfg_options(&self) -> &'db CfgOptions { + self.cfg_options.get_or_init(|| self.krate.cfg_options(self.db)) } pub(super) fn span_map(&self) -> SpanMapRef<'_> { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index 1926ed74e869..b71b25a1a51d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -6,7 +6,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, file_id) = TestDB::with_single_file(ra_fixture); - let item_tree = db.file_item_tree(file_id.into()); + let item_tree = db.file_item_tree(file_id.into(), db.test_crate()); let pretty = item_tree.pretty_print(&db, Edition::CURRENT); expect.assert_eq(&pretty); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index de674be05f64..9a7fbc812f87 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -49,7 +49,6 @@ use intern::{Interned, Symbol}; pub use rustc_abi as layout; use thin_vec::ThinVec; -use triomphe::Arc; pub use crate::signatures::LocalFieldId; @@ -86,14 +85,19 @@ builtin_type::BuiltinType, db::DefDatabase, expr_store::ExpressionStoreSourceMap, - hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId}, + hir::{ + ExprId, + generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId}, + }, nameres::{ LocalDefMap, assoc::{ImplItems, TraitItems}, block_def_map, crate_def_map, crate_local_def_map, diagnostics::DefDiagnostics, }, - signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields}, + signatures::{ + ConstSignature, EnumVariants, InactiveEnumVariantCode, StaticSignature, VariantFields, + }, }; type FxIndexMap = indexmap::IndexMap; @@ -255,14 +259,15 @@ fn module(&self, db: &dyn DefDatabase) -> ModuleId { impl StructId { pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { - VariantFields::firewall(db, self.into()) + VariantFields::of(db, self.into()) } pub fn fields_with_source_map( self, db: &dyn DefDatabase, - ) -> (Arc, Arc) { - VariantFields::query(db, self.into()) + ) -> (&VariantFields, &ExpressionStoreSourceMap) { + let r = VariantFields::with_source_map(db, self.into()); + (&r.0, &r.1) } } @@ -271,14 +276,15 @@ pub fn fields_with_source_map( impl UnionId { pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { - VariantFields::firewall(db, self.into()) + VariantFields::of(db, self.into()) } pub fn fields_with_source_map( self, db: &dyn DefDatabase, - ) -> (Arc, Arc) { - VariantFields::query(db, self.into()) + ) -> (&VariantFields, &ExpressionStoreSourceMap) { + let r = VariantFields::with_source_map(db, self.into()); + (&r.0, &r.1) } } @@ -306,6 +312,19 @@ pub fn enum_variants_with_diagnostics( pub type StaticLoc = AssocItemLoc; impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); +/// An anonymous const expression that appears in a type position (e.g., array lengths, +/// const generic arguments like `{ N + 1 }`). Unlike named constants, these don't have +/// their own `Body` — their expressions live in the parent's signature `ExpressionStore`. +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub struct AnonConstLoc { + /// The owner store containing this expression. + pub owner: ExpressionStoreOwnerId, + /// The ExprId within the owner's ExpressionStore that is the root + /// of this anonymous const expression. + pub expr: ExprId, +} +impl_intern!(AnonConstId, AnonConstLoc, intern_anon_const, lookup_intern_anon_const); + pub type TraitLoc = ItemLoc; impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); @@ -377,14 +396,15 @@ pub struct EnumVariantLoc { impl EnumVariantId { pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { - VariantFields::firewall(db, self.into()) + VariantFields::of(db, self.into()) } pub fn fields_with_source_map( self, db: &dyn DefDatabase, - ) -> (Arc, Arc) { - VariantFields::query(db, self.into()) + ) -> (&VariantFields, &ExpressionStoreSourceMap) { + let r = VariantFields::with_source_map(db, self.into()); + (&r.0, &r.1) } } @@ -706,46 +726,47 @@ fn from(value: DefWithBodyId) -> Self { pub enum GeneralConstId { ConstId(ConstId), StaticId(StaticId), + AnonConstId(AnonConstId), } -impl_from!(ConstId, StaticId for GeneralConstId); +impl_from!(ConstId, StaticId, AnonConstId for GeneralConstId); impl GeneralConstId { - pub fn generic_def(self, _db: &dyn DefDatabase) -> Option { + pub fn generic_def(self, db: &dyn DefDatabase) -> Option { match self { GeneralConstId::ConstId(it) => Some(it.into()), GeneralConstId::StaticId(it) => Some(it.into()), + GeneralConstId::AnonConstId(it) => Some(it.lookup(db).owner.generic_def(db)), } } pub fn name(self, db: &dyn DefDatabase) -> String { match self { GeneralConstId::StaticId(it) => { - db.static_signature(it).name.display(db, Edition::CURRENT).to_string() + StaticSignature::of(db, it).name.display(db, Edition::CURRENT).to_string() } GeneralConstId::ConstId(const_id) => { - db.const_signature(const_id).name.as_ref().map_or_else( + ConstSignature::of(db, const_id).name.as_ref().map_or_else( || "_".to_owned(), |name| name.display(db, Edition::CURRENT).to_string(), ) } + GeneralConstId::AnonConstId(_) => "{anon const}".to_owned(), } } } -/// The defs which have a body (have root expressions for type inference). +/// The defs which have a body. #[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum DefWithBodyId { + /// A function body. FunctionId(FunctionId), + /// A static item initializer. StaticId(StaticId), + /// A const item initializer ConstId(ConstId), + /// An enum variant discrimiant VariantId(EnumVariantId), - // /// All fields of a variant are inference roots - // VariantId(VariantId), - // /// The signature can contain inference roots in a bunch of places - // /// like const parameters or const arguments in paths - // This should likely be kept on its own with a separate query - // GenericDefId(GenericDefId), } impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId); @@ -814,6 +835,62 @@ pub enum GenericDefId { for GenericDefId ); +/// Owner of an expression store - either a body or a signature. +/// This is used for queries that operate on expression stores generically, +/// such as `expr_scopes`. +// NOTE: This type cannot be `salsa::Supertype` as its variants are overlapping. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord /* !salsa::Supertype */)] +pub enum ExpressionStoreOwnerId { + Signature(GenericDefId), + /// A body, something with a root expression. + /// + /// An enum variant's body is considered its discriminant initializer. + Body(DefWithBodyId), + VariantFields(VariantId), +} + +impl ExpressionStoreOwnerId { + // FIXME: Check callers of this, this method likely can be removed + pub fn as_def_with_body(self) -> Option { + if let Self::Body(v) = self { Some(v) } else { None } + } + + pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId { + match self { + ExpressionStoreOwnerId::Signature(generic_def_id) => generic_def_id, + ExpressionStoreOwnerId::Body(def_with_body_id) => match def_with_body_id { + DefWithBodyId::FunctionId(id) => GenericDefId::FunctionId(id), + DefWithBodyId::StaticId(id) => GenericDefId::StaticId(id), + DefWithBodyId::ConstId(id) => GenericDefId::ConstId(id), + DefWithBodyId::VariantId(it) => it.lookup(db).parent.into(), + }, + ExpressionStoreOwnerId::VariantFields(variant_id) => match variant_id { + VariantId::EnumVariantId(it) => it.lookup(db).parent.into(), + VariantId::StructId(it) => it.into(), + VariantId::UnionId(it) => it.into(), + }, + } + } +} + +impl From for ExpressionStoreOwnerId { + fn from(id: GenericDefId) -> Self { + ExpressionStoreOwnerId::Signature(id) + } +} + +impl From for ExpressionStoreOwnerId { + fn from(id: DefWithBodyId) -> Self { + ExpressionStoreOwnerId::Body(id) + } +} + +impl From for ExpressionStoreOwnerId { + fn from(id: VariantId) -> Self { + ExpressionStoreOwnerId::VariantFields(id) + } +} + impl GenericDefId { pub fn file_id_and_params_of( self, @@ -954,7 +1031,9 @@ fn from(vid: VariantId) -> Self { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype, salsa::Update)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa_macros::Supertype, salsa::Update, +)] pub enum VariantId { EnumVariantId(EnumVariantId), StructId(StructId), @@ -964,14 +1043,15 @@ pub enum VariantId { impl VariantId { pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { - VariantFields::firewall(db, self) + VariantFields::of(db, self) } pub fn fields_with_source_map( self, db: &dyn DefDatabase, - ) -> (Arc, Arc) { - VariantFields::query(db, self) + ) -> (&VariantFields, &ExpressionStoreSourceMap) { + let r = VariantFields::with_source_map(db, self); + (&r.0, &r.1) } pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId { @@ -1172,6 +1252,16 @@ fn module(&self, db: &dyn DefDatabase) -> ModuleId { } } +impl HasModule for ExpressionStoreOwnerId { + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + match self { + ExpressionStoreOwnerId::Signature(def) => def.module(db), + ExpressionStoreOwnerId::Body(def) => def.module(db), + ExpressionStoreOwnerId::VariantFields(variant_id) => variant_id.module(db), + } + } +} + impl HasModule for GenericDefId { fn module(&self, db: &dyn DefDatabase) -> ModuleId { match self { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index eeaf865338bd..46cdb39c5b46 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -568,6 +568,12 @@ fn cfg_select() { _ => { fn true_2() {} } } +const _: ((),) = cfg_select! { _ => ((), ) }; +const _: i32 = cfg_select! { true => 2 + 3, _ => 3 + 4 }; +const _: i32 = cfg_select! { false => 2 + 3, _ => 3 + 4 }; +const _: bool = cfg_select! { _ => 2 < 3 }; +const _: bool = cfg_select! { true => foo::<(), fn() -> Foo>(1,), _ => false }; + cfg_select! { false => { fn false_3() {} } } @@ -589,6 +595,12 @@ fn true_1() {} fn true_2() {} +const _: ((),) = ((), ); +const _: i32 = 2+3; +const _: i32 = 3+4; +const _: bool = 2<3; +const _: bool = foo::<(), fn() -> Foo>(1, ); + /* error: none of the predicates in this `cfg_select` evaluated to true */ /* error: expected `=>` after cfg expression */ diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index 7b5d0103e66e..d93df7af6a73 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -35,9 +35,9 @@ struct $ident { }; } -struct#0:MacroRules[BE8F, 0]@58..64#17408# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#17408# - map#0:MacroRules[BE8F, 0]@86..89#17408#:#0:MacroRules[BE8F, 0]@89..90#17408# #0:MacroRules[BE8F, 0]@89..90#17408#::#0:MacroRules[BE8F, 0]@91..93#17408#std#0:MacroRules[BE8F, 0]@93..96#17408#::#0:MacroRules[BE8F, 0]@96..98#17408#collections#0:MacroRules[BE8F, 0]@98..109#17408#::#0:MacroRules[BE8F, 0]@109..111#17408#HashSet#0:MacroRules[BE8F, 0]@111..118#17408#<#0:MacroRules[BE8F, 0]@118..119#17408#(#0:MacroRules[BE8F, 0]@119..120#17408#)#0:MacroRules[BE8F, 0]@120..121#17408#>#0:MacroRules[BE8F, 0]@121..122#17408#,#0:MacroRules[BE8F, 0]@122..123#17408# -}#0:MacroRules[BE8F, 0]@132..133#17408# +struct#0:MacroRules[BE8F, 0]@58..64#18432# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#18432# + map#0:MacroRules[BE8F, 0]@86..89#18432#:#0:MacroRules[BE8F, 0]@89..90#18432# #0:MacroRules[BE8F, 0]@89..90#18432#::#0:MacroRules[BE8F, 0]@91..93#18432#std#0:MacroRules[BE8F, 0]@93..96#18432#::#0:MacroRules[BE8F, 0]@96..98#18432#collections#0:MacroRules[BE8F, 0]@98..109#18432#::#0:MacroRules[BE8F, 0]@109..111#18432#HashSet#0:MacroRules[BE8F, 0]@111..118#18432#<#0:MacroRules[BE8F, 0]@118..119#18432#(#0:MacroRules[BE8F, 0]@119..120#18432#)#0:MacroRules[BE8F, 0]@120..121#18432#>#0:MacroRules[BE8F, 0]@121..122#18432#,#0:MacroRules[BE8F, 0]@122..123#18432# +}#0:MacroRules[BE8F, 0]@132..133#18432# "#]], ); } @@ -197,7 +197,7 @@ macro_rules! mk_struct { #[macro_use] mod foo; -struct#1:MacroRules[DB0C, 0]@59..65#17408# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#17408#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#17408#;#1:MacroRules[DB0C, 0]@75..76#17408# +struct#1:MacroRules[DB0C, 0]@59..65#18432# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#18432#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#18432#;#1:MacroRules[DB0C, 0]@75..76#18432# "#]], ); } @@ -423,10 +423,10 @@ macro_rules! m { macro_rules! m { ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } ); } -impl#\17408# Bar#\17408# {#\17408# - fn#\17408# foo#\ROOT2024#(#\17408#)#\17408# {#\17408#}#\17408# - fn#\17408# bar#\ROOT2024#(#\17408#)#\17408# {#\17408#}#\17408# -}#\17408# +impl#\18432# Bar#\18432# {#\18432# + fn#\18432# foo#\ROOT2024#(#\18432#)#\18432# {#\18432#}#\18432# + fn#\18432# bar#\ROOT2024#(#\18432#)#\18432# {#\18432#}#\18432# +}#\18432# "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index c63f2c1d786b..8317c56caf76 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -45,6 +45,7 @@ use crate::{ AdtId, Lookup, ModuleDefId, db::DefDatabase, + expr_store::Body, nameres::{DefMap, ModuleSource, crate_def_map}, src::HasSource, test_db::TestDB, @@ -276,7 +277,7 @@ fn resolve_macro_call_id( _ => continue, }; - let (body, sm) = db.body_with_source_map(body); + let (body, sm) = Body::with_source_map(db, body); if let Some(it) = body .blocks(db) .find_map(|block| resolve_macro_call_id(db, block.1, ast_id, ast_ptr)) @@ -458,7 +459,7 @@ fn $func_name() { todo!() } "#; let (db, file_id) = TestDB::with_single_file(fixture); - let krate = file_id.krate(&db); + let krate = db.test_crate(); let def_map = crate_def_map(&db, krate); let source = def_map[def_map.root].definition_source(&db); let source_file = match source.value { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index 9d2b2109fbcb..f5a852b39c8d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -17,7 +17,6 @@ ast::{self, HasModuleItem, HasName}, }; use thin_vec::ThinVec; -use triomphe::Arc; use crate::{ AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId, @@ -133,14 +132,14 @@ pub fn macro_calls(&self) -> impl Iterator, MacroCallId } } -struct AssocItemCollector<'a> { - db: &'a dyn DefDatabase, +struct AssocItemCollector<'db> { + db: &'db dyn DefDatabase, module_id: ModuleId, - def_map: &'a DefMap, - local_def_map: &'a LocalDefMap, - ast_id_map: Arc, + def_map: &'db DefMap, + local_def_map: &'db LocalDefMap, + ast_id_map: &'db AstIdMap, span_map: SpanMap, - cfg_options: &'a CfgOptions, + cfg_options: &'db CfgOptions, file_id: HirFileId, diagnostics: Vec, container: ItemContainerId, @@ -150,9 +149,9 @@ struct AssocItemCollector<'a> { macro_calls: ThinVec<(AstId, MacroCallId)>, } -impl<'a> AssocItemCollector<'a> { +impl<'db> AssocItemCollector<'db> { fn new( - db: &'a dyn DefDatabase, + db: &'db dyn DefDatabase, module_id: ModuleId, container: ItemContainerId, file_id: HirFileId, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index e672e83f0194..9c101c127b41 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -279,7 +279,7 @@ fn seed_with_top_level(&mut self) { let _p = tracing::info_span!("seed_with_top_level").entered(); let file_id = self.def_map.krate.root_file_id(self.db); - let item_tree = self.db.file_item_tree(file_id.into()); + let item_tree = self.db.file_item_tree(file_id.into(), self.def_map.krate); let attrs = match item_tree.top_level_attrs() { AttrsOrCfg::Enabled { attrs } => attrs.as_ref(), AttrsOrCfg::CfgDisabled(it) => it.1.as_ref(), @@ -387,7 +387,7 @@ fn seed_with_top_level(&mut self) { } fn seed_with_inner(&mut self, tree_id: TreeId) { - let item_tree = tree_id.item_tree(self.db); + let item_tree = tree_id.item_tree(self.db, self.def_map.krate); let is_cfg_enabled = matches!(item_tree.top_level_attrs(), AttrsOrCfg::Enabled { .. }); if is_cfg_enabled { self.inject_prelude(); @@ -1708,7 +1708,7 @@ fn collect_macro_expansion( } let file_id = macro_call_id.into(); - let item_tree = self.db.file_item_tree(file_id); + let item_tree = self.db.file_item_tree(file_id, self.def_map.krate); // Derive helpers that are in scope for an item are also in scope for attribute macro expansions // of that item (but not derive or fn like macros). @@ -2335,10 +2335,10 @@ fn collect_module(&mut self, module_ast_id: ItemTreeAstId, attrs: Attrs<'_> self.file_id(), &module.name, path_attr.as_deref(), - self.def_collector.def_map.krate, ) { Ok((file_id, is_mod_rs, mod_dir)) => { - let item_tree = db.file_item_tree(file_id.into()); + let item_tree = + db.file_item_tree(file_id.into(), self.def_collector.def_map.krate); match item_tree.top_level_attrs() { AttrsOrCfg::CfgDisabled(cfg) => { self.emit_unconfigured_diagnostic( @@ -2828,8 +2828,8 @@ fn crate_attrs() { let fixture = r#" //- /lib.rs crate:foo crate-attr:recursion_limit="4" crate-attr:no_core crate-attr:no_std crate-attr:feature(register_tool) "#; - let (db, file_id) = TestDB::with_single_file(fixture); - let def_map = crate_def_map(&db, file_id.krate(&db)); + let (db, _) = TestDB::with_single_file(fixture); + let def_map = crate_def_map(&db, db.test_crate()); assert_eq!(def_map.recursion_limit(), 4); assert!(def_map.is_no_core()); assert!(def_map.is_no_std()); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs index 140b77ac002f..0c50f13edfb6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs @@ -1,6 +1,6 @@ //! This module resolves `mod foo;` declaration to file. use arrayvec::ArrayVec; -use base_db::{AnchoredPath, Crate}; +use base_db::AnchoredPath; use hir_expand::{EditionedFileId, name::Name}; use crate::{HirFileId, db::DefDatabase}; @@ -62,7 +62,6 @@ pub(super) fn resolve_declaration( file_id: HirFileId, name: &Name, attr_path: Option<&str>, - krate: Crate, ) -> Result<(EditionedFileId, bool, ModDir), Box<[String]>> { let name = name.as_str(); @@ -92,7 +91,7 @@ pub(super) fn resolve_declaration( if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) { return Ok(( // FIXME: Edition, is this rightr? - EditionedFileId::new(db, file_id, orig_file_id.edition(db), krate), + EditionedFileId::new(db, file_id, orig_file_id.edition(db)), is_mod_rs, mod_dir, )); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index 225ba958634e..5b75c078ecfa 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -166,15 +166,15 @@ fn no() {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "EnumVariants::of_", @@ -183,7 +183,7 @@ fn no() {} expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "EnumVariants::of_", @@ -224,21 +224,21 @@ pub struct S {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "decl_macro_expander_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", ] @@ -246,12 +246,12 @@ pub struct S {} expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "macro_arg_shim", "parse_macro_expansion_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", ] "#]], @@ -282,26 +282,26 @@ fn f() { foo } [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "crate_local_def_map", "proc_macros_for_crate_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "expand_proc_macro_shim", "macro_arg_shim", @@ -311,13 +311,13 @@ fn f() { foo } expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "macro_arg_shim", "expand_proc_macro_shim", "parse_macro_expansion_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", ] "#]], @@ -406,38 +406,38 @@ pub struct S {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "crate_local_def_map", "proc_macros_for_crate_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "decl_macro_expander_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", "decl_macro_expander_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "expand_proc_macro_shim", "macro_arg_shim", @@ -447,7 +447,7 @@ pub struct S {} expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "macro_arg_shim", @@ -523,29 +523,29 @@ fn quux() { 1$0 } [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "decl_macro_expander_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", ] @@ -572,7 +572,7 @@ fn quux() { 92 } expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "macro_arg_shim", @@ -604,13 +604,13 @@ impl Tr for () {} execute_assert_events( &db, || { - db.file_item_tree(pos.file_id.into()); + db.file_item_tree(pos.file_id.into(), db.test_crate()); }, &[("file_item_tree_query", 1), ("parse", 1)], expect![[r#" [ "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", ] @@ -624,13 +624,13 @@ impl Tr for () {} execute_assert_events( &db, || { - db.file_item_tree(pos.file_id.into()); + db.file_item_tree(pos.file_id.into(), db.test_crate()); }, &[("file_item_tree_query", 1), ("parse", 1)], expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", ] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index d32e53fc6bee..bb292ac1a6bc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -13,14 +13,13 @@ use smallvec::{SmallVec, smallvec}; use span::SyntaxContext; use syntax::ast::HasName; -use triomphe::Arc; use crate::{ - AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, - ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ImplId, - ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, - ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, - TypeParamId, UseId, VariantId, + AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, + ExpressionStoreOwnerId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, + GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId, + MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, db::DefDatabase, expr_store::{ @@ -36,6 +35,7 @@ lang_item::LangItemTarget, nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map}, per_ns::PerNs, + signatures::ImplSignature, src::HasSource, type_ref::LifetimeRef, visibility::{RawVisibility, Visibility}, @@ -65,13 +65,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } #[derive(Clone)] -struct ExprScope { - owner: DefWithBodyId, - expr_scopes: Arc, +struct ExprScope<'db> { + owner: ExpressionStoreOwnerId, + expr_scopes: &'db ExprScopes, scope_id: ScopeId, } -impl fmt::Debug for ExprScope { +impl fmt::Debug for ExprScope<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExprScope") .field("owner", &self.owner) @@ -86,9 +86,9 @@ enum Scope<'db> { BlockScope(ModuleItemMap<'db>), /// Brings the generic parameters of an item into scope as well as the `Self` type alias / /// generic for ADTs and impls. - GenericParams { def: GenericDefId, params: Arc }, + GenericParams { def: GenericDefId, params: &'db GenericParams }, /// Local bindings - ExprScope(ExprScope), + ExprScope(ExprScope<'db>), /// Macro definition inside bodies that affects all paths after it in the same block. MacroDefScope(MacroDefId), } @@ -653,7 +653,7 @@ pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { match scope { Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::GenericParams { def: GenericDefId::ImplId(impl_), .. } => { - let impl_data = db.impl_signature(impl_); + let impl_data = ImplSignature::of(db, impl_); if let Some(target_trait) = impl_data.target_trait && let Some(TypeNs::TraitId(trait_)) = self .resolve_path_in_type_ns_fully(db, &impl_data.store[target_trait.path]) @@ -724,19 +724,19 @@ pub fn generic_def(&self) -> Option { pub fn generic_params(&self) -> Option<&GenericParams> { self.scopes().find_map(|scope| match scope { - Scope::GenericParams { params, .. } => Some(&**params), + &Scope::GenericParams { params, .. } => Some(params), _ => None, }) } - pub fn all_generic_params(&self) -> impl Iterator { + pub fn all_generic_params(&self) -> impl Iterator { self.scopes().filter_map(|scope| match scope { - Scope::GenericParams { params, def } => Some((&**params, def)), + &Scope::GenericParams { params, def } => Some((params, def)), _ => None, }) } - pub fn body_owner(&self) -> Option { + pub fn expression_store_owner(&self) -> Option { self.scopes().find_map(|scope| match scope { Scope::ExprScope(it) => Some(it.owner), _ => None, @@ -854,25 +854,30 @@ pub fn rename_will_conflict_with_renamed( pub fn update_to_inner_scope( &mut self, db: &'db dyn DefDatabase, - owner: DefWithBodyId, + owner: impl Into, + expr_id: ExprId, + ) -> UpdateGuard { + self.update_to_inner_scope_(db, owner.into(), expr_id) + } + + fn update_to_inner_scope_( + &mut self, + db: &'db dyn DefDatabase, + owner: ExpressionStoreOwnerId, expr_id: ExprId, ) -> UpdateGuard { #[inline(always)] fn append_expr_scope<'db>( db: &'db dyn DefDatabase, resolver: &mut Resolver<'db>, - owner: DefWithBodyId, - expr_scopes: &Arc, + owner: ExpressionStoreOwnerId, + expr_scopes: &'db ExprScopes, scope_id: ScopeId, ) { if let Some(macro_id) = expr_scopes.macro_def(scope_id) { resolver.scopes.push(Scope::MacroDefScope(**macro_id)); } - resolver.scopes.push(Scope::ExprScope(ExprScope { - owner, - expr_scopes: expr_scopes.clone(), - scope_id, - })); + resolver.scopes.push(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })); if let Some(block) = expr_scopes.block(scope_id) { let def_map = block_def_map(db, block); let local_def_map = block.lookup(db).module.only_local_def_map(db); @@ -890,21 +895,20 @@ fn append_expr_scope<'db>( let start = self.scopes.len(); let innermost_scope = self.scopes().find(|scope| !matches!(scope, Scope::MacroDefScope(_))); match innermost_scope { - Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => { - let expr_scopes = expr_scopes.clone(); + Some(&Scope::ExprScope(ExprScope { scope_id, expr_scopes, owner })) => { let scope_chain = expr_scopes .scope_chain(expr_scopes.scope_for(expr_id)) .take_while(|&it| it != scope_id); for scope_id in scope_chain { - append_expr_scope(db, self, owner, &expr_scopes, scope_id); + append_expr_scope(db, self, owner, expr_scopes, scope_id); } } _ => { - let expr_scopes = db.expr_scopes(owner); + let expr_scopes = ExprScopes::of(db, owner); let scope_chain = expr_scopes.scope_chain(expr_scopes.scope_for(expr_id)); for scope_id in scope_chain { - append_expr_scope(db, self, owner, &expr_scopes, scope_id); + append_expr_scope(db, self, owner, expr_scopes, scope_id); } } } @@ -1016,7 +1020,7 @@ fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { }) }); } - &Scope::GenericParams { ref params, def: parent } => { + &Scope::GenericParams { params, def: parent } => { if let GenericDefId::ImplId(impl_) = parent { acc.add(&Name::new_symbol_root(sym::Self_), ScopeDef::ImplSelfType(impl_)); } else if let GenericDefId::AdtId(adt) = parent { @@ -1026,7 +1030,7 @@ fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { for (local_id, param) in params.iter_type_or_consts() { if let Some(name) = ¶m.name() { let id = TypeOrConstParamId { parent, local_id }; - let data = &db.generic_params(parent)[local_id]; + let data = &GenericParams::of(db, parent)[local_id]; acc.add( name, ScopeDef::GenericParam(match data { @@ -1060,20 +1064,21 @@ fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { pub fn resolver_for_scope( db: &dyn DefDatabase, - owner: DefWithBodyId, + owner: impl Into + HasResolver, scope_id: Option, ) -> Resolver<'_> { - let r = owner.resolver(db); - let scopes = db.expr_scopes(owner); - resolver_for_scope_(db, scopes, scope_id, r, owner) + let store_owner = owner.into(); + let r = store_owner.resolver(db); + let scopes = ExprScopes::of(db, store_owner); + resolver_for_scope_(db, scopes, scope_id, r, store_owner) } fn resolver_for_scope_<'db>( db: &'db dyn DefDatabase, - scopes: Arc, + scopes: &'db ExprScopes, scope_id: Option, mut r: Resolver<'db>, - owner: DefWithBodyId, + owner: ExpressionStoreOwnerId, ) -> Resolver<'db> { let scope_chain = scopes.scope_chain(scope_id).collect::>(); r.scopes.reserve(scope_chain.len()); @@ -1093,7 +1098,7 @@ fn resolver_for_scope_<'db>( r = r.push_scope(Scope::MacroDefScope(**macro_id)); } - r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); + r = r.push_expr_scope(owner, scopes, scope); } r } @@ -1109,7 +1114,7 @@ fn push_generic_params_scope( db: &'db dyn DefDatabase, def: GenericDefId, ) -> Resolver<'db> { - let params = db.generic_params(def); + let params = GenericParams::of(db, def); self.push_scope(Scope::GenericParams { def, params }) } @@ -1124,8 +1129,8 @@ fn push_block_scope( fn push_expr_scope( self, - owner: DefWithBodyId, - expr_scopes: Arc, + owner: ExpressionStoreOwnerId, + expr_scopes: &'db ExprScopes, scope_id: ScopeId, ) -> Resolver<'db> { self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })) @@ -1409,6 +1414,16 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { } } +impl HasResolver for ExpressionStoreOwnerId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + match self { + ExpressionStoreOwnerId::Signature(def) => def.resolver(db), + ExpressionStoreOwnerId::Body(def) => def.resolver(db), + ExpressionStoreOwnerId::VariantFields(variant_id) => variant_id.resolver(db), + } + } +} + impl HasResolver for EnumVariantId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { self.lookup(db).parent.resolver(db) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 37c8f762fe5d..6d704274f45d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -24,7 +24,7 @@ attrs::AttrFlags, db::DefDatabase, expr_store::{ - ExpressionStore, ExpressionStoreSourceMap, + Body, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreSourceMap, lower::{ ExprCollector, lower_function, lower_generic_params, lower_trait, lower_type_alias, }, @@ -32,7 +32,7 @@ hir::{ExprId, PatId, generics::GenericParams}, item_tree::{FieldsShape, RawVisibility, visibility_from_ast}, src::HasSource, - type_ref::{TraitRef, TypeBound, TypeRefId}, + type_ref::{ConstRef, TraitRef, TypeBound, TypeRefId}, }; #[inline] @@ -43,8 +43,8 @@ fn as_name_opt(name: Option) -> Name { #[derive(Debug, PartialEq, Eq)] pub struct StructSignature { pub name: Name, - pub generic_params: Arc, - pub store: Arc, + pub generic_params: GenericParams, + pub store: ExpressionStore, pub flags: StructFlags, pub shape: FieldsShape, } @@ -71,8 +71,18 @@ pub struct StructFlags: u8 { } } +#[salsa::tracked] impl StructSignature { - pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: StructId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: StructId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let InFile { file_id, value: source } = loc.source(db); let attrs = AttrFlags::query(db, id.into()); @@ -115,10 +125,12 @@ pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc, Arc Option { if self.flags.contains(StructFlags::HAS_REPR) { @@ -141,13 +153,23 @@ fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape { #[derive(Debug, PartialEq, Eq)] pub struct UnionSignature { pub name: Name, - pub generic_params: Arc, - pub store: Arc, + pub generic_params: GenericParams, + pub store: ExpressionStore, pub flags: StructFlags, } +#[salsa::tracked] impl UnionSignature { - pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: UnionId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: UnionId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let attrs = AttrFlags::query(db, id.into()); let mut flags = StructFlags::empty(); @@ -177,7 +199,7 @@ pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc, Arc, - pub store: Arc, + pub generic_params: GenericParams, + pub store: ExpressionStore, pub flags: EnumFlags, } +#[salsa::tracked] impl EnumSignature { - pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: EnumId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: EnumId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let attrs = AttrFlags::query(db, id.into()); let mut flags = EnumFlags::empty(); @@ -229,10 +261,12 @@ pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc, Arc IntegerType { match AttrFlags::repr(db, id.into()) { Some(ReprOptions { int: Some(builtin), .. }) => builtin, @@ -256,14 +290,24 @@ pub struct ConstFlags: u8 { #[derive(Debug, PartialEq, Eq)] pub struct ConstSignature { pub name: Option, - // generic_params: Arc, - pub store: Arc, + // generic_params: GenericParams, + pub store: ExpressionStore, pub type_ref: TypeRefId, pub flags: ConstFlags, } +#[salsa::tracked] impl ConstSignature { - pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: ConstId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: ConstId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let module = loc.container.module(db); @@ -282,15 +326,17 @@ pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc, Arc bool { self.flags.contains(ConstFlags::HAS_BODY) } @@ -312,13 +358,24 @@ pub struct StaticFlags: u8 { pub struct StaticSignature { pub name: Name, - // generic_params: Arc, - pub store: Arc, + // generic_params: GenericParams, + pub store: ExpressionStore, pub type_ref: TypeRefId, pub flags: StaticFlags, } + +#[salsa::tracked] impl StaticSignature { - pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: StaticId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: StaticId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let module = loc.container.module(db); @@ -351,12 +408,12 @@ pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc, Arc, - pub store: Arc, + pub generic_params: GenericParams, + pub store: ExpressionStore, pub self_ty: TypeRefId, pub target_trait: Option, pub flags: ImplFlags, } +#[salsa::tracked] impl ImplSignature { - pub fn query(db: &dyn DefDatabase, id: ImplId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: ImplId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: ImplId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let mut flags = ImplFlags::empty(); @@ -399,17 +466,13 @@ pub fn query(db: &dyn DefDatabase, id: ImplId) -> (Arc, Arc bool { self.flags.contains(ImplFlags::NEGATIVE) @@ -439,13 +502,23 @@ pub struct TraitFlags: u16 { #[derive(Debug, PartialEq, Eq)] pub struct TraitSignature { pub name: Name, - pub generic_params: Arc, - pub store: Arc, + pub generic_params: GenericParams, + pub store: ExpressionStore, pub flags: TraitFlags, } +#[salsa::tracked] impl TraitSignature { - pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: TraitId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: TraitId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let mut flags = TraitFlags::empty(); @@ -483,10 +556,7 @@ pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc, Arc, - pub store: Arc, + pub generic_params: GenericParams, + pub store: ExpressionStore, pub params: Box<[TypeRefId]>, pub ret_type: Option, pub abi: Option, pub flags: FnFlags, } +#[salsa::tracked] impl FunctionSignature { - pub fn query( + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: FunctionId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( db: &dyn DefDatabase, id: FunctionId, - ) -> (Arc, Arc) { + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let module = loc.container.module(db); @@ -589,17 +666,19 @@ pub fn query( ( Arc::new(FunctionSignature { generic_params, - store: Arc::new(store), + store, params, ret_type, abi, flags, name, }), - Arc::new(source_map), + source_map, ) } +} +impl FunctionSignature { pub fn has_body(&self) -> bool { self.flags.contains(FnFlags::HAS_BODY) } @@ -656,7 +735,7 @@ pub fn legacy_const_generics_indices<'db>( } pub fn is_intrinsic(db: &dyn DefDatabase, id: FunctionId) -> bool { - let data = db.function_signature(id); + let data = FunctionSignature::of(db, id); data.flags.contains(FnFlags::RUSTC_INTRINSIC) // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used || match &data.abi { @@ -683,18 +762,25 @@ pub struct TypeAliasFlags: u8 { #[derive(Debug, PartialEq, Eq)] pub struct TypeAliasSignature { pub name: Name, - pub generic_params: Arc, - pub store: Arc, + pub generic_params: GenericParams, + pub store: ExpressionStore, pub bounds: Box<[TypeBound]>, pub ty: Option, pub flags: TypeAliasFlags, } +#[salsa::tracked] impl TypeAliasSignature { - pub fn query( + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: TypeAliasId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( db: &dyn DefDatabase, id: TypeAliasId, - ) -> (Arc, Arc) { + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let mut flags = TypeAliasFlags::empty(); @@ -714,28 +800,21 @@ pub fn query( lower_type_alias(db, loc.container.module(db), source, id); ( - Arc::new(TypeAliasSignature { - store: Arc::new(store), - generic_params, - flags, - bounds, - name, - ty, - }), - Arc::new(source_map), + Arc::new(TypeAliasSignature { store, generic_params, flags, bounds, name, ty }), + source_map, ) } } #[derive(Debug, PartialEq, Eq)] pub struct FunctionBody { - pub store: Arc, + pub store: ExpressionStore, pub parameters: Box<[PatId]>, } #[derive(Debug, PartialEq, Eq)] pub struct SimpleBody { - pub store: Arc, + pub store: ExpressionStore, } pub type StaticBody = SimpleBody; pub type ConstBody = SimpleBody; @@ -743,7 +822,7 @@ pub struct SimpleBody { #[derive(Debug, PartialEq, Eq)] pub struct VariantFieldsBody { - pub store: Arc, + pub store: ExpressionStore, pub fields: Box<[Option]>, } @@ -754,7 +833,7 @@ pub struct FieldData { pub type_ref: TypeRefId, pub visibility: RawVisibility, pub is_unsafe: bool, - pub default_value: Option, + pub default_value: Option, } pub type LocalFieldId = Idx; @@ -762,17 +841,17 @@ pub struct FieldData { #[derive(Debug, Clone, PartialEq, Eq)] pub struct VariantFields { fields: Arena, - pub store: Arc, + pub store: ExpressionStore, pub shape: FieldsShape, } #[salsa::tracked] impl VariantFields { - #[salsa::tracked(returns(clone))] - pub(crate) fn query( + #[salsa::tracked(returns(ref))] + pub fn with_source_map( db: &dyn DefDatabase, id: VariantId, - ) -> (Arc, Arc) { + ) -> (Arc, ExpressionStoreSourceMap) { let (shape, result) = match id { VariantId::EnumVariantId(id) => { let loc = id.lookup(db); @@ -809,20 +888,26 @@ pub(crate) fn query( } }; match result { - Some((fields, store, source_map)) => ( - Arc::new(VariantFields { fields, store: Arc::new(store), shape }), - Arc::new(source_map), - ), + Some((fields, store, source_map)) => { + (Arc::new(VariantFields { fields, store, shape }), source_map) + } None => { - let (store, source_map) = ExpressionStore::empty_singleton(); - (Arc::new(VariantFields { fields: Arena::default(), store, shape }), source_map) + let source_map = ExpressionStoreSourceMap::default(); + ( + Arc::new(VariantFields { + fields: Arena::default(), + store: ExpressionStoreBuilder::default().finish().0, + shape, + }), + source_map, + ) } } } #[salsa::tracked(returns(deref))] - pub(crate) fn firewall(db: &dyn DefDatabase, id: VariantId) -> Arc { - Self::query(db, id).0 + pub fn of(db: &dyn DefDatabase, id: VariantId) -> Arc { + Self::with_source_map(db, id).0.clone() } } @@ -873,7 +958,7 @@ fn lower_fields( override_visibility: Option>, ) -> Option<(Arena, ExpressionStore, ExpressionStoreSourceMap)> { let cfg_options = module.krate(db).cfg_options(db); - let mut col = ExprCollector::new(db, module, fields.file_id); + let mut col = ExprCollector::signature(db, module, fields.file_id); let override_visibility = override_visibility.map(|vis| { LazyCell::new(|| { let span_map = db.span_map(fields.file_id); @@ -907,9 +992,9 @@ fn lower_fields( // Check if field has default value (only for record fields) let default_value = ast::RecordField::cast(field.syntax().clone()) - .and_then(|rf| rf.eq_token().is_some().then_some(rf.expr())) + .and_then(|rf| rf.eq_token().is_some().then_some(rf.default_val())) .flatten() - .map(|expr| col.collect_expr_opt(Some(expr))); + .map(|expr| col.lower_const_arg(expr)); arena.alloc(FieldData { name, type_ref, visibility, is_unsafe, default_value }); idx += 1; @@ -1014,9 +1099,9 @@ pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { } // The outer if condition is whether this variant has const ctor or not if !matches!(variant.shape, FieldsShape::Unit) { - let body = db.body(v.into()); + let body = Body::of(db, v.into()); // A variant with explicit discriminant - if !matches!(body[body.body_expr], crate::hir::Expr::Missing) { + if !matches!(body[body.root_expr()], crate::hir::Expr::Missing) { return false; } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs index 6fe016f1e680..e33fd95908b9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs @@ -7,7 +7,7 @@ use crate::{ AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, - UseId, VariantId, attrs::AttrFlags, db::DefDatabase, + UseId, VariantId, attrs::AttrFlags, db::DefDatabase, hir::generics::GenericParams, }; pub trait HasSource { @@ -76,7 +76,7 @@ fn child_source( &self, db: &dyn DefDatabase, ) -> InFile> { - let generic_params = db.generic_params(*self); + let generic_params = GenericParams::of(db, *self); let mut idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx); let (file_id, generic_params_list) = self.file_id_and_params_of(db); @@ -110,7 +110,7 @@ fn child_source( &self, db: &dyn DefDatabase, ) -> InFile> { - let generic_params = db.generic_params(*self); + let generic_params = GenericParams::of(db, *self); let idx_iter = generic_params.iter_lt().map(|(idx, _)| idx); let (file_id, generic_params_list) = self.file_id_and_params_of(db); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index e8377fde4987..0d260279f98c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -15,6 +15,7 @@ use crate::{ Lookup, ModuleDefId, ModuleId, db::DefDatabase, + expr_store::{Body, scope::ExprScopes}, nameres::{DefMap, ModuleSource, block_def_map, crate_def_map}, src::HasSource, }; @@ -284,8 +285,8 @@ fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option< // Find the innermost block expression that has a `DefMap`. let (def_with_body, file_id) = fn_def?; let def_with_body = def_with_body.into(); - let source_map = self.body_with_source_map(def_with_body).1; - let scopes = self.expr_scopes(def_with_body); + let source_map = &Body::with_source_map(self, def_with_body).1; + let scopes = ExprScopes::body_expr_scopes(self, def_with_body); let root_syntax_node = self.parse(file_id).syntax_node(); let scope_iter = diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index cb5eed1b8b6c..81a61ec20f17 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -6,11 +6,11 @@ use hir_expand::{InFile, Lookup}; use la_arena::ArenaMap; use syntax::ast::{self, HasVisibility}; -use triomphe::Arc; use crate::{ AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, TraitId, VariantId, - db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource, + db::DefDatabase, nameres::DefMap, resolver::HasResolver, signatures::VariantFields, + src::HasSource, }; pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; @@ -277,23 +277,26 @@ pub(crate) fn min( } } -/// Resolve visibility of all specific fields of a struct or union variant. -pub(crate) fn field_visibilities_query( - db: &dyn DefDatabase, - variant_id: VariantId, -) -> Arc> { - let variant_fields = variant_id.fields(db); - let fields = variant_fields.fields(); - if fields.is_empty() { - return Arc::default(); +#[salsa::tracked] +impl VariantFields { + /// Resolve visibility of all specific fields of a struct or union variant. + #[salsa::tracked(returns(ref))] + pub fn field_visibilities( + db: &dyn DefDatabase, + variant_id: VariantId, + ) -> ArenaMap { + let variant_fields = variant_id.fields(db); + let fields = variant_fields.fields(); + if fields.is_empty() { + return ArenaMap::default(); + } + let resolver = variant_id.module(db).resolver(db); + let mut res = ArenaMap::with_capacity(fields.len()); + for (field_id, field_data) in fields.iter() { + res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility)); + } + res } - let resolver = variant_id.module(db).resolver(db); - let mut res = ArenaMap::default(); - for (field_id, field_data) in fields.iter() { - res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility)); - } - res.shrink_to_fit(); - Arc::new(res) } pub fn visibility_from_ast( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 949b22b0adaa..b3572a1cefcc 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -381,16 +381,40 @@ fn cfg_select_expand( ); } } - let expand_to_if_active = match iter.next() { - Some(tt::TtElement::Subtree(_, tt)) => tt.remaining(), - _ => { + let expand_to_if_active = match iter.peek() { + Some(tt::TtElement::Subtree(sub, tt)) if sub.delimiter.kind == DelimiterKind::Brace => { + iter.next(); + tt.remaining() + } + None | Some(TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))) => { let err_span = iter.peek().map(|it| it.first_span()).unwrap_or(span); + iter.next(); return ExpandResult::new( tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), ExpandError::other(err_span, "expected a token tree after `=>`"), ); } + Some(_) => { + let expr = expect_fragment( + db, + &mut iter, + parser::PrefixEntryPoint::Expr, + tt.top_subtree().delimiter.delim_span(), + ); + if let Some(err) = expr.err { + return ExpandResult::new( + tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), + err.into(), + ); + } + expr.value + } }; + if let Some(TtElement::Leaf(tt::Leaf::Punct(p))) = iter.peek() + && p.char == ',' + { + iter.next(); + } if expand_to.is_none() && active { expand_to = Some(expand_to_if_active); @@ -750,7 +774,7 @@ fn relative_file( if res == call_site && !allow_recursion { Err(ExpandError::other(err_span, format!("recursive inclusion of `{path_str}`"))) } else { - Ok(EditionedFileId::new(db, res, lookup.krate.data(db).edition, lookup.krate)) + Ok(EditionedFileId::new(db, res, lookup.krate.data(db).edition)) } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 51767f87ffb9..020731cf9aca 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -58,8 +58,8 @@ pub trait ExpandDatabase: RootQueryDb { fn proc_macros_for_crate(&self, krate: Crate) -> Option>; #[salsa::invoke(ast_id_map)] - #[salsa::lru(1024)] - fn ast_id_map(&self, file_id: HirFileId) -> Arc; + #[salsa::transparent] + fn ast_id_map(&self, file_id: HirFileId) -> &AstIdMap; #[salsa::transparent] fn resolve_span(&self, span: Span) -> FileRange; @@ -162,7 +162,7 @@ fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> } fn resolve_span(db: &dyn ExpandDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange { - let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); + let file_id = EditionedFileId::from_span_file_id(db, anchor.file_id); let anchor_offset = db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start(); FileRange { file_id, range: range + anchor_offset } @@ -334,8 +334,9 @@ pub fn expand_speculative( Some((node.syntax_node(), token)) } -fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> triomphe::Arc { - triomphe::Arc::new(AstIdMap::from_source(&db.parse_or_expand(file_id))) +#[salsa::tracked(lru = 1024, returns(ref))] +fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> AstIdMap { + AstIdMap::from_source(&db.parse_or_expand(file_id)) } /// Main public API -- parses a hir file, not caring whether it's a real diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 92ddd7fa8b07..424655ed651b 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -208,7 +208,6 @@ pub(crate) fn fixup_syntax( ]); } }, - // FIXME: foo:: ast::MatchExpr(it) => { if it.expr().is_none() { let match_token = match it.match_token() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 05541e782efd..4b2c75ed386e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -386,7 +386,7 @@ pub(crate) fn call_style(&self) -> MacroCallStyle { impl HirFileId { pub fn edition(self, db: &dyn ExpandDatabase) -> Edition { match self { - HirFileId::FileId(file_id) => file_id.editioned_file_id(db).edition(), + HirFileId::FileId(file_id) => file_id.edition(db), HirFileId::MacroFile(m) => db.lookup_intern_macro_call(m).def.edition, } } @@ -1118,14 +1118,6 @@ pub fn file_id(self) -> Option { HirFileId::MacroFile(_) => None, } } - - #[inline] - pub fn krate(self, db: &dyn ExpandDatabase) -> Crate { - match self { - HirFileId::FileId(it) => it.krate(db), - HirFileId::MacroFile(it) => it.loc(db).krate, - } - } } impl PartialEq for HirFileId { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs index 586b8152947b..71d0b880caa1 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs @@ -135,7 +135,7 @@ pub(crate) fn real_span_map( }); Arc::new(RealSpanMap::from_file( - editioned_file_id.editioned_file_id(db), + editioned_file_id.span_file_id(db), pairs.into_boxed_slice(), tree.syntax().text_range().end(), )) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs index 5a93c2b53606..92629b7a0532 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs @@ -80,7 +80,7 @@ pub(crate) fn generics_of<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplI pub fn generic_params_count(db: &dyn HirDatabase, id: BuiltinDeriveImplId) -> usize { let loc = id.loc(db); - let adt_params = GenericParams::new(db, loc.adt.into()); + let adt_params = GenericParams::of(db, loc.adt.into()); let extra_params_count = match loc.trait_ { BuiltinDeriveImplTrait::Copy | BuiltinDeriveImplTrait::Clone @@ -128,12 +128,12 @@ pub fn impl_trait<'db>( )) } BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { - let generic_params = GenericParams::new(db, loc.adt.into()); + let generic_params = GenericParams::of(db, loc.adt.into()); let interner = DbInterner::new_no_crate(db); let args = GenericArgs::identity_for_item(interner, loc.adt.into()); let self_ty = Ty::new_adt(interner, loc.adt, args); let Some((pointee_param_idx, _, new_param_ty)) = - coerce_pointee_params(interner, loc, &generic_params, trait_id) + coerce_pointee_params(interner, loc, generic_params, trait_id) else { // Malformed derive. return EarlyBinder::bind(TraitRef::new( @@ -152,7 +152,7 @@ pub fn impl_trait<'db>( #[salsa::tracked(returns(ref))] pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> GenericPredicates { let loc = impl_.loc(db); - let generic_params = GenericParams::new(db, loc.adt.into()); + let generic_params = GenericParams::of(db, loc.adt.into()); let interner = DbInterner::new_with(db, loc.module(db).krate(db)); let adt_predicates = GenericPredicates::query(db, loc.adt.into()); let trait_id = loc @@ -168,7 +168,7 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> | BuiltinDeriveImplTrait::PartialOrd | BuiltinDeriveImplTrait::Eq | BuiltinDeriveImplTrait::PartialEq => { - simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id) + simple_trait_predicates(interner, loc, generic_params, adt_predicates, trait_id) } BuiltinDeriveImplTrait::Default => { if matches!(loc.adt, AdtId::EnumId(_)) { @@ -178,12 +178,12 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> .store(), )) } else { - simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id) + simple_trait_predicates(interner, loc, generic_params, adt_predicates, trait_id) } } BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { let Some((pointee_param_idx, pointee_param_id, new_param_ty)) = - coerce_pointee_params(interner, loc, &generic_params, trait_id) + coerce_pointee_params(interner, loc, generic_params, trait_id) else { // Malformed derive. return GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index 5bc2446fdd2d..928396c63aaf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -5,10 +5,11 @@ use base_db::Crate; use hir_def::{ - ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId, + ConstId, EnumVariantId, ExpressionStoreOwnerId, GeneralConstId, GenericDefId, HasModule, + StaticId, attrs::AttrFlags, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, - expr_store::Body, + expr_store::{Body, ExpressionStore}, hir::{Expr, ExprId, Literal}, }; use hir_expand::Lookup; @@ -28,7 +29,7 @@ traits::StoredParamEnvAndCrate, }; -use super::mir::{interpret_mir, lower_to_mir, pad16}; +use super::mir::{interpret_mir, lower_body_to_mir, pad16}; pub fn unknown_const<'db>(_ty: Ty<'db>) -> Const<'db> { Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed)) @@ -235,6 +236,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option None, }, ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().memory, false))), ConstKind::Error(_) => None, @@ -258,6 +260,7 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< let ec = db.const_eval_static(id).ok()?; try_const_isize(db, &ec) } + GeneralConstId::AnonConstId(_) => None, }, ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().memory, true))), ConstKind::Error(_) => None, @@ -271,9 +274,9 @@ pub(crate) fn const_eval_discriminant_variant( ) -> Result { let interner = DbInterner::new_no_crate(db); let def = variant_id.into(); - let body = db.body(def); + let body = Body::of(db, def); let loc = variant_id.lookup(db); - if matches!(body[body.body_expr], Expr::Missing) { + if matches!(body[body.root_expr()], Expr::Missing) { let prev_idx = loc.index.checked_sub(1); let value = match prev_idx { Some(prev_idx) => { @@ -292,7 +295,7 @@ pub(crate) fn const_eval_discriminant_variant( let mir_body = db.monomorphized_mir_body( def, GenericArgs::empty(interner).store(), - ParamEnvAndCrate { param_env: db.trait_environment_for_body(def), krate: def.krate(db) } + ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } .store(), )?; let c = interpret_mir(db, mir_body, false, None)?.0?; @@ -309,23 +312,23 @@ pub(crate) fn const_eval_discriminant_variant( // and make this function private. See the fixme comment on `InferenceContext::resolve_all`. pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'db>) -> Const<'db> { let infer = ctx.fixme_resolve_all_clone(); - fn has_closure(body: &Body, expr: ExprId) -> bool { - if matches!(body[expr], Expr::Closure { .. }) { + fn has_closure(store: &ExpressionStore, expr: ExprId) -> bool { + if matches!(store[expr], Expr::Closure { .. }) { return true; } let mut r = false; - body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx)); + store.walk_child_exprs(expr, |idx| r |= has_closure(store, idx)); r } - if has_closure(ctx.body, expr) { + if has_closure(ctx.store, expr) { // Type checking clousres need an isolated body (See the above FIXME). Bail out early to prevent panic. return Const::error(ctx.interner()); } - if let Expr::Path(p) = &ctx.body[expr] { + if let Expr::Path(p) = &ctx.store[expr] { let mut ctx = TyLoweringContext::new( ctx.db, &ctx.resolver, - ctx.body, + ctx.store, ctx.generic_def, LifetimeElisionKind::Infer, ); @@ -333,7 +336,9 @@ fn has_closure(body: &Body, expr: ExprId) -> bool { return c; } } - if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) + if let Some(body_owner) = ctx.owner.as_def_with_body() + && let Ok(mir_body) = + lower_body_to_mir(ctx.db, body_owner, Body::of(ctx.db, body_owner), &infer, expr) && let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None) { return result; @@ -370,8 +375,12 @@ pub(crate) fn const_eval_query<'db>( let body = db.monomorphized_mir_body( def.into(), subst, - ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } - .store(), + ParamEnvAndCrate { + param_env: db + .trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(def))), + krate: def.krate(db), + } + .store(), )?; let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref()))?.0?; Ok(c.store()) @@ -407,7 +416,8 @@ pub(crate) fn const_eval_static_query<'db>( def.into(), GenericArgs::empty(interner).store(), ParamEnvAndCrate { - param_env: db.trait_environment_for_body(def.into()), + param_env: db + .trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(def))), krate: def.krate(db), } .store(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 5f6bcb4a602c..31cf86476f9a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -1,5 +1,5 @@ use base_db::RootQueryDb; -use hir_def::db::DefDatabase; +use hir_def::signatures::ConstSignature; use hir_expand::EditionedFileId; use rustc_apfloat::{ Float, @@ -131,7 +131,11 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEv .declarations() .find_map(|x| match x { hir_def::ModuleDefId::ConstId(x) => { - if db.const_signature(x).name.as_ref()?.display(db, file_id.edition(db)).to_string() + if ConstSignature::of(db, x) + .name + .as_ref()? + .display(db, file_id.edition(db)) + .to_string() == "GOAL" { Some(x) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 70474fc46919..a0fb75397a23 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -5,9 +5,9 @@ use either::Either; use hir_def::{ AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, - FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, - TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, hir::ExprId, - layout::TargetDataLayout, + ExpressionStoreOwnerId, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, + StaticId, TraitId, TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, + db::DefDatabase, hir::ExprId, layout::TargetDataLayout, }; use la_arena::ArenaMap; use salsa::plumbing::AsId; @@ -178,13 +178,9 @@ fn callable_item_signature<'db>( def: CallableDefId, ) -> EarlyBinder<'db, PolyFnSig<'db>>; - #[salsa::invoke(crate::lower::trait_environment_for_body_query)] - #[salsa::transparent] - fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) -> ParamEnv<'db>; - #[salsa::invoke(crate::lower::trait_environment)] #[salsa::transparent] - fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db>; + fn trait_environment<'db>(&'db self, def: ExpressionStoreOwnerId) -> ParamEnv<'db>; #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)] @@ -240,7 +236,7 @@ pub struct InternedOpaqueTyId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct InternedClosure(pub DefWithBodyId, pub ExprId); +pub struct InternedClosure(pub ExpressionStoreOwnerId, pub ExprId); #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] @@ -249,7 +245,7 @@ pub struct InternedClosureId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId); +pub struct InternedCoroutine(pub ExpressionStoreOwnerId, pub ExprId); #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 29da1b0c513b..89d8c0e91d18 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -17,8 +17,17 @@ use hir_def::{ AdtId, ConstId, EnumId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, - ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, attrs::AttrFlags, - db::DefDatabase, hir::Pat, item_tree::FieldsShape, signatures::StaticFlags, src::HasSource, + ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, + attrs::AttrFlags, + db::DefDatabase, + expr_store::Body, + hir::Pat, + item_tree::FieldsShape, + signatures::{ + ConstSignature, EnumSignature, FunctionSignature, StaticFlags, StaticSignature, + StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, + }, + src::HasSource, }; use hir_expand::{ HirFileId, @@ -77,6 +86,7 @@ pub enum IdentType { Structure, Trait, TypeAlias, + Union, Variable, Variant, } @@ -94,6 +104,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { IdentType::Structure => "Structure", IdentType::Trait => "Trait", IdentType::TypeAlias => "Type alias", + IdentType::Union => "Union", IdentType::Variable => "Variable", IdentType::Variant => "Variant", }; @@ -146,9 +157,7 @@ fn validate_adt(&mut self, adt: AdtId) { match adt { AdtId::StructId(struct_id) => self.validate_struct(struct_id), AdtId::EnumId(enum_id) => self.validate_enum(enum_id), - AdtId::UnionId(_) => { - // FIXME: Unions aren't yet supported by this validator. - } + AdtId::UnionId(union_id) => self.validate_union(union_id), } } @@ -178,7 +187,7 @@ fn validate_module(&mut self, module_id: ModuleId) { fn validate_trait(&mut self, trait_id: TraitId) { // Check the trait name. - let data = self.db.trait_signature(trait_id); + let data = TraitSignature::of(self.db, trait_id); self.create_incorrect_case_diagnostic_for_item_name( trait_id, &data.name, @@ -197,7 +206,7 @@ fn validate_func(&mut self, func: FunctionId) { // Check the function name. // Skipped if function is an associated item of a trait implementation. if !self.is_trait_impl_container(container) { - let data = self.db.function_signature(func); + let data = FunctionSignature::of(self.db, func); // Don't run the lint on extern "[not Rust]" fn items with the // #[no_mangle] attribute. @@ -223,7 +232,7 @@ fn validate_func(&mut self, func: FunctionId) { /// Check incorrect names for patterns inside the function body. /// This includes function parameters except for trait implementation associated functions. fn validate_func_body(&mut self, func: FunctionId) { - let body = self.db.body(func.into()); + let body = Body::of(self.db, func.into()); let edition = self.edition(func); let mut pats_replacements = body .pats() @@ -250,7 +259,7 @@ fn validate_func_body(&mut self, func: FunctionId) { return; } - let source_map = self.db.body_with_source_map(func.into()).1; + let source_map = &Body::with_source_map(self.db, func.into()).1; for (id, replacement) in pats_replacements { let Ok(source_ptr) = source_map.pat_syntax(id) else { continue; @@ -292,7 +301,7 @@ fn edition(&self, id: impl HasModule) -> span::Edition { fn validate_struct(&mut self, struct_id: StructId) { // Check the structure name. - let data = self.db.struct_signature(struct_id); + let data = StructSignature::of(self.db, struct_id); // rustc implementation excuses repr(C) since C structs predominantly don't // use camel case. @@ -383,9 +392,97 @@ fn validate_struct_fields(&mut self, struct_id: StructId) { } } + fn validate_union(&mut self, union_id: UnionId) { + // Check the union name. + let data = UnionSignature::of(self.db, union_id); + + // rustc implementation excuses repr(C) since C unions predominantly don't + // use camel case. + let has_repr_c = AttrFlags::repr(self.db, union_id.into()).is_some_and(|repr| repr.c()); + if !has_repr_c { + self.create_incorrect_case_diagnostic_for_item_name( + union_id, + &data.name, + CaseType::UpperCamelCase, + IdentType::Union, + ); + } + + // Check the field names. + self.validate_union_fields(union_id); + } + + /// Check incorrect names for union fields. + fn validate_union_fields(&mut self, union_id: UnionId) { + let data = union_id.fields(self.db); + let edition = self.edition(union_id); + let mut union_fields_replacements = data + .fields() + .iter() + .filter_map(|(_, field)| { + to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map( + |new_name| Replacement { + current_name: field.name.clone(), + suggested_text: new_name, + expected_case: CaseType::LowerSnakeCase, + }, + ) + }) + .peekable(); + + // XXX: Only look at sources if we do have incorrect names. + if union_fields_replacements.peek().is_none() { + return; + } + + let union_loc = union_id.lookup(self.db); + let union_src = union_loc.source(self.db); + + let Some(union_fields_list) = union_src.value.record_field_list() else { + always!( + union_fields_replacements.peek().is_none(), + "Replacements ({:?}) were generated for a union fields \ + which had no fields list: {:?}", + union_fields_replacements.collect::>(), + union_src + ); + return; + }; + let mut union_fields_iter = union_fields_list.fields(); + for field_replacement in union_fields_replacements { + // We assume that parameters in replacement are in the same order as in the + // actual params list, but just some of them (ones that named correctly) are skipped. + let field = loop { + if let Some(field) = union_fields_iter.next() { + let Some(field_name) = field.name() else { + continue; + }; + if field_name.as_name() == field_replacement.current_name { + break field; + } + } else { + never!( + "Replacement ({:?}) was generated for a union field \ + which was not found: {:?}", + field_replacement, + union_src + ); + return; + } + }; + + self.create_incorrect_case_diagnostic_for_ast_node( + field_replacement, + union_src.file_id, + &field, + IdentType::Field, + ); + } + } + fn validate_enum(&mut self, enum_id: EnumId) { // Check the enum name. - let data = self.db.enum_signature(enum_id); + let data = EnumSignature::of(self.db, enum_id); // rustc implementation excuses repr(C) since C structs predominantly don't // use camel case. @@ -556,7 +653,7 @@ fn validate_const(&mut self, const_id: ConstId) { return; } - let data = self.db.const_signature(const_id); + let data = ConstSignature::of(self.db, const_id); let Some(name) = &data.name else { return; }; @@ -569,7 +666,7 @@ fn validate_const(&mut self, const_id: ConstId) { } fn validate_static(&mut self, static_id: StaticId) { - let data = self.db.static_signature(static_id); + let data = StaticSignature::of(self.db, static_id); if data.flags.contains(StaticFlags::EXTERN) { cov_mark::hit!(extern_static_incorrect_case_ignored); return; @@ -595,7 +692,7 @@ fn validate_type_alias(&mut self, type_alias_id: TypeAliasId) { } // Check the type alias name. - let data = self.db.type_alias_signature(type_alias_id); + let data = TypeAliasSignature::of(self.db, type_alias_id); self.create_incorrect_case_diagnostic_for_item_name( type_alias_id, &data.name, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 4e1bb6f4c533..33d9dd538dd3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -21,7 +21,7 @@ ast::{self, UnaryOp}, }; use tracing::debug; -use triomphe::Arc; + use typed_arena::Arena; use crate::{ @@ -76,9 +76,9 @@ pub fn collect( validate_lints: bool, ) -> Vec { let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered(); - let infer = InferenceResult::for_body(db, owner); - let body = db.body(owner); - let env = db.trait_environment_for_body(owner); + let infer = InferenceResult::of(db, owner); + let body = Body::of(db, owner); + let env = db.trait_environment(owner.into()); let interner = DbInterner::new_with(db, owner.krate(db)); let infcx = interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into())); @@ -98,7 +98,7 @@ pub fn collect( struct ExprValidator<'db> { owner: DefWithBodyId, - body: Arc, + body: &'db Body, infer: &'db InferenceResult, env: ParamEnv<'db>, diagnostics: Vec, @@ -116,10 +116,10 @@ fn validate_body(&mut self) { let db = self.db(); let mut filter_map_next_checker = None; // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint - let body = Arc::clone(&self.body); + let body = self.body; if matches!(self.owner, DefWithBodyId::FunctionId(_)) { - self.check_for_trailing_return(body.body_expr, &body); + self.check_for_trailing_return(body.root_expr(), body); } for (id, expr) in body.exprs() { @@ -141,7 +141,7 @@ fn validate_body(&mut self) { self.validate_call(id, expr, &mut filter_map_next_checker); } Expr::Closure { body: body_expr, .. } => { - self.check_for_trailing_return(*body_expr, &body); + self.check_for_trailing_return(*body_expr, body); } Expr::If { .. } => { self.check_for_unnecessary_else(id, expr); @@ -240,7 +240,7 @@ fn validate_match(&mut self, match_expr: ExprId, scrutinee_expr: ExprId, arms: & .as_reference() .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) .unwrap_or(false)) - && types_of_subpatterns_do_match(arm.pat, &self.body, self.infer) + && types_of_subpatterns_do_match(arm.pat, self.body, self.infer) { // If we had a NotUsefulMatchArm diagnostic, we could // check the usefulness of each pattern as we added it @@ -388,7 +388,7 @@ fn lower_pattern<'a>( pat: PatId, have_errors: &mut bool, ) -> DeconstructedPat<'a, 'db> { - let mut patcx = match_check::PatCtxt::new(self.db(), self.infer, &self.body); + let mut patcx = match_check::PatCtxt::new(self.db(), self.infer, self.body); let pattern = patcx.lower_pattern(pat); let pattern = cx.lower_pat(&pattern); if !patcx.errors.is_empty() { @@ -451,7 +451,7 @@ fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr) { && last_then_expr_ty.is_never() { // Only look at sources if the then branch diverges and we have an else branch. - let source_map = self.db().body_with_source_map(self.owner).1; + let source_map = &Body::with_source_map(self.db(), self.owner).1; let Ok(source_ptr) = source_map.expr_syntax(id) else { return; }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index 8e6101e6a0e3..f559c26bf57e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -14,6 +14,7 @@ expr_store::{Body, path::Path}, hir::PatId, item_tree::FieldsShape, + signatures::{StructSignature, UnionSignature}, }; use hir_expand::name::Name; use rustc_type_ir::inherent::IntoKind; @@ -340,12 +341,12 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> VariantId::StructId(s) => write!( f, "{}", - f.db.struct_signature(s).name.display(f.db, f.edition()) + StructSignature::of(f.db, s).name.display(f.db, f.edition()) )?, VariantId::UnionId(u) => write!( f, "{}", - f.db.union_signature(u).name.display(f.db, f.edition()) + UnionSignature::of(f.db, u).name.display(f.db, f.edition()) )?, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index eda7e7e249b3..bc3d9bbec6fa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -4,6 +4,7 @@ use hir_def::{ EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId, attrs::AttrFlags, + signatures::VariantFields, }; use intern::sym; use rustc_pattern_analysis::{ @@ -363,7 +364,8 @@ fn ctor_sub_tys( let adt = adt_def.def_id().0; let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); - let visibilities = LazyCell::new(|| self.db.field_visibilities(variant)); + let visibilities = + LazyCell::new(|| VariantFields::field_visibilities(self.db, variant)); self.list_variant_fields(*ty, variant) .map(move |(fid, ty)| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 21f263723bb1..09c648139c45 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -5,11 +5,12 @@ use either::Either; use hir_def::{ - AdtId, CallableDefId, DefWithBodyId, FieldId, FunctionId, VariantId, - expr_store::{Body, path::Path}, + AdtId, CallableDefId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, FunctionId, GenericDefId, + VariantId, + expr_store::{Body, ExpressionStore, path::Path}, hir::{AsmOperand, Expr, ExprId, ExprOrPatId, InlineAsmKind, Pat, PatId, Statement, UnaryOp}, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, - signatures::StaticFlags, + signatures::{FunctionSignature, StaticFlags, StaticSignature}, type_ref::Rawness, }; use rustc_type_ir::inherent::IntoKind; @@ -34,15 +35,15 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafe let _p = tracing::info_span!("missing_unsafe").entered(); let is_unsafe = match def { - DefWithBodyId::FunctionId(it) => db.function_signature(it).is_unsafe(), + DefWithBodyId::FunctionId(it) => FunctionSignature::of(db, it).is_unsafe(), DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => { false } }; let mut res = MissingUnsafeResult { fn_is_unsafe: is_unsafe, ..MissingUnsafeResult::default() }; - let body = db.body(def); - let infer = InferenceResult::for_body(db, def); + let body = Body::of(db, def); + let infer = InferenceResult::of(db, def); let mut callback = |diag| match diag { UnsafeDiagnostic::UnsafeOperation { node, inside_unsafe_block, reason } => { if inside_unsafe_block == InsideUnsafeBlock::No { @@ -55,8 +56,8 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafe } } }; - let mut visitor = UnsafeVisitor::new(db, infer, &body, def, &mut callback); - visitor.walk_expr(body.body_expr); + let mut visitor = UnsafeVisitor::new(db, infer, body, def.into(), &mut callback); + visitor.walk_expr(body.root_expr()); if !is_unsafe { // Unsafety in function parameter patterns (that can only be union destructuring) @@ -109,8 +110,8 @@ pub fn unsafe_operations_for_body( callback(node); } }; - let mut visitor = UnsafeVisitor::new(db, infer, body, def, &mut visitor_callback); - visitor.walk_expr(body.body_expr); + let mut visitor = UnsafeVisitor::new(db, infer, body, def.into(), &mut visitor_callback); + visitor.walk_expr(body.root_expr()); for ¶m in &body.params { visitor.walk_pat(param); } @@ -119,8 +120,8 @@ pub fn unsafe_operations_for_body( pub fn unsafe_operations( db: &dyn HirDatabase, infer: &InferenceResult, - def: DefWithBodyId, - body: &Body, + def: ExpressionStoreOwnerId, + body: &ExpressionStore, current: ExprId, callback: &mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock), ) { @@ -137,9 +138,9 @@ pub fn unsafe_operations( struct UnsafeVisitor<'db> { db: &'db dyn HirDatabase, infer: &'db InferenceResult, - body: &'db Body, + body: &'db ExpressionStore, resolver: Resolver<'db>, - def: DefWithBodyId, + def: ExpressionStoreOwnerId, inside_unsafe_block: InsideUnsafeBlock, inside_assignment: bool, inside_union_destructure: bool, @@ -156,13 +157,16 @@ impl<'db> UnsafeVisitor<'db> { fn new( db: &'db dyn HirDatabase, infer: &'db InferenceResult, - body: &'db Body, - def: DefWithBodyId, + body: &'db ExpressionStore, + def: ExpressionStoreOwnerId, unsafe_expr_cb: &'db mut dyn FnMut(UnsafeDiagnostic), ) -> Self { let resolver = def.resolver(db); let def_target_features = match def { - DefWithBodyId::FunctionId(func) => TargetFeatures::from_fn(db, func), + ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(func)) + | ExpressionStoreOwnerId::Signature(GenericDefId::FunctionId(func)) => { + TargetFeatures::from_fn(db, func) + } _ => TargetFeatures::default(), }; let krate = resolver.krate(); @@ -431,7 +435,7 @@ fn mark_unsafe_path(&mut self, node: ExprOrPatId, path: &Path) { let hygiene = self.body.expr_or_pat_path_hygiene(node); let value_or_partial = self.resolver.resolve_path_in_value_ns(self.db, path, hygiene); if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial { - let static_data = self.db.static_signature(id); + let static_data = StaticSignature::of(self.db, id); if static_data.flags.contains(StaticFlags::MUTABLE) { self.on_unsafe_op(node, UnsafetyReason::MutableStatic); } else if static_data.flags.contains(StaticFlags::EXTERN) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 4e77e8be364b..d68058864564 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -10,15 +10,18 @@ use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId, - ModuleId, TraitId, + ExpressionStoreOwnerId, FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, + Lookup, ModuleDefId, ModuleId, TraitId, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, - hir::generics::{TypeOrConstParamData, TypeParamProvenance, WherePredicate}, + hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, item_scope::ItemInNs, item_tree::FieldsShape, lang_item::LangItems, - signatures::VariantFields, + signatures::{ + EnumSignature, FunctionSignature, StructSignature, TraitSignature, TypeAliasSignature, + UnionSignature, VariantFields, + }, type_ref::{ ConstRef, LifetimeRef, LifetimeRefId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, UseArgRef, @@ -671,7 +674,9 @@ fn write_projection<'db>( write!( f, ">::{}", - f.db.type_alias_signature(alias.def_id.expect_type_alias()).name.display(f.db, f.edition()) + TypeAliasSignature::of(f.db, alias.def_id.expect_type_alias()) + .name + .display(f.db, f.edition()) )?; let proj_params = &alias.args.as_slice()[trait_ref.args.len()..]; hir_fmt_generics(f, proj_params, None, None) @@ -853,7 +858,7 @@ fn render_const_scalar_inner<'db>( } TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.def_id().0 { hir_def::AdtId::StructId(s) => { - let data = f.db.struct_signature(s); + let data = StructSignature::of(f.db, s); write!(f, "&{}", data.name.display(f.db, f.edition()))?; Ok(()) } @@ -911,14 +916,16 @@ fn render_const_scalar_inner<'db>( }; match def { hir_def::AdtId::StructId(s) => { - let data = f.db.struct_signature(s); + let data = StructSignature::of(f.db, s); write!(f, "{}", data.name.display(f.db, f.edition()))?; let field_types = f.db.field_types(s.into()); render_variant_after_name( s.fields(f.db), f, field_types, - f.db.trait_environment(def.into()), + f.db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( + def, + ))), &layout, args, b, @@ -926,7 +933,7 @@ fn render_const_scalar_inner<'db>( ) } hir_def::AdtId::UnionId(u) => { - write!(f, "{}", f.db.union_signature(u).name.display(f.db, f.edition())) + write!(f, "{}", UnionSignature::of(f.db, u).name.display(f.db, f.edition())) } hir_def::AdtId::EnumId(e) => { let Ok(target_data_layout) = f.db.target_data_layout(f.krate()) else { @@ -950,7 +957,9 @@ fn render_const_scalar_inner<'db>( var_id.fields(f.db), f, field_types, - f.db.trait_environment(def.into()), + f.db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( + def, + ))), var_layout, args, b, @@ -1152,11 +1161,13 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) write!(f, "fn ")?; f.start_location_link(def.into()); match def { - CallableDefId::FunctionId(ff) => { - write!(f, "{}", db.function_signature(ff).name.display(f.db, f.edition()))? - } + CallableDefId::FunctionId(ff) => write!( + f, + "{}", + FunctionSignature::of(db, ff).name.display(f.db, f.edition()) + )?, CallableDefId::StructId(s) => { - write!(f, "{}", db.struct_signature(s).name.display(f.db, f.edition()))? + write!(f, "{}", StructSignature::of(db, s).name.display(f.db, f.edition()))? } CallableDefId::EnumVariantId(e) => { let loc = e.lookup(db); @@ -1235,9 +1246,11 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) match f.display_kind { DisplayKind::Diagnostics | DisplayKind::Test => { let name = match def_id { - hir_def::AdtId::StructId(it) => db.struct_signature(it).name.clone(), - hir_def::AdtId::UnionId(it) => db.union_signature(it).name.clone(), - hir_def::AdtId::EnumId(it) => db.enum_signature(it).name.clone(), + hir_def::AdtId::StructId(it) => { + StructSignature::of(db, it).name.clone() + } + hir_def::AdtId::UnionId(it) => UnionSignature::of(db, it).name.clone(), + hir_def::AdtId::EnumId(it) => EnumSignature::of(db, it).name.clone(), }; write!(f, "{}", name.display(f.db, f.edition()))?; } @@ -1272,7 +1285,7 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) write_projection(f, &alias_ty, trait_bounds_need_parens)? } TyKind::Foreign(alias) => { - let type_alias = db.type_alias_signature(alias.0); + let type_alias = TypeAliasSignature::of(db, alias.0); f.start_location_link(alias.0.into()); write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; f.end_location_link(); @@ -1336,8 +1349,8 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) } let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe); let sig = sig.skip_binder(); - let InternedClosure(def, _) = db.lookup_intern_closure(id); - let infer = InferenceResult::for_body(db, def); + let InternedClosure(owner, _) = db.lookup_intern_closure(id); + let infer = InferenceResult::of(db, owner); let (_, kind) = infer.closure_info(id); match f.closure_style { ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?, @@ -1526,7 +1539,7 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db); let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } = subst.split_coroutine_args(); - let body = db.body(owner); + let body = ExpressionStore::of(db, owner); let expr = &body[expr_id]; match expr { hir_def::hir::Expr::Closure { @@ -1867,7 +1880,7 @@ fn write_bounds_like_dyn_trait<'db>( // existential) here, which is the only thing that's // possible in actual Rust, and hence don't print it f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; + write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?; f.end_location_link(); if is_fn_trait { if let [_self, params @ ..] = trait_ref.trait_ref.args.as_slice() @@ -1930,7 +1943,7 @@ fn write_bounds_like_dyn_trait<'db>( angle_open = true; } let assoc_ty_id = projection.def_id().expect_type_alias(); - let type_alias = f.db.type_alias_signature(assoc_ty_id); + let type_alias = TypeAliasSignature::of(f.db, assoc_ty_id); f.start_location_link(assoc_ty_id.into()); write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; f.end_location_link(); @@ -2021,7 +2034,7 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let trait_ = self.def_id.0; f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; + write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?; f.end_location_link(); let substs = self.args.as_slice(); hir_fmt_generic_args(f, &substs[1..], None, Some(self.self_ty())) @@ -2128,7 +2141,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Res LifetimeRef::Placeholder => write!(f, "'_"), LifetimeRef::Error => write!(f, "'{{error}}"), &LifetimeRef::Param(lifetime_param_id) => { - let generic_params = f.db.generic_params(lifetime_param_id.parent); + let generic_params = GenericParams::of(f.db, lifetime_param_id.parent); write!( f, "{}", @@ -2144,7 +2157,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Res match &store[*self] { TypeRef::Never => write!(f, "!")?, TypeRef::TypeParam(param) => { - let generic_params = f.db.generic_params(param.parent()); + let generic_params = GenericParams::of(f.db, param.parent()); match generic_params[param.local_id()].name() { Some(name) => write!(f, "{}", name.display(f.db, f.edition()))?, None => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 9d6869eee9b8..ddc4e4ce85ef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -1,6 +1,9 @@ //! Utilities for computing drop info about types. -use hir_def::{AdtId, signatures::StructFlags}; +use hir_def::{ + AdtId, + signatures::{StructFlags, StructSignature}, +}; use rustc_hash::FxHashSet; use rustc_type_ir::inherent::{AdtDef, IntoKind}; use stdx::never; @@ -73,8 +76,7 @@ fn has_drop_glue_impl<'db>( } match adt_id { AdtId::StructId(id) => { - if db - .struct_signature(id) + if StructSignature::of(db, id) .flags .intersects(StructFlags::IS_MANUALLY_DROP | StructFlags::IS_PHANTOM_DATA) { @@ -132,9 +134,9 @@ fn has_drop_glue_impl<'db>( TyKind::Slice(ty) => has_drop_glue_impl(infcx, ty, env, visited), TyKind::Closure(closure_id, subst) => { let owner = db.lookup_intern_closure(closure_id.0).0; - let infer = InferenceResult::for_body(db, owner); + let infer = InferenceResult::of(db, owner); let (captures, _) = infer.closure_info(closure_id.0); - let env = db.trait_environment_for_body(owner); + let env = db.trait_environment(owner); captures .iter() .map(|capture| has_drop_glue_impl(infcx, capture.ty(db, subst), env, visited)) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 59cfd3fdc98c..4c300affd8a2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -4,8 +4,10 @@ use hir_def::{ AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, - TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId, - nameres::crate_def_map, signatures::TraitFlags, + TypeOrConstParamId, TypeParamId, + hir::generics::{GenericParams, LocalTypeOrConstParamId}, + nameres::crate_def_map, + signatures::{FunctionSignature, TraitFlags, TraitSignature}, }; use rustc_hash::FxHashSet; use rustc_type_ir::{ @@ -298,7 +300,7 @@ fn dyn_compatibility_violation_for_assoc_item( if def_map.is_unstable_feature_enabled(&intern::sym::generic_associated_type_extended) { ControlFlow::Continue(()) } else { - let generic_params = db.generic_params(item.into()); + let generic_params = GenericParams::of(db, item.into()); if !generic_params.is_empty() { cb(DynCompatibilityViolation::GAT(it)) } else { @@ -318,7 +320,7 @@ fn virtual_call_violations_for_method( where F: FnMut(MethodViolationCode) -> ControlFlow<()>, { - let func_data = db.function_signature(func); + let func_data = FunctionSignature::of(db, func); if !func_data.has_self_param() { cb(MethodViolationCode::StaticMethod)?; } @@ -349,7 +351,7 @@ fn virtual_call_violations_for_method( cb(mvc)?; } - let generic_params = db.generic_params(func.into()); + let generic_params = GenericParams::of(db, func.into()); if generic_params.len_type_or_consts() > 0 { cb(MethodViolationCode::Generic)?; } @@ -371,7 +373,7 @@ fn virtual_call_violations_for_method( trait_ref: pred_trait_ref, polarity: PredicatePolarity::Positive, }) = pred - && let trait_data = db.trait_signature(pred_trait_ref.def_id.0) + && let trait_data = TraitSignature::of(db, pred_trait_ref.def_id.0) && trait_data.flags.contains(TraitFlags::AUTO) && let rustc_type_ir::TyKind::Param(ParamTy { index: 0, .. }) = pred_trait_ref.self_ty().kind() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index 5c9b06e39a70..a70f98a0fe7b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use hir_def::db::DefDatabase; +use hir_def::signatures::TraitSignature; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ToSmolStr; use test_fixture::WithFixture; @@ -40,8 +40,7 @@ fn check_dyn_compatibility<'a>( .declarations() .filter_map(|def| { if let hir_def::ModuleDefId::TraitId(trait_id) = def { - let name = db - .trait_signature(trait_id) + let name = TraitSignature::of(&db, trait_id) .name .display_no_db(file_id.edition(&db)) .to_smolstr(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index b1500bcdb756..822942eec37d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -20,24 +20,23 @@ }, }; use itertools::chain; -use triomphe::Arc; -pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { +pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics<'_> { let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); - let (params, store) = db.generic_params_and_store(def); + let (params, store) = GenericParams::with_store(db, def); let has_trait_self_param = params.trait_self_param().is_some(); Generics { def, params, parent_generics, has_trait_self_param, store } } #[derive(Clone, Debug)] -pub struct Generics { +pub struct Generics<'db> { def: GenericDefId, - params: Arc, - store: Arc, - parent_generics: Option>, + params: &'db GenericParams, + store: &'db ExpressionStore, + parent_generics: Option>>, has_trait_self_param: bool, } -impl ops::Index for Generics +impl ops::Index for Generics<'_> where GenericParams: ops::Index, { @@ -47,13 +46,13 @@ fn index(&self, index: T) -> &Self::Output { } } -impl Generics { +impl<'db> Generics<'db> { pub(crate) fn def(&self) -> GenericDefId { self.def } pub(crate) fn store(&self) -> &ExpressionStore { - &self.store + self.store } pub(crate) fn where_predicates(&self) -> impl Iterator { @@ -97,7 +96,7 @@ pub(crate) fn iter_parents_with_store( ) -> impl Iterator), &ExpressionStore)> + '_ { self.iter_parent() - .zip(self.parent_generics().into_iter().flat_map(|it| std::iter::repeat(&*it.store))) + .zip(self.parent_generics().into_iter().flat_map(|it| std::iter::repeat(it.store))) } /// Iterate over the params without parent params. @@ -185,7 +184,7 @@ fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option { if param.parent == self.def { let idx = param.local_id.into_raw().into_u32() as usize; debug_assert!( - idx <= self.params.len_type_or_consts(), + idx < self.params.len_type_or_consts(), "idx: {} len: {}", idx, self.params.len_type_or_consts() @@ -219,7 +218,7 @@ fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option { } } - pub(crate) fn parent_generics(&self) -> Option<&Generics> { + pub(crate) fn parent_generics(&self) -> Option<&Generics<'db>> { self.parent_generics.as_deref() } } @@ -243,7 +242,7 @@ pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Opt } fn from_toc_id<'a>( - it: &'a Generics, + it: &'a Generics<'a>, ) -> impl Fn( (LocalTypeOrConstParamId, &'a TypeOrConstParamData), ) -> (GenericParamId, GenericParamDataRef<'a>) { @@ -263,7 +262,7 @@ fn from_toc_id<'a>( } fn from_lt_id<'a>( - it: &'a Generics, + it: &'a Generics<'a>, ) -> impl Fn((LocalLifetimeParamId, &'a LifetimeParamData)) -> (GenericParamId, GenericParamDataRef<'a>) { move |(local_id, p): (_, _)| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 991acda14bc7..d14e9d652654 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -33,14 +33,15 @@ use base_db::Crate; use either::Either; use hir_def::{ - AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId, - ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, - expr_store::{Body, ExpressionStore, HygieneId, path::Path}, + AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, + FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup, TraitId, + TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId, + expr_store::{Body, ExpressionStore, HygieneId, RootExprOrigin, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::LangItems, layout::Integer, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, - signatures::{ConstSignature, EnumSignature, StaticSignature}, + signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, type_ref::{ConstRef, LifetimeRefId, TypeRef, TypeRefId}, }; use hir_expand::{mod_path::ModPath, name::Name}; @@ -104,19 +105,18 @@ pub fn infer_query_with_inspect<'db>( ) -> InferenceResult { let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); - let body = db.body(def); - let mut ctx = InferenceContext::new(db, def, &body, resolver); + let body = Body::of(db, def); + let mut ctx = + InferenceContext::new(db, ExpressionStoreOwnerId::Body(def), &body.store, resolver); if let Some(inspect) = inspect { ctx.table.infer_ctxt.attach_obligation_inspector(inspect); } match def { - DefWithBodyId::FunctionId(f) => { - ctx.collect_fn(f); - } - DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)), - DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)), + DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param, &body.params), + DefWithBodyId::ConstId(c) => ctx.collect_const(c, ConstSignature::of(db, c)), + DefWithBodyId::StaticId(s) => ctx.collect_static(StaticSignature::of(db, s)), DefWithBodyId::VariantId(v) => { ctx.return_ty = match EnumSignature::variant_body_type(db, v.lookup(db).parent) { hir_def::layout::IntegerType::Pointer(signed) => match signed { @@ -143,10 +143,113 @@ pub fn infer_query_with_inspect<'db>( } } - ctx.infer_body(); + ctx.infer_body(body.root_expr()); - ctx.infer_mut_body(); + ctx.infer_mut_body(body.root_expr()); + infer_finalize(ctx) +} + +fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> InferenceResult { + InferenceResult { + has_errors: true, + ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) + } +} + +/// Infer types for all const expressions in an item's signature. +/// +/// This handles const expressions that appear in type positions within a generic +/// item's signature, such as array lengths (`[T; N]`) and const generic arguments +/// (`Foo<{ expr }>`). Each root expression is inferred independently within +/// a shared `InferenceContext`, accumulating results into a single `InferenceResult`. +fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { + let _p = tracing::info_span!("infer_signature_query").entered(); + let store = ExpressionStore::of(db, def.into()); + let mut roots = store.expr_roots_with_origins().peekable(); + let Some(_) = roots.peek() else { + return InferenceResult::new(crate::next_solver::default_types(db).types.error); + }; + + let resolver = def.resolver(db); + let owner = ExpressionStoreOwnerId::Signature(def); + + let mut ctx = InferenceContext::new(db, owner, store, resolver); + + for (root_expr, origin) in roots { + let expected = match origin { + // Array lengths are always `usize`. + RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), + // Const parameter default: look up the param's declared type. + RootExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns( + ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }), + )), + // Path const generic args: determining the expected type requires + // path resolution. + // FIXME + RootExprOrigin::GenericArgsPath => Expectation::None, + RootExprOrigin::BodyRoot => Expectation::None, + }; + ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); + } + + infer_finalize(ctx) +} + +fn infer_variant_fields_query(db: &dyn HirDatabase, def: VariantId) -> InferenceResult { + let _p = tracing::info_span!("infer_variant_fields_query").entered(); + let store = ExpressionStore::of(db, def.into()); + let mut roots = store.expr_roots_with_origins().peekable(); + let Some(_) = roots.peek() else { + return InferenceResult::new(crate::next_solver::default_types(db).types.error); + }; + + let resolver = def.resolver(db); + let owner = ExpressionStoreOwnerId::VariantFields(def); + + let mut ctx = InferenceContext::new(db, owner, store, resolver); + + for (root_expr, origin) in roots { + let expected = match origin { + // Array lengths are always `usize`. + RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), + // unreachable + RootExprOrigin::ConstParam(_) => Expectation::None, + // Path const generic args: determining the expected type requires + // path resolution. + // FIXME + RootExprOrigin::GenericArgsPath => Expectation::None, + RootExprOrigin::BodyRoot => Expectation::None, + }; + ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); + } + + infer_finalize(ctx) +} + +fn infer_signature_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _: GenericDefId, +) -> InferenceResult { + InferenceResult { + has_errors: true, + ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) + } +} + +fn infer_variant_fields_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _: VariantId, +) -> InferenceResult { + InferenceResult { + has_errors: true, + ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) + } +} + +fn infer_finalize(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { ctx.handle_opaque_type_uses(); ctx.type_inference_fallback(); @@ -171,14 +274,6 @@ pub fn infer_query_with_inspect<'db>( ctx.resolve_all() } - -fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> InferenceResult { - InferenceResult { - has_errors: true, - ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) - } -} - /// Binding modes inferred for patterns. /// #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] @@ -552,12 +647,39 @@ pub struct InferenceResult { #[salsa::tracked] impl InferenceResult { #[salsa::tracked(returns(ref), cycle_result = infer_cycle_result)] - pub fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { + fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { infer_query(db, def) } + + /// Infer types for all const expressions in an item's signature. + /// + /// Returns an `InferenceResult` containing type information for array lengths, + /// const generic arguments, and other const expressions appearing in type + /// positions within the item's signature. + #[salsa::tracked(returns(ref), cycle_result = infer_signature_cycle_result)] + fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { + infer_signature_query(db, def) + } + + #[salsa::tracked(returns(ref), cycle_result = infer_variant_fields_cycle_result)] + fn for_variant_fields(db: &dyn HirDatabase, def: VariantId) -> InferenceResult { + infer_variant_fields_query(db, def) + } } impl InferenceResult { + pub fn of(db: &dyn HirDatabase, def: impl Into) -> &InferenceResult { + match def.into() { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + Self::for_signature(db, generic_def_id) + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Self::for_body(db, def_with_body_id), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + Self::for_variant_fields(db, variant_id) + } + } + } + fn new(error_ty: Ty<'_>) -> Self { Self { method_resolutions: Default::default(), @@ -754,8 +876,8 @@ pub fn binding_ty<'db>(&self, id: BindingId) -> Ty<'db> { #[derive(Clone, Debug)] pub(crate) struct InferenceContext<'body, 'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) owner: DefWithBodyId, - pub(crate) body: &'body Body, + pub(crate) owner: ExpressionStoreOwnerId, + pub(crate) store: &'body ExpressionStore, /// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext /// and resolve the path via its methods. This will ensure proper error reporting. pub(crate) resolver: Resolver<'db>, @@ -855,11 +977,21 @@ fn find_continuable<'a, 'db>( impl<'body, 'db> InferenceContext<'body, 'db> { fn new( db: &'db dyn HirDatabase, - owner: DefWithBodyId, - body: &'body Body, + owner: ExpressionStoreOwnerId, + store: &'body ExpressionStore, resolver: Resolver<'db>, ) -> Self { - let trait_env = db.trait_environment_for_body(owner); + let trait_env = match owner { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + db.trait_environment(ExpressionStoreOwnerId::from(generic_def_id)) + } + ExpressionStoreOwnerId::Body(def_with_body_id) => { + db.trait_environment(ExpressionStoreOwnerId::Body(def_with_body_id)) + } + ExpressionStoreOwnerId::VariantFields(variant_id) => { + db.trait_environment(ExpressionStoreOwnerId::VariantFields(variant_id)) + } + }; let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner)); let types = crate::next_solver::default_types(db); InferenceContext { @@ -878,13 +1010,8 @@ fn new( return_coercion: None, db, owner, - generic_def: match owner { - DefWithBodyId::FunctionId(it) => it.into(), - DefWithBodyId::StaticId(it) => it.into(), - DefWithBodyId::ConstId(it) => it.into(), - DefWithBodyId::VariantId(it) => it.lookup(db).parent.into(), - }, - body, + generic_def: owner.generic_def(db), + store, traits_in_scope: resolver.traits_in_scope(db), resolver, diverges: Diverges::Maybe, @@ -908,7 +1035,9 @@ fn krate(&self) -> Crate { fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget) { let (target_features, target_feature_is_safe) = self.target_features.get_or_init(|| { let target_features = match self.owner { - DefWithBodyId::FunctionId(id) => TargetFeatures::from_fn(self.db, id), + ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => { + TargetFeatures::from_fn(self.db, id) + } _ => TargetFeatures::default(), }; let target_feature_is_safe = match &self.krate().workspace_data(self.db).target { @@ -1102,12 +1231,12 @@ fn collect_static(&mut self, data: &StaticSignature) { self.return_ty = return_ty; } - fn collect_fn(&mut self, func: FunctionId) { - let data = self.db.function_signature(func); + fn collect_fn(&mut self, func: FunctionId, self_param: Option, params: &[PatId]) { + let data = FunctionSignature::of(self.db, func); let mut param_tys = self.with_ty_lowering( &data.store, InferenceTyDiagnosticSource::Signature, - LifetimeElisionKind::for_fn_params(&data), + LifetimeElisionKind::for_fn_params(data), |ctx| data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::>(), ); @@ -1130,13 +1259,13 @@ fn collect_fn(&mut self, func: FunctionId) { param_tys.push(va_list_ty); } let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.next_ty_var())); - if let Some(self_param) = self.body.self_param + if let Some(self_param) = self_param && let Some(ty) = param_tys.next() { let ty = self.process_user_written_ty(ty); self.write_binding_ty(self_param, ty); } - for (ty, pat) in param_tys.zip(&*self.body.params) { + for (ty, pat) in param_tys.zip(params) { let ty = self.process_user_written_ty(ty); self.infer_top_pat(*pat, ty, None); @@ -1170,12 +1299,12 @@ pub(crate) fn infcx(&self) -> &InferCtxt<'db> { &self.table.infer_ctxt } - fn infer_body(&mut self) { + fn infer_body(&mut self, body_expr: ExprId) { match self.return_coercion { - Some(_) => self.infer_return(self.body.body_expr), + Some(_) => self.infer_return(body_expr), None => { _ = self.infer_expr_coerce( - self.body.body_expr, + body_expr, &Expectation::has_type(self.return_ty), ExprIsRead::Yes, ) @@ -1282,7 +1411,7 @@ fn with_body_ty_lowering( f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R, ) -> R { self.with_ty_lowering( - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, f, @@ -1324,7 +1453,7 @@ fn make_ty( pub(crate) fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { self.make_ty( type_ref, - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, ) @@ -1332,7 +1461,7 @@ pub(crate) fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { pub(crate) fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty<'db>) -> Const<'db> { let const_ = self.with_ty_lowering( - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, |ctx| ctx.lower_const(const_ref, ty), @@ -1342,7 +1471,7 @@ pub(crate) fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty<'db>) -> Co pub(crate) fn make_path_as_body_const(&mut self, path: &Path, ty: Ty<'db>) -> Const<'db> { let const_ = self.with_ty_lowering( - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, |ctx| ctx.lower_path_as_const(path, ty), @@ -1356,7 +1485,7 @@ fn err_ty(&self) -> Ty<'db> { pub(crate) fn make_body_lifetime(&mut self, lifetime_ref: LifetimeRefId) -> Region<'db> { let lt = self.with_ty_lowering( - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, |ctx| ctx.lower_lifetime(lifetime_ref), @@ -1571,7 +1700,7 @@ fn resolve_variant( let mut ctx = TyLoweringContext::new( self.db, &self.resolver, - &self.body.store, + self.store, &self.diagnostics, InferenceTyDiagnosticSource::Body, self.generic_def, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index fc38361d7e41..e5ee73447471 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -1,6 +1,10 @@ //! Type cast logic. Basically coercion + additional casts. -use hir_def::{AdtId, hir::ExprId, signatures::TraitFlags}; +use hir_def::{ + AdtId, + hir::ExprId, + signatures::{TraitFlags, TraitSignature}, +}; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_type_ir::{ @@ -383,8 +387,7 @@ fn check_ptr_ptr_cast( .chain( elaborate::supertrait_def_ids(ctx.interner(), src_principal) .filter(|trait_| { - ctx.db - .trait_signature(trait_.0) + TraitSignature::of(ctx.db, trait_.0) .flags .contains(TraitFlags::AUTO) }), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs index 5a3eba1a71ae..ce0ccfe82f27 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs @@ -4,14 +4,15 @@ use base_db::Crate; use hir_def::{ - DefWithBodyId, FieldId, HasModule, VariantId, - expr_store::path::Path, + ExpressionStoreOwnerId, FieldId, HasModule, VariantId, + expr_store::{Body, ExpressionStore, path::Path}, hir::{ Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId, RecordSpread, Statement, UnaryOp, }, item_tree::FieldsShape, resolver::ValueNs, + signatures::VariantFields, }; use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; @@ -179,9 +180,26 @@ pub fn kind(&self) -> CaptureKind { } /// Converts the place to a name that can be inserted into source code. - pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); - let mut result = body[self.place.local].name.as_str().to_owned(); + pub fn place_to_name(&self, owner: ExpressionStoreOwnerId, db: &dyn HirDatabase) -> String { + let krate = owner.krate(db); + let edition = krate.data(db).edition; + let mut result = match owner { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + ExpressionStore::of(db, generic_def_id.into())[self.place.local] + .name + .display(db, edition) + .to_string() + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Body::of(db, def_with_body_id) + [self.place.local] + .name + .display(db, edition) + .to_string(), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + let fields = VariantFields::of(db, variant_id); + fields.store[self.place.local].name.display(db, edition).to_string() + } + }; for proj in &self.place.projections { match proj { HirPlaceProjection::Deref => {} @@ -213,11 +231,30 @@ pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> Strin result } - pub fn display_place_source_code(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); + pub fn display_place_source_code( + &self, + owner: ExpressionStoreOwnerId, + db: &dyn HirDatabase, + ) -> String { let krate = owner.krate(db); let edition = krate.data(db).edition; - let mut result = body[self.place.local].name.display(db, edition).to_string(); + let mut result = match owner { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + ExpressionStore::of(db, generic_def_id.into())[self.place.local] + .name + .display(db, edition) + .to_string() + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Body::of(db, def_with_body_id) + [self.place.local] + .name + .display(db, edition) + .to_string(), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + let fields = VariantFields::of(db, variant_id); + fields.store[self.place.local].name.display(db, edition).to_string() + } + }; for proj in &self.place.projections { match proj { // In source code autoderef kicks in. @@ -258,11 +295,26 @@ pub fn display_place_source_code(&self, owner: DefWithBodyId, db: &dyn HirDataba result } - pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); + pub fn display_place(&self, owner: ExpressionStoreOwnerId, db: &dyn HirDatabase) -> String { let krate = owner.krate(db); let edition = krate.data(db).edition; - let mut result = body[self.place.local].name.display(db, edition).to_string(); + let mut result = match owner { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + ExpressionStore::of(db, generic_def_id.into())[self.place.local] + .name + .display(db, edition) + .to_string() + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Body::of(db, def_with_body_id) + [self.place.local] + .name + .display(db, edition) + .to_string(), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + let fields = VariantFields::of(db, variant_id); + fields.store[self.place.local].name.display(db, edition).to_string() + } + }; let mut field_need_paren = false; for proj in &self.place.projections { match proj { @@ -346,7 +398,7 @@ fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option { if path.type_anchor().is_some() { return None; } - let hygiene = self.body.expr_or_pat_path_hygiene(id); + let hygiene = self.store.expr_or_pat_path_hygiene(id); self.resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).and_then(|result| { match result { ValueNs::LocalBinding(binding) => { @@ -365,7 +417,7 @@ fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option { /// Changes `current_capture_span_stack` to contain the stack of spans for this expr. fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option { self.current_capture_span_stack.clear(); - match &self.body[tgt_expr] { + match &self.store[tgt_expr] { Expr::Path(p) => { let resolver_guard = self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); @@ -416,7 +468,7 @@ fn truncate_capture_spans(&self, capture: &mut CapturedItemWithoutTy, mut trunca let mut actual_truncate_to = 0; for &span in &*span_stack { actual_truncate_to += 1; - if !span.is_ref_span(self.body) { + if !span.is_ref_span(self.store) { remained -= 1; if remained == 0 { break; @@ -424,7 +476,7 @@ fn truncate_capture_spans(&self, capture: &mut CapturedItemWithoutTy, mut trunca } } if actual_truncate_to < span_stack.len() - && span_stack[actual_truncate_to].is_ref_span(self.body) + && span_stack[actual_truncate_to].is_ref_span(self.store) { // Include the ref operator if there is one, we will fix it later (in `strip_captures_ref_span()`) if it's incorrect. actual_truncate_to += 1; @@ -533,7 +585,7 @@ fn walk_expr(&mut self, tgt_expr: ExprId) { } fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) { - match &self.body[tgt_expr] { + match &self.store[tgt_expr] { Expr::OffsetOf(_) => (), Expr::InlineAsm(e) => e.operands.iter().for_each(|(_, op)| match op { AsmOperand::In { expr, .. } @@ -733,7 +785,7 @@ fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) { self.consume_with_pat(rhs_place, target); self.inside_assignment = false; } - None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] { + None => self.store.walk_pats(target, &mut |pat| match &self.store[pat] { Pat::Path(path) => self.mutate_path_pat(path, pat), &Pat::Expr(expr) => { let place = self.place_of_expr(expr); @@ -775,7 +827,7 @@ fn walk_pat_inner( update_result: &mut impl FnMut(CaptureKind), mut for_mut: BorrowKind, ) { - match &self.body[p] { + match &self.store[p] { Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing @@ -819,13 +871,13 @@ fn walk_pat_inner( if self.result.pat_adjustments.get(&p).is_some_and(|it| !it.is_empty()) { for_mut = BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }; } - self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); + self.store.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); } fn is_upvar(&self, place: &HirPlace) -> bool { if let Some(c) = self.current_closure { let InternedClosure(_, root) = self.db.lookup_intern_closure(c); - return self.body.is_binding_upvar(place.local, root); + return self.store.is_binding_upvar(place.local, root); } false } @@ -858,7 +910,7 @@ fn restrict_precision_for_unsafe(&mut self) { if ty.is_raw_ptr() || ty.is_union() { capture.kind = CaptureKind::ByRef(BorrowKind::Shared); self.truncate_capture_spans(capture, 0); - capture.place.projections.truncate(0); + capture.place.projections.clear(); continue; } for (i, p) in capture.place.projections.iter().enumerate() { @@ -866,7 +918,7 @@ fn restrict_precision_for_unsafe(&mut self) { &self.table.infer_ctxt, self.table.param_env, ty, - self.owner.module(self.db).krate(self.db), + self.owner.krate(self.db), ); if ty.is_raw_ptr() || ty.is_union() { capture.kind = CaptureKind::ByRef(BorrowKind::Shared); @@ -938,7 +990,7 @@ fn consume_with_pat(&mut self, mut place: HirPlace, tgt_pat: PatId) { self.current_capture_span_stack .extend((0..adjustments_count).map(|_| MirSpan::PatId(tgt_pat))); 'reset_span_stack: { - match &self.body[tgt_pat] { + match &self.store[tgt_pat] { Pat::Missing | Pat::Wild => (), Pat::Tuple { args, ellipsis } => { let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); @@ -1089,7 +1141,7 @@ fn closure_kind(&self) -> FnTrait { fn analyze_closure(&mut self, closure: InternedClosureId) -> FnTrait { let InternedClosure(_, root) = self.db.lookup_intern_closure(closure); self.current_closure = Some(closure); - let Expr::Closure { body, capture_by, .. } = &self.body[root] else { + let Expr::Closure { body, capture_by, .. } = &self.store[root] else { unreachable!("Closure expression id is always closure"); }; self.consume_expr(*body); @@ -1133,7 +1185,7 @@ fn strip_captures_ref_span(&mut self) { for capture in &mut captures { if matches!(capture.kind, CaptureKind::ByValue) { for span_stack in &mut capture.span_stacks { - if span_stack[span_stack.len() - 1].is_ref_span(self.body) { + if span_stack[span_stack.len() - 1].is_ref_span(self.store) { span_stack.truncate(span_stack.len() - 1); } } @@ -1149,7 +1201,7 @@ pub(crate) fn infer_closures(&mut self) { let kind = self.analyze_closure(closure); for (derefed_callee, callee_ty, params, expr) in exprs { - if let &Expr::Call { callee, .. } = &self.body[expr] { + if let &Expr::Call { callee, .. } = &self.store[expr] { let mut adjustments = self.result.expr_adjustments.remove(&callee).unwrap_or_default().into_vec(); self.write_fn_trait_method_resolution( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index e79868f4ae6b..47a70492487e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -1718,6 +1718,9 @@ fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool { let InternedClosure(owner, expr) = closure.loc(db); - upvars_mentioned(db, owner) + let Some(body_owner) = owner.as_def_with_body() else { + return false; + }; + upvars_mentioned(db, body_owner) .is_some_and(|upvars| upvars.get(&expr).is_some_and(|upvars| !upvars.is_empty())) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 45b181eff8f0..dc57b1d1c215 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -11,6 +11,7 @@ InlineAsmKind, LabelId, Literal, Pat, PatId, RecordSpread, Statement, UnaryOp, }, resolver::ValueNs, + signatures::{FunctionSignature, VariantFields}, }; use hir_def::{FunctionId, hir::ClosureKind}; use hir_expand::name::Name; @@ -155,7 +156,7 @@ pub(super) fn expr_guaranteed_to_constitute_read_for_never( /// it is matching against. This is used to determine whether we should /// perform `NeverToAny` coercions. fn pat_guaranteed_to_constitute_read_for_never(&self, pat: PatId) -> bool { - match &self.body[pat] { + match &self.store[pat] { // Does not constitute a read. Pat::Wild => false, @@ -197,25 +198,25 @@ fn pat_guaranteed_to_constitute_read_for_never(&self, pat: PatId) -> bool { // FIXME(tschottdorf): this is problematic as the HIR is being scraped, but // ref bindings are be implicit after #42640 (default match binding modes). See issue #44848. fn contains_explicit_ref_binding(&self, pat: PatId) -> bool { - if let Pat::Bind { id, .. } = self.body[pat] - && matches!(self.body[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) + if let Pat::Bind { id, .. } = self.store[pat] + && matches!(self.store[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) { return true; } let mut result = false; - self.body.walk_pats_shallow(pat, |pat| result |= self.contains_explicit_ref_binding(pat)); + self.store.walk_pats_shallow(pat, |pat| result |= self.contains_explicit_ref_binding(pat)); result } fn is_syntactic_place_expr(&self, expr: ExprId) -> bool { - match &self.body[expr] { + match &self.store[expr] { // Lang item paths cannot currently be local variables or statics. Expr::Path(Path::LangItem(_, _)) => false, Expr::Path(Path::Normal(path)) => path.type_anchor.is_none(), Expr::Path(path) => self .resolver - .resolve_path_in_value_ns_fully(self.db, path, self.body.expr_path_hygiene(expr)) + .resolve_path_in_value_ns_fully(self.db, path, self.store.expr_path_hygiene(expr)) .is_none_or(|res| matches!(res, ValueNs::LocalBinding(_) | ValueNs::StaticId(_))), Expr::Underscore => true, Expr::UnaryOp { op: UnaryOp::Deref, .. } => true, @@ -311,7 +312,7 @@ fn infer_expr_inner( ) -> Ty<'db> { self.db.unwind_if_revision_cancelled(); - let expr = &self.body[tgt_expr]; + let expr = &self.store[tgt_expr]; tracing::trace!(?expr); let ty = match expr { Expr::Missing => self.err_ty(), @@ -608,7 +609,7 @@ fn infer_expr_inner( Some(def) => { let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); - let visibilities = self.db.field_visibilities(def); + let visibilities = VariantFields::field_visibilities(self.db, def); for field in fields.iter() { let field_def = { match variant_data.field(&field.name) { @@ -717,7 +718,7 @@ fn infer_expr_inner( // instantiations in RHS can be coerced to it. Note that this // cannot happen in destructuring assignments because of how // they are desugared. - let lhs_ty = match &self.body[target] { + let lhs_ty = match &self.store[target] { // LHS of assignment doesn't constitute reads. &Pat::Expr(expr) => { Some(self.infer_expr(expr, &Expectation::none(), ExprIsRead::No)) @@ -728,7 +729,7 @@ fn infer_expr_inner( let resolution = self.resolver.resolve_path_in_value_ns_fully( self.db, path, - self.body.pat_path_hygiene(target), + self.store.pat_path_hygiene(target), ); self.resolver.reset_to_guard(resolver_guard); @@ -1351,7 +1352,7 @@ fn infer_expr_array(&mut self, array: &Array, expected: &Expectation<'db>) -> Ty ExprIsRead::Yes, ); let usize = self.types.types.usize; - let len = match self.body[repeat] { + let len = match self.store[repeat] { Expr::Underscore => { self.write_expr_ty(repeat, usize); self.table.next_const_var() @@ -1491,7 +1492,7 @@ fn infer_block( } else { ExprIsRead::No }; - let ty = if contains_explicit_ref_binding(this.body, *pat) { + let ty = if contains_explicit_ref_binding(this.store, *pat) { this.infer_expr( *expr, &Expectation::has_type(decl_ty), @@ -1624,7 +1625,8 @@ fn lookup_field( }, _ => return None, }; - let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id] + let is_visible = VariantFields::field_visibilities(self.db, field_id.parent) + [field_id.local_id] .is_visible_from(self.db, self.resolver.module()); if !is_visible { if private_field.is_none() { @@ -2117,7 +2119,7 @@ pub(in super::super) fn check_call_arguments( // the return value of an argument-position async block to an argument-position // closure wrapped in a block. // See . - let is_closure = if let Expr::Closure { closure_kind, .. } = self.body[*arg] { + let is_closure = if let Expr::Closure { closure_kind, .. } = self.store[*arg] { !matches!(closure_kind, ClosureKind::Coroutine(_)) } else { false @@ -2194,7 +2196,7 @@ fn check_legacy_const_generics(&mut self, callee: Ty<'db>, args: &[ExprId]) -> B _ => return Default::default(), }; - let data = self.db.function_signature(func); + let data = FunctionSignature::of(self.db, func); let Some(legacy_const_generics_indices) = data.legacy_const_generics_indices(self.db, func) else { return Default::default(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 45fa141b6d3d..bfe43fc92827 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -14,8 +14,8 @@ }; impl<'db> InferenceContext<'_, 'db> { - pub(crate) fn infer_mut_body(&mut self) { - self.infer_mut_expr(self.body.body_expr, Mutability::Not); + pub(crate) fn infer_mut_body(&mut self, body_expr: ExprId) { + self.infer_mut_expr(body_expr, Mutability::Not); } fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) { @@ -52,7 +52,7 @@ fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) { } fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) { - match &self.body[tgt_expr] { + match &self.store[tgt_expr] { Expr::Missing => (), Expr::InlineAsm(e) => { e.operands.iter().for_each(|(_, op)| match op { @@ -173,7 +173,7 @@ fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutabi self.infer_mut_expr(*rhs, Mutability::Not); } &Expr::Assignment { target, value } => { - self.body.walk_pats(target, &mut |pat| match self.body[pat] { + self.store.walk_pats(target, &mut |pat| match self.store[pat] { Pat::Expr(expr) => self.infer_mut_expr(expr, Mutability::Mut), Pat::ConstBlock(block) => self.infer_mut_expr(block, Mutability::Not), _ => {} @@ -220,8 +220,8 @@ fn pat_iter_bound_mutability(&self, mut pat: impl Iterator) -> Mut /// `let (ref x0, ref x1) = *it;` we should use `Deref`. fn pat_bound_mutability(&self, pat: PatId) -> Mutability { let mut r = Mutability::Not; - self.body.walk_bindings_in_pat(pat, |b| { - if self.body[b].mode == BindingAnnotation::RefMut { + self.store.walk_bindings_in_pat(pat, |b| { + if self.store[b].mode == BindingAnnotation::RefMut { r = Mutability::Mut; } }); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 87fd0dace38f..8033680dcc5c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -3,9 +3,10 @@ use std::{cmp, iter}; use hir_def::{ - HasModule, - expr_store::{Body, path::Path}, + HasModule as _, + expr_store::{ExpressionStore, path::Path}, hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId}, + signatures::VariantFields, }; use hir_expand::name::Name; use rustc_ast_ir::Mutability; @@ -60,7 +61,7 @@ pub(super) fn infer_tuple_struct_pat_like( Some(def) => { let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); - let visibilities = self.db.field_visibilities(def); + let visibilities = VariantFields::field_visibilities(self.db, def); let (pre, post) = match ellipsis { Some(idx) => subs.split_at(idx as usize), @@ -129,7 +130,7 @@ pub(super) fn infer_record_pat_like( Some(def) => { let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); - let visibilities = self.db.field_visibilities(def); + let visibilities = VariantFields::field_visibilities(self.db, def); let substs = ty.as_adt().map(TupleExt::tail); @@ -260,14 +261,14 @@ fn infer_pat( ) -> Ty<'db> { let mut expected = self.table.structurally_resolve_type(expected); - if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment { + if matches!(&self.store[pat], Pat::Ref { .. }) || self.inside_assignment { cov_mark::hit!(match_ergonomics_ref); // When you encounter a `&pat` pattern, reset to Move. // This is so that `w` is by value: `let (_, &w) = &(1, &2);` // Destructuring assignments also reset the binding mode and // don't do match ergonomics. default_bm = BindingMode::Move; - } else if self.is_non_ref_pat(self.body, pat) { + } else if self.is_non_ref_pat(self.store, pat) { let mut pat_adjustments = Vec::new(); while let TyKind::Ref(_lifetime, inner, mutability) = expected.kind() { pat_adjustments.push(expected.store()); @@ -289,7 +290,7 @@ fn infer_pat( let default_bm = default_bm; let expected = expected; - let ty = match &self.body[pat] { + let ty = match &self.store[pat] { Pat::Tuple { args, ellipsis } => { self.infer_tuple_pat_like(pat, expected, default_bm, *ellipsis, args, decl) } @@ -485,7 +486,7 @@ fn infer_bind_pat( expected: Ty<'db>, decl: Option, ) -> Ty<'db> { - let Binding { mode, .. } = self.body[binding]; + let Binding { mode, .. } = self.store[binding]; let mode = if mode == BindingAnnotation::Unannotated { default_bm } else { @@ -569,7 +570,7 @@ fn infer_slice_pat( fn infer_lit_pat(&mut self, expr: ExprId, expected: Ty<'db>) -> Ty<'db> { // Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`. - if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] + if let Expr::Literal(Literal::ByteString(_)) = self.store[expr] && let TyKind::Ref(_, inner, _) = expected.kind() { let inner = self.table.try_structurally_resolve_type(inner); @@ -590,14 +591,14 @@ fn infer_lit_pat(&mut self, expr: ExprId, expected: Ty<'db>) -> Ty<'db> { self.infer_expr(expr, &Expectation::has_type(expected), ExprIsRead::Yes) } - fn is_non_ref_pat(&mut self, body: &hir_def::expr_store::Body, pat: PatId) -> bool { - match &body[pat] { + fn is_non_ref_pat(&mut self, store: &hir_def::expr_store::ExpressionStore, pat: PatId) -> bool { + match &store[pat] { Pat::Tuple { .. } | Pat::TupleStruct { .. } | Pat::Record { .. } | Pat::Range { .. } | Pat::Slice { .. } => true, - Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)), + Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(store, *p)), Pat::Path(path) => { // A const is a reference pattern, but other value ns things aren't (see #16131). let resolved = self.resolve_value_path_inner(path, pat.into(), true); @@ -605,7 +606,7 @@ fn is_non_ref_pat(&mut self, body: &hir_def::expr_store::Body, pat: PatId) -> bo } Pat::ConstBlock(..) => false, Pat::Lit(expr) => !matches!( - body[*expr], + store[*expr], Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..)) ), Pat::Wild @@ -670,10 +671,10 @@ fn pat_is_irrefutable(&self, decl_ctxt: Option) -> bool { } } -pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool { +pub(super) fn contains_explicit_ref_binding(store: &ExpressionStore, pat_id: PatId) -> bool { let mut res = false; - body.walk_pats(pat_id, &mut |pat| { - res |= matches!(body[pat], Pat::Bind { id, .. } if matches!(body[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut)); + store.walk_pats(pat_id, &mut |pat| { + res |= matches!(store[pat], Pat::Bind { id, .. } if matches!(store[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut)); }); res } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 40c6fdf3cc88..71d68ccd47a6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -4,6 +4,7 @@ AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, expr_store::path::{Path, PathSegment}, resolver::{ResolveValueResult, TypeNs, ValueNs}, + signatures::{ConstSignature, FunctionSignature}, }; use hir_expand::name::Name; use rustc_type_ir::inherent::{SliceLike, Ty as _}; @@ -136,7 +137,7 @@ pub(super) fn resolve_value_path_inner( let mut ctx = TyLoweringContext::new( self.db, &self.resolver, - self.body, + self.store, &self.diagnostics, InferenceTyDiagnosticSource::Body, self.generic_def, @@ -159,7 +160,7 @@ pub(super) fn resolve_value_path_inner( let ty = self.table.process_user_written_ty(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? } else { - let hygiene = self.body.expr_or_pat_path_hygiene(id); + let hygiene = self.store.expr_or_pat_path_hygiene(id); // FIXME: report error, unresolved first path segment let value_or_partial = path_ctx.resolve_path_in_value_ns(hygiene)?; @@ -263,7 +264,7 @@ fn resolve_trait_assoc_item( trait_.trait_items(self.db).items.iter().map(|(_name, id)| *id).find_map(|item| { match item { AssocItemId::FunctionId(func) => { - if segment.name == &self.db.function_signature(func).name { + if segment.name == &FunctionSignature::of(self.db, func).name { Some(CandidateId::FunctionId(func)) } else { None @@ -271,7 +272,7 @@ fn resolve_trait_assoc_item( } AssocItemId::ConstId(konst) => { - if self.db.const_signature(konst).name.as_ref() == Some(segment.name) { + if ConstSignature::of(self.db, konst).name.as_ref() == Some(segment.name) { Some(CandidateId::ConstId(konst)) } else { None diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 2057159c46d2..d093412b4210 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -3,7 +3,7 @@ use std::fmt; use base_db::Crate; -use hir_def::{AdtId, DefWithBodyId, GenericParamId}; +use hir_def::{AdtId, ExpressionStoreOwnerId, GenericParamId}; use hir_expand::name::Name; use intern::sym; use rustc_hash::FxHashSet; @@ -147,7 +147,7 @@ pub(crate) fn new( db: &'db dyn HirDatabase, trait_env: ParamEnv<'db>, krate: Crate, - owner: Option, + owner: Option, ) -> Self { let interner = DbInterner::new_with(db, krate); let typing_mode = match owner { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index 402e9ce96971..74d66123ea53 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -1,7 +1,9 @@ //! Type inhabitedness logic. use std::ops::ControlFlow::{self, Break, Continue}; -use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility}; +use hir_def::{ + AdtId, EnumVariantId, ModuleId, VariantId, signatures::VariantFields, visibility::Visibility, +}; use rustc_hash::FxHashSet; use rustc_type_ir::{ TypeSuperVisitable, TypeVisitable, TypeVisitor, @@ -151,7 +153,11 @@ fn visit_variant( let is_enum = matches!(variant, VariantId::EnumVariantId(..)); let field_tys = self.db().field_types(variant); - let field_vis = if is_enum { None } else { Some(self.db().field_visibilities(variant)) }; + let field_vis = if is_enum { + None + } else { + Some(VariantFields::field_visibilities(self.db(), variant)) + }; for (fid, _) in fields.iter() { self.visit_field(field_vis.as_ref().map(|it| it[fid]), &field_tys[fid].get(), subst)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs index 18feb0f46a32..ae53276f56a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs @@ -1,13 +1,17 @@ //! Functions to detect special lang items -use hir_def::{AdtId, TraitId, lang_item::LangItems, signatures::StructFlags}; +use hir_def::{ + AdtId, TraitId, + lang_item::LangItems, + signatures::{StructFlags, StructSignature}, +}; use intern::{Symbol, sym}; use crate::db::HirDatabase; pub fn is_box(db: &dyn HirDatabase, adt: AdtId) -> bool { let AdtId::StructId(id) = adt else { return false }; - db.struct_signature(id).flags.contains(StructFlags::IS_BOX) + StructSignature::of(db, id).flags.contains(StructFlags::IS_BOX) } pub fn lang_items_for_bin_op( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 525100439f5b..54332122d0e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -333,7 +333,7 @@ pub fn layout_of_ty_query( } TyKind::Closure(id, args) => { let def = db.lookup_intern_closure(id.0); - let infer = InferenceResult::for_body(db, def.0); + let infer = InferenceResult::of(db, def.0); let (captures, _) = infer.closure_info(id.0); let fields = captures .iter() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index d2495917187e..6090ddfd45cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -5,7 +5,7 @@ use hir_def::{ AdtId, VariantId, attrs::AttrFlags, - signatures::{StructFlags, VariantFields}, + signatures::{StructFlags, StructSignature, VariantFields}, }; use rustc_abi::{Integer, ReprOptions, TargetDataLayout}; use rustc_index::IndexVec; @@ -41,7 +41,7 @@ pub fn layout_of_adt_query( }; let (variants, repr, is_special_no_niche) = match def { AdtId::StructId(s) => { - let sig = db.struct_signature(s); + let sig = StructSignature::of(db, s); let mut r = SmallVec::<[_; 1]>::new(); r.push(handle_variant(s.into(), s.fields(db))?); ( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 8c91be1d7811..484ecebba534 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -1,6 +1,12 @@ use base_db::target::TargetData; use either::Either; -use hir_def::{HasModule, db::DefDatabase}; +use hir_def::{ + DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, HasModule, + expr_store::Body, + signatures::{ + EnumSignature, FunctionSignature, StructSignature, TypeAliasSignature, UnionSignature, + }, +}; use project_model::{Sysroot, toolchain_info::QueryConfig}; use rustc_hash::FxHashMap; use rustc_type_ir::inherent::GenericArgs as _; @@ -49,18 +55,15 @@ fn eval_goal( let adt_or_type_alias_id = scope.declarations().find_map(|x| match x { hir_def::ModuleDefId::AdtId(x) => { let name = match x { - hir_def::AdtId::StructId(x) => db - .struct_signature(x) + hir_def::AdtId::StructId(x) => StructSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(), - hir_def::AdtId::UnionId(x) => db - .union_signature(x) + hir_def::AdtId::UnionId(x) => UnionSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(), - hir_def::AdtId::EnumId(x) => db - .enum_signature(x) + hir_def::AdtId::EnumId(x) => EnumSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(), @@ -68,8 +71,7 @@ fn eval_goal( (name == "Goal").then_some(Either::Left(x)) } hir_def::ModuleDefId::TypeAliasId(x) => { - let name = db - .type_alias_signature(x) + let name = TypeAliasSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(); @@ -90,10 +92,13 @@ fn eval_goal( ), Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity(), }; - let param_env = db.trait_environment(match adt_or_type_alias_id { - Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), - Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), - }); + let param_env = db.trait_environment( + match adt_or_type_alias_id { + Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), + Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), + } + .into(), + ); let krate = match adt_or_type_alias_id { Either::Left(it) => it.krate(&db), Either::Right(it) => it.krate(&db), @@ -123,8 +128,7 @@ fn eval_expr( .declarations() .find_map(|x| match x { hir_def::ModuleDefId::FunctionId(x) => { - let name = db - .function_signature(x) + let name = FunctionSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(); @@ -133,15 +137,16 @@ fn eval_expr( _ => None, }) .unwrap(); - let hir_body = db.body(function_id.into()); + let hir_body = Body::of(&db, function_id.into()); let b = hir_body .bindings() .find(|x| x.1.name.display_no_db(file_id.edition(&db)).to_smolstr() == "goal") .unwrap() .0; - let infer = InferenceResult::for_body(&db, function_id.into()); + let infer = InferenceResult::of(&db, DefWithBodyId::from(function_id)); let goal_ty = infer.type_of_binding[b].clone(); - let param_env = db.trait_environment(function_id.into()); + let param_env = + db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(function_id))); let krate = function_id.krate(&db); db.layout_of_ty(goal_ty, ParamEnvAndCrate { param_env, krate }.store()) }) @@ -379,6 +384,11 @@ impl Tr for S { #[test] fn simd_types() { + let size = 16; + #[cfg(not(target_arch = "s390x"))] + let align = 16; + #[cfg(target_arch = "s390x")] + let align = 8; check_size_and_align( r#" #[repr(simd)] @@ -386,8 +396,8 @@ fn simd_types() { struct Goal(SimdType); "#, "", - 16, - 16, + size, + align, ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 8d87276a0b15..e6b8329ca861 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -61,8 +61,8 @@ use std::{hash::Hash, ops::ControlFlow}; use hir_def::{ - CallableDefId, GenericDefId, TypeAliasId, TypeOrConstParamId, TypeParamId, - hir::generics::GenericParams, resolver::TypeNs, type_ref::Rawness, + CallableDefId, ExpressionStoreOwnerId, GenericDefId, TypeAliasId, TypeOrConstParamId, + TypeParamId, hir::generics::GenericParams, resolver::TypeNs, type_ref::Rawness, }; use hir_expand::name::Name; use indexmap::{IndexMap, map::Entry}; @@ -507,7 +507,7 @@ pub fn associated_type_shorthand_candidates( let mut dedup_map = FxHashSet::default(); let param_ty = Ty::new_param(interner, param, param_idx(db, param.into()).unwrap() as u32); // We use the ParamEnv and not the predicates because the ParamEnv elaborates bounds. - let param_env = db.trait_environment(def); + let param_env = db.trait_environment(ExpressionStoreOwnerId::from(def)); for clause in param_env.clauses { let ClauseKind::Trait(trait_clause) = clause.kind().skip_binder() else { continue }; if trait_clause.self_ty() != param_ty { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index c49e94343793..7259099107ca 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -13,10 +13,10 @@ use arrayvec::ArrayVec; use either::Either; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, - FunctionId, GeneralConstId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, - LifetimeParamId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, - TypeOrConstParamId, TypeParamId, UnionId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, EnumId, EnumVariantId, + ExpressionStoreOwnerId, FunctionId, GeneralConstId, GenericDefId, GenericParamId, HasModule, + ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, StaticId, StructId, TraitId, + TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, HygieneId, path::Path}, hir::generics::{ @@ -26,7 +26,10 @@ item_tree::FieldsShape, lang_item::LangItems, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs}, - signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, + signatures::{ + ConstSignature, FunctionSignature, ImplSignature, StaticSignature, StructSignature, + TraitFlags, TraitSignature, TypeAliasFlags, TypeAliasSignature, + }, type_ref::{ ConstRef, FnType, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, @@ -178,7 +181,7 @@ pub struct TyLoweringContext<'db, 'a> { resolver: &'a Resolver<'db>, store: &'a ExpressionStore, def: GenericDefId, - generics: OnceCell, + generics: OnceCell>, in_binders: DebruijnIndex, impl_trait_mode: ImplTraitLoweringState, /// Tracks types with explicit `?Sized` bounds. @@ -279,11 +282,12 @@ pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { } pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> { - let const_ref = &self.store[const_ref.expr]; - match const_ref { - hir_def::hir::Expr::Path(path) => { - self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) - } + let expr_id = const_ref.expr; + let expr = &self.store[expr_id]; + match expr { + hir_def::hir::Expr::Path(path) => self + .path_to_const(path) + .unwrap_or_else(|| Const::new(self.interner, ConstKind::Error(ErrorGuaranteed))), hir_def::hir::Expr::Literal(literal) => { intern_const_ref(self.db, literal, const_type, self.resolver.krate()) } @@ -300,20 +304,74 @@ pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) - self.resolver.krate(), ) } else { - unknown_const(const_type) + Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)) } } // For unsigned integers, chars, bools, etc., negation is not meaningful - _ => unknown_const(const_type), + _ => Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)), } } else { - unknown_const(const_type) + // Complex negation expression (e.g. `-N` where N is a const param) + self.lower_const_as_unevaluated(expr_id, const_type) } } - _ => unknown_const(const_type), + hir_def::hir::Expr::Underscore => { + Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)) + } + // Any other complex expression becomes an unevaluated anonymous const. + _ => self.lower_const_as_unevaluated(expr_id, const_type), } } + /// Lower a complex const expression to an `UnevaluatedConst` backed by an `AnonConstId`. + /// + /// The `expected_ty_ref` is `None` for array lengths (implicitly `usize`) or + /// `Some(type_ref_id)` for const generic arguments where the expected type comes + /// from the const parameter declaration. + fn lower_const_as_unevaluated( + &mut self, + _expr: hir_def::hir::ExprId, + _expected_ty: Ty<'db>, + ) -> Const<'db> { + // /// Build the identity generic args for the current generic context. + // /// + // /// This maps each generic parameter to itself (as a `ParamTy`, `ParamConst`, + // /// or `EarlyParamRegion`), which is the correct substitution when creating + // /// an `UnevaluatedConst` during type lowering — the anon const inherits the + // /// parent's generics and they haven't been substituted yet. + // fn current_generic_args(&self) -> GenericArgs<'db> { + // let generics = self.generics(); + // let interner = self.interner; + // GenericArgs::new_from_iter( + // interner, + // generics.iter_id().enumerate().map(|(index, id)| match id { + // GenericParamId::TypeParamId(id) => { + // GenericArg::from(Ty::new_param(interner, id, index as u32)) + // } + // GenericParamId::ConstParamId(id) => GenericArg::from(Const::new_param( + // interner, + // ParamConst { id, index: index as u32 }, + // )), + // GenericParamId::LifetimeParamId(id) => GenericArg::from(Region::new_early_param( + // interner, + // EarlyParamRegion { id, index: index as u32 }, + // )), + // }), + // ) + // } + // let loc = AnonConstLoc { owner: self.def, expr }; + // let id = loc.intern(self.db); + // let args = self.current_generic_args(); + // Const::new( + // self.interner, + // ConstKind::Unevaluated(UnevaluatedConst::new( + // GeneralConstId::AnonConstId(id).into(), + // args, + // )), + // ) + Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)) + } + pub(crate) fn path_to_const(&mut self, path: &Path) -> Option> { match self.resolver.resolve_path_in_value_ns_fully(self.db, path, HygieneId::ROOT) { Some(ValueNs::GenericParam(p)) => { @@ -349,7 +407,7 @@ pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) - self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) } - fn generics(&self) -> &Generics { + fn generics(&self) -> &Generics<'db> { self.generics.get_or_init(|| generics(self.db, self.def)) } @@ -727,7 +785,8 @@ fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> { match b.kind().skip_binder() { rustc_type_ir::ClauseKind::Trait(t) => { let id = t.def_id(); - let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); + let is_auto = + TraitSignature::of(db, id.0).flags.contains(TraitFlags::AUTO); if is_auto { auto_traits.push(t.def_id().0); } else { @@ -1111,7 +1170,7 @@ pub(crate) fn impl_trait_with_diagnostics_query<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, ) -> Option<(StoredEarlyBinder<(TraitId, StoredGenericArgs)>, Diagnostics)> { - let impl_data = db.impl_signature(impl_id); + let impl_data = ImplSignature::of(db, impl_id); let resolver = impl_id.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -1196,7 +1255,7 @@ pub(crate) fn return_type_impl_traits( def: hir_def::FunctionId, ) -> Option>> { // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe - let data = db.function_signature(def); + let data = FunctionSignature::of(db, def); let resolver = def.resolver(db); let mut ctx_ret = TyLoweringContext::new( db, @@ -1224,7 +1283,7 @@ pub(crate) fn type_alias_impl_traits( db: &dyn HirDatabase, def: hir_def::TypeAliasId, ) -> Option>> { - let data = db.type_alias_signature(def); + let data = TypeAliasSignature::of(db, def); let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -1314,7 +1373,7 @@ fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder StoredEarlyBinder { let resolver = def.resolver(db); - let data = db.const_signature(def); + let data = ConstSignature::of(db, def); let parent = def.loc(db).container; let mut ctx = TyLoweringContext::new( db, @@ -1330,7 +1389,7 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> StoredEarlyBinder StoredEarlyBinder { let resolver = def.resolver(db); - let data = db.static_signature(def); + let data = StaticSignature::of(db, def); let mut ctx = TyLoweringContext::new( db, &resolver, @@ -1347,7 +1406,7 @@ fn type_for_struct_constructor( db: &dyn HirDatabase, def: StructId, ) -> Option> { - let struct_data = db.struct_signature(def); + let struct_data = StructSignature::of(db, def); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.into())), @@ -1422,7 +1481,7 @@ pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>( db: &'db dyn HirDatabase, t: TypeAliasId, ) -> (StoredEarlyBinder, Diagnostics) { - let type_alias_data = db.type_alias_signature(t); + let type_alias_data = TypeAliasSignature::of(db, t); let mut diags = None; let resolver = t.resolver(db); let interner = DbInterner::new_no_crate(db); @@ -1485,7 +1544,7 @@ pub(crate) fn impl_self_ty_with_diagnostics_query<'db>( ) -> (StoredEarlyBinder, Diagnostics) { let resolver = impl_id.resolver(db); - let impl_data = db.impl_signature(impl_id); + let impl_data = ImplSignature::of(db, impl_id); let mut ctx = TyLoweringContext::new( db, &resolver, @@ -1531,14 +1590,14 @@ pub(crate) fn const_param_ty_with_diagnostics_query<'db>( _: (), def: ConstParamId, ) -> (StoredTy, Diagnostics) { - let (parent_data, store) = db.generic_params_and_store(def.parent()); + let (parent_data, store) = GenericParams::with_store(db, def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db); let interner = DbInterner::new_no_crate(db); let mut ctx = TyLoweringContext::new( db, &resolver, - &store, + store, def.parent(), LifetimeElisionKind::AnonymousReportError, ); @@ -1629,7 +1688,7 @@ fn supertraits_info(db: &dyn HirDatabase, trait_: TraitId) -> SupertraitsInfo { )); let resolver = trait_.resolver(db); - let signature = db.trait_signature(trait_); + let signature = TraitSignature::of(db, trait_); for pred in signature.generic_params.where_predicates() { let (WherePredicate::TypeBound { target, bound } | WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred @@ -1805,18 +1864,27 @@ fn resolve_type_param_assoc_type_shorthand( } AssocTypeShorthandResolution::Cycle => return AssocTypeShorthandResolution::Cycle, }; + let (assoc_type, args) = assoc_type_and_args + .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref())) + .skip_binder(); + let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args); + let current_result = StoredEarlyBinder::bind((assoc_type, args.store())); if let Some(this_trait_resolution) = this_trait_resolution { return AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: Some(this_trait_resolution), }; - } else if supertraits_resolution.is_some() { - return AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None }; + } else if let Some(prev_resolution) = &supertraits_resolution { + if let AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: Some(prev_resolution), + } + | AssocTypeShorthandResolution::Resolved(prev_resolution) = prev_resolution + && *prev_resolution == current_result + { + continue; + } else { + return AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None }; + } } else { - let (assoc_type, args) = assoc_type_and_args - .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref())) - .skip_binder(); - let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args); - let current_result = StoredEarlyBinder::bind((assoc_type, args.store())); supertraits_resolution = Some(match lookup_on_bounded_trait { AssocTypeShorthandResolution::Resolved(_) => { AssocTypeShorthandResolution::Resolved(current_result) @@ -1891,7 +1959,7 @@ pub fn type_alias_bounds_with_diagnostics_query<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, ) -> (TypeAliasBounds>, Diagnostics) { - let type_alias_data = db.type_alias_signature(type_alias); + let type_alias_data = TypeAliasSignature::of(db, type_alias); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); let mut ctx = TyLoweringContext::new( db, @@ -2070,16 +2138,6 @@ pub fn explicit_implied_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> { } } -pub(crate) fn trait_environment_for_body_query( - db: &dyn HirDatabase, - def: DefWithBodyId, -) -> ParamEnv<'_> { - let Some(def) = def.as_generic_def_id(db) else { - return ParamEnv::empty(); - }; - db.trait_environment(def) -} - pub(crate) fn param_env_from_predicates<'db>( interner: DbInterner<'db>, predicates: &'db GenericPredicates, @@ -2094,7 +2152,12 @@ pub(crate) fn param_env_from_predicates<'db>( ParamEnv { clauses } } -pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId) -> ParamEnv<'db> { +pub(crate) fn trait_environment<'db>( + db: &'db dyn HirDatabase, + def: ExpressionStoreOwnerId, +) -> ParamEnv<'db> { + let def = def.generic_def(db); + return ParamEnv { clauses: trait_environment_query(db, def).as_ref() }; #[salsa::tracked(returns(ref))] @@ -2294,7 +2357,7 @@ fn implicit_trait_predicate<'db>( fn push_const_arg_has_type_predicates<'db>( db: &'db dyn HirDatabase, predicates: &mut Vec>, - generics: &Generics, + generics: &Generics<'db>, ) { let interner = DbInterner::new_no_crate(db); let const_params_offset = generics.len_parent() + generics.len_lifetimes_self(); @@ -2347,10 +2410,11 @@ pub(crate) fn generic_defaults_with_diagnostics_query( } let resolver = def.resolver(db); + let store_for_self = generic_params.store(); let mut ctx = TyLoweringContext::new( db, &resolver, - generic_params.store(), + store_for_self, def, LifetimeElisionKind::AnonymousReportError, ) @@ -2368,6 +2432,7 @@ pub(crate) fn generic_defaults_with_diagnostics_query( }) .collect::>(); ctx.diagnostics.clear(); // Don't include diagnostics from the parent. + ctx.store = store_for_self; defaults.extend(generic_params.iter_self().map(|(_id, p)| { let (result, has_default) = handle_generic_param(&mut ctx, idx, p); has_any_default |= has_default; @@ -2438,7 +2503,7 @@ pub(crate) fn callable_item_signature_query<'db>( } fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder { - let data = db.function_signature(def); + let data = FunctionSignature::of(db, def); let resolver = def.resolver(db); let interner = DbInterner::new_no_crate(db); let mut ctx_params = TyLoweringContext::new( @@ -2446,7 +2511,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder( db: &'db dyn HirDatabase, type_alias: TypeAliasId, ) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> { - let type_alias_data = db.type_alias_signature(type_alias); + let type_alias_data = TypeAliasSignature::of(db, type_alias); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); let interner = DbInterner::new_no_crate(db); let mut ctx = TyLoweringContext::new( @@ -2546,7 +2611,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( .map_bound(|c| match c { rustc_type_ir::ClauseKind::Trait(t) => { let id = t.def_id(); - let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); + let is_auto = TraitSignature::of(db, id.0).flags.contains(TraitFlags::AUTO); if is_auto { Some(ExistentialPredicate::AutoTrait(t.def_id())) } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index 79f29d370f5c..889f0792d347 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -14,7 +14,7 @@ GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance, }, resolver::{ResolveValueResult, TypeNs, ValueNs}, - signatures::TraitFlags, + signatures::{TraitFlags, TraitSignature}, type_ref::{TypeRef, TypeRefId}, }; use rustc_type_ir::{ @@ -183,7 +183,7 @@ pub(crate) fn lower_partly_resolved_path( let trait_ref = self.lower_trait_ref_from_resolved_path( trait_, Ty::new_error(self.ctx.interner, ErrorGuaranteed), - false, + infer_args, ); tracing::debug!(?trait_ref); self.skip_resolved_segment(); @@ -201,7 +201,7 @@ pub(crate) fn lower_partly_resolved_path( // this point (`trait_ref.substitution`). let substitution = self.substs_from_path_segment( associated_ty.into(), - false, + infer_args, None, true, ); @@ -625,10 +625,7 @@ pub(crate) fn substs_from_path_segment( GenericDefId::TraitId(trait_) => { // RTN is prohibited anyways if we got here. let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation; - let is_fn_trait = self - .ctx - .db - .trait_signature(trait_) + let is_fn_trait = TraitSignature::of(self.ctx.db, trait_) .flags .contains(TraitFlags::RUSTC_PAREN_SUGAR); is_rtn || !is_fn_trait @@ -1024,7 +1021,7 @@ fn inferred_kind( fn check_generic_args_len<'db>( args_and_bindings: Option<&HirGenericArgs>, def: GenericDefId, - def_generics: &Generics, + def_generics: &Generics<'db>, infer_args: bool, lifetime_elision: &LifetimeElisionKind<'db>, lowering_assoc_type_generics: bool, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index ad4d79e68a9f..05b9ea5d748f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -17,11 +17,12 @@ ImplId, ItemContainerId, ModuleId, TraitId, attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, - expr_store::path::GenericArgs as HirGenericArgs, - hir::ExprId, + expr_store::{Body, path::GenericArgs as HirGenericArgs}, + hir::{ExprId, generics::GenericParams}, lang_item::LangItems, nameres::{DefMap, block_def_map, crate_def_map}, resolver::Resolver, + signatures::{ConstSignature, FunctionSignature}, }; use intern::{Symbol, sym}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -366,7 +367,7 @@ pub fn lookup_impl_const<'db>( }; let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), subs); - let const_signature = db.const_signature(const_id); + let const_signature = ConstSignature::of(db, const_id); let name = match const_signature.name.as_ref() { Some(name) => name, None => return (const_id, subs), @@ -396,7 +397,7 @@ pub fn is_dyn_method<'db>( let ItemContainerId::TraitId(trait_id) = func.loc(db).container else { return None; }; - let trait_params = db.generic_params(trait_id.into()).len(); + let trait_params = GenericParams::of(db, trait_id.into()).len(); let fn_params = fn_subst.len() - trait_params; let trait_ref = TraitRef::new_from_args( interner, @@ -432,14 +433,14 @@ pub(crate) fn lookup_impl_method_query<'db>( let ItemContainerId::TraitId(trait_id) = func.loc(db).container else { return (Either::Left(func), fn_subst); }; - let trait_params = db.generic_params(trait_id.into()).len(); + let trait_params = GenericParams::of(db, trait_id.into()).len(); let trait_ref = TraitRef::new_from_args( interner, trait_id.into(), GenericArgs::new_from_slice(&fn_subst[..trait_params]), ); - let name = &db.function_signature(func).name; + let name = &FunctionSignature::of(db, func).name; let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env.param_env, name).and_then( |(assoc, impl_args)| { @@ -623,7 +624,7 @@ fn collect( // To better support custom derives, collect impls in all unnamed const items. // const _: () = { ... }; for konst in module_data.scope.unnamed_consts() { - let body = db.body(konst.into()); + let body = Body::of(db, konst.into()); for (_, block_def_map) in body.blocks(db) { collect(db, block_def_map, map); } @@ -766,7 +767,7 @@ fn collect( // To better support custom derives, collect impls in all unnamed const items. // const _: () = { ... }; for konst in module_data.scope.unnamed_consts() { - let body = db.body(konst.into()); + let body = Body::of(db, konst.into()); for (_, block_def_map) in body.blocks(db) { collect(db, block_def_map, lang_items, map); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs index 0024ca16a594..ec589085a88d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs @@ -456,7 +456,7 @@ fn report_missing_lifetime(&mut self, _def: GenericDefId, _expected_count: u32) substs_from_args_and_bindings( self.db(), - self.ctx.body, + self.ctx.store, generic_args, self.candidate.into(), true, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs index fc2bd87ee429..8c76bfbc076b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs @@ -5,7 +5,8 @@ use hir_def::{ AssocItemId, FunctionId, GenericParamId, ImplId, ItemContainerId, TraitId, - signatures::TraitFlags, + hir::generics::GenericParams, + signatures::{FunctionSignature, TraitFlags, TraitSignature}, }; use hir_expand::name::Name; use rustc_ast_ir::Mutability; @@ -1605,7 +1606,8 @@ fn consider_probe( // Some trait methods are excluded for arrays before 2021. // (`array.into_iter()` wants a slice iterator for compatibility.) if self_ty.is_array() && !self.ctx.edition.at_least_2021() { - let trait_signature = self.db().trait_signature(poly_trait_ref.def_id().0); + let trait_signature = + TraitSignature::of(self.db(), poly_trait_ref.def_id().0); if trait_signature .flags .contains(TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH) @@ -1619,7 +1621,8 @@ fn consider_probe( if self_ty.boxed_ty().is_some_and(Ty::is_slice) && !self.ctx.edition.at_least_2024() { - let trait_signature = self.db().trait_signature(poly_trait_ref.def_id().0); + let trait_signature = + TraitSignature::of(self.db(), poly_trait_ref.def_id().0); if trait_signature .flags .contains(TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH) @@ -1963,7 +1966,7 @@ fn has_applicable_self(&self, item: CandidateId) -> bool { // associated value (i.e., methods, constants). match item { CandidateId::FunctionId(id) if self.mode == Mode::MethodCall => { - self.db().function_signature(id).has_self_param() + FunctionSignature::of(self.db(), id).has_self_param() } _ => true, } @@ -2008,7 +2011,7 @@ fn xform_method_sig(&self, method: FunctionId, args: &[GenericArg<'db>]) -> FnSi // we are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - let generics = self.db().generic_params(method.into()); + let generics = GenericParams::of(self.db(), method.into()); let xform_fn_sig = if generics.is_empty() { fn_sig.instantiate(self.interner(), args) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 664238601108..a8865cd54e6a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -6,7 +6,7 @@ use either::Either; use hir_def::{ DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId, - expr_store::Body, + expr_store::ExpressionStore, hir::{BindingAnnotation, BindingId, Expr, ExprId, Ordering, PatId}, }; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; @@ -40,7 +40,10 @@ pub use eval::{ Evaluator, MirEvalError, VTableMap, interpret_mir, pad16, render_const_using_debug_impl, }; -pub use lower::{MirLowerError, lower_to_mir, mir_body_for_closure_query, mir_body_query}; +pub use lower::{ + MirLowerError, lower_body_to_mir, lower_to_mir_with_store, mir_body_for_closure_query, + mir_body_query, +}; pub use monomorphization::{ monomorphized_mir_body_for_closure_query, monomorphized_mir_body_query, }; @@ -1207,12 +1210,12 @@ pub enum MirSpan { } impl MirSpan { - pub fn is_ref_span(&self, body: &Body) -> bool { + pub fn is_ref_span(&self, store: &ExpressionStore) -> bool { match *self { - MirSpan::ExprId(expr) => matches!(body[expr], Expr::Ref { .. }), + MirSpan::ExprId(expr) => matches!(store[expr], Expr::Ref { .. }), // FIXME: Figure out if this is correct wrt. match ergonomics. MirSpan::BindingId(binding) => { - matches!(body[binding].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) + matches!(store[binding].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) } MirSpan::PatId(_) | MirSpan::SelfParam | MirSpan::Unknown => false, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index dece61a57df5..3ff2db15aaf5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -5,7 +5,7 @@ use std::iter; -use hir_def::{DefWithBodyId, HasModule}; +use hir_def::{DefWithBodyId, ExpressionStoreOwnerId, HasModule}; use la_arena::ArenaMap; use rustc_hash::FxHashMap; use rustc_type_ir::inherent::GenericArgs as _; @@ -99,7 +99,7 @@ pub fn borrowck_query( let _p = tracing::info_span!("borrowck_query").entered(); let module = def.module(db); let interner = DbInterner::new_with(db, module.krate(db)); - let env = db.trait_environment_for_body(def); + let env = db.trait_environment(ExpressionStoreOwnerId::from(def)); let mut res = vec![]; // This calculates opaques defining scope which is a bit costly therefore is put outside `all_mir_bodies()`. let typing_mode = TypingMode::borrowck(interner, def.into()); @@ -121,11 +121,11 @@ fn make_fetch_closure_field<'db>( db: &'db dyn HirDatabase, ) -> impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db> + use<'db> { |c: InternedClosureId, subst: GenericArgs<'db>, f: usize| { - let InternedClosure(def, _) = db.lookup_intern_closure(c); - let infer = InferenceResult::for_body(db, def); + let InternedClosure(owner, _) = db.lookup_intern_closure(c); + let interner = DbInterner::new_no_crate(db); + let infer = InferenceResult::of(db, owner); let (captures, _) = infer.closure_info(c); let parent_subst = subst.as_closure().parent_args(); - let interner = DbInterner::new_no_crate(db); captures.get(f).expect("broken closure field").ty.get().instantiate(interner, parent_subst) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index ec0723c3f8c3..505db1776f28 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -5,14 +5,17 @@ use base_db::{Crate, target::TargetLoadError}; use either::Either; use hir_def::{ - AdtId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, HasModule, ItemContainerId, - Lookup, StaticId, VariantId, - expr_store::HygieneId, + AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, GeneralConstId, + HasModule, ItemContainerId, Lookup, StaticId, VariantId, + expr_store::{Body, HygieneId}, item_tree::FieldsShape, lang_item::LangItems, layout::{TagEncoding, Variants}, resolver::{HasResolver, TypeNs, ValueNs}, - signatures::{StaticFlags, StructFlags}, + signatures::{ + EnumSignature, FunctionSignature, StaticFlags, StaticSignature, StructFlags, + StructSignature, TraitSignature, + }, }; use hir_expand::{InFile, mod_path::path, name::Name}; use intern::sym; @@ -386,7 +389,7 @@ pub fn pretty_print( for (func, span, def) in stack.iter().take(30).rev() { match func { Either::Left(func) => { - let function_name = db.function_signature(*func); + let function_name = FunctionSignature::of(db, *func); writeln!( f, "In function {} ({:?})", @@ -398,7 +401,7 @@ pub fn pretty_print( writeln!(f, "In {closure:?}")?; } } - let source_map = db.body_with_source_map(*def).1; + let source_map = &Body::with_source_map(db, *def).1; let span: InFile = match span { MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { Ok(s) => s.map(|it| it.into()), @@ -441,7 +444,7 @@ pub fn pretty_print( )?; } MirEvalError::MirLowerError(func, err) => { - let function_name = db.function_signature(*func); + let function_name = FunctionSignature::of(db, *func); let self_ = match func.lookup(db).container { ItemContainerId::ImplId(impl_id) => Some({ db.impl_self_ty(impl_id) @@ -450,7 +453,10 @@ pub fn pretty_print( .to_string() }), ItemContainerId::TraitId(it) => Some( - db.trait_signature(it).name.display(db, display_target.edition).to_string(), + TraitSignature::of(db, it) + .name + .display(db, display_target.edition) + .to_string(), ), _ => None, }; @@ -660,7 +666,7 @@ pub fn new( db, random_state: oorandom::Rand64::new(0), param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate { - param_env: db.trait_environment_for_body(owner), + param_env: db.trait_environment(ExpressionStoreOwnerId::from(owner)), krate: crate_id, }), crate_id, @@ -730,8 +736,8 @@ fn projected_ty(&self, ty: Ty<'db>, proj: PlaceElem) -> Ty<'db> { self.param_env.param_env, ty, |c, subst, f| { - let InternedClosure(def, _) = self.db.lookup_intern_closure(c); - let infer = InferenceResult::for_body(self.db, def); + let InternedClosure(owner, _) = self.db.lookup_intern_closure(c); + let infer = InferenceResult::of(self.db, owner); let (captures, _) = infer.closure_info(c); let parent_subst = subst.as_closure().parent_args(); captures @@ -893,8 +899,8 @@ fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result<'db, Ty<'db>> { OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, OperandKind::Constant { konst: _, ty } => ty.as_ref(), &OperandKind::Static(s) => { - let ty = InferenceResult::for_body(self.db, s.into()) - .expr_ty(self.db.body(s.into()).body_expr); + let ty = InferenceResult::of(self.db, DefWithBodyId::from(s)) + .expr_ty(Body::of(self.db, s.into()).root_expr()); Ty::new_ref( self.interner(), Region::new_static(self.interner()), @@ -1954,6 +1960,9 @@ fn allocate_const_in_heap( MirEvalError::ConstEvalError(name, Box::new(e)) })? } + GeneralConstId::AnonConstId(_) => { + not_supported!("anonymous const evaluation") + } }; if let ConstKind::Value(value) = result_owner.kind() { break 'b value; @@ -2818,15 +2827,15 @@ fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result<'db, Address> if let Some(o) = self.static_locations.get(&st) { return Ok(*o); }; - let static_data = self.db.static_signature(st); + let static_data = StaticSignature::of(self.db, st); let result = if !static_data.flags.contains(StaticFlags::EXTERN) { let konst = self.db.const_eval_static(st).map_err(|e| { MirEvalError::ConstEvalError(static_data.name.as_str().to_owned(), Box::new(e)) })?; self.allocate_const_in_heap(locals, konst)? } else { - let ty = InferenceResult::for_body(self.db, st.into()) - .expr_ty(self.db.body(st.into()).body_expr); + let ty = InferenceResult::of(self.db, DefWithBodyId::from(st)) + .expr_ty(Body::of(self.db, st.into()).root_expr()); let Some((size, align)) = self.size_align_of(ty, locals)? else { not_supported!("unsized extern static"); }; @@ -2849,7 +2858,7 @@ fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> { let edition = self.crate_id.data(self.db).edition; let name = format!( "{}::{}", - self.db.enum_signature(loc.parent).name.display(db, edition), + EnumSignature::of(self.db, loc.parent).name.display(db, edition), loc.parent .enum_variants(self.db) .variant_name_by_id(variant) @@ -2909,7 +2918,7 @@ fn run_drop_glue_deep( let id = adt_def.def_id().0; match id { AdtId::StructId(s) => { - let data = self.db.struct_signature(s); + let data = StructSignature::of(self.db, s); if data.flags.contains(StructFlags::IS_MANUALLY_DROP) { return Ok(()); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 76c8701ea209..ff6c99ca53b3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -45,7 +45,7 @@ pub(super) fn detect_and_exec_special_function( return Ok(false); } - let function_data = self.db.function_signature(def); + let function_data = FunctionSignature::of(self.db, def); let attrs = AttrFlags::query(self.db, def.into()); let is_intrinsic = FunctionSignature::is_intrinsic(self.db, def); @@ -152,8 +152,8 @@ fn exec_clone( not_supported!("wrong arg count for clone"); }; let addr = Address::from_bytes(arg.get(self)?)?; - let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure(id.0); - let infer = InferenceResult::for_body(self.db, closure_owner); + let InternedClosure(owner, _) = self.db.lookup_intern_closure(id.0); + let infer = InferenceResult::of(self.db, owner); let (captures, _) = infer.closure_info(id.0); let layout = self.layout(self_ty)?; let db = self.db; @@ -840,7 +840,7 @@ fn exec_intrinsic( // cases. let [lhs, rhs] = args else { return Err(MirEvalError::InternalError( - "wrapping_add args are not provided".into(), + "ptr_guaranteed_cmp args are not provided".into(), )); }; let ans = lhs.get(self)? == rhs.get(self)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 61dd7757c90b..6bf966c3ef1d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -1,4 +1,4 @@ -use hir_def::{HasModule, db::DefDatabase}; +use hir_def::{GenericDefId, HasModule, signatures::FunctionSignature}; use hir_expand::EditionedFileId; use span::Edition; use syntax::{TextRange, TextSize}; @@ -25,7 +25,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), .declarations() .find_map(|x| match x { hir_def::ModuleDefId::FunctionId(x) => { - if db.function_signature(x).name.display(db, Edition::CURRENT).to_string() + if FunctionSignature::of(db, x).name.display(db, Edition::CURRENT).to_string() == "main" { Some(x) @@ -41,7 +41,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), func_id.into(), GenericArgs::empty(interner).store(), crate::ParamEnvAndCrate { - param_env: db.trait_environment(func_id.into()), + param_env: db.trait_environment(GenericDefId::from(func_id).into()), krate: func_id.krate(db), } .store(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 8d5e5c2e6e74..44785d948a49 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -4,16 +4,17 @@ use base_db::Crate; use hir_def::{ - AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, GenericParamId, HasModule, - ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId, + AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, GeneralConstId, GenericParamId, + HasModule, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId, expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{ ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, - Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, + Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, generics::GenericParams, }, item_tree::FieldsShape, lang_item::LangItems, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, + signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -82,7 +83,7 @@ struct MirLowerCtx<'a, 'db> { labeled_loop_blocks: FxHashMap, discr_temp: Option, db: &'db dyn HirDatabase, - body: &'a Body, + store: &'a ExpressionStore, infer: &'a InferenceResult, types: &'db crate::next_solver::DefaultAny<'db>, resolver: Resolver<'db>, @@ -185,7 +186,7 @@ pub fn pretty_print( } } MirLowerError::MissingFunctionDefinition(owner, it) => { - let body = db.body(*owner); + let body = Body::of(db, *owner); writeln!( f, "Missing function definition for {}", @@ -202,13 +203,13 @@ pub fn pretty_print( MirLowerError::GenericArgNotProvided(id, subst) => { let param_name = match *id { GenericParamId::TypeParamId(id) => { - db.generic_params(id.parent())[id.local_id()].name().cloned() + GenericParams::of(db, id.parent())[id.local_id()].name().cloned() } GenericParamId::ConstParamId(id) => { - db.generic_params(id.parent())[id.local_id()].name().cloned() + GenericParams::of(db, id.parent())[id.local_id()].name().cloned() } GenericParamId::LifetimeParamId(id) => { - Some(db.generic_params(id.parent)[id.local_id].name.clone()) + Some(GenericParams::of(db, id.parent)[id.local_id].name.clone()) } }; writeln!( @@ -285,7 +286,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn new( db: &'db dyn HirDatabase, owner: DefWithBodyId, - body: &'a Body, + store: &'a ExpressionStore, infer: &'a InferenceResult, ) -> Self { let mut basic_blocks = Arena::new(); @@ -307,7 +308,7 @@ fn new( closures: vec![], }; let resolver = owner.resolver(db); - let env = db.trait_environment_for_body(owner); + let env = db.trait_environment(ExpressionStoreOwnerId::from(owner)); let interner = DbInterner::new_with(db, resolver.krate()); // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body? let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); @@ -316,7 +317,7 @@ fn new( result: mir, db, infer, - body, + store, types: crate::next_solver::default_types(db), owner, resolver, @@ -354,7 +355,7 @@ fn lower_expr_to_some_operand( current: BasicBlockId, ) -> Result<'db, Option<(Operand, BasicBlockId)>> { if !self.has_adjustments(expr_id) - && let Expr::Literal(l) = &self.body[expr_id] + && let Expr::Literal(l) = &self.store[expr_id] { let ty = self.expr_ty_without_adjust(expr_id); return Ok(Some((self.lower_literal_to_operand(ty, l)?, current))); @@ -461,7 +462,7 @@ fn lower_expr_to_place_without_adjust( place: Place, mut current: BasicBlockId, ) -> Result<'db, Option> { - match &self.body[expr_id] { + match &self.store[expr_id] { Expr::OffsetOf(_) => { not_supported!("builtin#offset_of") } @@ -472,7 +473,7 @@ fn lower_expr_to_place_without_adjust( if let DefWithBodyId::FunctionId(f) = self.owner { let assoc = f.lookup(self.db); if let ItemContainerId::TraitId(t) = assoc.container { - let name = &self.db.function_signature(f).name; + let name = &FunctionSignature::of(self.db, f).name; return Err(MirLowerError::TraitFunctionDefinition(t, name.clone())); } } @@ -500,7 +501,7 @@ fn lower_expr_to_place_without_adjust( } else { let resolver_guard = self.resolver.update_to_inner_scope(self.db, self.owner, expr_id); - let hygiene = self.body.expr_path_hygiene(expr_id); + let hygiene = self.store.expr_path_hygiene(expr_id); let result = self .resolver .resolve_path_in_value_ns_fully(self.db, p, hygiene) @@ -509,7 +510,7 @@ fn lower_expr_to_place_without_adjust( self.db, p, DisplayTarget::from_crate(self.db, self.krate()), - self.body, + self.store, ) })?; self.resolver.reset_to_guard(resolver_guard); @@ -882,7 +883,7 @@ fn lower_expr_to_place_without_adjust( let variant_id = self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { Some(p) => MirLowerError::UnresolvedName( - hir_display_with_store(&**p, self.body) + hir_display_with_store(&**p, self.store) .display(self.db, self.display_target()) .to_string(), ), @@ -1382,7 +1383,7 @@ fn lower_expr_to_place_without_adjust( } fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<'db, ()> { - if let Expr::Field { expr, name } = &self.body[expr_id] { + if let Expr::Field { expr, name } = &self.store[expr_id] { if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind() { let index = name.as_tuple_index().ok_or(MirLowerError::TypeError("named field on tuple"))? @@ -1411,7 +1412,7 @@ fn lower_literal_or_const_to_operand( ty: Ty<'db>, loc: &ExprId, ) -> Result<'db, Operand> { - match &self.body[*loc] { + match &self.store[*loc] { Expr::Literal(l) => self.lower_literal_to_operand(ty, l), Expr::Path(c) => { let owner = self.owner; @@ -1421,7 +1422,7 @@ fn lower_literal_or_const_to_operand( self.db, c, DisplayTarget::from_crate(db, owner.krate(db)), - self.body, + self.store, ) }; let pr = self @@ -1546,6 +1547,9 @@ fn lower_const_to_operand( MirLowerError::ConstEvalError(name.into(), Box::new(e)) })? } + GeneralConstId::AnonConstId(_) => { + return Err(MirLowerError::IncompleteExpr); + } } }; let ty = self @@ -1553,6 +1557,7 @@ fn lower_const_to_operand( .value_ty(match const_id { GeneralConstId::ConstId(id) => id.into(), GeneralConstId::StaticId(id) => id.into(), + GeneralConstId::AnonConstId(_) => unreachable!("handled above"), }) .unwrap() .instantiate(self.interner(), subst); @@ -1859,7 +1864,7 @@ fn lower_block_to_place( } } else { let mut err = None; - self.body.walk_bindings_in_pat(*pat, |b| { + self.store.walk_bindings_in_pat(*pat, |b| { if let Err(e) = self.push_storage_live(b, current) { err = Some(e); } @@ -1913,9 +1918,9 @@ fn lower_params_and_bindings( self.result.param_locals.extend(params.clone().map(|(it, ty)| { let local_id = self.result.locals.alloc(Local { ty: ty.store() }); self.drop_scopes.last_mut().unwrap().locals.push(local_id); - if let Pat::Bind { id, subpat: None } = self.body[it] + if let Pat::Bind { id, subpat: None } = self.store[it] && matches!( - self.body[id].mode, + self.store[id].mode, BindingAnnotation::Unannotated | BindingAnnotation::Mutable ) { @@ -1924,7 +1929,7 @@ fn lower_params_and_bindings( local_id })); // and then rest of bindings - for (id, _) in self.body.bindings() { + for (id, _) in self.store.bindings() { if !pick_binding(id) { continue; } @@ -1953,7 +1958,7 @@ fn lower_params_and_bindings( .into_iter() .skip(base_param_count + self_binding.is_some() as usize); for ((param, _), local) in params.zip(local_params) { - if let Pat::Bind { id, .. } = self.body[param] + if let Pat::Bind { id, .. } = self.store[param] && local == self.binding_local(id)? { continue; @@ -1989,7 +1994,7 @@ fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> { let loc = variant.lookup(db); let name = format!( "{}::{}", - self.db.enum_signature(loc.parent).name.display(db, edition), + EnumSignature::of(db, loc.parent).name.display(db, edition), loc.parent .enum_variants(self.db) .variant_name_by_id(variant) @@ -2106,8 +2111,10 @@ pub fn mir_body_for_closure_query<'db>( closure: InternedClosureId, ) -> Result<'db, Arc> { let InternedClosure(owner, expr) = db.lookup_intern_closure(closure); - let body = db.body(owner); - let infer = InferenceResult::for_body(db, owner); + let body_owner = + owner.as_def_with_body().expect("MIR lowering should only happen for body-owned closures"); + let body = Body::of(db, body_owner); + let infer = InferenceResult::of(db, body_owner); let Expr::Closure { args, body: root, .. } = &body[expr] else { implementation_error!("closure expression is not closure"); }; @@ -2115,7 +2122,7 @@ pub fn mir_body_for_closure_query<'db>( implementation_error!("closure expression is not closure"); }; let (captures, kind) = infer.closure_info(closure); - let mut ctx = MirLowerCtx::new(db, owner, &body, infer); + let mut ctx = MirLowerCtx::new(db, body_owner, &body.store, infer); // 0 is return local ctx.result.locals.alloc(Local { ty: infer.expr_ty(*root).store() }); let closure_local = ctx.result.locals.alloc(Local { @@ -2138,7 +2145,7 @@ pub fn mir_body_for_closure_query<'db>( }); ctx.result.param_locals.push(closure_local); let sig = ctx.interner().signature_unclosure(substs.as_closure().sig(), Safety::Safe); - let resolver_guard = ctx.resolver.update_to_inner_scope(db, owner, expr); + let resolver_guard = ctx.resolver.update_to_inner_scope(db, body_owner, expr); let current = ctx.lower_params_and_bindings( args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, *y)), None, @@ -2205,7 +2212,7 @@ pub fn mir_body_for_closure_query<'db>( .result .binding_locals .into_iter() - .filter(|it| ctx.body.binding_owner(it.0) == Some(expr)) + .filter(|it| ctx.store.binding_owner(it.0) == Some(expr)) .collect(); if let Some(err) = err { return Err(MirLowerError::UnresolvedUpvar(err)); @@ -2222,13 +2229,12 @@ pub fn mir_body_query<'db>( let edition = krate.data(db).edition; let detail = match def { DefWithBodyId::FunctionId(it) => { - db.function_signature(it).name.display(db, edition).to_string() + FunctionSignature::of(db, it).name.display(db, edition).to_string() } DefWithBodyId::StaticId(it) => { - db.static_signature(it).name.display(db, edition).to_string() + StaticSignature::of(db, it).name.display(db, edition).to_string() } - DefWithBodyId::ConstId(it) => db - .const_signature(it) + DefWithBodyId::ConstId(it) => ConstSignature::of(db, it) .name .clone() .unwrap_or_else(Name::missing) @@ -2243,9 +2249,9 @@ pub fn mir_body_query<'db>( } }; let _p = tracing::info_span!("mir_body_query", ?detail).entered(); - let body = db.body(def); - let infer = InferenceResult::for_body(db, def); - let mut result = lower_to_mir(db, def, &body, infer, body.body_expr)?; + let body = Body::of(db, def); + let infer = InferenceResult::of(db, def); + let mut result = lower_body_to_mir(db, def, body, infer, body.root_expr())?; result.shrink_to_fit(); Ok(Arc::new(result)) } @@ -2258,44 +2264,74 @@ pub(crate) fn mir_body_cycle_result<'db>( Err(MirLowerError::Loop) } -pub fn lower_to_mir<'db>( +/// Extracts params from `body.params`/`body.self_param` and the callable signature, +/// then delegates to [`lower_to_mir_with_store`]. +pub fn lower_body_to_mir<'db>( db: &'db dyn HirDatabase, owner: DefWithBodyId, body: &Body, infer: &InferenceResult, - // FIXME: root_expr should always be the body.body_expr, but since `X` in `[(); X]` doesn't have its own specific body yet, we - // need to take this input explicitly. + // FIXME: root_expr should always be the body.body_expr, + // but this is currently also used for `X` in `[(); X]` which live in the same expression store root_expr: ExprId, +) -> Result<'db, MirBody> { + let is_root = root_expr == body.root_expr(); + // Extract params and self_param only when lowering the body's root expression for a function. + if is_root && let DefWithBodyId::FunctionId(fid) = owner { + let callable_sig = + db.callable_item_signature(fid.into()).instantiate_identity().skip_binder(); + let mut param_tys = callable_sig.inputs().iter().copied(); + let self_param = body.self_param.and_then(|id| Some((id, param_tys.next()?))); + + lower_to_mir_with_store( + db, + owner, + &body.store, + infer, + root_expr, + body.params.iter().copied().zip(param_tys), + self_param, + is_root, + ) + } else { + lower_to_mir_with_store( + db, + owner, + &body.store, + infer, + root_expr, + iter::empty(), + None, + is_root, + ) + } +} + +/// # Parameters +/// - `is_root`: `true` when `root_expr` is the body's top-level expression (picks +/// bindings with no owner); `false` when lowering an inline const or anonymous +/// const (picks bindings owned by `root_expr`). +pub fn lower_to_mir_with_store<'db>( + db: &'db dyn HirDatabase, + owner: DefWithBodyId, + store: &ExpressionStore, + infer: &InferenceResult, + root_expr: ExprId, + params: impl Iterator)> + Clone, + self_param: Option<(BindingId, Ty<'db>)>, + is_root: bool, ) -> Result<'db, MirBody> { if infer.type_mismatches().next().is_some() || infer.is_erroneous() { return Err(MirLowerError::HasErrors); } - let mut ctx = MirLowerCtx::new(db, owner, body, infer); + let mut ctx = MirLowerCtx::new(db, owner, store, infer); // 0 is return local ctx.result.locals.alloc(Local { ty: ctx.expr_ty_after_adjustments(root_expr).store() }); let binding_picker = |b: BindingId| { - let owner = ctx.body.binding_owner(b); - if root_expr == body.body_expr { owner.is_none() } else { owner == Some(root_expr) } - }; - // 1 to param_len is for params - // FIXME: replace with let chain once it becomes stable - let current = 'b: { - if body.body_expr == root_expr { - // otherwise it's an inline const, and has no parameter - if let DefWithBodyId::FunctionId(fid) = owner { - let callable_sig = - db.callable_item_signature(fid.into()).instantiate_identity().skip_binder(); - let mut params = callable_sig.inputs().iter().copied(); - let self_param = body.self_param.and_then(|id| Some((id, params.next()?))); - break 'b ctx.lower_params_and_bindings( - body.params.iter().zip(params).map(|(it, y)| (*it, y)), - self_param, - binding_picker, - )?; - } - } - ctx.lower_params_and_bindings([].into_iter(), None, binding_picker)? + let owner = ctx.store.binding_owner(b); + if is_root { owner.is_none() } else { owner == Some(root_expr) } }; + let current = ctx.lower_params_and_bindings(params, self_param, binding_picker)?; if let Some(current) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? { let current = ctx.pop_drop_scope_assert_finished(current, root_expr.into())?; ctx.set_terminator(current, TerminatorKind::Return, root_expr.into()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index cf05ec27ac37..17dc95fb248a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -137,11 +137,11 @@ pub(super) fn lower_expr_as_place_without_adjust( } this.lower_expr_to_some_place_without_adjust(expr_id, current) }; - match &self.body[expr_id] { + match &self.store[expr_id] { Expr::Path(p) => { let resolver_guard = self.resolver.update_to_inner_scope(self.db, self.owner, expr_id); - let hygiene = self.body.expr_path_hygiene(expr_id); + let hygiene = self.store.expr_path_hygiene(expr_id); let resolved = self.resolver.resolve_path_in_value_ns_fully(self.db, p, hygiene); self.resolver.reset_to_guard(resolver_guard); let Some(pr) = resolved else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 83139821e3b8..99c5f0fc653f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -131,7 +131,7 @@ fn pattern_match_inner( .collect::>() .into(), ); - Ok(match &self.body[pattern] { + Ok(match &self.store[pattern] { Pat::Missing => return Err(MirLowerError::IncompletePattern), Pat::Wild => (current, current_else), Pat::Tuple { args, ellipsis } => { @@ -322,7 +322,7 @@ fn pattern_match_inner( } if let &Some(slice) = slice && mode != MatchingMode::Check - && let Pat::Bind { id, subpat: _ } = self.body[slice] + && let Pat::Bind { id, subpat: _ } = self.store[slice] { let next_place = cond_place.project( ProjectionElem::Subslice { @@ -363,9 +363,14 @@ fn pattern_match_inner( )?, None => { let unresolved_name = || { - MirLowerError::unresolved_path(self.db, p, self.display_target(), self.body) + MirLowerError::unresolved_path( + self.db, + p, + self.display_target(), + self.store, + ) }; - let hygiene = self.body.pat_path_hygiene(pattern); + let hygiene = self.store.pat_path_hygiene(pattern); let pr = self .resolver .resolve_path_in_value_ns(self.db, p, hygiene) @@ -432,7 +437,7 @@ fn pattern_match_inner( (next, Some(else_target)) } }, - Pat::Lit(l) => match &self.body[*l] { + Pat::Lit(l) => match &self.store[*l] { Expr::Literal(l) => { if mode == MatchingMode::Check { let c = self.lower_literal_to_operand(self.infer.pat_ty(pattern), l)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index 96b90a3f4074..4b654a0fbe08 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -6,7 +6,11 @@ }; use either::Either; -use hir_def::{expr_store::Body, hir::BindingId}; +use hir_def::{ + expr_store::Body, + hir::BindingId, + signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, +}; use hir_expand::{Lookup, name::Name}; use la_arena::ArenaMap; @@ -38,19 +42,19 @@ macro_rules! wln { impl MirBody { pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { - let hir_body = db.body(self.owner); - let mut ctx = MirPrettyCtx::new(self, &hir_body, db, display_target); + let hir_body = Body::of(db, self.owner); + let mut ctx = MirPrettyCtx::new(self, hir_body, db, display_target); ctx.for_body(|this| match ctx.body.owner { hir_def::DefWithBodyId::FunctionId(id) => { - let data = db.function_signature(id); + let data = FunctionSignature::of(db, id); w!(this, "fn {}() ", data.name.display(db, this.display_target.edition)); } hir_def::DefWithBodyId::StaticId(id) => { - let data = db.static_signature(id); + let data = StaticSignature::of(db, id); w!(this, "static {}: _ = ", data.name.display(db, this.display_target.edition)); } hir_def::DefWithBodyId::ConstId(id) => { - let data = db.const_signature(id); + let data = ConstSignature::of(db, id); w!( this, "const {}: _ = ", @@ -66,7 +70,7 @@ pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) w!( this, "enum {}::{} = ", - db.enum_signature(loc.parent).name.display(db, edition), + EnumSignature::of(db, loc.parent).name.display(db, edition), loc.parent .enum_variants(db) .variant_name_by_id(id) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs index aa6caefc4a06..00161d6d0825 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -1,9 +1,13 @@ //! Definition of `SolverDefId` use hir_def::{ - AdtId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, EnumId, - EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, StaticId, StructId, TraitId, - TypeAliasId, UnionId, + AdtId, AnonConstId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, + EnumId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, GeneralConstId, GenericDefId, + ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, + signatures::{ + ConstSignature, EnumSignature, FunctionSignature, StaticSignature, StructSignature, + TraitSignature, TypeAliasSignature, UnionSignature, + }, }; use rustc_type_ir::inherent; use stdx::impl_from; @@ -12,13 +16,13 @@ use super::DbInterner; -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash)] pub enum Ctor { Struct(StructId), Enum(EnumVariantId), } -#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash)] pub enum SolverDefId { AdtId(AdtId), ConstId(ConstId), @@ -26,13 +30,13 @@ pub enum SolverDefId { ImplId(ImplId), BuiltinDeriveImplId(BuiltinDeriveImplId), StaticId(StaticId), + AnonConstId(AnonConstId), TraitId(TraitId), TypeAliasId(TypeAliasId), InternedClosureId(InternedClosureId), InternedCoroutineId(InternedCoroutineId), InternedOpaqueTyId(InternedOpaqueTyId), EnumVariantId(EnumVariantId), - // FIXME(next-solver): Do we need the separation of `Ctor`? It duplicates some variants. Ctor(Ctor), } @@ -42,32 +46,33 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let db = interner.db; match *self { SolverDefId::AdtId(AdtId::StructId(id)) => { - f.debug_tuple("AdtId").field(&db.struct_signature(id).name.as_str()).finish() + f.debug_tuple("AdtId").field(&StructSignature::of(db, id).name.as_str()).finish() } SolverDefId::AdtId(AdtId::EnumId(id)) => { - f.debug_tuple("AdtId").field(&db.enum_signature(id).name.as_str()).finish() + f.debug_tuple("AdtId").field(&EnumSignature::of(db, id).name.as_str()).finish() } SolverDefId::AdtId(AdtId::UnionId(id)) => { - f.debug_tuple("AdtId").field(&db.union_signature(id).name.as_str()).finish() + f.debug_tuple("AdtId").field(&UnionSignature::of(db, id).name.as_str()).finish() } SolverDefId::ConstId(id) => f .debug_tuple("ConstId") - .field(&db.const_signature(id).name.as_ref().map_or("_", |name| name.as_str())) + .field(&ConstSignature::of(db, id).name.as_ref().map_or("_", |name| name.as_str())) + .finish(), + SolverDefId::FunctionId(id) => f + .debug_tuple("FunctionId") + .field(&FunctionSignature::of(db, id).name.as_str()) .finish(), - SolverDefId::FunctionId(id) => { - f.debug_tuple("FunctionId").field(&db.function_signature(id).name.as_str()).finish() - } SolverDefId::ImplId(id) => f.debug_tuple("ImplId").field(&id).finish(), SolverDefId::BuiltinDeriveImplId(id) => f.debug_tuple("ImplId").field(&id).finish(), SolverDefId::StaticId(id) => { - f.debug_tuple("StaticId").field(&db.static_signature(id).name.as_str()).finish() + f.debug_tuple("StaticId").field(&StaticSignature::of(db, id).name.as_str()).finish() } SolverDefId::TraitId(id) => { - f.debug_tuple("TraitId").field(&db.trait_signature(id).name.as_str()).finish() + f.debug_tuple("TraitId").field(&TraitSignature::of(db, id).name.as_str()).finish() } SolverDefId::TypeAliasId(id) => f .debug_tuple("TypeAliasId") - .field(&db.type_alias_signature(id).name.as_str()) + .field(&TypeAliasSignature::of(db, id).name.as_str()) .finish(), SolverDefId::InternedClosureId(id) => { f.debug_tuple("InternedClosureId").field(&id).finish() @@ -83,20 +88,21 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("EnumVariantId") .field(&format_args!( "\"{}::{}\"", - db.enum_signature(parent_enum).name.as_str(), + EnumSignature::of(db, parent_enum).name.as_str(), parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str() )) .finish() } + SolverDefId::AnonConstId(id) => f.debug_tuple("AnonConstId").field(&id).finish(), SolverDefId::Ctor(Ctor::Struct(id)) => { - f.debug_tuple("Ctor").field(&db.struct_signature(id).name.as_str()).finish() + f.debug_tuple("Ctor").field(&StructSignature::of(db, id).name.as_str()).finish() } SolverDefId::Ctor(Ctor::Enum(id)) => { let parent_enum = id.loc(db).parent; f.debug_tuple("Ctor") .field(&format_args!( "\"{}::{}\"", - db.enum_signature(parent_enum).name.as_str(), + EnumSignature::of(db, parent_enum).name.as_str(), parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str() )) .finish() @@ -112,6 +118,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ImplId, BuiltinDeriveImplId, StaticId, + AnonConstId, TraitId, TypeAliasId, InternedClosureId, @@ -142,6 +149,7 @@ fn from(value: GeneralConstId) -> Self { match value { GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id), GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id), + GeneralConstId::AnonConstId(anon_const_id) => SolverDefId::AnonConstId(anon_const_id), } } } @@ -158,6 +166,28 @@ fn from(value: DefWithBodyId) -> Self { } } +impl From for SolverDefId { + #[inline] + fn from(value: VariantId) -> Self { + match value { + VariantId::EnumVariantId(id) => id.into(), + VariantId::StructId(id) => id.into(), + VariantId::UnionId(id) => id.into(), + } + } +} + +impl From for SolverDefId { + #[inline] + fn from(value: ExpressionStoreOwnerId) -> Self { + match value { + ExpressionStoreOwnerId::Body(body_id) => body_id.into(), + ExpressionStoreOwnerId::Signature(sig_id) => sig_id.into(), + ExpressionStoreOwnerId::VariantFields(variant_id) => variant_id.into(), + } + } +} + impl TryFrom for AttrDefId { type Error = (); #[inline] @@ -176,7 +206,8 @@ fn try_from(value: SolverDefId) -> Result { SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::InternedClosureId(_) | SolverDefId::InternedCoroutineId(_) - | SolverDefId::InternedOpaqueTyId(_) => Err(()), + | SolverDefId::InternedOpaqueTyId(_) + | SolverDefId::AnonConstId(_) => Err(()), } } } @@ -199,6 +230,7 @@ fn try_from(value: SolverDefId) -> Result { | SolverDefId::InternedClosureId(_) | SolverDefId::InternedCoroutineId(_) | SolverDefId::Ctor(Ctor::Struct(_)) + | SolverDefId::AnonConstId(_) | SolverDefId::AdtId(_) => return Err(()), }; Ok(id) @@ -222,6 +254,7 @@ fn try_from(value: SolverDefId) -> Result { | SolverDefId::InternedOpaqueTyId(_) | SolverDefId::EnumVariantId(_) | SolverDefId::BuiltinDeriveImplId(_) + | SolverDefId::AnonConstId(_) | SolverDefId::Ctor(_) => return Err(()), }) } @@ -343,6 +376,7 @@ fn from(value: GeneralConstIdWrapper) -> SolverDefId { match value.0 { GeneralConstId::ConstId(id) => SolverDefId::ConstId(id), GeneralConstId::StaticId(id) => SolverDefId::StaticId(id), + GeneralConstId::AnonConstId(id) => SolverDefId::AnonConstId(id), } } } @@ -353,6 +387,7 @@ fn try_from(value: SolverDefId) -> Result { match value { SolverDefId::ConstId(it) => Ok(Self(it.into())), SolverDefId::StaticId(it) => Ok(Self(it.into())), + SolverDefId::AnonConstId(it) => Ok(Self(it.into())), _ => Err(()), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs index 8f798b4ade24..0e8218b33aaa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs @@ -617,6 +617,7 @@ pub fn to_debuggable_error(&self, infcx: &InferCtxt<'db>) -> FulfillmentError<'d } mod wf { + use hir_def::signatures::ImplSignature; use hir_def::{GeneralConstId, ItemContainerId}; use rustc_type_ir::inherent::{ AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Term as _, @@ -1054,7 +1055,7 @@ fn visit_const(&mut self, c: Const<'db>) -> Self::Result { if let GeneralConstId::ConstId(uv_def) = uv.def.0 && let ItemContainerId::ImplId(impl_) = uv_def.loc(self.interner().db).container - && self.interner().db.impl_signature(impl_).target_trait.is_none() + && ImplSignature::of(self.interner().db, impl_).target_trait.is_none() { return; // Subtree is handled by above function } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs index a8288b4e8259..f31de21796fe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs @@ -55,7 +55,7 @@ pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics { let (parent, own_params) = match (def.try_into(), def) { (Ok(def), _) => ( parent_generic_def(db, def), - own_params_for_generic_params(def, &db.generic_params(def)), + own_params_for_generic_params(def, GenericParams::of(db, def)), ), (_, SolverDefId::InternedOpaqueTyId(id)) => { match db.lookup_intern_impl_trait_id(id) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index e17bdac68cdd..5b81c7675dbb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -10,11 +10,15 @@ use base_db::Crate; use hir_def::{ - AdtId, CallableDefId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, StructId, - UnionId, VariantId, + AdtId, CallableDefId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, HasModule, + ItemContainerId, StructId, UnionId, VariantId, attrs::AttrFlags, + expr_store::{Body, ExpressionStore}, lang_item::LangItems, - signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}, + signatures::{ + EnumSignature, FieldData, FnFlags, FunctionSignature, ImplFlags, ImplSignature, + StructFlags, StructSignature, TraitFlags, TraitSignature, UnionSignature, + }, }; use la_arena::Idx; use rustc_abi::{ReprFlags, ReprOptions}; @@ -548,7 +552,7 @@ pub fn new<'db>(def_id: AdtId, interner: DbInterner<'db>) -> Self { let db = interner.db(); let (flags, variants, repr) = match def_id { AdtId::StructId(struct_id) => { - let data = db.struct_signature(struct_id); + let data = StructSignature::of(db, struct_id); let flags = AdtFlags { is_enum: false, @@ -775,15 +779,15 @@ impl fmt::Debug for AdtDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { crate::with_attached_db(|db| match self.inner().id { AdtId::StructId(struct_id) => { - let data = db.struct_signature(struct_id); + let data = StructSignature::of(db, struct_id); f.write_str(data.name.as_str()) } AdtId::UnionId(union_id) => { - let data = db.union_signature(union_id); + let data = UnionSignature::of(db, union_id); f.write_str(data.name.as_str()) } AdtId::EnumId(enum_id) => { - let data = db.enum_signature(enum_id); + let data = EnumSignature::of(db, enum_id); f.write_str(data.name.as_str()) } }) @@ -1193,7 +1197,8 @@ fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { | SolverDefId::ImplId(_) | SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::InternedClosureId(_) - | SolverDefId::InternedCoroutineId(_) => { + | SolverDefId::InternedCoroutineId(_) + | SolverDefId::AnonConstId(_) => { return VariancesOf::empty(self); } }; @@ -1230,7 +1235,7 @@ fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy) -> AliasTyKind { SolverDefId::InternedOpaqueTyId(_) => AliasTyKind::Opaque, SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container { ItemContainerId::ImplId(impl_) - if self.db.impl_signature(impl_).target_trait.is_none() => + if ImplSignature::of(self.db, impl_).target_trait.is_none() => { AliasTyKind::Inherent } @@ -1249,7 +1254,7 @@ fn alias_term_kind( SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container { ItemContainerId::ImplId(impl_) - if self.db.impl_signature(impl_).target_trait.is_none() => + if ImplSignature::of(self.db, impl_).target_trait.is_none() => { AliasTermKind::InherentTy } @@ -1260,7 +1265,9 @@ fn alias_term_kind( }, // rustc creates an `AnonConst` for consts, and evaluates them with CTFE (normalizing projections // via selection, similar to ours `find_matching_impl()`, and not with the trait solver), so mimic it. - SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, + SolverDefId::ConstId(_) | SolverDefId::AnonConstId(_) => { + AliasTermKind::UnevaluatedConst + } _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), } } @@ -1308,22 +1315,10 @@ fn parent(self, def_id: Self::DefId) -> Self::DefId { SolverDefId::TypeAliasId(it) => it.lookup(self.db()).container, SolverDefId::ConstId(it) => it.lookup(self.db()).container, SolverDefId::InternedClosureId(it) => { - return self - .db() - .lookup_intern_closure(it) - .0 - .as_generic_def_id(self.db()) - .unwrap() - .into(); + return self.db().lookup_intern_closure(it).0.generic_def(self.db()).into(); } SolverDefId::InternedCoroutineId(it) => { - return self - .db() - .lookup_intern_coroutine(it) - .0 - .as_generic_def_id(self.db()) - .unwrap() - .into(); + return self.db().lookup_intern_coroutine(it).0.generic_def(self.db()).into(); } SolverDefId::StaticId(_) | SolverDefId::AdtId(_) @@ -1332,7 +1327,8 @@ fn parent(self, def_id: Self::DefId) -> Self::DefId { | SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::EnumVariantId(..) | SolverDefId::Ctor(..) - | SolverDefId::InternedOpaqueTyId(..) => panic!(), + | SolverDefId::InternedOpaqueTyId(..) + | SolverDefId::AnonConstId(_) => panic!(), }; match container { @@ -1361,8 +1357,8 @@ fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movabi // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let body = self.db.body(owner); - let expr = &body[expr_id]; + let store = ExpressionStore::of(self.db, owner); + let expr = &store[expr_id]; match *expr { hir_def::hir::Expr::Closure { closure_kind, .. } => match closure_kind { hir_def::hir::ClosureKind::Coroutine(movability) => match movability { @@ -1795,6 +1791,7 @@ fn for_each_relevant_impl( | SolverDefId::InternedCoroutineId(_) | SolverDefId::InternedOpaqueTyId(_) | SolverDefId::EnumVariantId(_) + | SolverDefId::AnonConstId(_) | SolverDefId::Ctor(_) => return None, }; module.block(self.db) @@ -1933,7 +1930,7 @@ fn has_item_definition(self, _def_id: Self::DefId) -> bool { fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool { match impl_def_id { - AnyImplId::ImplId(impl_id) => self.db.impl_signature(impl_id).is_default(), + AnyImplId::ImplId(impl_id) => ImplSignature::of(self.db, impl_id).is_default(), AnyImplId::BuiltinDeriveImplId(_) => false, } } @@ -1960,7 +1957,7 @@ fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity { let AnyImplId::ImplId(impl_id) = impl_id else { return ImplPolarity::Positive; }; - let impl_data = self.db().impl_signature(impl_id); + let impl_data = ImplSignature::of(self.db(), impl_id); if impl_data.flags.contains(ImplFlags::NEGATIVE) { ImplPolarity::Negative } else { @@ -1969,12 +1966,12 @@ fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity { } fn trait_is_auto(self, trait_: Self::TraitId) -> bool { - let trait_data = self.db().trait_signature(trait_.0); + let trait_data = TraitSignature::of(self.db(), trait_.0); trait_data.flags.contains(TraitFlags::AUTO) } fn trait_is_alias(self, trait_: Self::TraitId) -> bool { - let trait_data = self.db().trait_signature(trait_.0); + let trait_data = TraitSignature::of(self.db(), trait_.0); trait_data.flags.contains(TraitFlags::ALIAS) } @@ -1983,7 +1980,7 @@ fn trait_is_dyn_compatible(self, trait_: Self::TraitId) -> bool { } fn trait_is_fundamental(self, trait_: Self::TraitId) -> bool { - let trait_data = self.db().trait_signature(trait_.0); + let trait_data = TraitSignature::of(self.db(), trait_.0); trait_data.flags.contains(TraitFlags::FUNDAMENTAL) } @@ -2006,9 +2003,9 @@ fn is_general_coroutine(self, def_id: Self::CoroutineId) -> bool { // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let body = self.db.body(owner); + let store = ExpressionStore::of(self.db, owner); matches!( - body[expr_id], + store[expr_id], hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Coroutine(_), .. @@ -2020,9 +2017,9 @@ fn coroutine_is_async(self, def_id: Self::CoroutineId) -> bool { // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let body = self.db.body(owner); + let store = ExpressionStore::of(self.db, owner); matches!( - body[expr_id], + store[expr_id], hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Async, .. } | hir_def::hir::Expr::Async { .. } ) @@ -2143,7 +2140,7 @@ fn opaque_types_and_coroutines_defined_by(self, def_id: Self::LocalDefId) -> Sel crate::opaques::opaque_types_defined_by(self.db, def_id, &mut result); // Collect coroutines. - let body = self.db.body(def_id); + let body = Body::of(self.db, def_id); body.exprs().for_each(|(expr_id, expr)| { if matches!( expr, @@ -2154,8 +2151,10 @@ fn opaque_types_and_coroutines_defined_by(self, def_id: Self::LocalDefId) -> Sel .. } ) { - let coroutine = - InternedCoroutineId::new(self.db, InternedCoroutine(def_id, expr_id)); + let coroutine = InternedCoroutineId::new( + self.db, + InternedCoroutine(ExpressionStoreOwnerId::Body(def_id), expr_id), + ); result.push(coroutine.into()); } }); @@ -2184,7 +2183,7 @@ fn fn_is_const(self, id: Self::FunctionId) -> bool { CallableDefId::FunctionId(id) => id, _ => return false, }; - self.db().function_signature(id).flags.contains(FnFlags::CONST) + FunctionSignature::of(self.db(), id).flags.contains(FnFlags::CONST) } fn impl_is_const(self, _def_id: Self::ImplId) -> bool { @@ -2232,11 +2231,11 @@ fn is_default_trait(self, def_id: Self::TraitId) -> bool { } fn trait_is_coinductive(self, trait_: Self::TraitId) -> bool { - self.db().trait_signature(trait_.0).flags.contains(TraitFlags::COINDUCTIVE) + TraitSignature::of(self.db(), trait_.0).flags.contains(TraitFlags::COINDUCTIVE) } fn trait_is_unsafe(self, trait_: Self::TraitId) -> bool { - self.db().trait_signature(trait_.0).flags.contains(TraitFlags::UNSAFE) + TraitSignature::of(self.db(), trait_.0).flags.contains(TraitFlags::UNSAFE) } fn impl_self_is_guaranteed_unsized(self, _def_id: Self::ImplId) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs index 998aab5a3fff..e0732b347374 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs @@ -1,7 +1,6 @@ //! Things related to IR printing in the next-trait-solver. -use std::any::type_name_of_val; - +use hir_def::signatures::{TraitSignature, TypeAliasSignature}; use rustc_type_ir::{self as ty, ir_print::IrPrint}; use super::SolverDefId; @@ -16,7 +15,7 @@ fn print_debug(t: &ty::AliasTy, fmt: &mut std::fmt::Formatter<'_>) -> std: crate::with_attached_db(|db| match t.def_id { SolverDefId::TypeAliasId(id) => fmt.write_str(&format!( "AliasTy({:?}[{:?}])", - db.type_alias_signature(id).name.as_str(), + TypeAliasSignature::of(db, id).name.as_str(), t.args )), SolverDefId::InternedOpaqueTyId(id) => { @@ -36,7 +35,7 @@ fn print_debug(t: &ty::AliasTerm, fmt: &mut std::fmt::Formatter<'_>) -> st crate::with_attached_db(|db| match t.def_id { SolverDefId::TypeAliasId(id) => fmt.write_str(&format!( "AliasTerm({:?}[{:?}])", - db.type_alias_signature(id).name.as_str(), + TypeAliasSignature::of(db, id).name.as_str(), t.args )), SolverDefId::InternedOpaqueTyId(id) => { @@ -60,13 +59,13 @@ fn print_debug(t: &ty::TraitRef, fmt: &mut std::fmt::Formatter<'_>) -> std fmt.write_str(&format!( "{:?}: {}", self_ty, - db.trait_signature(trait_).name.as_str() + TraitSignature::of(db, trait_).name.as_str() )) } else { fmt.write_str(&format!( "{:?}: {}<{:?}>", self_ty, - db.trait_signature(trait_).name.as_str(), + TraitSignature::of(db, trait_).name.as_str(), trait_args )) } @@ -82,7 +81,10 @@ fn print_debug( t: &ty::TraitPredicate, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + match t.polarity { + ty::PredicatePolarity::Positive => write!(fmt, "{:?}", t.trait_ref), + ty::PredicatePolarity::Negative => write!(fmt, "!{:?}", t.trait_ref), + } } } impl<'db> IrPrint> for DbInterner<'db> { @@ -97,7 +99,11 @@ fn print_debug( t: &rustc_type_ir::HostEffectPredicate, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + let prefix = match t.constness { + ty::BoundConstness::Const => "const", + ty::BoundConstness::Maybe => "[const]", + }; + write!(fmt, "{prefix} {:?}", t.trait_ref) } } impl<'db> IrPrint> for DbInterner<'db> { @@ -116,7 +122,7 @@ fn print_debug( let trait_ = t.def_id.0; fmt.write_str(&format!( "ExistentialTraitRef({:?}[{:?}])", - db.trait_signature(trait_).name.as_str(), + TraitSignature::of(db, trait_).name.as_str(), t.args )) }) @@ -141,7 +147,7 @@ fn print_debug( }; fmt.write_str(&format!( "ExistentialProjection(({:?}[{:?}]) -> {:?})", - db.type_alias_signature(id).name.as_str(), + TypeAliasSignature::of(db, id).name.as_str(), t.args, t.term )) @@ -167,7 +173,7 @@ fn print_debug( }; fmt.write_str(&format!( "ProjectionPredicate(({:?}[{:?}]) -> {:?})", - db.type_alias_signature(id).name.as_str(), + TypeAliasSignature::of(db, id).name.as_str(), t.projection_term.args, t.term )) @@ -183,7 +189,7 @@ fn print_debug( t: &ty::NormalizesTo, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + write!(fmt, "NormalizesTo({} -> {:?})", t.alias, t.term) } } impl<'db> IrPrint> for DbInterner<'db> { @@ -198,7 +204,7 @@ fn print_debug( t: &ty::SubtypePredicate, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + write!(fmt, "{:?} <: {:?}", t.a, t.b) } } impl<'db> IrPrint> for DbInterner<'db> { @@ -210,7 +216,7 @@ fn print_debug( t: &ty::CoercePredicate, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + write!(fmt, "CoercePredicate({:?} -> {:?})", t.a, t.b) } } impl<'db> IrPrint> for DbInterner<'db> { @@ -219,7 +225,9 @@ fn print(t: &ty::FnSig, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Re } fn print_debug(t: &ty::FnSig, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + let tys = t.inputs_and_output.as_slice(); + let (output, inputs) = tys.split_last().unwrap(); + write!(fmt, "fn({:?}) -> {:?}", inputs, output) } } @@ -235,6 +243,10 @@ fn print_debug( t: &rustc_type_ir::PatternKind>, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + match t { + ty::PatternKind::Range { start, end } => write!(fmt, "{:?}..={:?}", start, end), + ty::PatternKind::Or(list) => write!(fmt, "or({:?})", list), + ty::PatternKind::NotNull => fmt.write_str("!null"), + } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index 15d6e2e4516e..848bb110af2d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -1,6 +1,9 @@ //! Defining `SolverContext` for next-trait-solver. -use hir_def::{AssocItemId, GeneralConstId}; +use hir_def::{ + AssocItemId, GeneralConstId, + signatures::{ConstSignature, TypeAliasSignature}, +}; use rustc_next_trait_solver::delegate::SolverDelegate; use rustc_type_ir::{ AliasTyKind, GenericArgKind, InferCtxtLike, Interner, PredicatePolarity, TypeFlags, @@ -18,7 +21,7 @@ }; use super::{ - DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span, + Const, DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span, infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt}, }; @@ -181,52 +184,53 @@ fn fetch_eligible_assoc_item( return Ok(None); }; let impl_items = impl_id.impl_items(self.0.interner.db()); - let id = - match trait_assoc_def_id { - SolverDefId::TypeAliasId(trait_assoc_id) => { - let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id); - impl_items - .items - .iter() - .find_map(|(impl_assoc_name, impl_assoc_id)| { - if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id - && *impl_assoc_name == trait_assoc_data.name - { - Some(impl_assoc_id) - } else { - None - } - }) - .or_else(|| { - if trait_assoc_data.ty.is_some() { Some(trait_assoc_id) } else { None } - }) - .map(SolverDefId::TypeAliasId) - } - SolverDefId::ConstId(trait_assoc_id) => { - let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id); - let trait_assoc_name = trait_assoc_data - .name - .as_ref() - .expect("unnamed consts should not get passed to the solver"); - impl_items - .items - .iter() - .find_map(|(impl_assoc_name, impl_assoc_id)| { - if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id - && impl_assoc_name == trait_assoc_name - { - Some(impl_assoc_id) - } else { - None - } - }) - .or_else(|| { + let id = match trait_assoc_def_id { + SolverDefId::TypeAliasId(trait_assoc_id) => { + let trait_assoc_data = TypeAliasSignature::of(self.0.interner.db, trait_assoc_id); + impl_items + .items + .iter() + .find_map(|(impl_assoc_name, impl_assoc_id)| { + if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id + && *impl_assoc_name == trait_assoc_data.name + { + Some(impl_assoc_id) + } else { + None + } + }) + .or_else(|| { + if trait_assoc_data.ty.is_some() { Some(trait_assoc_id) } else { None } + }) + .map(SolverDefId::TypeAliasId) + } + SolverDefId::ConstId(trait_assoc_id) => { + let trait_assoc_data = ConstSignature::of(self.0.interner.db, trait_assoc_id); + let trait_assoc_name = trait_assoc_data + .name + .as_ref() + .expect("unnamed consts should not get passed to the solver"); + impl_items + .items + .iter() + .find_map(|(impl_assoc_name, impl_assoc_id)| { + if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id + && impl_assoc_name == trait_assoc_name + { + Some(impl_assoc_id) + } else { + None + } + }) + .or_else( + || { if trait_assoc_data.has_body() { Some(trait_assoc_id) } else { None } - }) - .map(SolverDefId::ConstId) - } - _ => panic!("Unexpected SolverDefId"), - }; + }, + ) + .map(SolverDefId::ConstId) + } + _ => panic!("Unexpected SolverDefId"), + }; Ok(id) } @@ -256,6 +260,11 @@ fn evaluate_const( let ec = self.cx().db.const_eval_static(c).ok()?; Some(ec) } + // TODO: Wire up const_eval_anon query in Phase 5. + // For now, return an error const so normalization resolves the + // unevaluated const to Error (matching the old behavior where + // complex expressions produced ConstKind::Error directly). + GeneralConstId::AnonConstId(_) => Some(Const::error(self.cx())), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 1173028a1092..192cdb70aee5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -4,7 +4,7 @@ use hir_def::{ AdtId, HasModule, TypeParamId, - hir::generics::{TypeOrConstParamData, TypeParamProvenance}, + hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance}, }; use hir_def::{TraitId, type_ref::Rawness}; use intern::{Interned, InternedRef, impl_internable}; @@ -690,7 +690,7 @@ pub fn impl_trait_bounds(self, db: &'db dyn HirDatabase) -> Option { // FIXME: We shouldn't use `param.id` here. - let generic_params = db.generic_params(param.id.parent()); + let generic_params = GenericParams::of(db, param.id.parent()); let param_data = &generic_params[param.id.local_id()]; match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { @@ -714,7 +714,7 @@ pub fn impl_trait_bounds(self, db: &'db dyn HirDatabase) -> Option { let InternedCoroutine(owner, _) = coroutine_id.0.loc(db); - let krate = owner.module(db).krate(db); + let krate = owner.krate(db); if let Some(future_trait) = hir_def::lang_item::lang_items(db, krate).Future { // This is only used by type walking. // Parameters will be walked outside, and projection predicate is not used. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs index 27ae5e39d55b..ce93a334221c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs @@ -1,7 +1,8 @@ //! Handling of opaque types, detection of defining scope and hidden type. use hir_def::{ - AssocItemId, AssocItemLoc, DefWithBodyId, FunctionId, HasModule, ItemContainerId, TypeAliasId, + AssocItemId, AssocItemLoc, DefWithBodyId, ExpressionStoreOwnerId, FunctionId, GenericDefId, + HasModule, ItemContainerId, TypeAliasId, signatures::ImplSignature, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -55,7 +56,7 @@ pub(crate) fn opaque_types_defined_by( }; let extend_with_atpit_from_container = |container| match container { ItemContainerId::ImplId(impl_id) => { - if db.impl_signature(impl_id).target_trait.is_some() { + if ImplSignature::of(db, impl_id).target_trait.is_some() { extend_with_atpit_from_assoc_items(&impl_id.impl_items(db).items); } } @@ -94,7 +95,7 @@ pub(crate) fn rpit_hidden_types<'db>( db: &'db dyn HirDatabase, function: FunctionId, ) -> ArenaMap> { - let infer = InferenceResult::for_body(db, function.into()); + let infer = InferenceResult::of(db, DefWithBodyId::from(function)); let mut result = ArenaMap::new(); for (opaque, hidden_type) in infer.return_position_impl_trait_types(db) { result.insert(opaque, StoredEarlyBinder::bind(hidden_type.store())); @@ -122,13 +123,14 @@ pub(crate) fn tait_hidden_types<'db>( let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let mut ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); - let param_env = db.trait_environment(type_alias.into()); + let param_env = + db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(type_alias))); let defining_bodies = tait_defining_bodies(db, &loc); let mut result = ArenaMap::with_capacity(taits_count); for defining_body in defining_bodies { - let infer = InferenceResult::for_body(db, defining_body); + let infer = InferenceResult::of(db, defining_body); for (&opaque, hidden_type) in &infer.type_of_opaque { let ImplTraitId::TypeAliasImplTrait(opaque_owner, opaque_idx) = opaque.loc(db) else { continue; @@ -195,7 +197,7 @@ fn tait_defining_bodies( }; match loc.container { ItemContainerId::ImplId(impl_id) => { - if db.impl_signature(impl_id).target_trait.is_some() { + if ImplSignature::of(db, impl_id).target_trait.is_some() { return from_assoc_items(&impl_id.impl_items(db).items); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs index 7e40f2d7ac75..bae204c4ef7c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs @@ -1,6 +1,6 @@ //! Detecting whether a type is infinitely-sized. -use hir_def::{AdtId, VariantId}; +use hir_def::{AdtId, VariantId, hir::generics::GenericParams}; use rustc_type_ir::inherent::{AdtDef, IntoKind}; use crate::{ @@ -88,7 +88,7 @@ fn representability_adt_ty<'db>( } fn params_in_repr(db: &dyn HirDatabase, def_id: AdtId) -> Box<[bool]> { - let generics = db.generic_params(def_id.into()); + let generics = GenericParams::of(db, def_id.into()); let mut params_in_repr = (0..generics.len_lifetimes() + generics.len_type_or_consts()) .map(|_| false) .collect::>(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs index d97a35549ca4..90cbcfea6abe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs @@ -1,6 +1,9 @@ //! Impl specialization related things -use hir_def::{HasModule, ImplId, nameres::crate_def_map}; +use hir_def::{ + ExpressionStoreOwnerId, GenericDefId, HasModule, ImplId, nameres::crate_def_map, + signatures::ImplSignature, +}; use intern::sym; use tracing::debug; @@ -45,11 +48,13 @@ fn specializes_query( specializing_impl_def_id: ImplId, parent_impl_def_id: ImplId, ) -> bool { - let trait_env = db.trait_environment(specializing_impl_def_id.into()); + let trait_env = db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( + specializing_impl_def_id, + ))); let interner = DbInterner::new_with(db, specializing_impl_def_id.krate(db)); - let specializing_impl_signature = db.impl_signature(specializing_impl_def_id); - let parent_impl_signature = db.impl_signature(parent_impl_def_id); + let specializing_impl_signature = ImplSignature::of(db, specializing_impl_def_id); + let parent_impl_signature = ImplSignature::of(db, parent_impl_def_id); // We determine whether there's a subset relationship by: // diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs b/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs index 2bd675ba124e..29a933f92263 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs @@ -217,6 +217,7 @@ pub(crate) fn from_fn_no_implications(db: &'db dyn HirDatabase, owner: FunctionI ("relaxed-simd", &["simd128"]), // BPF ("alu32", &[]), + ("allows-misaligned-mem-access", &[]), // CSKY ("10e60", &["7e10"]), ("2e3", &["e2"]), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index 67ab89f5ec8f..430a570444d8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -16,9 +16,9 @@ use base_db::{Crate, SourceDatabase}; use expect_test::Expect; use hir_def::{ - AssocItemId, DefWithBodyId, HasModule, Lookup, ModuleDefId, ModuleId, SyntheticSyntax, - db::DefDatabase, - expr_store::{Body, BodySourceMap}, + AssocItemId, DefWithBodyId, GenericDefId, HasModule, Lookup, ModuleDefId, ModuleId, + SyntheticSyntax, + expr_store::{Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap}, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, nameres::DefMap, @@ -34,7 +34,6 @@ ast::{self, AstNode, HasName}, }; use test_fixture::WithFixture; -use triomphe::Arc; use crate::{ InferenceResult, @@ -146,15 +145,15 @@ fn check_impl( let mut unexpected_type_mismatches = String::new(); for (def, krate) in defs { let display_target = DisplayTarget::from_crate(&db, krate); - let (body, body_source_map) = db.body_with_source_map(def); - let inference_result = InferenceResult::for_body(&db, def); + let (body, body_source_map) = Body::with_source_map(&db, def); + let inference_result = InferenceResult::of(&db, def); for (pat, ty) in inference_result.type_of_pat.iter() { let mut ty = ty.as_ref(); if let Pat::Bind { id, .. } = body[pat] { ty = inference_result.type_of_binding[id].as_ref(); } - let node = match pat_node(&body_source_map, pat, &db) { + let node = match pat_node(body_source_map, pat, &db) { Some(value) => value, None => continue, }; @@ -171,7 +170,7 @@ fn check_impl( for (expr, ty) in inference_result.type_of_expr.iter() { let ty = ty.as_ref(); - let node = match expr_node(&body_source_map, expr, &db) { + let node = match expr_node(body_source_map, expr, &db) { Some(value) => value, None => continue, }; @@ -202,9 +201,9 @@ fn check_impl( for (expr_or_pat, mismatch) in inference_result.type_mismatches() { let Some(node) = (match expr_or_pat { hir_def::hir::ExprOrPatId::ExprId(expr) => { - expr_node(&body_source_map, expr, &db) + expr_node(body_source_map, expr, &db) } - hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db), + hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(body_source_map, pat, &db), }) else { continue; }; @@ -223,7 +222,7 @@ fn check_impl( } for (type_ref, ty) in inference_result.placeholder_types() { - let node = match type_node(&body_source_map, type_ref, &db) { + let node = match type_node(body_source_map, type_ref, &db) { Some(value) => value, None => continue, }; @@ -321,16 +320,20 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let mut buf = String::new(); let mut infer_def = |inference_result: &InferenceResult, - body: Arc, - body_source_map: Arc, + store: &ExpressionStore, + source_map: &ExpressionStoreSourceMap, + self_param: Option<( + hir_def::hir::BindingId, + Option>, + )>, krate: Crate| { let display_target = DisplayTarget::from_crate(&db, krate); let mut types: Vec<(InFile, Ty<'_>)> = Vec::new(); let mut mismatches: Vec<(InFile, &TypeMismatch)> = Vec::new(); - if let Some(self_param) = body.self_param { - let ty = &inference_result.type_of_binding[self_param]; - if let Some(syntax_ptr) = body_source_map.self_param_syntax() { + if let Some((binding_id, syntax_ptr)) = self_param { + let ty = &inference_result.type_of_binding[binding_id]; + if let Some(syntax_ptr) = syntax_ptr { let root = db.parse_or_expand(syntax_ptr.file_id); let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone()); types.push((node, ty.as_ref())); @@ -338,10 +341,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } for (pat, mut ty) in inference_result.type_of_pat.iter() { - if let Pat::Bind { id, .. } = body[pat] { + if let Pat::Bind { id, .. } = store[pat] { ty = &inference_result.type_of_binding[id]; } - let node = match body_source_map.pat_syntax(pat) { + let node = match source_map.pat_syntax(pat) { Ok(sp) => { let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) @@ -355,7 +358,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } for (expr, ty) in inference_result.type_of_expr.iter() { - let node = match body_source_map.expr_syntax(expr) { + let node = match source_map.expr_syntax(expr) { Ok(sp) => { let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) @@ -414,16 +417,56 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let def_map = module.def_map(&db); let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); + let mut generic_defs: Vec<(GenericDefId, Crate)> = Vec::new(); visit_module(&db, def_map, module, &mut |it| { - let def = match it { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }; - defs.push((def, module.krate(&db))) + let krate = module.krate(&db); + match it { + ModuleDefId::FunctionId(it) => { + defs.push((it.into(), krate)); + generic_defs.push((it.into(), krate)); + } + ModuleDefId::EnumVariantId(it) => { + defs.push((it.into(), krate)); + } + ModuleDefId::ConstId(it) => { + defs.push((it.into(), krate)); + generic_defs.push((it.into(), krate)); + } + ModuleDefId::StaticId(it) => { + defs.push((it.into(), krate)); + generic_defs.push((it.into(), krate)); + } + ModuleDefId::AdtId(it) => { + generic_defs.push((it.into(), krate)); + } + ModuleDefId::TraitId(it) => { + generic_defs.push((it.into(), krate)); + } + ModuleDefId::TypeAliasId(it) => { + generic_defs.push((it.into(), krate)); + } + _ => {} + } }); + // Also collect impls + for impl_id in def_map[module].scope.impls() { + generic_defs.push((impl_id.into(), module.krate(&db))); + let impl_data = impl_id.impl_items(&db); + for &(_, item) in impl_data.items.iter() { + match item { + AssocItemId::FunctionId(it) => { + generic_defs.push((it.into(), module.krate(&db))); + } + AssocItemId::ConstId(it) => { + generic_defs.push((it.into(), module.krate(&db))); + } + AssocItemId::TypeAliasId(it) => { + generic_defs.push((it.into(), module.krate(&db))); + } + } + } + } + defs.sort_by_key(|(def, _)| match def { DefWithBodyId::FunctionId(it) => { let loc = it.lookup(&db); @@ -443,9 +486,22 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } }); for (def, krate) in defs { - let (body, source_map) = db.body_with_source_map(def); - let infer = InferenceResult::for_body(&db, def); - infer_def(infer, body, source_map, krate); + let (body, source_map) = Body::with_source_map(&db, def); + let infer = InferenceResult::of(&db, def); + let self_param = body.self_param.map(|id| (id, source_map.self_param_syntax())); + infer_def(infer, body, source_map, self_param, krate); + } + + // Also infer signature const expressions (array lengths, const generic args, etc.) + generic_defs.dedup(); + for (def, krate) in generic_defs { + let (store, source_map) = ExpressionStore::with_source_map(&db, def.into()); + // Skip if there are no const expressions in the signature + if store.const_expr_origins().is_empty() { + continue; + } + let infer = InferenceResult::of(&db, def); + infer_def(infer, store, source_map, None, krate); } buf.truncate(buf.trim_end().len()); @@ -465,14 +521,14 @@ pub(crate) fn visit_module( for &(_, item) in impl_data.items.iter() { match item { AssocItemId::FunctionId(it) => { - let body = db.body(it.into()); + let body = Body::of(db, it.into()); cb(it.into()); - visit_body(db, &body, cb); + visit_body(db, body, cb); } AssocItemId::ConstId(it) => { - let body = db.body(it.into()); + let body = Body::of(db, it.into()); cb(it.into()); - visit_body(db, &body, cb); + visit_body(db, body, cb); } AssocItemId::TypeAliasId(it) => { cb(it.into()); @@ -491,22 +547,22 @@ fn visit_scope( cb(decl); match decl { ModuleDefId::FunctionId(it) => { - let body = db.body(it.into()); - visit_body(db, &body, cb); + let body = Body::of(db, it.into()); + visit_body(db, body, cb); } ModuleDefId::ConstId(it) => { - let body = db.body(it.into()); - visit_body(db, &body, cb); + let body = Body::of(db, it.into()); + visit_body(db, body, cb); } ModuleDefId::StaticId(it) => { - let body = db.body(it.into()); - visit_body(db, &body, cb); + let body = Body::of(db, it.into()); + visit_body(db, body, cb); } ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { it.enum_variants(db).variants.iter().for_each(|&(it, _, _)| { - let body = db.body(it.into()); + let body = Body::of(db, it.into()); cb(it.into()); - visit_body(db, &body, cb); + visit_body(db, body, cb); }); } ModuleDefId::TraitId(it) => { @@ -596,16 +652,14 @@ fn main() { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { - InferenceResult::for_body( - &db, - match def { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }, - ); + let body_def: DefWithBodyId = match def { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }; + InferenceResult::of(&db, body_def); }); }); @@ -640,16 +694,14 @@ fn main() { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { - InferenceResult::for_body( - &db, - match def { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }, - ); + let body_def: DefWithBodyId = match def { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }; + InferenceResult::of(&db, body_def); }); }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs index f089120cd7b8..9e687568216d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs @@ -1,5 +1,8 @@ use expect_test::{Expect, expect}; -use hir_def::db::DefDatabase; +use hir_def::{ + DefWithBodyId, + expr_store::{Body, ExpressionStore}, +}; use hir_expand::{HirFileId, files::InFileWrapper}; use itertools::Itertools; use span::TextRange; @@ -28,19 +31,20 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec let mut captures_info = Vec::new(); for def in defs { - let def = match def { + let def: DefWithBodyId = match def { hir_def::ModuleDefId::FunctionId(it) => it.into(), hir_def::ModuleDefId::EnumVariantId(it) => it.into(), hir_def::ModuleDefId::ConstId(it) => it.into(), hir_def::ModuleDefId::StaticId(it) => it.into(), _ => continue, }; - let infer = InferenceResult::for_body(&db, def); + let infer = InferenceResult::of(&db, def); let db = &db; captures_info.extend(infer.closure_info.iter().flat_map( |(closure_id, (captures, _))| { let closure = db.lookup_intern_closure(*closure_id); - let source_map = db.body_with_source_map(closure.0).1; + let body_owner = closure.0; + let source_map = ExpressionStore::with_source_map(db, body_owner).1; let closure_text_range = source_map .expr_syntax(closure.1) .expect("failed to map closure to SyntaxNode") @@ -56,7 +60,8 @@ fn text_range( } // FIXME: Deduplicate this with hir::Local::sources(). - let (body, source_map) = db.body_with_source_map(closure.0); + let (body, source_map) = + Body::with_source_map(db, body_owner.as_def_with_body().unwrap()); let local_text_range = match body.self_param.zip(source_map.self_param_syntax()) { Some((param, source)) if param == capture.local() => { @@ -71,7 +76,7 @@ fn text_range( .map(|it| format!("{it:?}")) .join(", "), }; - let place = capture.display_place(closure.0, db); + let place = capture.display_place(body_owner, db); let capture_ty = capture .ty .get() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index cf7ff6f7ecca..e806999cb44e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -24,30 +24,31 @@ fn foo() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - InferenceResult::for_body(&db, it.into()); + InferenceResult::of(&db, DefWithBodyId::from(it)); } }); }, &[("InferenceResult::for_body_", 1)], expect_test::expect![[r#" [ + "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "lang_items", "crate_lang_items", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "ExprScopes::body_expr_scopes_", ] "#]], ); @@ -68,7 +69,7 @@ fn foo() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - InferenceResult::for_body(&db, it.into()); + InferenceResult::of(&db, DefWithBodyId::from(it)); } }); }, @@ -76,14 +77,14 @@ fn foo() -> i32 { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", ] "#]], ); @@ -111,50 +112,51 @@ fn baz() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - InferenceResult::for_body(&db, it.into()); + InferenceResult::of(&db, DefWithBodyId::from(it)); } }); }, &[("InferenceResult::for_body_", 3)], expect_test::expect![[r#" [ + "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "lang_items", "crate_lang_items", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "ExprScopes::body_expr_scopes_", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "ExprScopes::body_expr_scopes_", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "ExprScopes::body_expr_scopes_", ] "#]], ); @@ -180,7 +182,7 @@ fn baz() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - InferenceResult::for_body(&db, it.into()); + InferenceResult::of(&db, DefWithBodyId::from(it)); } }); }, @@ -188,26 +190,26 @@ fn baz() -> i32 { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", "InferenceResult::for_body_", - "expr_scopes_shim", + "ExprScopes::body_expr_scopes_", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", ] "#]], ); @@ -237,9 +239,10 @@ fn bar() -> f32 { &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" [ + "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitImpls::for_crate_", @@ -276,7 +279,7 @@ pub struct NewStruct { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -311,9 +314,10 @@ fn bar() -> f32 { &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" [ + "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitImpls::for_crate_", @@ -351,7 +355,7 @@ pub enum SomeEnum { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -386,9 +390,10 @@ fn bar() -> f32 { &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" [ + "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitImpls::for_crate_", @@ -423,7 +428,7 @@ fn bar() -> f32 { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -462,9 +467,10 @@ pub struct SomeStruct { &[("TraitImpls::for_crate_", 1)], expect_test::expect![[r#" [ + "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitImpls::for_crate_", @@ -507,7 +513,7 @@ pub fn new(value: i32) -> Self { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -556,31 +562,32 @@ fn main() { }); for def in defs { - let _inference_result = InferenceResult::for_body(&db, def); + let _inference_result = InferenceResult::of(&db, def); } }, &[("trait_solve_shim", 0)], expect_test::expect![[r#" [ + "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitItems::query_with_diagnostics_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "AttrFlags::query_", "ImplItems::of_", "InferenceResult::for_body_", - "trait_signature_shim", - "trait_signature_with_source_map_shim", + "TraitSignature::of_", + "TraitSignature::with_source_map_", "AttrFlags::query_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "lang_items", "crate_lang_items", @@ -588,14 +595,14 @@ fn main() { "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", - "struct_signature_shim", - "struct_signature_with_source_map_shim", + "ExprScopes::body_expr_scopes_", + "StructSignature::of_", + "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "value_ty_query", @@ -604,8 +611,8 @@ fn main() { "TraitImpls::for_crate_and_deps_", "TraitImpls::for_crate_", "impl_trait_with_diagnostics_query", - "impl_signature_shim", - "impl_signature_with_source_map_shim", + "ImplSignature::of_", + "ImplSignature::with_source_map_", "impl_self_ty_with_diagnostics_query", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", @@ -651,47 +658,47 @@ fn main() { }); for def in defs { - let _inference_result = InferenceResult::for_body(&db, def); + let _inference_result = InferenceResult::of(&db, def); } }, &[("trait_solve_shim", 0)], expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", "TraitItems::query_with_diagnostics_", - "body_with_source_map_shim", + "Body::with_source_map_", "AttrFlags::query_", - "body_shim", + "Body::of_", "ImplItems::of_", "InferenceResult::for_body_", "AttrFlags::query_", - "trait_signature_with_source_map_shim", + "TraitSignature::with_source_map_", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", "crate_lang_items", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "InferenceResult::for_body_", - "function_signature_with_source_map_shim", + "FunctionSignature::with_source_map_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", - "struct_signature_with_source_map_shim", + "ExprScopes::body_expr_scopes_", + "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "InherentImpls::for_crate_", "callable_item_signature_query", "TraitImpls::for_crate_", - "impl_signature_with_source_map_shim", - "impl_signature_shim", + "ImplSignature::with_source_map_", + "ImplSignature::of_", "impl_trait_with_diagnostics_query", "impl_self_ty_with_diagnostics_query", "AttrFlags::query_", @@ -709,6 +716,7 @@ fn execute_assert_events( ) { crate::attach_db(db, || { let (executed, events) = db.log_executed(f); + expect.assert_debug_eq(&executed); for (event, count) in required { let n = executed.iter().filter(|it| it.contains(event)).count(); assert_eq!( @@ -724,6 +732,5 @@ fn execute_assert_events( .collect::>(), ); } - expect.assert_debug_eq(&executed); }); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index 2f41de64cbbd..28a688d4a39b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -9,16 +9,16 @@ fn cfg_impl_def() { check_types( r#" -//- /main.rs crate:main deps:foo cfg:test +//- /main.rs crate:main deps:foo cfg:some_cfg use foo::S as T; struct S; -#[cfg(test)] +#[cfg(some_cfg)] impl S { fn foo1(&self) -> i32 { 0 } } -#[cfg(not(test))] +#[cfg(not(some_cfg))] impl S { fn foo2(&self) -> i32 { 0 } } @@ -31,12 +31,12 @@ fn test() { //- /foo.rs crate:foo pub struct S; -#[cfg(not(test))] +#[cfg(not(some_cfg))] impl S { pub fn foo3(&self) -> i32 { 0 } } -#[cfg(test)] +#[cfg(some_cfg)] impl S { pub fn foo4(&self) -> i32 { 0 } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 8c7d29f99371..42dc07430935 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -421,6 +421,8 @@ fn index(&self, index: core::ops::RangeFull) -> &Self::Output { 254..256 '&v': &'? [u8; 3] 255..256 'v': [u8; 3] 257..259 '{}': () + 199..200 '3': usize + 62..63 'N': usize "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 1939db0ef5a7..e4fc7e56c6ae 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2754,6 +2754,7 @@ fn filter(&self, filter: &Filter) -> Self::Output { 664..680 'filter...ter_fn': dyn Fn(&'? T) -> bool + 'static 691..698 'loop {}': ! 696..698 '{}': () + 512..513 'N': usize "#]], ); } @@ -2815,3 +2816,28 @@ fn contains_0>(points: &S) { "#, ); } + +#[test] +fn regression_21773() { + check_no_mismatches( + r#" +trait Neg { + type Output; +} + +trait Abs: Neg { + fn abs(&self) -> Self::Output; +} + +trait SelfAbs: Abs + Neg +where + Self::Output: Neg + Abs, +{ +} + +fn wrapped_abs>(v: T) -> T { + v.abs() +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index f47a26d429fd..e6b3244cda24 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -34,6 +34,7 @@ pub trait Space: IntoIterator { 223..227 'iter': IntoIter 230..231 'a': Vec 230..243 'a.into_iter()': IntoIter + 322..323 '1': usize "#]], ); } @@ -472,6 +473,8 @@ fn foo() { 249..257 'to_bytes': fn to_bytes() -> [u8; _] 249..259 'to_bytes()': [u8; _] 249..268 'to_byt..._vec()': Vec<<[u8; _] as Foo>::Item> + 205..206 '_': usize + 156..157 'N': usize "#]], ); } @@ -541,6 +544,11 @@ fn test_at_most() { 617..620 'num': Between<0, 1, char> 623..626 ''9'': char 623..641 ''9'.at...:<1>()': Between<0, 1, char> + 320..335 '{ Consts::MAX }': usize + 322..333 'Consts::MAX': usize + 421..422 '0': i32 + 144..159 '{ Consts::MAX }': usize + 146..157 'Consts::MAX': usize "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index dab8bdb54b69..3ea21f8265a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -3868,6 +3868,8 @@ fn main() { 208..209 'c': u8 213..214 'a': A 213..221 'a.into()': [u8; 2] + 33..34 '2': usize + 111..112 '3': usize "#]], ); } @@ -4061,6 +4063,8 @@ fn foo() { 248..282 'LazyLo..._LOCK)': &'? [u32; _] 264..281 '&VALUE...Y_LOCK': &'? LazyLock<[u32; _]> 265..281 'VALUES...Y_LOCK': LazyLock<[u32; _]> + 197..202 '{ 0 }': usize + 199..200 '0': usize "#]], ); } @@ -4109,3 +4113,38 @@ fn foo() { "#, ); } + +#[test] +fn signature_inference() { + check_infer( + r#" +trait Trait {} +struct S, const C: f32 = 0.0> +where + (): Trait<2> +{ + field: [(); { C as usize }], + field2: *mut S +} + +struct S2; + +type Alias = S2<0>; +impl S2<0> {} +enum E { + V(S2<0>) = 0, +} +union U { + field: S2<0> +} + "#, + expect![[r#" + 242..243 '0': isize + 46..47 '2': i32 + 65..68 '0.0': f32 + 90..91 '2': i32 + 200..201 '0': i32 + 212..213 '0': i32 + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 74e9a8dac0e7..22359d8f1f1d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1271,6 +1271,7 @@ fn bar() { 241..245 'R::B': fn B<(), i32>(i32) -> R<(), i32> 241..248 'R::B(7)': R<(), i32> 246..247 '7': i32 + 46..47 '2': usize "#]], ); } @@ -3781,6 +3782,8 @@ fn main() { 371..373 'v4': usize 376..378 'v3': [u8; 4] 376..389 'v3.do_thing()': usize + 86..87 '4': usize + 192..193 '2': usize "#]], ) } @@ -3820,6 +3823,9 @@ fn main() { 240..242 'v2': [u8; 2] 245..246 'v': [u8; 2] 245..257 'v.do_thing()': [u8; 2] + 130..131 'L': usize + 102..103 'L': usize + 130..131 'L': usize "#]], ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index fb598fe5acb0..878696c72129 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -7,7 +7,11 @@ AdtId, AssocItemId, HasModule, ImplId, Lookup, TraitId, lang_item::LangItems, nameres::DefMap, - signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags}, + signatures::{ + ConstFlags, ConstSignature, EnumFlags, EnumSignature, FnFlags, FunctionSignature, + StructFlags, StructSignature, TraitFlags, TraitSignature, TypeAliasFlags, + TypeAliasSignature, UnionSignature, + }, }; use hir_expand::name::Name; use intern::sym; @@ -279,21 +283,18 @@ pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id | TyKind::Float(_) => true, TyKind::Adt(adt_def, _) => match adt_def.def_id().0 { - hir_def::AdtId::StructId(id) => db - .struct_signature(id) + hir_def::AdtId::StructId(id) => StructSignature::of(db, id) .flags .contains(StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS), - hir_def::AdtId::UnionId(id) => db - .union_signature(id) + hir_def::AdtId::UnionId(id) => UnionSignature::of(db, id) .flags .contains(StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS), - hir_def::AdtId::EnumId(it) => db - .enum_signature(it) + hir_def::AdtId::EnumId(it) => EnumSignature::of(db, it) .flags .contains(EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS), }, TyKind::Dynamic(it, _) => it.principal_def_id().is_some_and(|trait_id| { - db.trait_signature(trait_id.0) + TraitSignature::of(db, trait_id.0) .flags .contains(TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS) }), @@ -304,14 +305,13 @@ pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id rustc_has_incoherent_inherent_impls && !items.items.is_empty() && items.items.iter().all(|&(_, assoc)| match assoc { - AssocItemId::FunctionId(it) => { - db.function_signature(it).flags.contains(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL) - } - AssocItemId::ConstId(it) => { - db.const_signature(it).flags.contains(ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL) - } - AssocItemId::TypeAliasId(it) => db - .type_alias_signature(it) + AssocItemId::FunctionId(it) => FunctionSignature::of(db, it) + .flags + .contains(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL), + AssocItemId::ConstId(it) => ConstSignature::of(db, it) + .flags + .contains(ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL), + AssocItemId::TypeAliasId(it) => TypeAliasSignature::of(db, it) .flags .contains(TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPL), }) @@ -350,7 +350,7 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool let AdtId::StructId(s) = adt_def.def_id().0 else { break ty; }; - let struct_signature = db.struct_signature(s); + let struct_signature = StructSignature::of(db, s); if struct_signature.flags.contains(StructFlags::FUNDAMENTAL) { let next = subs.types().next(); match next { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs b/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs index ee864ab068d2..489895fe3cb7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs @@ -44,10 +44,10 @@ pub fn upvars_mentioned( db: &dyn HirDatabase, owner: DefWithBodyId, ) -> Option>> { - let body = db.body(owner); + let body = Body::of(db, owner); let mut resolver = owner.resolver(db); let mut result = FxHashMap::default(); - handle_expr_outside_closure(db, &mut resolver, owner, &body, body.body_expr, &mut result); + handle_expr_outside_closure(db, &mut resolver, owner, body, body.root_expr(), &mut result); return if result.is_empty() { None } else { @@ -198,7 +198,7 @@ fn resolve_maybe_upvar<'db>( #[cfg(test)] mod tests { use expect_test::{Expect, expect}; - use hir_def::{ModuleDefId, db::DefDatabase, nameres::crate_def_map}; + use hir_def::{ModuleDefId, expr_store::Body, nameres::crate_def_map}; use itertools::Itertools; use span::Edition; use test_fixture::WithFixture; @@ -219,7 +219,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) { }) .exactly_one() .unwrap_or_else(|_| panic!("expected one function")); - let (body, source_map) = db.body_with_source_map(func.into()); + let (body, source_map) = Body::with_source_map(&db, func.into()); let Some(upvars) = upvars_mentioned(&db, func.into()) else { expectation.assert_eq(""); return; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index be64f55ea550..509109543cd6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -4,6 +4,7 @@ use base_db::target::{self, TargetData}; use hir_def::{ EnumId, EnumVariantId, FunctionId, Lookup, TraitId, attrs::AttrFlags, lang_item::LangItems, + signatures::FunctionSignature, }; use intern::sym; use rustc_abi::TargetDataLayout; @@ -79,7 +80,7 @@ pub fn is_fn_unsafe_to_call( call_edition: Edition, target_feature_is_safe: TargetFeatureIsSafeInTarget, ) -> Unsafety { - let data = db.function_signature(func); + let data = FunctionSignature::of(db, func); if data.is_unsafe() { return Unsafety::Unsafe; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 6f415a5289c9..1945b04bb3cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -13,7 +13,10 @@ //! by the next salsa version. If not, we will likely have to adapt and go with the rustc approach //! while installing firewall per item queries to prevent invalidation issues. -use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId, signatures::StructFlags}; +use hir_def::{ + AdtId, GenericDefId, GenericParamId, VariantId, + signatures::{StructFlags, StructSignature}, +}; use rustc_ast_ir::Mutability; use rustc_type_ir::{ Variance, @@ -45,7 +48,7 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance GenericDefId::FunctionId(_) => (), GenericDefId::AdtId(adt) => { if let AdtId::StructId(id) = adt { - let flags = &db.struct_signature(id).flags; + let flags = &StructSignature::of(db, id).flags; let types = || crate::next_solver::default_types(db); if flags.contains(StructFlags::IS_UNSAFE_CELL) { return types().one_invariant.store(); @@ -113,7 +116,7 @@ pub(crate) fn variances_of_cycle_initial( struct Context<'db> { db: &'db dyn HirDatabase, - generics: Generics, + generics: Generics<'db>, variances: Box<[Variance]>, } diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index cfb95e07c362..27e798514610 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -7,6 +7,7 @@ TraitId, TypeOrConstParamId, attrs::{AttrFlags, Docs, IsInnerDoc}, expr_store::path::Path, + hir::generics::GenericParams, item_scope::ItemInNs, per_ns::Namespace, resolver::{HasResolver, Resolver, TypeNs}, @@ -26,9 +27,9 @@ use stdx::never; use crate::{ - Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, - Field, Function, GenericParam, HasCrate, Impl, LangItem, LifetimeParam, Macro, Module, - ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, + Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, EnumVariant, + ExternCrateDecl, Field, Function, GenericParam, HasCrate, Impl, LangItem, LifetimeParam, Macro, + Module, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, }; #[derive(Debug, Clone, Copy)] @@ -199,7 +200,7 @@ fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner { } impl_has_attrs![ - (Variant, EnumVariantId), + (EnumVariant, EnumVariantId), (Static, StaticId), (Const, ConstId), (Trait, TraitId), @@ -377,7 +378,7 @@ fn resolve_assoc_or_field( let ty = match base_def { TypeNs::SelfType(id) => Impl::from(id).self_ty(db), TypeNs::GenericParam(param) => { - let generic_params = db.generic_params(param.parent()); + let generic_params = GenericParams::of(db, param.parent()); if generic_params[param.local_id()].is_trait_self() { // `Self::assoc` in traits should refer to the trait itself. let parent_trait = |container| match container { @@ -406,7 +407,7 @@ fn resolve_assoc_or_field( TypeNs::AdtId(id) | TypeNs::AdtSelfType(id) => Adt::from(id).ty(db), TypeNs::EnumVariantId(id) => { // Enum variants don't have path candidates. - let variant = Variant::from(id); + let variant = EnumVariant::from(id); return resolve_field(db, variant.into(), name, ns); } TypeNs::TypeAliasId(id) => { @@ -443,7 +444,7 @@ fn resolve_assoc_or_field( .id .enum_variants(db) .variant(&name) - .map(|variant| DocLinkDef::ModuleDef(ModuleDef::Variant(variant.into()))); + .map(|variant| DocLinkDef::ModuleDef(ModuleDef::EnumVariant(variant.into()))); } }; resolve_field(db, variant_def, name, ns) @@ -505,7 +506,7 @@ fn resolve_impl_trait_item<'db>( fn resolve_field( db: &dyn HirDatabase, - def: VariantDef, + def: Variant, name: Name, ns: Option, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 050777a4806d..7f672a697c41 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -51,20 +51,6 @@ fn from(d: $diag $(<$lt>)?) -> $AnyDiagnostic<$db> { )* }; } -// FIXME Accept something like the following in the macro call instead -// diagnostics![ -// pub struct BreakOutsideOfLoop { -// pub expr: InFile>, -// pub is_break: bool, -// pub bad_value_break: bool, -// }, ... -// or more concisely -// BreakOutsideOfLoop { -// expr: InFile>, -// is_break: bool, -// bad_value_break: bool, -// }, ... -// ] diagnostics![AnyDiagnostic<'db> -> AwaitOutsideOfAsync, diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 91fdcb8e6369..4bfdd239f937 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -4,10 +4,13 @@ use hir_def::{ AdtId, BuiltinDeriveImplId, FunctionId, GenericDefId, ImplId, ItemContainerId, builtin_derive::BuiltinDeriveImplMethod, - expr_store::ExpressionStore, + expr_store::{Body, ExpressionStore}, hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, item_tree::FieldsShape, - signatures::{StaticFlags, TraitFlags}, + signatures::{ + ConstSignature, FunctionSignature, ImplSignature, StaticFlags, StaticSignature, TraitFlags, + TraitSignature, TypeAliasSignature, + }, type_ref::{TypeBound, TypeRef, TypeRefId}, }; use hir_expand::name::Name; @@ -26,9 +29,9 @@ use crate::{ Adt, AnyFunctionId, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, - ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, - Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, Type, - TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant, + EnumVariant, ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, + LifetimeParam, Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, + TupleField, Type, TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, }; fn write_builtin_derive_impl_method<'db>( @@ -38,7 +41,7 @@ fn write_builtin_derive_impl_method<'db>( ) -> Result { let db = f.db; let loc = impl_.loc(db); - let (adt_params, _adt_params_store) = db.generic_params_and_store(loc.adt.into()); + let adt_params = GenericParams::of(db, loc.adt.into()); if f.show_container_bounds() && !adt_params.is_empty() { f.write_str("impl")?; @@ -94,22 +97,22 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { // Write container (trait or impl) let container_params = match container { ItemContainerId::TraitId(trait_) => { - let (params, params_store) = f.db.generic_params_and_store(trait_.into()); + let (params, params_store) = GenericParams::with_store(f.db, trait_.into()); if f.show_container_bounds() && !params.is_empty() { write_trait_header(trait_.into(), f)?; f.write_char('\n')?; - has_disaplayable_predicates(f.db, ¶ms, ¶ms_store) + has_disaplayable_predicates(f.db, params, params_store) .then_some((params, params_store)) } else { None } } ItemContainerId::ImplId(impl_) => { - let (params, params_store) = f.db.generic_params_and_store(impl_.into()); + let (params, params_store) = GenericParams::with_store(f.db, impl_.into()); if f.show_container_bounds() && !params.is_empty() { write_impl_header(impl_, f)?; f.write_char('\n')?; - has_disaplayable_predicates(f.db, ¶ms, ¶ms_store) + has_disaplayable_predicates(f.db, params, params_store) .then_some((params, params_store)) } else { None @@ -131,7 +134,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { _ => unreachable!(), }; write!(f, "\n // Bounds from {container_name}:",)?; - write_where_predicates(&container_params, &container_params_store, f)?; + write_where_predicates(container_params, container_params_store, f)?; } Ok(()) } @@ -140,7 +143,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Result { let db = f.db; let func = Function::from(func_id); - let data = db.function_signature(func_id); + let data = FunctionSignature::of(db, func_id); let mut module = func.module(db); // Block-local impls are "hoisted" to the nearest (non-block) module. @@ -189,7 +192,7 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re let comma = if too_long_param { ",\n " } else { ", " }; // FIXME: Use resolved `param.ty` once we no longer discard lifetimes - let body = db.body(func_id.into()); + let body = Body::of(db, func_id.into()); for (type_ref, param) in data.params.iter().zip(func.assoc_fn_params(db)).skip(skip_self) { if !first { f.write_str(comma)?; @@ -268,7 +271,7 @@ fn write_impl_header<'db>(impl_: ImplId, f: &mut HirFormatter<'_, 'db>) -> Resul let def_id = GenericDefId::ImplId(impl_); write_generic_params(def_id, f)?; - let impl_data = db.impl_signature(impl_); + let impl_data = ImplSignature::of(db, impl_); if let Some(target_trait) = &impl_data.target_trait { f.write_char(' ')?; hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?; @@ -297,7 +300,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { } }, }; - let data = f.db.function_signature(func); + let data = FunctionSignature::of(f.db, func); let param = *data.params.first().unwrap(); match &data.store[param] { TypeRef::Path(p) if p.is_self_type() => f.write_str("self"), @@ -440,7 +443,7 @@ fn write_fields<'db>( } fn write_variants<'db>( - variants: &[Variant], + variants: &[EnumVariant], has_where_clause: bool, limit: usize, f: &mut HirFormatter<'_, 'db>, @@ -494,7 +497,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { } } -impl<'db> HirDisplay<'db> for Variant { +impl<'db> HirDisplay<'db> for EnumVariant { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; let data = self.id.fields(f.db); @@ -569,7 +572,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { impl<'db> HirDisplay<'db> for TypeParam { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { - let params = f.db.generic_params(self.id.parent()); + let params = GenericParams::of(f.db, self.id.parent()); let param_data = ¶ms[self.id.local_id()]; let krate = self.id.parent().krate(f.db).id; let ty = self.ty(f.db).ty; @@ -657,7 +660,7 @@ fn write_generic_params_or_args<'db>( f: &mut HirFormatter<'_, 'db>, include_defaults: bool, ) -> Result { - let (params, store) = f.db.generic_params_and_store(def); + let (params, store) = GenericParams::with_store(f.db, def); if params.iter_lt().next().is_none() && params.iter_type_or_consts().all(|it| it.1.const_param().is_none()) && params @@ -693,17 +696,17 @@ fn write_generic_params_or_args<'db>( write!(f, "{}", name.display(f.db, f.edition()))?; if include_defaults && let Some(default) = &ty.default { f.write_str(" = ")?; - default.hir_fmt(f, &store)?; + default.hir_fmt(f, store)?; } } TypeOrConstParamData::ConstParamData(c) => { delim(f)?; write!(f, "const {}: ", name.display(f.db, f.edition()))?; - c.ty.hir_fmt(f, &store)?; + c.ty.hir_fmt(f, store)?; if include_defaults && let Some(default) = &c.default { f.write_str(" = ")?; - default.hir_fmt(f, &store)?; + default.hir_fmt(f, store)?; } } } @@ -715,13 +718,13 @@ fn write_generic_params_or_args<'db>( } fn write_where_clause<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result { - let (params, store) = f.db.generic_params_and_store(def); - if !has_disaplayable_predicates(f.db, ¶ms, &store) { + let (params, store) = GenericParams::with_store(f.db, def); + if !has_disaplayable_predicates(f.db, params, store) { return Ok(false); } f.write_str("\nwhere")?; - write_where_predicates(¶ms, &store, f)?; + write_where_predicates(params, store, f)?; Ok(true) } @@ -736,7 +739,7 @@ fn has_disaplayable_predicates( pred, WherePredicate::TypeBound { target, .. } if matches!(store[*target], - TypeRef::TypeParam(id) if db.generic_params(id.parent())[id.local_id()].name().is_none() + TypeRef::TypeParam(id) if GenericParams::of(db,id.parent())[id.local_id()].name().is_none() ) ) }) @@ -752,7 +755,7 @@ fn write_where_predicates<'db>( // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. let is_unnamed_type_target = |target: TypeRefId| { matches!(store[target], - TypeRef::TypeParam(id) if f.db.generic_params(id.parent())[id.local_id()].name().is_none() + TypeRef::TypeParam(id) if GenericParams::of(f.db,id.parent())[id.local_id()].name().is_none() ) }; @@ -816,7 +819,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { module = module.nearest_non_block_module(db); } write_visibility(module.id, self.visibility(db), f)?; - let data = db.const_signature(self.id); + let data = ConstSignature::of(db, self.id); f.write_str("const ")?; match &data.name { Some(name) => write!(f, "{}: ", name.display(f.db, f.edition()))?, @@ -830,7 +833,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { impl<'db> HirDisplay<'db> for Static { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.static_signature(self.id); + let data = StaticSignature::of(f.db, self.id); f.write_str("static ")?; if data.flags.contains(StaticFlags::MUTABLE) { f.write_str("mut ")?; @@ -889,7 +892,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { fn write_trait_header<'db>(trait_: Trait, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; - let data = f.db.trait_signature(trait_.id); + let data = TraitSignature::of(f.db, trait_.id); if data.flags.contains(TraitFlags::UNSAFE) { f.write_str("unsafe ")?; } @@ -904,7 +907,7 @@ fn write_trait_header<'db>(trait_: Trait, f: &mut HirFormatter<'_, 'db>) -> Resu impl<'db> HirDisplay<'db> for TypeAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.type_alias_signature(self.id); + let data = TypeAliasSignature::of(f.db, self.id); write!(f, "type {}", data.name.display(f.db, f.edition()))?; let def_id = GenericDefId::TypeAliasId(self.id); write_generic_params(def_id, f)?; diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index fc20f4b46bb9..0a48be5473d2 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -4,15 +4,15 @@ //! are splitting the hir. use hir_def::{ - AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, - GenericParamId, ModuleDefId, VariantId, + AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, + FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, ModuleDefId, VariantId, hir::{BindingId, LabelId}, }; use hir_ty::next_solver::AnyImplId; use crate::{ - Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, - ItemInNs, Label, Local, ModuleDef, Variant, VariantDef, + Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, EnumVariant, ExpressionStoreOwner, + Field, Function, GenericDef, GenericParam, Impl, ItemInNs, Label, Local, ModuleDef, Variant, }; macro_rules! from_id { @@ -71,6 +71,15 @@ fn from(id: Adt) -> Self { } } +impl From for Variant { + fn from(v: VariantId) -> Self { + match v { + VariantId::EnumVariantId(it) => Variant::EnumVariant(it.into()), + VariantId::StructId(it) => Variant::Struct(it.into()), + VariantId::UnionId(it) => Variant::Union(it.into()), + } + } +} impl From for GenericParam { fn from(id: GenericParamId) -> Self { match id { @@ -91,14 +100,14 @@ fn from(id: GenericParam) -> Self { } } -impl From for Variant { +impl From for EnumVariant { fn from(id: EnumVariantId) -> Self { - Variant { id } + EnumVariant { id } } } -impl From for EnumVariantId { - fn from(def: Variant) -> Self { +impl From for EnumVariantId { + fn from(def: EnumVariant) -> Self { def.id } } @@ -109,7 +118,7 @@ fn from(id: ModuleDefId) -> Self { ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()), ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()), ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()), - ModuleDefId::EnumVariantId(it) => ModuleDef::Variant(it.into()), + ModuleDefId::EnumVariantId(it) => ModuleDef::EnumVariant(it.into()), ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()), ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()), ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()), @@ -130,7 +139,7 @@ fn try_from(id: ModuleDef) -> Result { AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()), }, ModuleDef::Adt(it) => ModuleDefId::AdtId(it.into()), - ModuleDef::Variant(it) => ModuleDefId::EnumVariantId(it.into()), + ModuleDef::EnumVariant(it) => ModuleDefId::EnumVariantId(it.into()), ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()), ModuleDef::Static(it) => ModuleDefId::StaticId(it.into()), ModuleDef::Trait(it) => ModuleDefId::TraitId(it.into()), @@ -151,7 +160,7 @@ fn try_from(def: DefWithBody) -> Result { }, DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), - DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()), + DefWithBody::EnumVariant(it) => DefWithBodyId::VariantId(it.into()), }) } } @@ -162,7 +171,7 @@ fn from(def: DefWithBodyId) -> Self { DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()), DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), - DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()), + DefWithBodyId::VariantId(it) => DefWithBody::EnumVariant(it.into()), } } } @@ -209,22 +218,12 @@ fn from(id: Adt) -> Self { } } -impl From for VariantDef { - fn from(def: VariantId) -> Self { +impl From for VariantId { + fn from(def: Variant) -> Self { match def { - VariantId::StructId(it) => VariantDef::Struct(it.into()), - VariantId::EnumVariantId(it) => VariantDef::Variant(it.into()), - VariantId::UnionId(it) => VariantDef::Union(it.into()), - } - } -} - -impl From for VariantId { - fn from(def: VariantDef) -> Self { - match def { - VariantDef::Struct(it) => VariantId::StructId(it.id), - VariantDef::Variant(it) => VariantId::EnumVariantId(it.into()), - VariantDef::Union(it) => VariantId::UnionId(it.id), + Variant::Struct(it) => VariantId::StructId(it.id), + Variant::EnumVariant(it) => VariantId::EnumVariantId(it.into()), + Variant::Union(it) => VariantId::UnionId(it.id), } } } @@ -255,14 +254,19 @@ fn try_from(item: AssocItem) -> Result { } } -impl From<(DefWithBodyId, BindingId)> for Local { - fn from((parent, binding_id): (DefWithBodyId, BindingId)) -> Self { +impl From<(ExpressionStoreOwnerId, BindingId)> for Local { + fn from((parent, binding_id): (ExpressionStoreOwnerId, BindingId)) -> Self { Local { parent, binding_id } } } +impl From<(DefWithBodyId, BindingId)> for Local { + fn from((parent, binding_id): (DefWithBodyId, BindingId)) -> Self { + Local { parent: parent.into(), binding_id } + } +} -impl From<(DefWithBodyId, LabelId)> for Label { - fn from((parent, label_id): (DefWithBodyId, LabelId)) -> Self { +impl From<(ExpressionStoreOwnerId, LabelId)> for Label { + fn from((parent, label_id): (ExpressionStoreOwnerId, LabelId)) -> Self { Label { parent, label_id } } } @@ -317,3 +321,43 @@ fn from(value: hir_def::FunctionId) -> Self { crate::Function { id: AnyFunctionId::FunctionId(value) } } } + +impl TryFrom for ExpressionStoreOwnerId { + type Error = (); + + fn try_from(v: ExpressionStoreOwner) -> Result { + match v { + ExpressionStoreOwner::Signature(generic_def_id) => { + Ok(Self::Signature(generic_def_id.try_into()?)) + } + ExpressionStoreOwner::Body(def_with_body_id) => { + Ok(Self::Body(def_with_body_id.try_into()?)) + } + ExpressionStoreOwner::VariantFields(variant_id) => { + Ok(Self::VariantFields(variant_id.into())) + } + } + } +} + +impl TryFrom for FunctionId { + type Error = (); + + fn try_from(v: Function) -> Result { + match v.id { + AnyFunctionId::FunctionId(id) => Ok(id), + _ => Err(()), + } + } +} + +impl TryFrom for ImplId { + type Error = (); + + fn try_from(v: Impl) -> Result { + match v.id { + AnyImplId::ImplId(id) => Ok(id), + _ => Err(()), + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index e032a16989ff..f9badc0b7901 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -3,6 +3,7 @@ use either::Either; use hir_def::{ CallableDefId, Lookup, MacroId, VariantId, + expr_store::ExpressionStore, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource as _}, }; @@ -12,9 +13,9 @@ use tt::TextRange; use crate::{ - Adt, AnyFunctionId, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, - InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, - Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, VariantDef, db::HirDatabase, + Adt, AnyFunctionId, Callee, Const, Enum, EnumVariant, ExternCrateDecl, Field, FieldSource, + Function, Impl, InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, + SelfParam, Static, Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, db::HirDatabase, }; pub trait HasSource: Sized { @@ -123,13 +124,13 @@ fn source(self, db: &dyn HirDatabase) -> Option> { } } } -impl HasSource for VariantDef { +impl HasSource for Variant { type Ast = ast::VariantDef; fn source(self, db: &dyn HirDatabase) -> Option> { match self { - VariantDef::Struct(s) => Some(s.source(db)?.map(ast::VariantDef::Struct)), - VariantDef::Union(u) => Some(u.source(db)?.map(ast::VariantDef::Union)), - VariantDef::Variant(v) => Some(v.source(db)?.map(ast::VariantDef::Variant)), + Variant::Struct(s) => Some(s.source(db)?.map(ast::VariantDef::Struct)), + Variant::Union(u) => Some(u.source(db)?.map(ast::VariantDef::Union)), + Variant::EnumVariant(v) => Some(v.source(db)?.map(ast::VariantDef::Variant)), } } } @@ -151,7 +152,7 @@ fn source(self, db: &dyn HirDatabase) -> Option> { Some(self.id.lookup(db).source(db)) } } -impl HasSource for Variant { +impl HasSource for EnumVariant { type Ast = ast::Variant; fn source(self, db: &dyn HirDatabase) -> Option> { Some(self.id.lookup(db).source(db)) @@ -293,7 +294,7 @@ fn source(self, db: &dyn HirDatabase) -> Option> { } Callee::Closure(closure, _) => { let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure); - let (_, source_map) = db.body_with_source_map(owner); + let (_, source_map) = ExpressionStore::with_source_map(db, owner); let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; let root = db.parse_or_expand(file_id); match value.to_node(&root) { @@ -327,8 +328,7 @@ impl HasSource for Label { type Ast = ast::Label; fn source(self, db: &dyn HirDatabase) -> Option> { - let (_body, source_map) = db.body_with_source_map(self.parent); - let src = source_map.label_syntax(self.label_id); + let src = ExpressionStore::with_source_map(db, self.parent).1.label_syntax(self.label_id); let root = src.file_syntax(db); src.map(|ast| ast.to_node(&root).left()).transpose() } @@ -345,7 +345,7 @@ fn source(self, db: &dyn HirDatabase) -> Option> { impl HasSource for InlineAsmOperand { type Ast = ast::AsmOperandNamed; fn source(self, db: &dyn HirDatabase) -> Option> { - let source_map = db.body_with_source_map(self.owner).1; + let (_, source_map) = ExpressionStore::with_source_map(db, self.owner); if let Ok(src) = source_map.expr_syntax(self.expr) { let root = src.file_syntax(db); return src diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 11d79e2d7bf8..bc5e16483054 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -49,16 +49,16 @@ use either::Either; use hir_def::{ AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, - DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, - HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, - MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId, - TypeParamId, UnionId, + DefWithBodyId, EnumId, EnumVariantId, ExpressionStoreOwnerId, ExternBlockId, ExternCrateId, + FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, + Lookup, MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, - expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, + expr_store::{ExpressionStore, ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, hir::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, - generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, + generics::{GenericParams, LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, }, item_tree::ImportAlias, lang_item::LangItemTarget, @@ -69,7 +69,11 @@ }, per_ns::PerNs, resolver::{HasResolver, Resolver}, - signatures::{EnumSignature, ImplFlags, StaticFlags, StructFlags, TraitFlags, VariantFields}, + signatures::{ + ConstSignature, EnumSignature, FunctionSignature, ImplFlags, ImplSignature, StaticFlags, + StaticSignature, StructFlags, StructSignature, TraitFlags, TraitSignature, + TypeAliasSignature, UnionSignature, VariantFields, + }, src::HasSource as _, visibility::visibility_from_ast, }; @@ -141,6 +145,7 @@ Complete, FindPathConfig, attrs::{Docs, IsInnerDoc}, + expr_store::Body, find_path::PrefixKind, import_map, lang_item::{LangItemEnum as LangItem, crate_lang_items}, @@ -351,8 +356,7 @@ pub enum ModuleDef { Function(Function), Adt(Adt), // Can't be directly declared, but can be imported. - // FIXME: Rename to `EnumVariant` - Variant(Variant), + EnumVariant(EnumVariant), Const(Const), Static(Static), Trait(Trait), @@ -364,7 +368,7 @@ pub enum ModuleDef { Module, Function, Adt(Struct, Enum, Union), - Variant, + EnumVariant, Const, Static, Trait, @@ -374,12 +378,12 @@ pub enum ModuleDef { for ModuleDef ); -impl From for ModuleDef { - fn from(var: VariantDef) -> Self { +impl From for ModuleDef { + fn from(var: Variant) -> Self { match var { - VariantDef::Struct(t) => Adt::from(t).into(), - VariantDef::Union(t) => Adt::from(t).into(), - VariantDef::Variant(t) => t.into(), + Variant::Struct(t) => Adt::from(t).into(), + Variant::Union(t) => Adt::from(t).into(), + Variant::EnumVariant(t) => t.into(), } } } @@ -390,7 +394,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Option { ModuleDef::Module(it) => it.parent(db), ModuleDef::Function(it) => Some(it.module(db)), ModuleDef::Adt(it) => Some(it.module(db)), - ModuleDef::Variant(it) => Some(it.module(db)), + ModuleDef::EnumVariant(it) => Some(it.module(db)), ModuleDef::Const(it) => Some(it.module(db)), ModuleDef::Static(it) => Some(it.module(db)), ModuleDef::Trait(it) => Some(it.module(db)), @@ -423,7 +427,7 @@ pub fn name(self, db: &dyn HirDatabase) -> Option { ModuleDef::Adt(it) => it.name(db), ModuleDef::Trait(it) => it.name(db), ModuleDef::Function(it) => it.name(db), - ModuleDef::Variant(it) => it.name(db), + ModuleDef::EnumVariant(it) => it.name(db), ModuleDef::TypeAlias(it) => it.name(db), ModuleDef::Static(it) => it.name(db), ModuleDef::Macro(it) => it.name(db), @@ -452,7 +456,7 @@ pub fn diagnostics<'db>( ModuleDef::Module(it) => it.id.into(), ModuleDef::Const(it) => it.id.into(), ModuleDef::Static(it) => it.id.into(), - ModuleDef::Variant(it) => it.id.into(), + ModuleDef::EnumVariant(it) => it.id.into(), ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(), }; @@ -481,7 +485,7 @@ pub fn as_def_with_body(self) -> Option { ModuleDef::Function(it) => Some(it.into()), ModuleDef::Const(it) => Some(it.into()), ModuleDef::Static(it) => Some(it.into()), - ModuleDef::Variant(it) => Some(it.into()), + ModuleDef::EnumVariant(it) => Some(it.into()), ModuleDef::Module(_) | ModuleDef::Adt(_) @@ -500,7 +504,7 @@ pub fn as_self_generic_def(self) -> Option { ModuleDef::Trait(it) => Some(it.into()), ModuleDef::TypeAlias(it) => Some(it.into()), ModuleDef::Module(_) - | ModuleDef::Variant(_) + | ModuleDef::EnumVariant(_) | ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::BuiltinType(_) @@ -508,12 +512,27 @@ pub fn as_self_generic_def(self) -> Option { } } + pub fn as_generic_def(self) -> Option { + match self { + ModuleDef::Function(it) => Some(it.into()), + ModuleDef::Adt(it) => Some(it.into()), + ModuleDef::Trait(it) => Some(it.into()), + ModuleDef::TypeAlias(it) => Some(it.into()), + ModuleDef::Static(it) => Some(it.into()), + ModuleDef::Const(it) => Some(it.into()), + ModuleDef::EnumVariant(_) + | ModuleDef::Module(_) + | ModuleDef::BuiltinType(_) + | ModuleDef::Macro(_) => None, + } + } + pub fn attrs(&self, db: &dyn HirDatabase) -> Option { Some(match self { ModuleDef::Module(it) => it.attrs(db), ModuleDef::Function(it) => HasAttrs::attrs(*it, db), ModuleDef::Adt(it) => it.attrs(db), - ModuleDef::Variant(it) => it.attrs(db), + ModuleDef::EnumVariant(it) => it.attrs(db), ModuleDef::Const(it) => it.attrs(db), ModuleDef::Static(it) => it.attrs(db), ModuleDef::Trait(it) => it.attrs(db), @@ -543,7 +562,7 @@ fn visibility(&self, db: &dyn HirDatabase) -> Visibility { ModuleDef::Static(it) => it.visibility(db), ModuleDef::Trait(it) => it.visibility(db), ModuleDef::TypeAlias(it) => it.visibility(db), - ModuleDef::Variant(it) => it.visibility(db), + ModuleDef::EnumVariant(it) => it.visibility(db), ModuleDef::Macro(it) => it.visibility(db), ModuleDef::BuiltinType(_) => Visibility::Public, } @@ -714,8 +733,8 @@ pub fn diagnostics<'db>( ModuleDef::Adt(adt) => { match adt { Adt::Struct(s) => { - let source_map = db.struct_signature_with_source_map(s.id).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &StructSignature::with_source_map(db, s.id).1; + expr_store_diagnostics(db, acc, source_map); let source_map = &s.id.fields_with_source_map(db).1; expr_store_diagnostics(db, acc, source_map); push_ty_diagnostics( @@ -726,8 +745,8 @@ pub fn diagnostics<'db>( ); } Adt::Union(u) => { - let source_map = db.union_signature_with_source_map(u.id).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &UnionSignature::with_source_map(db, u.id).1; + expr_store_diagnostics(db, acc, source_map); let source_map = &u.id.fields_with_source_map(db).1; expr_store_diagnostics(db, acc, source_map); push_ty_diagnostics( @@ -738,8 +757,8 @@ pub fn diagnostics<'db>( ); } Adt::Enum(e) => { - let source_map = db.enum_signature_with_source_map(e.id).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &EnumSignature::with_source_map(db, e.id).1; + expr_store_diagnostics(db, acc, source_map); let (variants, diagnostics) = e.id.enum_variants_with_diagnostics(db); let file = e.id.lookup(db).id.file_id; let ast_id_map = db.ast_id_map(file); @@ -774,13 +793,13 @@ pub fn diagnostics<'db>( } ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), ModuleDef::TypeAlias(type_alias) => { - let source_map = db.type_alias_signature_with_source_map(type_alias.id).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &TypeAliasSignature::with_source_map(db, type_alias.id).1; + expr_store_diagnostics(db, acc, source_map); push_ty_diagnostics( db, acc, db.type_for_type_alias_with_diagnostics(type_alias.id).1, - &source_map, + source_map, ); acc.extend(def.diagnostics(db, style_lints)); } @@ -800,8 +819,8 @@ pub fn diagnostics<'db>( continue; }; let loc = impl_id.lookup(db); - let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_id); - expr_store_diagnostics(db, acc, &source_map); + let (impl_signature, source_map) = ImplSignature::with_source_map(db, impl_id); + expr_store_diagnostics(db, acc, source_map); let file_id = loc.id.file_id; if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) { @@ -873,9 +892,9 @@ pub fn diagnostics<'db>( if let (false, Some(trait_)) = (impl_is_negative, trait_) { let items = &trait_.id.trait_items(db).items; let required_items = items.iter().filter(|&(_, assoc)| match *assoc { - AssocItemId::FunctionId(it) => !db.function_signature(it).has_body(), - AssocItemId::ConstId(id) => !db.const_signature(id).has_body(), - AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(), + AssocItemId::FunctionId(it) => !FunctionSignature::of(db, it).has_body(), + AssocItemId::ConstId(id) => !ConstSignature::of(db, id).has_body(), + AssocItemId::TypeAliasId(it) => TypeAliasSignature::of(db, it).ty.is_none(), }); impl_assoc_items_scratch.extend(impl_id.impl_items(db).items.iter().cloned()); @@ -913,7 +932,7 @@ pub fn diagnostics<'db>( let self_ty = structurally_normalize_ty( &infcx, self_ty, - db.trait_environment(impl_id.into()), + db.trait_environment(GenericDefId::from(impl_id).into()), ); let self_ty_is_guaranteed_unsized = matches!( self_ty.kind(), @@ -968,7 +987,7 @@ pub fn diagnostics<'db>( continue; } - if db.function_signature(*fn_).is_default() { + if FunctionSignature::of(db, *fn_).is_default() { return false; } } @@ -992,12 +1011,12 @@ pub fn diagnostics<'db>( impl_assoc_items_scratch.clear(); } - push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, &source_map); + push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, source_map); push_ty_diagnostics( db, acc, db.impl_trait_with_diagnostics(impl_id).and_then(|it| it.1), - &source_map, + source_map, ); for &(_, item) in impl_id.impl_items(db).items.iter() { @@ -1091,7 +1110,7 @@ fn macro_call_diagnostics<'db>( let file_id = loc.kind.file_id(); let mut range = precise_macro_call_location(&loc.kind, db, loc.krate); let RenderedExpandError { message, error, kind } = err.render_to_string(db); - if Some(err.span().anchor.file_id) == file_id.file_id().map(|it| it.editioned_file_id(db)) { + if Some(err.span().anchor.file_id) == file_id.file_id().map(|it| it.span_file_id(db)) { range.value = err.span().range + db.ast_id_map(file_id).get_erased(err.span().anchor.ast_id).text_range().start(); } @@ -1280,7 +1299,7 @@ fn visibility(&self, db: &dyn HirDatabase) -> Visibility { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Field { - pub(crate) parent: VariantDef, + pub(crate) parent: Variant, pub(crate) id: LocalFieldId, } @@ -1304,7 +1323,7 @@ pub fn ty(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> { #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct TupleField { - pub owner: DefWithBodyId, + pub owner: ExpressionStoreOwnerId, pub tuple: TupleId, pub index: u32, } @@ -1316,7 +1335,7 @@ pub fn name(&self) -> Name { pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let interner = DbInterner::new_no_crate(db); - let ty = InferenceResult::for_body(db, self.owner) + let ty = InferenceResult::of(db, self.owner) .tuple_field_access_type(self.tuple) .as_slice() .get(self.index as usize) @@ -1386,9 +1405,9 @@ pub fn ty_with_args<'db>( ) -> Type<'db> { let var_id = self.parent.into(); let def_id: AdtId = match self.parent { - VariantDef::Struct(it) => it.id.into(), - VariantDef::Union(it) => it.id.into(), - VariantDef::Variant(it) => it.parent_enum(db).id.into(), + Variant::Struct(it) => it.id.into(), + Variant::Union(it) => it.id.into(), + Variant::EnumVariant(it) => it.parent_enum(db).id.into(), }; let interner = DbInterner::new_no_crate(db); let args = generic_args_from_tys(interner, def_id.into(), generics.map(|ty| ty.ty)); @@ -1414,7 +1433,7 @@ pub fn layout(&self, db: &dyn HirDatabase) -> Result { .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap())) } - pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { + pub fn parent_def(&self, _db: &dyn HirDatabase) -> Variant { self.parent } } @@ -1440,7 +1459,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.struct_signature(self.id).name.clone() + StructSignature::of(db, self.id).name.clone() } pub fn fields(self, db: &dyn HirDatabase) -> Vec { @@ -1533,7 +1552,7 @@ pub struct Union { impl Union { pub fn name(self, db: &dyn HirDatabase) -> Name { - db.union_signature(self.id).name.clone() + UnionSignature::of(db, self.id).name.clone() } pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -1592,11 +1611,11 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.enum_signature(self.id).name.clone() + EnumSignature::of(db, self.id).name.clone() } - pub fn variants(self, db: &dyn HirDatabase) -> Vec { - self.id.enum_variants(db).variants.iter().map(|&(id, _, _)| Variant { id }).collect() + pub fn variants(self, db: &dyn HirDatabase) -> Vec { + self.id.enum_variants(db).variants.iter().map(|&(id, _, _)| EnumVariant { id }).collect() } pub fn num_variants(self, db: &dyn HirDatabase) -> usize { @@ -1688,19 +1707,18 @@ pub fn ty(self, db: &'db dyn HirDatabase) -> TypeNs<'db> { } } -impl From<&Variant> for DefWithBodyId { - fn from(&v: &Variant) -> Self { +impl From<&EnumVariant> for DefWithBodyId { + fn from(&v: &EnumVariant) -> Self { DefWithBodyId::VariantId(v.into()) } } -// FIXME: Rename to `EnumVariant` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Variant { +pub struct EnumVariant { pub(crate) id: EnumVariantId, } -impl Variant { +impl EnumVariant { pub fn module(self, db: &dyn HirDatabase) -> Module { Module { id: self.id.module(db) } } @@ -1737,7 +1755,7 @@ pub fn kind(self, db: &dyn HirDatabase) -> StructKind { } pub fn value(self, db: &dyn HirDatabase) -> Option { - self.source(db)?.value.expr() + self.source(db)?.value.const_arg()?.expr() } pub fn eval(self, db: &dyn HirDatabase) -> Result { @@ -1774,7 +1792,7 @@ pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> Instantiated // FIXME: Rename to `EnumVariant` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InstantiatedVariant<'db> { - pub(crate) inner: Variant, + pub(crate) inner: EnumVariant, pub(crate) args: GenericArgs<'db>, } @@ -1805,7 +1823,7 @@ pub enum StructKind { } /// Variants inherit visibility from the parent enum. -impl HasVisibility for Variant { +impl HasVisibility for EnumVariant { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { self.parent_enum(db).visibility(db) } @@ -1914,35 +1932,78 @@ fn visibility(&self, db: &dyn HirDatabase) -> Visibility { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum VariantDef { +pub enum Variant { Struct(Struct), Union(Union), - Variant(Variant), + EnumVariant(EnumVariant), } -impl_from!(Struct, Union, Variant for VariantDef); +impl_from!(Struct, Union, EnumVariant for Variant); -impl VariantDef { +impl Variant { pub fn fields(self, db: &dyn HirDatabase) -> Vec { match self { - VariantDef::Struct(it) => it.fields(db), - VariantDef::Union(it) => it.fields(db), - VariantDef::Variant(it) => it.fields(db), + Variant::Struct(it) => it.fields(db), + Variant::Union(it) => it.fields(db), + Variant::EnumVariant(it) => it.fields(db), } } pub fn module(self, db: &dyn HirDatabase) -> Module { match self { - VariantDef::Struct(it) => it.module(db), - VariantDef::Union(it) => it.module(db), - VariantDef::Variant(it) => it.module(db), + Variant::Struct(it) => it.module(db), + Variant::Union(it) => it.module(db), + Variant::EnumVariant(it) => it.module(db), } } pub fn name(&self, db: &dyn HirDatabase) -> Name { match self { - VariantDef::Struct(s) => (*s).name(db), - VariantDef::Union(u) => (*u).name(db), - VariantDef::Variant(e) => (*e).name(db), + Variant::Struct(s) => (*s).name(db), + Variant::Union(u) => (*u).name(db), + Variant::EnumVariant(e) => (*e).name(db), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ExpressionStoreOwner { + Body(DefWithBody), + Signature(GenericDef), + VariantFields(Variant), +} + +impl From for ExpressionStoreOwner { + fn from(v: GenericDef) -> Self { + Self::Signature(v) + } +} + +impl From for ExpressionStoreOwner { + fn from(v: DefWithBody) -> Self { + Self::Body(v) + } +} + +impl From for ExpressionStoreOwner { + fn from(v: ExpressionStoreOwnerId) -> Self { + match v { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + Self::Signature(generic_def_id.into()) + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Self::Body(def_with_body_id.into()), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + Self::VariantFields(variant_id.into()) + } + } + } +} + +impl ExpressionStoreOwner { + pub fn module(self, db: &dyn HirDatabase) -> Module { + match self { + Self::Body(body) => body.module(db), + Self::Signature(generic_def) => generic_def.module(db), + Self::VariantFields(variant) => variant.module(db), } } } @@ -1953,9 +2014,9 @@ pub enum DefWithBody { Function(Function), Static(Static), Const(Const), - Variant(Variant), + EnumVariant(EnumVariant), } -impl_from!(Function, Const, Static, Variant for DefWithBody); +impl_from!(Function, Const, Static, EnumVariant for DefWithBody); impl DefWithBody { pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -1963,7 +2024,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { DefWithBody::Const(c) => c.module(db), DefWithBody::Function(f) => f.module(db), DefWithBody::Static(s) => s.module(db), - DefWithBody::Variant(v) => v.module(db), + DefWithBody::EnumVariant(v) => v.module(db), } } @@ -1972,7 +2033,7 @@ pub fn name(self, db: &dyn HirDatabase) -> Option { DefWithBody::Function(f) => Some(f.name(db)), DefWithBody::Static(s) => Some(s.name(db)), DefWithBody::Const(c) => c.name(db), - DefWithBody::Variant(v) => Some(v.name(db)), + DefWithBody::EnumVariant(v) => Some(v.name(db)), } } @@ -1982,7 +2043,7 @@ pub fn body_type(self, db: &dyn HirDatabase) -> Type<'_> { DefWithBody::Function(it) => it.ret_type(db), DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), - DefWithBody::Variant(it) => it.parent_enum(db).variant_body_ty(db), + DefWithBody::EnumVariant(it) => it.parent_enum(db).variant_body_ty(db), } } @@ -1994,7 +2055,7 @@ fn id(&self) -> Option { }, DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), - DefWithBody::Variant(it) => it.into(), + DefWithBody::EnumVariant(it) => it.into(), }) } @@ -2003,7 +2064,7 @@ pub fn debug_hir(self, db: &dyn HirDatabase) -> String { let Some(id) = self.id() else { return String::new(); }; - let body = db.body(id); + let body = Body::of(db, id); body.pretty_print(db, id, Edition::CURRENT) } @@ -2030,17 +2091,17 @@ pub fn diagnostics<'db>( }; let krate = self.module(db).id.krate(db); - let (body, source_map) = db.body_with_source_map(id); + let (body, source_map) = Body::with_source_map(db, id); let sig_source_map = match self { DefWithBody::Function(id) => match id.id { - AnyFunctionId::FunctionId(id) => db.function_signature_with_source_map(id).1, + AnyFunctionId::FunctionId(id) => &FunctionSignature::with_source_map(db, id).1, AnyFunctionId::BuiltinDeriveImplMethod { .. } => return, }, - DefWithBody::Static(id) => db.static_signature_with_source_map(id.into()).1, - DefWithBody::Const(id) => db.const_signature_with_source_map(id.into()).1, - DefWithBody::Variant(variant) => { + DefWithBody::Static(id) => &StaticSignature::with_source_map(db, id.into()).1, + DefWithBody::Const(id) => &ConstSignature::with_source_map(db, id.into()).1, + DefWithBody::EnumVariant(variant) => { let enum_id = variant.parent_enum(db).id; - db.enum_signature_with_source_map(enum_id).1 + &EnumSignature::with_source_map(db, enum_id).1 } }; @@ -2048,17 +2109,11 @@ pub fn diagnostics<'db>( Module { id: def_map.root_module_id() }.diagnostics(db, acc, style_lints); } - expr_store_diagnostics(db, acc, &source_map); + expr_store_diagnostics(db, acc, source_map); - let infer = InferenceResult::for_body(db, id); + let infer = InferenceResult::of(db, id); for d in infer.diagnostics() { - acc.extend(AnyDiagnostic::inference_diagnostic( - db, - id, - d, - &source_map, - &sig_source_map, - )); + acc.extend(AnyDiagnostic::inference_diagnostic(db, id, d, source_map, sig_source_map)); } for (pat_or_expr, mismatch) in infer.type_mismatches() { @@ -2180,7 +2235,7 @@ pub fn diagnostics<'db>( { need_mut = &mir::MutabilityReason::Not; } - let local = Local { parent: id, binding_id }; + let local = Local { parent: id.into(), binding_id }; let is_mut = body[binding_id].mode == BindingAnnotation::Mutable; match (need_mut, is_mut) { @@ -2237,7 +2292,7 @@ pub fn diagnostics<'db>( } for diagnostic in BodyValidationDiagnostic::collect(db, id, style_lints) { - acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, &source_map)); + acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, source_map)); } for diag in hir_ty::diagnostics::incorrect_case(db, id.into()) { @@ -2251,7 +2306,7 @@ pub fn expression_types<'db>( db: &'db dyn HirDatabase, ) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { - let infer = InferenceResult::for_body(db, def_id); + let infer = InferenceResult::of(db, def_id); let resolver = def_id.resolver(db); infer.expression_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) @@ -2261,7 +2316,7 @@ pub fn expression_types<'db>( /// Returns an iterator over the inferred types of all patterns in this body. pub fn pattern_types<'db>(self, db: &'db dyn HirDatabase) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { - let infer = InferenceResult::for_body(db, def_id); + let infer = InferenceResult::of(db, def_id); let resolver = def_id.resolver(db); infer.pattern_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) @@ -2271,7 +2326,7 @@ pub fn pattern_types<'db>(self, db: &'db dyn HirDatabase) -> impl Iterator(self, db: &'db dyn HirDatabase) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { - let infer = InferenceResult::for_body(db, def_id); + let infer = InferenceResult::of(db, def_id); let resolver = def_id.resolver(db); infer.binding_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) @@ -2339,7 +2394,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { pub fn name(self, db: &dyn HirDatabase) -> Name { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).name.clone(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).name.clone(), AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => { Name::new_symbol_root(method.name()) } @@ -2541,7 +2596,7 @@ pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option> pub fn has_self_param(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).has_self_param(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).has_self_param(), AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method { BuiltinDeriveImplMethod::clone | BuiltinDeriveImplMethod::fmt @@ -2576,7 +2631,7 @@ pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec> { pub fn num_params(self, db: &dyn HirDatabase) -> usize { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).params.len(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).params.len(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => { self.fn_sig(db).1.skip_binder().inputs().len() } @@ -2620,21 +2675,21 @@ pub fn params_without_self_with_args<'db>( pub fn is_const(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).is_const(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).is_const(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, } } pub fn is_async(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).is_async(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).is_async(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, } } pub fn is_varargs(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).is_varargs(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).is_varargs(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, } } @@ -2687,7 +2742,7 @@ pub fn is_main(self, db: &dyn HirDatabase) -> bool { AnyFunctionId::FunctionId(id) => { self.exported_main(db) || self.module(db).is_crate_root(db) - && db.function_signature(id).name == sym::main + && FunctionSignature::of(db, id).name == sym::main } AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, } @@ -2764,7 +2819,7 @@ pub fn is_unsafe_to_call( /// This is false in the case of required (not provided) trait methods. pub fn has_body(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).has_body(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).has_body(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => true, } } @@ -2792,7 +2847,7 @@ pub fn eval( id.into(), GenericArgs::empty(interner).store(), ParamEnvAndCrate { - param_env: db.trait_environment(id.into()), + param_env: db.trait_environment(GenericDefId::from(id).into()), krate: id.module(db).krate(db), } .store(), @@ -2878,24 +2933,26 @@ pub fn as_local(&self, db: &dyn HirDatabase) -> Option { match self.func { Callee::Def(CallableDefId::FunctionId(it)) => { let parent = DefWithBodyId::FunctionId(it); - let body = db.body(parent); + let body = Body::of(db, parent); if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) { - Some(Local { parent, binding_id: self_param }) + Some(Local { parent: parent.into(), binding_id: self_param }) } else if let Pat::Bind { id, .. } = &body[body.params[self.idx - body.self_param.is_some() as usize]] { - Some(Local { parent, binding_id: *id }) + Some(Local { parent: parent.into(), binding_id: *id }) } else { None } } Callee::Closure(closure, _) => { let c = db.lookup_intern_closure(closure); - let body = db.body(c.0); - if let Expr::Closure { args, .. } = &body[c.1] - && let Pat::Bind { id, .. } = &body[args[self.idx]] + let body_owner = c.0; + let store = ExpressionStore::of(db, c.0); + + if let Expr::Closure { args, .. } = &store[c.1] + && let Pat::Bind { id, .. } = &store[args[self.idx]] { - return Some(Local { parent: c.0, binding_id: *id }); + return Some(Local { parent: body_owner, binding_id: *id }); } None } @@ -2917,7 +2974,7 @@ impl SelfParam { pub fn access(self, db: &dyn HirDatabase) -> Access { match self.func.id { AnyFunctionId::FunctionId(id) => { - let func_data = db.function_signature(id); + let func_data = FunctionSignature::of(db, id); func_data .params .first() @@ -3046,7 +3103,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Option { - db.const_signature(self.id).name.clone() + ConstSignature::of(db, self.id).name.clone() } pub fn value(self, db: &dyn HirDatabase) -> Option { @@ -3119,11 +3176,11 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.static_signature(self.id).name.clone() + StaticSignature::of(db, self.id).name.clone() } pub fn is_mut(self, db: &dyn HirDatabase) -> bool { - db.static_signature(self.id).flags.contains(StaticFlags::MUTABLE) + StaticSignature::of(db, self.id).flags.contains(StaticFlags::MUTABLE) } pub fn value(self, db: &dyn HirDatabase) -> Option { @@ -3179,7 +3236,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.trait_signature(self.id).name.clone() + TraitSignature::of(db, self.id).name.clone() } pub fn direct_supertraits(self, db: &dyn HirDatabase) -> Vec { @@ -3209,11 +3266,11 @@ pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec { } pub fn is_auto(self, db: &dyn HirDatabase) -> bool { - db.trait_signature(self.id).flags.contains(TraitFlags::AUTO) + TraitSignature::of(db, self.id).flags.contains(TraitFlags::AUTO) } pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool { - db.trait_signature(self.id).flags.contains(TraitFlags::UNSAFE) + TraitSignature::of(db, self.id).flags.contains(TraitFlags::UNSAFE) } pub fn type_or_const_param_count( @@ -3221,7 +3278,7 @@ pub fn type_or_const_param_count( db: &dyn HirDatabase, count_required_only: bool, ) -> usize { - db.generic_params(self.id.into()) + GenericParams::of(db,self.id.into()) .iter_type_or_consts() .filter(|(_, ty)| !matches!(ty, TypeOrConstParamData::TypeParamData(ty) if ty.provenance != TypeParamProvenance::TypeParamList)) .filter(|(_, ty)| !count_required_only || !ty.has_default()) @@ -3289,7 +3346,7 @@ pub fn ty_params(self, db: &dyn HirDatabase) -> Type<'_> { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.type_alias_signature(self.id).name.clone() + TypeAliasSignature::of(db, self.id).name.clone() } } @@ -3731,7 +3788,18 @@ fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { match self { DefWithBody::Function(it) => it.as_assoc_item(db), DefWithBody::Const(it) => it.as_assoc_item(db), - DefWithBody::Static(_) | DefWithBody::Variant(_) => None, + DefWithBody::Static(_) | DefWithBody::EnumVariant(_) => None, + } + } +} + +impl AsAssocItem for GenericDef { + fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { + match self { + GenericDef::Function(it) => it.as_assoc_item(db), + GenericDef::Const(it) => it.as_assoc_item(db), + GenericDef::TypeAlias(it) => it.as_assoc_item(db), + _ => None, } } } @@ -3918,7 +3986,7 @@ pub fn diagnostics<'db>( db, acc, db.type_for_type_alias_with_diagnostics(type_alias.id).1, - &db.type_alias_signature_with_source_map(type_alias.id).1, + &TypeAliasSignature::with_source_map(db, type_alias.id).1, ); for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { acc.push(diag.into()); @@ -3971,12 +4039,36 @@ pub enum GenericDef { ); impl GenericDef { + pub fn name(self, db: &dyn HirDatabase) -> Option { + match self { + GenericDef::Function(it) => Some(it.name(db)), + GenericDef::Adt(it) => Some(it.name(db)), + GenericDef::Trait(it) => Some(it.name(db)), + GenericDef::TypeAlias(it) => Some(it.name(db)), + GenericDef::Impl(_) => None, + GenericDef::Const(it) => it.name(db), + GenericDef::Static(it) => Some(it.name(db)), + } + } + + pub fn module(self, db: &dyn HirDatabase) -> Module { + match self { + GenericDef::Function(it) => it.module(db), + GenericDef::Adt(it) => it.module(db), + GenericDef::Trait(it) => it.module(db), + GenericDef::TypeAlias(it) => it.module(db), + GenericDef::Impl(it) => it.module(db), + GenericDef::Const(it) => it.module(db), + GenericDef::Static(it) => it.module(db), + } + } + pub fn params(self, db: &dyn HirDatabase) -> Vec { let Ok(id) = self.try_into() else { // Let's pretend builtin derive impls don't have generic parameters. return Vec::new(); }; - let generics = db.generic_params(id); + let generics = GenericParams::of(db, id); let ty_params = generics.iter_type_or_consts().map(|(local_id, _)| { let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: id, local_id } }; match toc.split(db) { @@ -3996,7 +4088,7 @@ pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec { // Let's pretend builtin derive impls don't have generic parameters. return Vec::new(); }; - let generics = db.generic_params(id); + let generics = GenericParams::of(db, id); generics .iter_lt() .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: id, local_id } }) @@ -4008,7 +4100,7 @@ pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec // Let's pretend builtin derive impls don't have generic parameters. return Vec::new(); }; - let generics = db.generic_params(id); + let generics = GenericParams::of(db, id); generics .iter_type_or_consts() .map(|(local_id, _)| TypeOrConstParam { @@ -4038,31 +4130,31 @@ fn id(self) -> Option { pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec>) { let Some(def) = self.id() else { return }; - let generics = db.generic_params(def); + let generics = GenericParams::of(db, def); if generics.is_empty() && generics.has_no_predicates() { return; } let source_map = match def { - GenericDefId::AdtId(AdtId::EnumId(it)) => db.enum_signature_with_source_map(it).1, - GenericDefId::AdtId(AdtId::StructId(it)) => db.struct_signature_with_source_map(it).1, - GenericDefId::AdtId(AdtId::UnionId(it)) => db.union_signature_with_source_map(it).1, + GenericDefId::AdtId(AdtId::EnumId(it)) => &EnumSignature::with_source_map(db, it).1, + GenericDefId::AdtId(AdtId::StructId(it)) => &StructSignature::with_source_map(db, it).1, + GenericDefId::AdtId(AdtId::UnionId(it)) => &UnionSignature::with_source_map(db, it).1, GenericDefId::ConstId(_) => return, - GenericDefId::FunctionId(it) => db.function_signature_with_source_map(it).1, - GenericDefId::ImplId(it) => db.impl_signature_with_source_map(it).1, + GenericDefId::FunctionId(it) => &FunctionSignature::with_source_map(db, it).1, + GenericDefId::ImplId(it) => &ImplSignature::with_source_map(db, it).1, GenericDefId::StaticId(_) => return, - GenericDefId::TraitId(it) => db.trait_signature_with_source_map(it).1, - GenericDefId::TypeAliasId(it) => db.type_alias_signature_with_source_map(it).1, + GenericDefId::TraitId(it) => &TraitSignature::with_source_map(db, it).1, + GenericDefId::TypeAliasId(it) => &TypeAliasSignature::with_source_map(db, it).1, }; - expr_store_diagnostics(db, acc, &source_map); - push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, &source_map); + expr_store_diagnostics(db, acc, source_map); + push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, source_map); push_ty_diagnostics( db, acc, GenericPredicates::query_with_diagnostics(db, def).1.clone(), - &source_map, + source_map, ); for (param_id, param) in generics.iter_type_or_consts() { if let TypeOrConstParamData::ConstParamData(_) = param { @@ -4073,7 +4165,7 @@ pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec Vec<(Symbol, Type<'db>)> { _ => None, }) .map(|container| { - db.generic_params(container) + GenericParams::of(db, container) .iter_type_or_consts() .filter_map(|param| match param.1 { TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()), @@ -4142,7 +4234,7 @@ pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { }) .collect::>() }); - let generics = db.generic_params(self.def); + let generics = GenericParams::of(db, self.def); let type_params = generics.iter_type_or_consts().filter_map(|param| match param.1 { TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()), TypeOrConstParamData::ConstParamData(_) => None, @@ -4170,7 +4262,7 @@ pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { /// A single local definition. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Local { - pub(crate) parent: DefWithBodyId, + pub(crate) parent: ExpressionStoreOwnerId, pub(crate) binding_id: BindingId, } @@ -4232,7 +4324,7 @@ pub fn is_param(self, db: &dyn HirDatabase) -> bool { pub fn as_self_param(self, db: &dyn HirDatabase) -> Option { match self.parent { - DefWithBodyId::FunctionId(func) if self.is_self(db) => { + ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(func)) if self.is_self(db) => { Some(SelfParam { func: func.into() }) } _ => None, @@ -4240,8 +4332,7 @@ pub fn as_self_param(self, db: &dyn HirDatabase) -> Option { } pub fn name(self, db: &dyn HirDatabase) -> Name { - let body = db.body(self.parent); - body[self.binding_id].name.clone() + ExpressionStore::of(db, self.parent)[self.binding_id].name.clone() } pub fn is_self(self, db: &dyn HirDatabase) -> bool { @@ -4249,16 +4340,17 @@ pub fn is_self(self, db: &dyn HirDatabase) -> bool { } pub fn is_mut(self, db: &dyn HirDatabase) -> bool { - let body = db.body(self.parent); - body[self.binding_id].mode == BindingAnnotation::Mutable + ExpressionStore::of(db, self.parent)[self.binding_id].mode == BindingAnnotation::Mutable } pub fn is_ref(self, db: &dyn HirDatabase) -> bool { - let body = db.body(self.parent); - matches!(body[self.binding_id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) + matches!( + ExpressionStore::of(db, self.parent)[self.binding_id].mode, + BindingAnnotation::Ref | BindingAnnotation::RefMut + ) } - pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { + pub fn parent(self, _db: &dyn HirDatabase) -> ExpressionStoreOwner { self.parent.into() } @@ -4272,67 +4364,91 @@ pub fn as_id(self) -> u32 { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let def = self.parent; - let infer = InferenceResult::for_body(db, def); + let infer = InferenceResult::of(db, def); let ty = infer.binding_ty(self.binding_id); Type::new(db, def, ty) } /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` pub fn sources(self, db: &dyn HirDatabase) -> Vec { - let (body, source_map) = db.body_with_source_map(self.parent); - match body.self_param.zip(source_map.self_param_syntax()) { - Some((param, source)) if param == self.binding_id => { - let root = source.file_syntax(db); - vec![LocalSource { - local: self, - source: source.map(|ast| Either::Right(ast.to_node(&root))), - }] + let b; + let (_, source_map) = match self.parent { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + ExpressionStore::with_source_map(db, generic_def_id.into()) } - _ => source_map - .patterns_for_binding(self.binding_id) - .iter() - .map(|&definition| { - let src = source_map.pat_syntax(definition).unwrap(); // Hmm... - let root = src.file_syntax(db); - LocalSource { + ExpressionStoreOwnerId::Body(def_with_body_id) => { + b = Body::with_source_map(db, def_with_body_id); + if let Some((param, source)) = b.0.self_param.zip(b.1.self_param_syntax()) + && param == self.binding_id + { + let root = source.file_syntax(db); + return vec![LocalSource { local: self, - source: src.map(|ast| match ast.to_node(&root) { - Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), - _ => unreachable!("local with non ident-pattern"), - }), - } - }) - .collect(), - } + source: source.map(|ast| Either::Right(ast.to_node(&root))), + }]; + } + (&b.0.store, &b.1.store) + } + ExpressionStoreOwnerId::VariantFields(def) => { + ExpressionStore::with_source_map(db, def.into()) + } + }; + source_map + .patterns_for_binding(self.binding_id) + .iter() + .map(|&definition| { + let src = source_map.pat_syntax(definition).unwrap(); // Hmm... + let root = src.file_syntax(db); + LocalSource { + local: self, + source: src.map(|ast| match ast.to_node(&root) { + Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), + _ => unreachable!("local with non ident-pattern"), + }), + } + }) + .collect() } /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = it;` pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { - let (body, source_map) = db.body_with_source_map(self.parent); - match body.self_param.zip(source_map.self_param_syntax()) { - Some((param, source)) if param == self.binding_id => { - let root = source.file_syntax(db); + let b; + let (_, source_map) = match self.parent { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + ExpressionStore::with_source_map(db, generic_def_id.into()) + } + ExpressionStoreOwnerId::Body(def_with_body_id) => { + b = Body::with_source_map(db, def_with_body_id); + if let Some((param, source)) = b.0.self_param.zip(b.1.self_param_syntax()) + && param == self.binding_id + { + let root = source.file_syntax(db); + return LocalSource { + local: self, + source: source.map(|ast| Either::Right(ast.to_node(&root))), + }; + } + (&b.0.store, &b.1.store) + } + ExpressionStoreOwnerId::VariantFields(def) => { + ExpressionStore::with_source_map(db, def.into()) + } + }; + source_map + .patterns_for_binding(self.binding_id) + .first() + .map(|&definition| { + let src = source_map.pat_syntax(definition).unwrap(); // Hmm... + let root = src.file_syntax(db); LocalSource { local: self, - source: source.map(|ast| Either::Right(ast.to_node(&root))), + source: src.map(|ast| match ast.to_node(&root) { + Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), + _ => unreachable!("local with non ident-pattern"), + }), } - } - _ => source_map - .patterns_for_binding(self.binding_id) - .first() - .map(|&definition| { - let src = source_map.pat_syntax(definition).unwrap(); // Hmm... - let root = src.file_syntax(db); - LocalSource { - local: self, - source: src.map(|ast| match ast.to_node(&root) { - Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), - _ => unreachable!("local with non ident-pattern"), - }), - } - }) - .unwrap(), - } + }) + .unwrap() } } @@ -4417,7 +4533,7 @@ pub fn krate(&self) -> Crate { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Label { - pub(crate) parent: DefWithBodyId, + pub(crate) parent: ExpressionStoreOwnerId, pub(crate) label_id: LabelId, } @@ -4426,13 +4542,12 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { self.parent(db).module(db) } - pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { + pub fn parent(self, _db: &dyn HirDatabase) -> ExpressionStoreOwner { self.parent.into() } pub fn name(self, db: &dyn HirDatabase) -> Name { - let body = db.body(self.parent); - body[self.label_id].name.clone() + ExpressionStore::of(db, self.parent)[self.label_id].name.clone() } } @@ -4543,7 +4658,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { /// Is this type parameter implicitly introduced (eg. `Self` in a trait or an `impl Trait` /// argument)? pub fn is_implicit(self, db: &dyn HirDatabase) -> bool { - let params = db.generic_params(self.id.parent()); + let params = GenericParams::of(db, self.id.parent()); let data = ¶ms[self.id.local_id()]; match data.type_param().unwrap().provenance { TypeParamProvenance::TypeParamList => false, @@ -4598,7 +4713,7 @@ pub struct LifetimeParam { impl LifetimeParam { pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); params[self.id.local_id].name.clone() } @@ -4622,7 +4737,7 @@ pub fn merge(self) -> TypeOrConstParam { } pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent()); + let params = GenericParams::of(db, self.id.parent()); match params[self.id.local_id()].name() { Some(it) => it.clone(), None => { @@ -4669,7 +4784,7 @@ pub struct TypeOrConstParam { impl TypeOrConstParam { pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); match params[self.id.local_id].name() { Some(n) => n.clone(), _ => Name::missing(), @@ -4685,7 +4800,7 @@ pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { } pub fn split(self, db: &dyn HirDatabase) -> Either { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); match ¶ms[self.id.local_id] { TypeOrConstParamData::TypeParamData(_) => { Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) }) @@ -4704,7 +4819,7 @@ pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { } pub fn as_type_param(self, db: &dyn HirDatabase) -> Option { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); match ¶ms[self.id.local_id] { TypeOrConstParamData::TypeParamData(_) => { Some(TypeParam { id: TypeParamId::from_unchecked(self.id) }) @@ -4714,7 +4829,7 @@ pub fn as_type_param(self, db: &dyn HirDatabase) -> Option { } pub fn as_const_param(self, db: &dyn HirDatabase) -> Option { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); match ¶ms[self.id.local_id] { TypeOrConstParamData::TypeParamData(_) => None, TypeOrConstParamData::ConstParamData(_) => { @@ -4741,7 +4856,7 @@ fn extend_with_def_map(db: &dyn HirDatabase, def_map: &DefMap, result: &mut Vec< result.extend(module.scope.builtin_derive_impls().map(Impl::from)); for unnamed_const in module.scope.unnamed_consts() { - for (_, block_def_map) in db.body(unnamed_const.into()).blocks(db) { + for (_, block_def_map) in Body::of(db, unnamed_const.into()).blocks(db) { extend_with_def_map(db, block_def_map, result); } } @@ -4898,14 +5013,14 @@ pub fn items(self, db: &dyn HirDatabase) -> Vec { pub fn is_negative(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::NEGATIVE), + AnyImplId::ImplId(id) => ImplSignature::of(db, id).flags.contains(ImplFlags::NEGATIVE), AnyImplId::BuiltinDeriveImplId(_) => false, } } pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::UNSAFE), + AnyImplId::ImplId(id) => ImplSignature::of(db, id).flags.contains(ImplFlags::UNSAFE), AnyImplId::BuiltinDeriveImplId(_) => false, } } @@ -5012,7 +5127,7 @@ pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec Vec> { return Vec::new(); }; let owner = db.lookup_intern_closure(id).0; - let infer = InferenceResult::for_body(db, owner); + let Some(body_owner) = owner.as_def_with_body() else { + return Vec::new(); + }; + let infer = InferenceResult::of(db, body_owner); let (captures, _) = infer.closure_info(id); - let env = body_param_env_from_has_crate(db, owner); + let env = body_param_env_from_has_crate(db, body_owner); captures.iter().map(|capture| Type { env, ty: capture.ty(db, self.subst) }).collect() } @@ -5042,7 +5160,10 @@ pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { match self.id { AnyClosureId::ClosureId(id) => { let owner = db.lookup_intern_closure(id).0; - let infer = InferenceResult::for_body(db, owner); + let Some(body_owner) = owner.as_def_with_body() else { + return FnTrait::FnOnce; + }; + let infer = InferenceResult::of(db, body_owner); let info = infer.closure_info(id); info.1.into() } @@ -5125,7 +5246,7 @@ pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option { #[derive(Clone, Debug, PartialEq, Eq)] pub struct ClosureCapture<'db> { - owner: DefWithBodyId, + owner: ExpressionStoreOwnerId, closure: InternedClosureId, capture: hir_ty::CapturedItem, _marker: PhantomCovariantLifetime<'db>, @@ -5184,17 +5305,16 @@ pub enum CaptureKind { #[derive(Debug, Clone)] pub struct CaptureUsages { - parent: DefWithBodyId, + parent: ExpressionStoreOwnerId, spans: SmallVec<[mir::MirSpan; 3]>, } impl CaptureUsages { pub fn sources(&self, db: &dyn HirDatabase) -> Vec { - let (body, source_map) = db.body_with_source_map(self.parent); - + let (body, source_map) = ExpressionStore::with_source_map(db, self.parent); let mut result = Vec::with_capacity(self.spans.len()); for &span in self.spans.iter() { - let is_ref = span.is_ref_span(&body); + let is_ref = span.is_ref_span(body); match span { mir::MirSpan::ExprId(expr) => { if let Ok(expr) = source_map.expr_syntax(expr) { @@ -5362,7 +5482,7 @@ pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool { fn is_phantom_data(db: &dyn HirDatabase, adt_id: AdtId) -> bool { match adt_id { AdtId::StructId(s) => { - let flags = db.struct_signature(s).flags; + let flags = StructSignature::of(db, s).flags; flags.contains(StructFlags::IS_PHANTOM_DATA) } AdtId::UnionId(_) | AdtId::EnumId(_) => false, @@ -5956,8 +6076,8 @@ fn with_method_resolution( // for a nicer IDE experience. However, method resolution is always done on real code (either // existing code or code to be inserted), and there using PostAnalysis is dangerous - we may // suggest invalid methods. So we're using the TypingMode of the body we're in. - let typing_mode = if let Some(body_owner) = resolver.body_owner() { - TypingMode::analysis_in_body(interner, body_owner.into()) + let typing_mode = if let Some(store_owner) = resolver.expression_store_owner() { + TypingMode::analysis_in_body(interner, store_owner.into()) } else { TypingMode::non_body_analysis() }; @@ -6362,18 +6482,19 @@ pub fn is_bool(&self) -> bool { #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct InlineAsmOperand { - owner: DefWithBodyId, + owner: ExpressionStoreOwnerId, expr: ExprId, index: usize, } impl InlineAsmOperand { - pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { + pub fn parent(self, _db: &dyn HirDatabase) -> ExpressionStoreOwner { self.owner.into() } pub fn name(&self, db: &dyn HirDatabase) -> Option { - match &db.body(self.owner)[self.expr] { + let body = ExpressionStore::of(db, self.owner); + match &body[self.expr] { hir_def::hir::Expr::InlineAsm(e) => e.operands.get(self.index)?.0.clone(), _ => None, } @@ -6403,7 +6524,7 @@ enum Callee<'db> { pub enum CallableKind<'db> { Function(Function), TupleStruct(Struct), - TupleEnumVariant(Variant), + TupleEnumVariant(EnumVariant), Closure(Closure<'db>), FnPtr, FnImpl(FnTrait), @@ -6753,7 +6874,7 @@ fn krate(&self, db: &dyn HirDatabase) -> Crate { } } -impl HasCrate for Variant { +impl HasCrate for EnumVariant { fn krate(&self, db: &dyn HirDatabase) -> Crate { self.module(db).krate(db) } @@ -6922,9 +7043,9 @@ fn name(&self, db: &dyn HirDatabase) -> Option { Struct, Union, Enum, - Variant, + EnumVariant, Adt, - VariantDef, + Variant, DefWithBody, Function, ExternCrateDecl, @@ -7113,7 +7234,7 @@ fn generic_args_from_tys<'db>( } fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) -> bool { - let params = db.generic_params(generic_def); + let params = GenericParams::of(db, generic_def); let defaults = db.generic_defaults(generic_def); params .iter_type_or_consts() @@ -7134,7 +7255,7 @@ fn param_env_from_resolver<'db>( ParamEnvAndCrate { param_env: resolver .generic_def() - .map_or_else(ParamEnv::empty, |generic_def| db.trait_environment(generic_def)), + .map_or_else(ParamEnv::empty, |generic_def| db.trait_environment(generic_def.into())), krate: resolver.krate(), } } @@ -7143,14 +7264,14 @@ fn param_env_from_has_crate<'db>( db: &'db dyn HirDatabase, id: impl hir_def::HasModule + Into + Copy, ) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } + ParamEnvAndCrate { param_env: db.trait_environment(id.into().into()), krate: id.krate(db) } } fn body_param_env_from_has_crate<'db>( db: &'db dyn HirDatabase, - id: impl hir_def::HasModule + Into + Copy, + id: impl hir_def::HasModule + Into + Copy, ) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { param_env: db.trait_environment_for_body(id.into()), krate: id.krate(db) } + ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } } fn empty_param_env<'db>(krate: base_db::Crate) -> ParamEnvAndCrate<'db> { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 1cf3b9816082..4e9e3c44be11 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -13,9 +13,10 @@ use base_db::FxIndexSet; use either::Either; use hir_def::{ - BuiltinDeriveImplId, DefWithBodyId, HasModule, MacroId, StructId, TraitId, VariantId, + BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, HasModule, MacroId, StructId, + TraitId, VariantId, attrs::parse_extra_crate_attrs, - expr_store::{Body, ExprOrPatSource, HygieneId, path::Path}, + expr_store::{Body, ExprOrPatSource, ExpressionStore, HygieneId, path::Path}, hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat}, nameres::{ModuleOrigin, crate_def_map}, resolver::{self, HasResolver, Resolver, TypeNs, ValueNs}, @@ -31,7 +32,7 @@ }; use hir_ty::{ InferenceResult, - diagnostics::{unsafe_operations, unsafe_operations_for_body}, + diagnostics::unsafe_operations, infer_query_with_inspect, next_solver::{ AnyImplId, DbInterner, Span, @@ -54,10 +55,10 @@ use crate::{ Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, - ConstParam, Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, - HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, - Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, - TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, + ConstParam, Crate, DeriveHelper, Enum, EnumVariant, ExpressionStoreOwner, Field, Function, + GenericSubstitution, HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, + Local, Macro, Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, + Trait, TupleField, Type, TypeAlias, TypeParam, Union, Variant, db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{SourceAnalyzer, resolve_hir_path}, @@ -90,7 +91,7 @@ pub(crate) fn in_type_ns(&self) -> Option { } PathResolution::Def( ModuleDef::Const(_) - | ModuleDef::Variant(_) + | ModuleDef::EnumVariant(_) | ModuleDef::Macro(_) | ModuleDef::Function(_) | ModuleDef::Module(_) @@ -367,8 +368,8 @@ pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { self.imp.resolve_try_expr(try_expr) } - pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { - self.imp.resolve_variant(record_lit).map(VariantDef::from) + pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { + self.imp.resolve_variant(record_lit).map(Variant::from) } pub fn file_to_module_def(&self, file: impl Into) -> Option { @@ -409,7 +410,7 @@ pub fn to_enum_def(&self, e: &ast::Enum) -> Option { self.imp.to_def(e) } - pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option { + pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option { self.imp.to_def(v) } @@ -472,12 +473,12 @@ pub fn first_crate(&self, file: FileId) -> Option { pub fn attach_first_edition_opt(&self, file: FileId) -> Option { let krate = self.file_to_module_defs(file).next()?.krate(self.db); - Some(EditionedFileId::new(self.db, file, krate.edition(self.db), krate.id)) + Some(EditionedFileId::new(self.db, file, krate.edition(self.db))) } pub fn attach_first_edition(&self, file: FileId) -> EditionedFileId { self.attach_first_edition_opt(file) - .unwrap_or_else(|| EditionedFileId::current_edition_guess_origin(self.db, file)) + .unwrap_or_else(|| EditionedFileId::current_edition(self.db, file)) } pub fn parse_guess_edition(&self, file_id: FileId) -> ast::SourceFile { @@ -785,16 +786,21 @@ pub fn speculative_expand_derive_as_pseudo_attr_macro( /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, /// and returns the conflicting locals. pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec { - let body = self.db.body(to_be_renamed.parent); + // FIXME: signatures + let Some(def) = to_be_renamed.parent.as_def_with_body() else { + return Vec::new(); + }; + let body = Body::of(self.db, def); let resolver = to_be_renamed.parent.resolver(self.db); - let starting_expr = body.binding_owner(to_be_renamed.binding_id).unwrap_or(body.body_expr); + let starting_expr = + body.binding_owner(to_be_renamed.binding_id).unwrap_or(body.root_expr()); let mut visitor = RenameConflictsVisitor { - body: &body, + body, conflicts: FxHashSet::default(), db: self.db, new_name: new_name.symbol().clone(), old_name: to_be_renamed.name(self.db).symbol().clone(), - owner: to_be_renamed.parent, + owner: def, to_be_renamed: to_be_renamed.binding_id, resolver, }; @@ -1913,36 +1919,32 @@ pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option self.db.parse_macro_expansion(file_id).value.1.matched_arm } - pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet { - let Ok(def) = DefWithBodyId::try_from(def) else { - return FxHashSet::default(); - }; - let (body, source_map) = self.db.body_with_source_map(def); - let infer = InferenceResult::for_body(self.db, def); + pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet { + let Ok(def) = ExpressionStoreOwnerId::try_from(def) else { return Default::default() }; + let (body, source_map) = ExpressionStore::with_source_map(self.db, def); + let infer = InferenceResult::of(self.db, def); let mut res = FxHashSet::default(); - unsafe_operations_for_body(self.db, infer, def, &body, &mut |node| { - if let Ok(node) = source_map.expr_or_pat_syntax(node) { - res.insert(node); - } - }); + for root in body.expr_roots() { + unsafe_operations(self.db, infer, def, body, root, &mut |node, _| { + if let Ok(node) = source_map.expr_or_pat_syntax(node) { + res.insert(node); + } + }); + } res } pub fn get_unsafe_ops_for_unsafe_block(&self, block: ast::BlockExpr) -> Vec { always!(block.unsafe_token().is_some()); + let Some(sa) = self.analyze(block.syntax()) else { return vec![] }; + let Some((def, store, sm, Some(infer))) = sa.def() else { return vec![] }; let block = self.wrap_node_infile(ast::Expr::from(block)); - let Some(def) = self.body_for(block.syntax()) else { return Vec::new() }; - let Ok(def) = def.try_into() else { - return Vec::new(); - }; - let (body, source_map) = self.db.body_with_source_map(def); - let infer = InferenceResult::for_body(self.db, def); - let Some(ExprOrPatId::ExprId(block)) = source_map.node_expr(block.as_ref()) else { + let Some(ExprOrPatId::ExprId(block)) = sm.node_expr(block.as_ref()) else { return Vec::new(); }; let mut res = Vec::default(); - unsafe_operations(self.db, infer, def, &body, block, &mut |node, _| { - if let Ok(node) = source_map.expr_or_pat_syntax(node) { + unsafe_operations(self.db, infer, def, store, block, &mut |node, _| { + if let Ok(node) = sm.expr_or_pat_syntax(node) { res.push(node); } }); @@ -1994,7 +1996,7 @@ pub fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option { pub fn resolve_offset_of_field( &self, name_ref: &ast::NameRef, - ) -> Option<(Either, GenericSubstitution<'db>)> { + ) -> Option<(Either, GenericSubstitution<'db>)> { self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref) } @@ -2114,13 +2116,9 @@ pub fn source_with_range( Some(res) } - pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option { + pub fn store_owner_for(&self, node: InFile<&SyntaxNode>) -> Option { let container = self.with_ctx(|ctx| ctx.find_container(node))?; - - match container { - ChildContainer::DefWithBodyId(def) => Some(def.into()), - _ => None, - } + container.as_expression_store_owner().map(|id| id.into()) } /// Returns none if the file of the node is not part of a crate. @@ -2149,7 +2147,7 @@ fn analyze_impl( node: InFile<&SyntaxNode>, offset: Option, // replace this, just make the inference result a `LazyCell` - infer_body: bool, + infer: bool, ) -> Option> { let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered(); @@ -2157,26 +2155,42 @@ fn analyze_impl( let resolver = match container { ChildContainer::DefWithBodyId(def) => { - return Some(if infer_body { + return Some(if infer { SourceAnalyzer::new_for_body(self.db, def, node, offset) } else { SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset) }); } ChildContainer::VariantId(def) => { - return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset)); + return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset, infer)); } ChildContainer::TraitId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); + return Some(if infer { + SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + } else { + SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + }); } ChildContainer::ImplId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); + return Some(if infer { + SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + } else { + SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + }); } ChildContainer::EnumId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); + return Some(if infer { + SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + } else { + SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + }); } ChildContainer::GenericDefId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it, node, offset)); + return Some(if infer { + SourceAnalyzer::new_generic_def(self.db, it, node, offset) + } else { + SourceAnalyzer::new_generic_def_no_infer(self.db, it, node, offset) + }); } ChildContainer::ModuleId(it) => it.resolver(self.db), }; @@ -2259,7 +2273,7 @@ pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool { let Some(def) = def else { return false }; let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax()); - let (body, source_map) = self.db.body_with_source_map(def); + let (body, source_map) = Body::with_source_map(self.db, def); let file_id = self.find_file(expr.syntax()).file_id; @@ -2310,7 +2324,7 @@ pub fn locals_used( let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?; let store = sa.store()?; let mut resolver = sa.resolver.clone(); - let def = resolver.body_owner()?; + let def = resolver.expression_store_owner()?; let is_not_generated = |path: &Path| { !path.mod_path().and_then(|path| path.as_ident()).is_some_and(Name::is_generated) @@ -2501,7 +2515,7 @@ fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option { (crate::Function, ast::Fn, fn_to_def), (crate::Field, ast::RecordField, record_field_to_def), (crate::Field, ast::TupleField, tuple_field_to_def), - (crate::Variant, ast::Variant, enum_variant_to_def), + (crate::EnumVariant, ast::Variant, enum_variant_to_def), (crate::TypeParam, ast::TypeParam, type_param_to_def), (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), (crate::ConstParam, ast::ConstParam, const_param_to_def), @@ -2560,13 +2574,18 @@ pub fn krate(&self) -> Crate { Crate { id: self.resolver.krate() } } + // FIXME: This is a weird function, we shouldn't have this? pub fn containing_function(&self) -> Option { - self.resolver.body_owner().and_then(|owner| match owner { - DefWithBodyId::FunctionId(id) => Some(id.into()), + self.resolver.expression_store_owner().and_then(|owner| match owner { + ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => Some(id.into()), _ => None, }) } + pub fn expression_store_owner(&self) -> Option { + self.resolver.expression_store_owner().map(Into::into) + } + pub(crate) fn resolver(&self) -> &Resolver<'db> { &self.resolver } @@ -2588,14 +2607,18 @@ pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()), - resolver::ScopeDef::Local(binding_id) => match self.resolver.body_owner() { - Some(parent) => ScopeDef::Local(Local { parent, binding_id }), - None => continue, - }, - resolver::ScopeDef::Label(label_id) => match self.resolver.body_owner() { - Some(parent) => ScopeDef::Label(Label { parent, label_id }), - None => continue, - }, + resolver::ScopeDef::Local(binding_id) => { + match self.resolver.expression_store_owner() { + Some(parent) => ScopeDef::Local(Local { parent, binding_id }), + None => continue, + } + } + resolver::ScopeDef::Label(label_id) => { + match self.resolver.expression_store_owner() { + Some(parent) => ScopeDef::Label(Label { parent, label_id }), + None => continue, + } + } }; f(name.clone(), def) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index c1f72debe54f..f6d1bec5754c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -18,8 +18,10 @@ DynMap, keys::{self, Key}, }, + expr_store::Body, hir::generics::GenericParams, item_scope::ItemScope, + signatures::{EnumSignature, ImplSignature, TraitSignature}, src::{HasChildSource, HasSource}, }; @@ -49,7 +51,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi data.items.iter().for_each(|&(_, item)| { add_assoc_item(db, res, file_id, item); }); - let (_, source_map) = db.trait_signature_with_source_map(*self); + let (_, source_map) = TraitSignature::with_source_map(db, *self); source_map.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each( |(ast, &exp_id)| { res[keys::MACRO_CALL].insert(ast.value, exp_id); @@ -74,7 +76,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi data.items.iter().for_each(|&(_, item)| { add_assoc_item(db, res, file_id, item); }); - let (_, source_map) = db.impl_signature_with_source_map(*self); + let (_, source_map) = ImplSignature::with_source_map(db, *self); source_map.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each( |(ast, &exp_id)| { res[keys::MACRO_CALL].insert(ast.value, exp_id); @@ -93,7 +95,6 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi impl ChildBySource for ItemScope { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { - let krate = file_id.krate(db); self.declarations().for_each(|item| add_module_def(db, res, file_id, item)); self.impls().for_each(|imp| insert_item_loc(db, res, file_id, imp, keys::IMPL)); self.extern_blocks().for_each(|extern_block| { @@ -123,6 +124,8 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi |(ast_id, calls)| { let adt = ast_id.to_node(db); calls.for_each(|(attr_id, call_id, calls)| { + // FIXME: Is this the right crate? + let krate = call_id.lookup(db).krate; // FIXME: Fix cfg_attr handling. let (attr, _, _, _) = attr_id.find_attr_range_with_source(db, krate, &adt); res[keys::DERIVE_MACRO_CALL] @@ -203,7 +206,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi self.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| { res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant); }); - let (_, source_map) = db.enum_signature_with_source_map(*self); + let (_, source_map) = EnumSignature::with_source_map(db, *self); source_map .expansions() .filter(|(ast, _)| ast.file_id == file_id) @@ -213,7 +216,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi impl ChildBySource for DefWithBodyId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { - let (body, sm) = db.body_with_source_map(*self); + let (body, sm) = Body::with_source_map(db, *self); if let &DefWithBodyId::VariantId(v) = self { VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id) } @@ -238,8 +241,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi return; } - let (generic_params, _, source_map) = - GenericParams::generic_params_and_store_and_source_map(db, *self); + let (generic_params, _, source_map) = GenericParams::with_source_map(db, *self); let mut toc_idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx); let lts_idx_iter = generic_params.iter_lt().map(|(idx, _)| idx); diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index d222c3dc7ed1..a9a779a287d6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -88,13 +88,14 @@ use either::Either; use hir_def::{ AdtId, BlockId, BuiltinDeriveImplId, ConstId, ConstParamId, DefWithBodyId, EnumId, - EnumVariantId, ExternBlockId, ExternCrateId, FieldId, FunctionId, GenericDefId, GenericParamId, - ImplId, LifetimeParamId, Lookup, MacroId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, - TypeParamId, UnionId, UseId, VariantId, + EnumVariantId, ExpressionStoreOwnerId, ExternBlockId, ExternCrateId, FieldId, FunctionId, + GenericDefId, GenericParamId, ImplId, LifetimeParamId, Lookup, MacroId, ModuleId, StaticId, + StructId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId, VariantId, dyn_map::{ DynMap, keys::{self, Key}, }, + expr_store::{Body, ExpressionStore}, hir::{BindingId, Expr, LabelId}, nameres::{block_def_map, crate_def_map}, }; @@ -334,8 +335,8 @@ pub(super) fn asm_operand_to_def( _ => None, }) .position(|it| it == *src.value)?; - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let source_map = self.db.body_with_source_map(container).1; + let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; + let (_, source_map) = ExpressionStore::with_source_map(self.db, container); let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?.as_expr()?; Some(InlineAsmOperand { owner: container, expr, index }) } @@ -343,13 +344,13 @@ pub(super) fn asm_operand_to_def( pub(super) fn bind_pat_to_def( &mut self, src: InFile<&ast::IdentPat>, - ) -> Option<(DefWithBodyId, BindingId)> { - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let (body, source_map) = self.db.body_with_source_map(container); + ) -> Option<(ExpressionStoreOwnerId, BindingId)> { + let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; + let (store, source_map) = ExpressionStore::with_source_map(self.db, container); let src = src.cloned().map(ast::Pat::from); let pat_id = source_map.node_pat(src.as_ref())?; // the pattern could resolve to a constant, verify that this is not the case - if let crate::Pat::Bind { id, .. } = body[pat_id.as_pat()?] { + if let crate::Pat::Bind { id, .. } = store[pat_id.as_pat()?] { Some((container, id)) } else { None @@ -359,17 +360,19 @@ pub(super) fn self_param_to_def( &mut self, src: InFile<&ast::SelfParam>, ) -> Option<(DefWithBodyId, BindingId)> { - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let body = self.db.body(container); + let container = self + .find_container(src.syntax_ref())? + .as_expression_store_owner()? + .as_def_with_body()?; + let body = Body::of(self.db, container); Some((container, body.self_param?)) } pub(super) fn label_to_def( &mut self, src: InFile<&ast::Label>, - ) -> Option<(DefWithBodyId, LabelId)> { - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let source_map = self.db.body_with_source_map(container).1; - + ) -> Option<(ExpressionStoreOwnerId, LabelId)> { + let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; + let (_, source_map) = ExpressionStore::with_source_map(self.db, container); let label_id = source_map.node_label(src)?; Some((container, label_id)) } @@ -377,13 +380,14 @@ pub(super) fn label_to_def( pub(super) fn label_ref_to_def( &mut self, src: InFile<&ast::Lifetime>, - ) -> Option<(DefWithBodyId, LabelId)> { + ) -> Option<(ExpressionStoreOwnerId, LabelId)> { let break_or_continue = ast::Expr::cast(src.value.syntax().parent()?)?; - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let (body, source_map) = self.db.body_with_source_map(container); + let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; + let (store, source_map) = ExpressionStore::with_source_map(self.db, container); let break_or_continue = source_map.node_expr(src.with_value(&break_or_continue))?.as_expr()?; - let (Expr::Break { label, .. } | Expr::Continue { label }) = body[break_or_continue] else { + let (Expr::Break { label, .. } | Expr::Continue { label }) = store[break_or_continue] + else { return None; }; Some((container, label?)) @@ -557,29 +561,6 @@ fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option) -> Option { - self.parent_ancestors_with_macros(src, |this, InFile { file_id, value }, _| { - let item = match ast::Item::cast(value.clone()) { - Some(it) => it, - None => { - let variant = ast::Variant::cast(value)?; - return this - .enum_variant_to_def(InFile::new(file_id, &variant)) - .map(Into::into); - } - }; - match &item { - ast::Item::Fn(it) => this.fn_to_def(InFile::new(file_id, it)).map(Into::into), - ast::Item::Const(it) => this.const_to_def(InFile::new(file_id, it)).map(Into::into), - ast::Item::Static(it) => { - this.static_to_def(InFile::new(file_id, it)).map(Into::into) - } - _ => None, - } - }) - } - /// Skips the attributed item that caused the macro invocation we are climbing up fn parent_ancestors_with_macros( &mut self, @@ -756,4 +737,22 @@ fn child_by_source(self, db: &dyn HirDatabase, file_id: HirFileId) -> DynMap { ChildContainer::GenericDefId(it) => it.child_by_source(db, file_id), } } + + pub(crate) fn as_expression_store_owner(self) -> Option { + match self { + ChildContainer::DefWithBodyId(it) => Some(it.into()), + ChildContainer::ModuleId(_) => None, + ChildContainer::TraitId(it) => { + Some(ExpressionStoreOwnerId::Signature(GenericDefId::TraitId(it))) + } + ChildContainer::EnumId(it) => { + Some(ExpressionStoreOwnerId::Signature(GenericDefId::AdtId(it.into()))) + } + ChildContainer::ImplId(it) => { + Some(ExpressionStoreOwnerId::Signature(GenericDefId::ImplId(it))) + } + ChildContainer::VariantId(_) => None, + ChildContainer::GenericDefId(it) => Some(it.into()), + } + } } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index c6f2d151f582..1a34fa913425 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -9,18 +9,18 @@ use either::Either; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, - LocalFieldId, ModuleDefId, StructId, TraitId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, + FunctionId, GenericDefId, LocalFieldId, ModuleDefId, StructId, TraitId, VariantId, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId, lower::ExprCollector, path::Path, scope::{ExprScopes, ScopeId}, }, - hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat, PatId}, + hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat, PatId, generics::GenericParams}, lang_item::LangItems, nameres::MacroSubNs, - resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope}, + resolver::{Resolver, TypeNs, ValueNs, resolver_for_scope}, type_ref::{Mutability, TypeRef, TypeRefId}, }; use hir_expand::{ @@ -55,12 +55,11 @@ SyntaxKind, SyntaxNode, TextRange, TextSize, ast::{self, AstNode, RangeItem, RangeOp}, }; -use triomphe::Arc; use crate::{ Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, - DeriveHelper, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, - ToolModule, Trait, TupleField, Type, TypeAlias, Variant, + DeriveHelper, EnumVariant, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, + Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias, db::HirDatabase, semantics::{PathResolution, PathResolutionPerNs}, }; @@ -78,21 +77,23 @@ pub(crate) struct SourceAnalyzer<'db> { pub(crate) enum BodyOrSig<'db> { Body { def: DefWithBodyId, - body: Arc, - source_map: Arc, + body: &'db Body, + source_map: &'db BodySourceMap, infer: Option<&'db InferenceResult>, }, - // To be folded into body once it is considered one VariantFields { def: VariantId, - store: Arc, - source_map: Arc, + store: &'db ExpressionStore, + source_map: &'db ExpressionStoreSourceMap, + infer: Option<&'db InferenceResult>, }, Sig { def: GenericDefId, - store: Arc, - source_map: Arc, - // infer: Option>, + store: &'db ExpressionStore, + source_map: &'db ExpressionStoreSourceMap, + infer: Option<&'db InferenceResult>, + #[expect(dead_code)] + generics: &'db GenericParams, }, } @@ -103,7 +104,7 @@ pub(crate) fn new_for_body( node: InFile<&SyntaxNode>, offset: Option, ) -> SourceAnalyzer<'db> { - Self::new_for_body_(db, def, node, offset, Some(InferenceResult::for_body(db, def))) + Self::new_for_body_(db, def, node, offset, Some(InferenceResult::of(db, def))) } pub(crate) fn new_for_body_no_infer( @@ -122,10 +123,10 @@ pub(crate) fn new_for_body_( offset: Option, infer: Option<&'db InferenceResult>, ) -> SourceAnalyzer<'db> { - let (body, source_map) = db.body_with_source_map(def); - let scopes = db.expr_scopes(def); + let (body, source_map) = Body::with_source_map(db, def); + let scopes = ExprScopes::of(db, def); let scope = match offset { - None => scope_for(db, &scopes, &source_map, node), + None => scope_for(db, scopes, source_map, node), Some(offset) => { debug_assert!( node.text_range().contains_inclusive(offset), @@ -133,7 +134,7 @@ pub(crate) fn new_for_body_( offset, node.text_range() ); - scope_for_offset(db, &scopes, &source_map, node.file_id, offset) + scope_for_offset(db, scopes, source_map, node.file_id, offset) } }; let resolver = resolver_for_scope(db, def, scope); @@ -147,14 +148,47 @@ pub(crate) fn new_for_body_( pub(crate) fn new_generic_def( db: &'db dyn HirDatabase, def: GenericDefId, - InFile { file_id, .. }: InFile<&SyntaxNode>, - _offset: Option, + node: InFile<&SyntaxNode>, + offset: Option, ) -> SourceAnalyzer<'db> { - let (_params, store, source_map) = db.generic_params_and_store_and_source_map(def); - let resolver = def.resolver(db); + Self::new_generic_def_(db, def, node, offset, true) + } + + pub(crate) fn new_generic_def_no_infer( + db: &'db dyn HirDatabase, + def: GenericDefId, + node: InFile<&SyntaxNode>, + offset: Option, + ) -> SourceAnalyzer<'db> { + Self::new_generic_def_(db, def, node, offset, false) + } + + pub(crate) fn new_generic_def_( + db: &'db dyn HirDatabase, + def: GenericDefId, + node @ InFile { file_id, .. }: InFile<&SyntaxNode>, + offset: Option, + infer: bool, + ) -> SourceAnalyzer<'db> { + let (generics, store, source_map) = GenericParams::with_source_map(db, def); + let scopes = ExprScopes::of(db, def); + let scope = match offset { + None => scope_for(db, scopes, source_map, node), + Some(offset) => { + debug_assert!( + node.text_range().contains_inclusive(offset), + "{:?} not in {:?}", + offset, + node.text_range() + ); + scope_for_offset(db, scopes, source_map, node.file_id, offset) + } + }; + let resolver = resolver_for_scope(db, def, scope); + let infer = if infer { Some(InferenceResult::of(db, def)) } else { None }; SourceAnalyzer { resolver, - body_or_sig: Some(BodyOrSig::Sig { def, store, source_map }), + body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }), file_id, } } @@ -162,17 +196,33 @@ pub(crate) fn new_generic_def( pub(crate) fn new_variant_body( db: &'db dyn HirDatabase, def: VariantId, - InFile { file_id, .. }: InFile<&SyntaxNode>, - _offset: Option, + node @ InFile { file_id, .. }: InFile<&SyntaxNode>, + offset: Option, + infer: bool, ) -> SourceAnalyzer<'db> { let (fields, source_map) = def.fields_with_source_map(db); - let resolver = def.resolver(db); + let scopes = ExprScopes::of(db, def); + let scope = match offset { + None => scope_for(db, scopes, source_map, node), + Some(offset) => { + debug_assert!( + node.text_range().contains_inclusive(offset), + "{:?} not in {:?}", + offset, + node.text_range() + ); + scope_for_offset(db, scopes, source_map, node.file_id, offset) + } + }; + let resolver = resolver_for_scope(db, def, scope); + let infer = if infer { Some(InferenceResult::of(db, def)) } else { None }; SourceAnalyzer { resolver, body_or_sig: Some(BodyOrSig::VariantFields { def, - store: fields.store.clone(), - source_map: source_map.clone(), + store: &fields.store, + source_map, + infer, }), file_id, } @@ -185,29 +235,40 @@ pub(crate) fn new_for_resolver( SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id } } - // FIXME: Remove this - fn body_(&self) -> Option<(DefWithBodyId, &Body, &BodySourceMap, Option<&InferenceResult>)> { - self.body_or_sig.as_ref().and_then(|it| match it { - BodyOrSig::Body { def, body, source_map, infer } => { - Some((*def, &**body, &**source_map, infer.as_deref())) - } - _ => None, + fn owner(&self) -> Option { + self.body_or_sig.as_ref().map(|it| match *it { + BodyOrSig::VariantFields { def, .. } => def.into(), + BodyOrSig::Sig { def, .. } => def.into(), + BodyOrSig::Body { def, .. } => def.into(), }) } fn infer(&self) -> Option<&InferenceResult> { self.body_or_sig.as_ref().and_then(|it| match it { - BodyOrSig::Sig { .. } => None, - BodyOrSig::VariantFields { .. } => None, - BodyOrSig::Body { infer, .. } => infer.as_deref(), + BodyOrSig::VariantFields { infer, .. } + | BodyOrSig::Sig { infer, .. } + | BodyOrSig::Body { infer, .. } => infer.as_deref(), }) } - fn body(&self) -> Option<&Body> { - self.body_or_sig.as_ref().and_then(|it| match it { - BodyOrSig::Sig { .. } => None, - BodyOrSig::VariantFields { .. } => None, - BodyOrSig::Body { body, .. } => Some(&**body), + pub(crate) fn def( + &self, + ) -> Option<( + ExpressionStoreOwnerId, + &ExpressionStore, + &ExpressionStoreSourceMap, + Option<&InferenceResult>, + )> { + self.body_or_sig.as_ref().map(|it| match *it { + BodyOrSig::VariantFields { def, store, source_map, infer, .. } => { + (def.into(), store, source_map, infer) + } + BodyOrSig::Sig { def, store, source_map, infer, .. } => { + (def.into(), store, source_map, infer) + } + BodyOrSig::Body { def, body, source_map, infer, .. } => { + (def.into(), &body.store, &source_map.store, infer) + } }) } @@ -232,11 +293,13 @@ fn param_and<'a>(&self, param_env: ParamEnv<'a>) -> ParamEnvAndCrate<'a> { } fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { - self.param_and( - self.body_() - .map(|(def, ..)| def) - .map_or_else(ParamEnv::empty, |def| db.trait_environment_for_body(def)), - ) + self.param_and(self.body_or_sig.as_ref().map_or_else(ParamEnv::empty, |body_or_sig| { + match *body_or_sig { + BodyOrSig::Body { def, .. } => db.trait_environment(def.into()), + BodyOrSig::VariantFields { def, .. } => db.trait_environment(def.into()), + BodyOrSig::Sig { def, .. } => db.trait_environment(def.into()), + } + })) } pub(crate) fn expr_id(&self, expr: ast::Expr) -> Option { @@ -371,7 +434,10 @@ pub(crate) fn type_of_self( db: &'db dyn HirDatabase, _param: &ast::SelfParam, ) -> Option> { - let binding = self.body()?.self_param?; + let binding = match self.body_or_sig.as_ref()? { + BodyOrSig::Sig { .. } | BodyOrSig::VariantFields { .. } => return None, + BodyOrSig::Body { body, .. } => body.self_param?, + }; let ty = self.infer()?.binding_ty(binding); Some(Type::new_with_resolver(db, &self.resolver, ty)) } @@ -472,7 +538,7 @@ pub(crate) fn resolve_field( &self, field: &ast::FieldExpr, ) -> Option> { - let (def, ..) = self.body_()?; + let def = self.owner()?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; self.infer()?.field_resolution(expr_id).map(|it| { it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index }) @@ -499,7 +565,7 @@ pub(crate) fn resolve_field_fallback( field: &ast::FieldExpr, ) -> Option<(Either, Function>, Option>)> { - let (def, ..) = self.body_()?; + let def = self.owner()?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; let inference_result = self.infer()?; match inference_result.field_resolution(expr_id) { @@ -771,7 +837,7 @@ pub(crate) fn resolve_record_field( name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())), ) { Some(ValueNs::LocalBinding(binding_id)) => { - Some(Local { binding_id, parent: self.resolver.body_owner()? }) + Some(Local { binding_id, parent: self.resolver.expression_store_owner()? }) } _ => None, } @@ -831,8 +897,8 @@ pub(crate) fn resolve_bind_pat_to_const( }, }; - let body_owner = self.resolver.body_owner(); - let res = resolve_hir_value_path(db, &self.resolver, body_owner, path, HygieneId::ROOT)?; + let store_owner = self.resolver.expression_store_owner(); + let res = resolve_hir_value_path(db, &self.resolver, store_owner, path, HygieneId::ROOT)?; match res { PathResolution::Def(def) => Some(def), _ => None, @@ -843,7 +909,7 @@ pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option Option<(Either, GenericSubstitution<'db>)> { + ) -> Option<(Either, GenericSubstitution<'db>)> { let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?; let container = offset_of_expr.ty()?; let container = self.type_of_type(db, &container)?; @@ -902,7 +968,7 @@ pub(crate) fn resolve_offset_of_field( let variants = id.enum_variants(db); let variant = variants.variant(&field_name.as_name())?; container = Either::Left((variant, subst)); - (Either::Left(Variant { id: variant }), id.into(), subst) + (Either::Left(EnumVariant { id: variant }), id.into(), subst) } }, _ => return None, @@ -982,7 +1048,10 @@ pub(crate) fn resolve_path( if let Some(VariantId::EnumVariantId(variant)) = infer.variant_resolution_for_expr_or_pat(expr_id) { - return Some((PathResolution::Def(ModuleDef::Variant(variant.into())), None)); + return Some(( + PathResolution::Def(ModuleDef::EnumVariant(variant.into())), + None, + )); } prefer_value_ns = true; } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) { @@ -1014,14 +1083,20 @@ pub(crate) fn resolve_path( if let Some(VariantId::EnumVariantId(variant)) = infer.variant_resolution_for_expr_or_pat(expr_or_pat_id) { - return Some((PathResolution::Def(ModuleDef::Variant(variant.into())), None)); + return Some(( + PathResolution::Def(ModuleDef::EnumVariant(variant.into())), + None, + )); } } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) { let expr_id = self.expr_id(rec_lit.into())?; if let Some(VariantId::EnumVariantId(variant)) = infer.variant_resolution_for_expr_or_pat(expr_id) { - return Some((PathResolution::Def(ModuleDef::Variant(variant.into())), None)); + return Some(( + PathResolution::Def(ModuleDef::EnumVariant(variant.into())), + None, + )); } } else { let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from); @@ -1032,7 +1107,7 @@ pub(crate) fn resolve_path( let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id.as_pat()?); if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat { return Some(( - PathResolution::Def(ModuleDef::Variant(variant.into())), + PathResolution::Def(ModuleDef::EnumVariant(variant.into())), None, )); } @@ -1045,7 +1120,7 @@ pub(crate) fn resolve_path( } // FIXME: collectiong here shouldnt be necessary? - let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id); + let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id); let hir_path = collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?; let parent_hir_path = path @@ -1253,7 +1328,7 @@ pub(crate) fn resolve_hir_path_per_ns( db: &dyn HirDatabase, path: &ast::Path, ) -> Option { - let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id); + let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id); let hir_path = collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?; let (store, _) = collector.store.finish(); @@ -1366,7 +1441,7 @@ pub(crate) fn is_unsafe_macro_call_expr( db: &'db dyn HirDatabase, macro_expr: InFile<&ast::MacroExpr>, ) -> bool { - if let Some((def, body, sm, Some(infer))) = self.body_() + if let Some((def, body, sm, Some(infer))) = self.def() && let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) { let mut is_unsafe = false; @@ -1400,7 +1475,7 @@ pub(crate) fn resolve_offset_in_format_args( resolve_hir_value_path( db, &self.resolver, - self.resolver.body_owner(), + self.resolver.expression_store_owner(), &Path::from_known_path_with_no_generic(ModPath::from_segments( PathKind::Plain, Some(name.clone()), @@ -1416,9 +1491,9 @@ pub(crate) fn resolve_offset_in_asm_template( asm: InFile<&ast::AsmExpr>, line: usize, offset: TextSize, - ) -> Option<(DefWithBodyId, (ExprId, TextRange, usize))> { - let (def, _, body_source_map, _) = self.body_()?; - let (expr, args) = body_source_map.asm_template_args(asm)?; + ) -> Option<(ExpressionStoreOwnerId, (ExprId, TextRange, usize))> { + let (def, _, sm, _) = self.def()?; + let (expr, args) = sm.asm_template_args(asm)?; Some(def).zip( args.get(line)? .iter() @@ -1439,7 +1514,7 @@ pub(crate) fn as_format_args_parts<'a>( resolve_hir_value_path( db, &self.resolver, - self.resolver.body_owner(), + self.resolver.expression_store_owner(), &Path::from_known_path_with_no_generic(ModPath::from_segments( PathKind::Plain, Some(name.clone()), @@ -1453,9 +1528,9 @@ pub(crate) fn as_format_args_parts<'a>( pub(crate) fn as_asm_parts( &self, asm: InFile<&ast::AsmExpr>, - ) -> Option<(DefWithBodyId, (ExprId, &[Vec<(TextRange, usize)>]))> { - let (def, _, body_source_map, _) = self.body_()?; - Some(def).zip(body_source_map.asm_template_args(asm)) + ) -> Option<(ExpressionStoreOwnerId, (ExprId, &[Vec<(TextRange, usize)>]))> { + let (def, _, sm, _) = self.def()?; + Some(def).zip(sm.asm_template_args(asm)) } fn resolve_impl_method_or_trait_def( @@ -1473,11 +1548,11 @@ fn resolve_impl_method_or_trait_def_with_subst( func: FunctionId, substs: GenericArgs<'db>, ) -> (Function, GenericArgs<'db>) { - let owner = match self.resolver.body_owner() { + let owner = match self.resolver.expression_store_owner() { Some(it) => it, None => return (func.into(), substs), }; - let env = self.param_and(db.trait_environment_for_body(owner)); + let env = self.param_and(db.trait_environment(owner)); let (func, args) = db.lookup_impl_method(env, func, substs); match func { Either::Left(func) => (func.into(), args), @@ -1493,11 +1568,11 @@ fn resolve_impl_const_or_trait_def_with_subst( const_id: ConstId, subs: GenericArgs<'db>, ) -> (ConstId, GenericArgs<'db>) { - let owner = match self.resolver.body_owner() { + let owner = match self.resolver.expression_store_owner() { Some(it) => it, None => return (const_id, subs), }; - let env = self.param_and(db.trait_environment_for_body(owner)); + let env = self.param_and(db.trait_environment(owner)); let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); method_resolution::lookup_impl_const(&infcx, env.param_env, const_id, subs) @@ -1526,7 +1601,7 @@ fn ty_of_expr(&self, expr: ast::Expr) -> Option> { fn scope_for( db: &dyn HirDatabase, scopes: &ExprScopes, - source_map: &BodySourceMap, + source_map: &ExpressionStoreSourceMap, node: InFile<&SyntaxNode>, ) -> Option { node.ancestors_with_macros(db) @@ -1545,7 +1620,7 @@ fn scope_for( fn scope_for_offset( db: &dyn HirDatabase, scopes: &ExprScopes, - source_map: &BodySourceMap, + source_map: &ExpressionStoreSourceMap, from_file: HirFileId, offset: TextSize, ) -> Option { @@ -1579,7 +1654,7 @@ fn scope_for_offset( fn adjust( db: &dyn HirDatabase, scopes: &ExprScopes, - source_map: &BodySourceMap, + source_map: &ExpressionStoreSourceMap, expr_range: TextRange, from_file: HirFileId, offset: TextSize, @@ -1684,7 +1759,7 @@ fn resolve_hir_path_( TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { PathResolution::Def(Adt::from(it).into()) } - TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), + TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), @@ -1708,7 +1783,7 @@ fn resolve_hir_path_( } }; - let body_owner = resolver.body_owner(); + let body_owner = resolver.expression_store_owner(); let values = || resolve_hir_value_path(db, resolver, body_owner, path, hygiene); let items = || { @@ -1754,21 +1829,21 @@ fn resolve_hir_path_( fn resolve_hir_value_path( db: &dyn HirDatabase, resolver: &Resolver<'_>, - body_owner: Option, + store_owner: Option, path: &Path, hygiene: HygieneId, ) -> Option { resolver.resolve_path_in_value_ns_fully(db, path, hygiene).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { - let var = Local { parent: body_owner?, binding_id }; + let var = Local { parent: store_owner?, binding_id }; PathResolution::Local(var) } ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), - ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), + ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()), }; @@ -1833,7 +1908,7 @@ fn resolve_hir_path_qualifier( TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { PathResolution::Def(Adt::from(it).into()) } - TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), + TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index c088f3aa0cc0..ff56544d82e0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -8,9 +8,11 @@ AdtId, AssocItemId, AstIdLoc, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, db::DefDatabase, + expr_store::Body, item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob}, nameres::crate_def_map, per_ns::Item, + signatures::{EnumSignature, ImplSignature, TraitSignature}, src::{HasChildSource, HasSource}, visibility::{Visibility, VisibilityExplicitness}, }; @@ -185,7 +187,7 @@ fn collect_from_module(&mut self, module_id: ModuleId) { } ModuleDefId::AdtId(AdtId::EnumId(id)) => { this.push_decl(id, name, false, None); - let enum_name = Symbol::intern(this.db.enum_signature(id).name.as_str()); + let enum_name = Symbol::intern(EnumSignature::of(this.db, id).name.as_str()); this.with_container_name(Some(enum_name), |this| { let variants = id.enum_variants(this.db); for (variant_id, variant_name, _) in &variants.variants { @@ -386,7 +388,7 @@ fn collect_from_body(&mut self, body_id: impl Into, name: Option< return; } let body_id = body_id.into(); - let body = self.db.body(body_id); + let body = Body::of(self.db, body_id); // Descend into the blocks and enqueue collection of all modules within. for (_, def_map) in body.blocks(self.db) { @@ -397,7 +399,7 @@ fn collect_from_body(&mut self, body_id: impl Into, name: Option< } fn collect_from_impl(&mut self, impl_id: ImplId) { - let impl_data = self.db.impl_signature(impl_id); + let impl_data = ImplSignature::of(self.db, impl_id); let impl_name = Some( hir_display_with_store(impl_data.self_ty, &impl_data.store) .display( @@ -419,7 +421,7 @@ fn collect_from_impl(&mut self, impl_id: ImplId) { } fn collect_from_trait(&mut self, trait_id: TraitId, trait_do_not_complete: Complete) { - let trait_data = self.db.trait_signature(trait_id); + let trait_data = TraitSignature::of(self.db, trait_id); self.with_container_name(Some(Symbol::intern(trait_data.name.as_str())), |s| { for &(ref name, assoc_item_id) in &trait_id.trait_items(self.db).items { s.push_assoc_item(assoc_item_id, name, Some(trait_do_not_complete)); diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs index e56f9e91e3f3..e3d0121e4912 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs @@ -10,8 +10,8 @@ use span::Edition; use crate::{ - Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, Local, ModuleDef, - SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant, + Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, EnumVariant, Field, Function, Local, + ModuleDef, SemanticsScope, Static, Struct, StructKind, Trait, Type, }; /// Helper function to get path to `ModuleDef` @@ -80,7 +80,7 @@ pub enum Expr<'db> { params: Vec>, }, /// Enum variant construction - Variant { variant: Variant, generics: Vec>, params: Vec> }, + Variant { variant: EnumVariant, generics: Vec>, params: Vec> }, /// Struct construction Struct { strukt: Struct, generics: Vec>, params: Vec> }, /// Tuple construction @@ -222,7 +222,7 @@ pub fn gen_source_code( StructKind::Unit => String::new(), }; - let prefix = mod_item_path_str(sema_scope, &ModuleDef::Variant(*variant))?; + let prefix = mod_item_path_str(sema_scope, &ModuleDef::EnumVariant(*variant))?; Ok(format!("{prefix}{inner}")) } Expr::Struct { strukt, params, .. } => { diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs index 8622aa1378b3..c7ef4e5d5deb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs @@ -53,7 +53,7 @@ pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( ScopeDef::GenericParam(GenericParam::ConstParam(it)) => Some(Expr::ConstParam(*it)), ScopeDef::Local(it) => { if ctx.config.enable_borrowcheck { - let borrowck = db.borrowck(it.parent).ok()?; + let borrowck = db.borrowck(it.parent.as_def_with_body()?).ok()?; let invalid = borrowck.iter().any(|b| { b.partially_moved.iter().any(|moved| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index 99ee50fa5848..da1322de4b64 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -84,6 +84,7 @@ fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Exp match parent { ast::LetStmt(it) => it.initializer()?, ast::LetExpr(it) => it.expr()?, + ast::BinExpr(it) => it.rhs()?, ast::Static(it) => it.body()?, ast::Const(it) => it.body()?, _ => return None, @@ -174,6 +175,70 @@ fn foo() { n + 100 }; } +"#, + ); + + check_assist( + add_braces, + r#" +fn foo() { + let x; + x =$0 n + 100; +} +"#, + r#" +fn foo() { + let x; + x = { + n + 100 + }; +} +"#, + ); + + check_assist( + add_braces, + r#" +fn foo() { + if let x =$0 n + 100 {} +} +"#, + r#" +fn foo() { + if let x = { + n + 100 + } {} +} +"#, + ); + } + + #[test] + fn suggest_add_braces_for_const_initializer() { + check_assist( + add_braces, + r#" +const X: i32 =$0 1 + 2; +"#, + r#" +const X: i32 = { + 1 + 2 +}; +"#, + ); + } + + #[test] + fn suggest_add_braces_for_static_initializer() { + check_assist( + add_braces, + r#" +static X: i32 $0= 1 + 2; +"#, + r#" +static X: i32 = { + 1 + 2 +}; "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs index 7960373e6193..75c5f84b8501 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs @@ -47,7 +47,7 @@ pub(crate) fn add_explicit_enum_discriminant( // Don't offer the assist if the enum has no variants or if all variants already have an // explicit discriminant. - if variant_list.variants().all(|variant_node| variant_node.expr().is_some()) { + if variant_list.variants().all(|variant_node| variant_node.const_arg().is_some()) { return None; } @@ -72,7 +72,9 @@ fn add_variant_discriminant( variant_node: &ast::Variant, radix: &mut Radix, ) { - if let Some(expr) = variant_node.expr() { + if let Some(expr) = variant_node.const_arg() + && let Some(expr) = expr.expr() + { *radix = expr_radix(&expr).unwrap_or(*radix); return; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs index b84ad24cfcef..6a408e5254fd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs @@ -3,11 +3,7 @@ }; use syntax::{ SyntaxToken, T, - ast::{ - self, AstNode, HasLoopBody, - make::{self, tokens}, - syntax_factory::SyntaxFactory, - }, + ast::{self, AstNode, HasLoopBody, syntax_factory::SyntaxFactory}, syntax_editor::{Position, SyntaxEditor}, }; @@ -35,9 +31,9 @@ // } // ``` pub(crate) fn add_label_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let loop_kw = ctx.find_token_syntax_at_offset(T![loop])?; - let loop_expr = loop_kw.parent().and_then(ast::LoopExpr::cast)?; - if loop_expr.label().is_some() { + let loop_expr = ctx.find_node_at_offset::()?; + let loop_kw = loop_token(&loop_expr)?; + if loop_expr.label().is_some() || !loop_kw.text_range().contains_inclusive(ctx.offset()) { return None; } @@ -52,8 +48,8 @@ pub(crate) fn add_label_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) -> O let label = make.lifetime("'l"); let elements = vec![ label.syntax().clone().into(), - make::token(T![:]).into(), - tokens::single_space().into(), + make.token(T![:]).into(), + make.whitespace(" ").into(), ]; editor.insert_all(Position::before(&loop_kw), elements); @@ -80,6 +76,14 @@ pub(crate) fn add_label_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) -> O ) } +fn loop_token(loop_expr: &ast::AnyHasLoopBody) -> Option { + loop_expr + .syntax() + .children_with_tokens() + .filter_map(|it| it.into_token()) + .find(|it| matches!(it.kind(), T![for] | T![loop] | T![while])) +} + fn insert_label_after_token( editor: &mut SyntaxEditor, make: &SyntaxFactory, @@ -88,7 +92,7 @@ fn insert_label_after_token( builder: &mut SourceChangeBuilder, ) { let label = make.lifetime("'l"); - let elements = vec![tokens::single_space().into(), label.syntax().clone().into()]; + let elements = vec![make.whitespace(" ").into(), label.syntax().clone().into()]; editor.insert_all(Position::after(token), elements); if let Some(cap) = ctx.config.snippet_cap { @@ -123,6 +127,48 @@ fn main() { ); } + #[test] + fn add_label_to_while_expr() { + check_assist( + add_label_to_loop, + r#" +fn main() { + while$0 true { + break; + continue; + } +}"#, + r#" +fn main() { + ${1:'l}: while true { + break ${2:'l}; + continue ${0:'l}; + } +}"#, + ); + } + + #[test] + fn add_label_to_for_expr() { + check_assist( + add_label_to_loop, + r#" +fn main() { + for$0 _ in 0..5 { + break; + continue; + } +}"#, + r#" +fn main() { + ${1:'l}: for _ in 0..5 { + break ${2:'l}; + continue ${0:'l}; + } +}"#, + ); + } + #[test] fn add_label_to_outer_loop() { check_assist( @@ -191,6 +237,31 @@ fn main() { break 'l; continue 'l; } +}"#, + ); + } + + #[test] + fn do_not_add_label_if_outside_keyword() { + check_assist_not_applicable( + add_label_to_loop, + r#" +fn main() { + 'l: loop {$0 + break 'l; + continue 'l; + } +}"#, + ); + + check_assist_not_applicable( + add_label_to_loop, + r#" +fn main() { + 'l: while true {$0 + break 'l; + continue 'l; + } }"#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs index 27dbdcf2c4d5..265ee3d2d4e7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs @@ -1,4 +1,7 @@ -use syntax::ast::{self, AstNode, HasGenericParams, HasName}; +use syntax::{ + SyntaxKind, SyntaxNode, SyntaxToken, + ast::{self, AstNode, HasGenericParams, HasName}, +}; use crate::{AssistContext, AssistId, Assists}; @@ -21,7 +24,7 @@ // ``` pub(crate) fn add_lifetime_to_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let ref_type_focused = ctx.find_node_at_offset::()?; - if ref_type_focused.lifetime().is_some() { + if ref_type_focused.lifetime().is_some_and(|lifetime| lifetime.text() != "'_") { return None; } @@ -34,10 +37,10 @@ pub(crate) fn add_lifetime_to_type(acc: &mut Assists, ctx: &AssistContext<'_>) - return None; } - let ref_types = fetch_borrowed_types(&node)?; + let changes = fetch_borrowed_types(&node)?; let target = node.syntax().text_range(); - acc.add(AssistId::generate("add_lifetime_to_type"), "Add lifetime", target, |builder| { + acc.add(AssistId::quick_fix("add_lifetime_to_type"), "Add lifetime", target, |builder| { match node.generic_param_list() { Some(gen_param) => { if let Some(left_angle) = gen_param.l_angle_token() { @@ -51,16 +54,21 @@ pub(crate) fn add_lifetime_to_type(acc: &mut Assists, ctx: &AssistContext<'_>) - } } - for ref_type in ref_types { - if let Some(amp_token) = ref_type.amp_token() { - builder.insert(amp_token.text_range().end(), "'a "); + for change in changes { + match change { + Change::Replace(it) => { + builder.replace(it.text_range(), "'a"); + } + Change::Insert(it) => { + builder.insert(it.text_range().end(), "'a "); + } } } }) } -fn fetch_borrowed_types(node: &ast::Adt) -> Option> { - let ref_types: Vec = match node { +fn fetch_borrowed_types(node: &ast::Adt) -> Option> { + let ref_types: Vec<_> = match node { ast::Adt::Enum(enum_) => { let variant_list = enum_.variant_list()?; variant_list @@ -79,55 +87,50 @@ fn fetch_borrowed_types(node: &ast::Adt) -> Option> { } ast::Adt::Union(un) => { let record_field_list = un.record_field_list()?; - record_field_list - .fields() - .filter_map(|r_field| { - if let ast::Type::RefType(ref_type) = r_field.ty()? - && ref_type.lifetime().is_none() - { - return Some(ref_type); - } - - None - }) - .collect() + find_ref_types_from_field_list(&record_field_list.into())? } }; if ref_types.is_empty() { None } else { Some(ref_types) } } -fn find_ref_types_from_field_list(field_list: &ast::FieldList) -> Option> { - let ref_types: Vec = match field_list { - ast::FieldList::RecordFieldList(record_list) => record_list - .fields() - .filter_map(|f| { - if let ast::Type::RefType(ref_type) = f.ty()? - && ref_type.lifetime().is_none() - { - return Some(ref_type); - } - - None - }) - .collect(), - ast::FieldList::TupleFieldList(tuple_field_list) => tuple_field_list - .fields() - .filter_map(|f| { - if let ast::Type::RefType(ref_type) = f.ty()? - && ref_type.lifetime().is_none() - { - return Some(ref_type); - } - - None - }) - .collect(), +fn find_ref_types_from_field_list(field_list: &ast::FieldList) -> Option> { + let ref_types: Vec<_> = match field_list { + ast::FieldList::RecordFieldList(record_list) => { + record_list.fields().flat_map(|f| infer_lifetimes(f.syntax())).collect() + } + ast::FieldList::TupleFieldList(tuple_field_list) => { + tuple_field_list.fields().flat_map(|f| infer_lifetimes(f.syntax())).collect() + } }; if ref_types.is_empty() { None } else { Some(ref_types) } } +enum Change { + Replace(SyntaxToken), + Insert(SyntaxToken), +} + +fn infer_lifetimes(node: &SyntaxNode) -> Vec { + node.children() + .filter(|it| !matches!(it.kind(), SyntaxKind::FN_PTR_TYPE | SyntaxKind::TYPE_BOUND_LIST)) + .flat_map(|it| { + infer_lifetimes(&it) + .into_iter() + .chain(ast::Lifetime::cast(it.clone()).and_then(|lt| { + lt.lifetime_ident_token().filter(|lt| lt.text() == "'_").map(Change::Replace) + })) + .chain( + ast::RefType::cast(it) + .filter(|ty| ty.lifetime().is_none()) + .and_then(|ty| ty.amp_token()) + .map(Change::Insert), + ) + }) + .collect() +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -164,6 +167,24 @@ fn add_lifetime_to_struct() { check_assist_not_applicable(add_lifetime_to_type, r#"struct Foo { a: &'a$0 i32 }"#); } + #[test] + fn add_lifetime_to_nested_types() { + check_assist( + add_lifetime_to_type, + r#"struct Foo { a: &$0i32, b: &(&i32, fn(&str) -> &str) }"#, + r#"struct Foo<'a> { a: &'a i32, b: &'a (&'a i32, fn(&str) -> &str) }"#, + ); + } + + #[test] + fn add_lifetime_to_explicit_infer_lifetime() { + check_assist( + add_lifetime_to_type, + r#"struct Foo { a: &'_ $0i32, b: &'_ (&'_ i32, fn(&str) -> &str) }"#, + r#"struct Foo<'a> { a: &'a i32, b: &'a (&'a i32, fn(&str) -> &str) }"#, + ); + } + #[test] fn add_lifetime_to_enum() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index c0ce057d7798..b063e5ffce87 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -3,14 +3,14 @@ use either::Either; use hir::{Adt, AsAssocItem, Crate, FindPathConfig, HasAttrs, ModuleDef, Semantics}; use ide_db::RootDatabase; -use ide_db::assists::ExprFillDefaultMode; use ide_db::syntax_helpers::suggest_name; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; -use syntax::ToSmolStr; -use syntax::ast::edit::{AstNodeEdit, IndentLevel}; +use syntax::ast::edit::IndentLevel; use syntax::ast::syntax_factory::SyntaxFactory; use syntax::ast::{self, AstNode, MatchArmList, MatchExpr, Pat, make}; +use syntax::syntax_editor::{Position, SyntaxEditor}; +use syntax::{SyntaxKind, SyntaxNode, ToSmolStr}; use crate::{AssistContext, AssistId, Assists, utils}; @@ -80,9 +80,16 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let module = scope.module(); let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(scope.krate())); let self_ty = if ctx.config.prefer_self_ty { - scope - .containing_function() - .and_then(|function| function.as_assoc_item(ctx.db())?.implementing_ty(ctx.db())) + scope.expression_store_owner().and_then(|def| { + match def { + hir::ExpressionStoreOwner::Body(def_with_body) => { + def_with_body.as_assoc_item(ctx.db()) + } + hir::ExpressionStoreOwner::Signature(def) => def.as_assoc_item(ctx.db()), + hir::ExpressionStoreOwner::VariantFields(_) => None, + }? + .implementing_ty(ctx.db()) + }) } else { None }; @@ -224,68 +231,26 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) // having any hidden variants means that we need a catch-all arm needs_catch_all_arm |= has_hidden_variants; - let missing_arms = missing_pats + let mut missing_arms = missing_pats .filter(|(_, hidden)| { // filter out hidden patterns because they're handled by the catch-all arm !hidden }) - .map(|(pat, _)| { - make.match_arm( - pat, - None, - match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }, - ) - }); - - let mut arms: Vec<_> = match_arm_list - .arms() - .filter(|arm| { - if matches!(arm.pat(), Some(ast::Pat::WildcardPat(_))) { - let is_empty_expr = arm.expr().is_none_or(|e| match e { - ast::Expr::BlockExpr(b) => { - b.statements().next().is_none() && b.tail_expr().is_none() - } - ast::Expr::TupleExpr(t) => t.fields().next().is_none(), - _ => false, - }); - if is_empty_expr { - false - } else { - cov_mark::hit!(add_missing_match_arms_empty_expr); - true - } - } else { - true - } - }) - .map(|arm| arm.reset_indent().indent(IndentLevel(1))) - .collect(); - - let first_new_arm_idx = arms.len(); - arms.extend(missing_arms); + .map(|(pat, _)| make.match_arm(pat, None, utils::expr_fill_default(ctx.config))) + .collect::>(); if needs_catch_all_arm && !has_catch_all_arm { cov_mark::hit!(added_wildcard_pattern); let arm = make.match_arm( make.wildcard_pat().into(), None, - match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }, + utils::expr_fill_default(ctx.config), ); - arms.push(arm); + missing_arms.push(arm); } - let new_match_arm_list = make.match_arm_list(arms); - // FIXME: Hack for syntax trees not having great support for macros - // Just replace the element that the original range came from + // Just edit the element that the original range came from let old_place = { // Find the original element let file = ctx.sema.parse(arm_list_range.file_id); @@ -302,25 +267,27 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) }; let mut editor = builder.make_editor(&old_place); - let new_match_arm_list = new_match_arm_list.indent(IndentLevel::from_node(&old_place)); - editor.replace(old_place, new_match_arm_list.syntax()); + let mut arms_edit = ArmsEdit { match_arm_list, place: old_place, last_arm: None }; + + arms_edit.remove_wildcard_arms(ctx, &mut editor); + arms_edit.add_comma_after_last_arm(ctx, &make, &mut editor); + arms_edit.append_arms(&missing_arms, &make, &mut editor); if let Some(cap) = ctx.config.snippet_cap { - if let Some(it) = new_match_arm_list - .arms() - .nth(first_new_arm_idx) + if let Some(it) = missing_arms + .first() .and_then(|arm| arm.syntax().descendants().find_map(ast::WildcardPat::cast)) { editor.add_annotation(it.syntax(), builder.make_placeholder_snippet(cap)); } - for arm in new_match_arm_list.arms().skip(first_new_arm_idx) { + for arm in &missing_arms { if let Some(expr) = arm.expr() { editor.add_annotation(expr.syntax(), builder.make_placeholder_snippet(cap)); } } - if let Some(arm) = new_match_arm_list.arms().skip(first_new_arm_idx).last() { + if let Some(arm) = missing_arms.last() { editor.add_annotation(arm.syntax(), builder.make_tabstop_after(cap)); } } @@ -347,12 +314,24 @@ fn cursor_at_trivial_match_arm_list( // $0 // } if let Some(last_arm) = match_arm_list.arms().last() { - let last_arm_range = ctx.sema.original_range_opt(last_arm.syntax())?.range; + let last_node = match last_arm.expr() { + Some(expr) => expr.syntax().clone(), + None => last_arm.syntax().clone(), + }; + let last_node_range = ctx.sema.original_range_opt(&last_node)?.range; let match_expr_range = ctx.sema.original_range_opt(match_expr.syntax())?.range; - if last_arm_range.end() <= ctx.offset() && ctx.offset() < match_expr_range.end() { + if last_node_range.end() <= ctx.offset() && ctx.offset() < match_expr_range.end() { cov_mark::hit!(add_missing_match_arms_end_of_last_arm); return Some(()); } + + if ast::Expr::cast(last_node.clone()).is_some_and(is_empty_expr) + && last_node_range.contains(ctx.offset()) + && !last_node.text().contains_char('\n') + { + cov_mark::hit!(add_missing_match_arms_end_of_last_empty_arm); + return Some(()); + } } // match { _$0 => {...} } @@ -367,10 +346,113 @@ fn cursor_at_trivial_match_arm_list( None } +struct ArmsEdit { + match_arm_list: MatchArmList, + place: SyntaxNode, + last_arm: Option, +} + +impl ArmsEdit { + fn remove_wildcard_arms(&mut self, ctx: &AssistContext<'_>, editor: &mut SyntaxEditor) { + for arm in self.match_arm_list.arms() { + if !matches!(arm.pat(), Some(Pat::WildcardPat(_))) { + self.last_arm = Some(arm); + continue; + } + if !arm.expr().is_none_or(is_empty_expr) { + cov_mark::hit!(add_missing_match_arms_empty_expr); + self.last_arm = Some(arm); + continue; + } + let Some(range) = self.cover_edit_range(ctx, &arm) else { continue }; + + let prev = match range.start() { + syntax::NodeOrToken::Node(node) => { + node.first_token().and_then(|it| it.prev_token()) + } + syntax::NodeOrToken::Token(tok) => tok.prev_token(), + }; + if let Some(prev) = prev + && prev.kind() == SyntaxKind::WHITESPACE + { + editor.delete(prev); + } + + editor.delete_all(range); + } + } + + fn append_arms(&self, arms: &[ast::MatchArm], make: &SyntaxFactory, editor: &mut SyntaxEditor) { + let Some(mut before) = self.place.last_token() else { + stdx::never!("match arm list not contain any token"); + return; + }; + if let Some(prev) = before.prev_token() + && prev.kind() == SyntaxKind::WHITESPACE + { + before = prev; + } + let open_curly = + !self.place.text().contains_char('\n') || before.kind() == SyntaxKind::WHITESPACE; + let indent = IndentLevel::from_node(&self.place); + let arm_indent = indent + 1; + let indent = make.whitespace(&format!("\n{indent}")); + let arm_indent = make.whitespace(&format!("\n{arm_indent}")); + let elements = arms + .iter() + .flat_map(|arm| [arm_indent.clone().into(), arm.syntax().clone().into()]) + .chain(open_curly.then(|| indent.clone().into())) + .collect(); + + if before.kind() == SyntaxKind::WHITESPACE { + editor.replace_with_many(before, elements); + } else { + editor.insert_all(Position::before(before), elements); + } + } + + fn add_comma_after_last_arm( + &self, + ctx: &AssistContext<'_>, + make: &SyntaxFactory, + editor: &mut SyntaxEditor, + ) { + if let Some(last_arm) = &self.last_arm + && last_arm.comma_token().is_none() + && last_arm.expr().is_none_or(|it| !it.is_block_like()) + && let Some(range) = self.cover_edit_range(ctx, last_arm) + { + editor.insert(Position::after(range.end()), make.token(syntax::T![,])); + } + } + + fn cover_edit_range( + &self, + ctx: &AssistContext<'_>, + node: &impl AstNode, + ) -> Option> { + let range = ctx.sema.original_range_opt(node.syntax())?; + + if !self.place.text_range().contains_range(range.range) { + return None; + } + + Some(utils::cover_edit_range(&self.place, range.range)) + } +} + fn is_variant_missing(existing_pats: &[Pat], var: &Pat) -> bool { !existing_pats.iter().any(|pat| does_pat_match_variant(pat, var)) } +fn is_empty_expr(e: ast::Expr) -> bool { + match e { + ast::Expr::BlockExpr(b) => b.statements().next().is_none() && b.tail_expr().is_none(), + ast::Expr::TupleExpr(t) => t.fields().next().is_none(), + _ => false, + } +} + // Fixme: this is still somewhat limited, use hir_ty::diagnostics::match_check? fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { match (pat, var) { @@ -396,7 +478,7 @@ enum ExtendedEnum { enum ExtendedVariant { True, False, - Variant { variant: hir::Variant, use_self: bool }, + Variant { variant: hir::EnumVariant, use_self: bool }, } impl ExtendedVariant { @@ -1066,7 +1148,7 @@ fn main() { #[test] fn add_missing_match_arms_end_of_last_arm() { - cov_mark::check!(add_missing_match_arms_end_of_last_arm); + cov_mark::check_count!(add_missing_match_arms_end_of_last_arm, 2); check_assist( add_missing_match_arms, r#" @@ -1095,6 +1177,103 @@ fn main() { (A::Two, B::Two) => ${3:todo!()},$0 } } +"#, + ); + + check_assist( + add_missing_match_arms, + r#" +enum A { One, Two } +enum B { One, Two } + +fn main() { + let a = A::One; + let b = B::One; + match (a, b) { + (A::Two, B::One) => 2$0, + } +} +"#, + r#" +enum A { One, Two } +enum B { One, Two } + +fn main() { + let a = A::One; + let b = B::One; + match (a, b) { + (A::Two, B::One) => 2, + (A::One, B::One) => ${1:todo!()}, + (A::One, B::Two) => ${2:todo!()}, + (A::Two, B::Two) => ${3:todo!()},$0 + } +} +"#, + ); + } + + #[test] + fn add_missing_match_arms_end_of_last_empty_arm() { + cov_mark::check_count!(add_missing_match_arms_end_of_last_empty_arm, 2); + check_assist( + add_missing_match_arms, + r#" +enum A { One, Two } +enum B { One, Two } + +fn main() { + let a = A::One; + let b = B::One; + match (a, b) { + (A::Two, B::One) => {$0} + } +} +"#, + r#" +enum A { One, Two } +enum B { One, Two } + +fn main() { + let a = A::One; + let b = B::One; + match (a, b) { + (A::Two, B::One) => {} + (A::One, B::One) => ${1:todo!()}, + (A::One, B::Two) => ${2:todo!()}, + (A::Two, B::Two) => ${3:todo!()},$0 + } +} +"#, + ); + + check_assist( + add_missing_match_arms, + r#" +enum A { One, Two } +enum B { One, Two } + +fn main() { + let a = A::One; + let b = B::One; + match (a, b) { + (A::Two, B::One) => ($0) + } +} +"#, + r#" +enum A { One, Two } +enum B { One, Two } + +fn main() { + let a = A::One; + let b = B::One; + match (a, b) { + (A::Two, B::One) => (), + (A::One, B::One) => ${1:todo!()}, + (A::One, B::Two) => ${2:todo!()}, + (A::Two, B::Two) => ${3:todo!()},$0 + } +} "#, ); } @@ -1639,7 +1818,7 @@ enum Test { fn foo(t: Test) { m!(match t { - Test::A=>(), + Test::A => (), Test::B => ${1:todo!()}, Test::C => ${2:todo!()},$0 }); @@ -2077,6 +2256,35 @@ fn foo(t: E) { ); } + #[test] + fn keep_comments() { + check_assist( + add_missing_match_arms, + r#" +enum E { A, B, C } + +fn foo(t: E) -> i32 { + match $0t { + // variant a + E::A => 2 + // comment on end + } +}"#, + r#" +enum E { A, B, C } + +fn foo(t: E) -> i32 { + match t { + // variant a + E::A => 2, + // comment on end + E::B => ${1:todo!()}, + E::C => ${2:todo!()},$0 + } +}"#, + ); + } + #[test] fn not_applicable_when_match_arm_list_cannot_be_upmapped() { check_assist_not_applicable( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs index be13b04873c8..c5e722d87e1a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -2,7 +2,7 @@ use ide_db::defs::{Definition, NameRefClass}; use syntax::{ AstNode, - ast::{self, HasArgList, HasGenericArgs, make, syntax_factory::SyntaxFactory}, + ast::{self, HasArgList, HasGenericArgs, syntax_factory::SyntaxFactory}, syntax_editor::Position, }; @@ -94,20 +94,21 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti ident.text_range(), |builder| { let mut editor = builder.make_editor(let_stmt.syntax()); + let make = SyntaxFactory::without_mappings(); if let_stmt.semicolon_token().is_none() { editor.insert( Position::last_child_of(let_stmt.syntax()), - make::tokens::semicolon(), + make.token(syntax::SyntaxKind::SEMICOLON), ); } - let placeholder_ty = make::ty_placeholder().clone_for_update(); + let placeholder_ty = make.ty_placeholder(); if let Some(pat) = let_stmt.pat() { let elements = vec![ - make::token(syntax::SyntaxKind::COLON).into(), - make::token(syntax::SyntaxKind::WHITESPACE).into(), + make.token(syntax::SyntaxKind::COLON).into(), + make.whitespace(" ").into(), placeholder_ty.syntax().clone().into(), ]; editor.insert_all(Position::after(pat.syntax()), elements); @@ -188,7 +189,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti /// This will create a turbofish generic arg list corresponding to the number of arguments fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList { - let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into()); + let args = (0..number_of_arguments).map(|_| make.type_arg(make.ty_placeholder()).into()); make.generic_arg_list(args, true) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs index 80d0a6da1243..4ee49702489d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -197,7 +197,7 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_> let (name, arg_expr) = validate_method_call_expr(ctx, &method_call)?; let ast::Expr::ClosureExpr(closure_expr) = arg_expr else { return None }; - let closure_body = closure_expr.body()?.clone_for_update(); + let closure_body = closure_expr.body()?; let op_range = method_call.syntax().text_range(); let label = format!("Apply De Morgan's law to `Iterator::{}`", name.text().as_str()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index da5c12395771..de5dfdf4d954 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -268,7 +268,7 @@ pub(crate) fn relevance_score( hir::Adt::Union(it) => it.ty(ctx.db()), hir::Adt::Enum(it) => it.ty(ctx.db()), }), - hir::ModuleDef::Variant(variant) => Some(variant.constructor_ty(ctx.db())), + hir::ModuleDef::EnumVariant(variant) => Some(variant.constructor_ty(ctx.db())), hir::ModuleDef::Const(it) => Some(it.ty(ctx.db())), hir::ModuleDef::Static(it) => Some(it.ty(ctx.db())), hir::ModuleDef::TypeAlias(it) => Some(it.ty(ctx.db())), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index d2c4ed9b5a2c..b3bfe5b8c41a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -102,11 +102,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_> ast::Expr::BlockExpr(block) => unwrap_trivial_block(block), e => e, }; - let cond = if invert_cond { - invert_boolean_expression(&make, cond) - } else { - cond.clone_for_update() - }; + let cond = if invert_cond { invert_boolean_expression(&make, cond) } else { cond }; let parenthesize = matches!( cond, @@ -241,7 +237,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> fn option_variants( sema: &Semantics<'_, RootDatabase>, expr: &SyntaxNode, -) -> Option<(hir::Variant, hir::Variant)> { +) -> Option<(hir::EnumVariant, hir::EnumVariant)> { let fam = FamousDefs(sema, sema.scope(expr)?.krate()); let option_variants = fam.core_option_Option()?.variants(sema.db); match &*option_variants { @@ -258,7 +254,7 @@ fn option_variants( /// If any of these conditions are met it is impossible to rewrite this as a `bool::then` call. fn is_invalid_body( sema: &Semantics<'_, RootDatabase>, - some_variant: hir::Variant, + some_variant: hir::EnumVariant, expr: &ast::Expr, ) -> bool { let mut invalid = false; @@ -281,7 +277,7 @@ fn is_invalid_body( && let Some(ast::Expr::PathExpr(p)) = call.expr() { let res = p.path().and_then(|p| sema.resolve_path(&p)); - if let Some(hir::PathResolution::Def(hir::ModuleDef::Variant(v))) = res { + if let Some(hir::PathResolution::Def(hir::ModuleDef::EnumVariant(v))) = res { return invalid |= v != some_variant; } } @@ -294,11 +290,11 @@ fn is_invalid_body( fn block_is_none_variant( sema: &Semantics<'_, RootDatabase>, block: &ast::BlockExpr, - none_variant: hir::Variant, + none_variant: hir::EnumVariant, ) -> bool { block_as_lone_tail(block).and_then(|e| match e { ast::Expr::PathExpr(pat) => match sema.resolve_path(&pat.path()?)? { - hir::PathResolution::Def(hir::ModuleDef::Variant(v)) => Some(v), + hir::PathResolution::Def(hir::ModuleDef::EnumVariant(v)) => Some(v), _ => None, }, _ => None, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index 434fbbae05c4..e88778a62e19 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -12,9 +12,10 @@ }; use itertools::Itertools; use syntax::ast::edit::AstNodeEdit; +use syntax::ast::syntax_factory::SyntaxFactory; use syntax::{ AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, - ast::{self, HasName, edit::IndentLevel, make}, + ast::{self, HasName, edit::IndentLevel}, }; use crate::{ @@ -62,19 +63,28 @@ pub(crate) fn convert_bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) - "Convert boolean to enum", target, |edit| { + let make = SyntaxFactory::without_mappings(); if let Some(ty) = &ty_annotation { cov_mark::hit!(replaces_ty_annotation); edit.replace(ty.syntax().text_range(), "Bool"); } if let Some(initializer) = initializer { - replace_bool_expr(edit, initializer); + replace_bool_expr(edit, initializer, &make); } let usages = definition.usages(&ctx.sema).all(); - add_enum_def(edit, ctx, &usages, target_node, &target_module); + add_enum_def(edit, ctx, &usages, target_node, &target_module, &make); let mut delayed_mutations = Vec::new(); - replace_usages(edit, ctx, usages, definition, &target_module, &mut delayed_mutations); + replace_usages( + edit, + ctx, + usages, + definition, + &target_module, + &mut delayed_mutations, + &make, + ); for (scope, path) in delayed_mutations { insert_use(&scope, path, &ctx.config.insert_use); } @@ -168,16 +178,16 @@ fn find_bool_node(ctx: &AssistContext<'_>) -> Option { } } -fn replace_bool_expr(edit: &mut SourceChangeBuilder, expr: ast::Expr) { +fn replace_bool_expr(edit: &mut SourceChangeBuilder, expr: ast::Expr, make: &SyntaxFactory) { let expr_range = expr.syntax().text_range(); - let enum_expr = bool_expr_to_enum_expr(expr); + let enum_expr = bool_expr_to_enum_expr(expr, make); edit.replace(expr_range, enum_expr.syntax().text()) } /// Converts an expression of type `bool` to one of the new enum type. -fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr { - let true_expr = make::expr_path(make::path_from_text("Bool::True")); - let false_expr = make::expr_path(make::path_from_text("Bool::False")); +fn bool_expr_to_enum_expr(expr: ast::Expr, make: &SyntaxFactory) -> ast::Expr { + let true_expr = make.expr_path(make.path_from_text("Bool::True")); + let false_expr = make.expr_path(make.path_from_text("Bool::False")); if let ast::Expr::Literal(literal) = &expr { match literal.kind() { @@ -186,10 +196,10 @@ fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr { _ => expr, } } else { - make::expr_if( + make.expr_if( expr, - make::tail_only_block_expr(true_expr), - Some(ast::ElseBranch::Block(make::tail_only_block_expr(false_expr))), + make.tail_only_block_expr(true_expr), + Some(ast::ElseBranch::Block(make.tail_only_block_expr(false_expr))), ) .into() } @@ -203,11 +213,13 @@ fn replace_usages( target_definition: Definition, target_module: &hir::Module, delayed_mutations: &mut Vec<(ImportScope, ast::Path)>, + make: &SyntaxFactory, ) { for (file_id, references) in usages { edit.edit_file(file_id.file_id(ctx.db())); - let refs_with_imports = augment_references_with_imports(ctx, references, target_module); + let refs_with_imports = + augment_references_with_imports(ctx, references, target_module, make); refs_with_imports.into_iter().rev().for_each( |FileReferenceWithImport { range, name, import_data }| { @@ -224,12 +236,13 @@ fn replace_usages( target_definition, target_module, delayed_mutations, + make, ) } } else if let Some(initializer) = find_assignment_usage(&name) { cov_mark::hit!(replaces_assignment); - replace_bool_expr(edit, initializer); + replace_bool_expr(edit, initializer, make); } else if let Some((prefix_expr, inner_expr)) = find_negated_usage(&name) { cov_mark::hit!(replaces_negation); @@ -247,7 +260,7 @@ fn replace_usages( { cov_mark::hit!(replaces_record_expr); - let enum_expr = bool_expr_to_enum_expr(initializer); + let enum_expr = bool_expr_to_enum_expr(initializer, make); utils::replace_record_field_expr(ctx, edit, record_field, enum_expr); } else if let Some(pat) = find_record_pat_field_usage(&name) { match pat { @@ -263,6 +276,7 @@ fn replace_usages( target_definition, target_module, delayed_mutations, + make, ) } } @@ -272,14 +286,14 @@ fn replace_usages( if let Some(expr) = literal_pat.literal().and_then(|literal| { literal.syntax().ancestors().find_map(ast::Expr::cast) }) { - replace_bool_expr(edit, expr); + replace_bool_expr(edit, expr, make); } } _ => (), } } else if let Some((ty_annotation, initializer)) = find_assoc_const_usage(&name) { edit.replace(ty_annotation.syntax().text_range(), "Bool"); - replace_bool_expr(edit, initializer); + replace_bool_expr(edit, initializer, make); } else if let Some(receiver) = find_method_call_expr_usage(&name) { edit.replace( receiver.syntax().text_range(), @@ -296,10 +310,10 @@ fn replace_usages( ctx, edit, record_field, - make::expr_bin_op( + make.expr_bin_op( expr, ast::BinaryOp::CmpOp(ast::CmpOp::Eq { negated: false }), - make::expr_path(make::path_from_text("Bool::True")), + make.expr_path(make.path_from_text("Bool::True")), ), ); } else { @@ -327,6 +341,7 @@ fn augment_references_with_imports( ctx: &AssistContext<'_>, references: Vec, target_module: &hir::Module, + make: &SyntaxFactory, ) -> Vec { let mut visited_modules = FxHashSet::default(); @@ -357,9 +372,9 @@ fn augment_references_with_imports( cfg, ) .map(|mod_path| { - make::path_concat( + make.path_concat( mod_path_to_ast(&mod_path, edition), - make::path_from_text("Bool"), + make.path_from_text("Bool"), ) })?; @@ -458,6 +473,7 @@ fn add_enum_def( usages: &UsageSearchResult, target_node: SyntaxNode, target_module: &hir::Module, + make: &SyntaxFactory, ) -> Option<()> { let insert_before = node_to_insert_before(target_node); @@ -482,7 +498,7 @@ fn add_enum_def( .any(|module| module.nearest_non_block_module(ctx.db()) != *target_module); let indent = IndentLevel::from_node(&insert_before); - let enum_def = make_bool_enum(make_enum_pub).reset_indent().indent(indent); + let enum_def = make_bool_enum(make_enum_pub, make).reset_indent().indent(indent); edit.insert( insert_before.text_range().start(), @@ -504,31 +520,30 @@ fn node_to_insert_before(target_node: SyntaxNode) -> SyntaxNode { .unwrap_or(target_node) } -fn make_bool_enum(make_pub: bool) -> ast::Enum { - let derive_eq = make::attr_outer(make::meta_token_tree( - make::ext::ident_path("derive"), - make::token_tree( +fn make_bool_enum(make_pub: bool, make: &SyntaxFactory) -> ast::Enum { + let derive_eq = make.attr_outer(make.meta_token_tree( + make.ident_path("derive"), + make.token_tree( T!['('], vec![ - NodeOrToken::Token(make::tokens::ident("PartialEq")), - NodeOrToken::Token(make::token(T![,])), - NodeOrToken::Token(make::tokens::single_space()), - NodeOrToken::Token(make::tokens::ident("Eq")), + NodeOrToken::Token(make.ident("PartialEq")), + NodeOrToken::Token(make.token(T![,])), + NodeOrToken::Token(make.whitespace(" ")), + NodeOrToken::Token(make.ident("Eq")), ], ), )); - make::enum_( + make.item_enum( [derive_eq], - if make_pub { Some(make::visibility_pub()) } else { None }, - make::name("Bool"), + if make_pub { Some(make.visibility_pub()) } else { None }, + make.name("Bool"), None, None, - make::variant_list(vec![ - make::variant(None, make::name("True"), None, None), - make::variant(None, make::name("False"), None, None), + make.variant_list(vec![ + make.variant(None, make.name("True"), None, None), + make.variant(None, make.name("False"), None, None), ]), ) - .clone_for_update() } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 5a223e11301c..9f9ced98d73b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -220,7 +220,7 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>) } let body = if wrap_body_in_block { - make::block_expr([], Some(body)) + make::block_expr([], Some(body.reset_indent().indent(1.into()))) } else { ast::BlockExpr::cast(body.syntax().clone()).unwrap() }; @@ -969,6 +969,32 @@ fn closure() { } closure(); } +"#, + ); + check_assist( + convert_closure_to_fn, + r#" +//- minicore: copy +fn foo() { + { + let closure = |$0| match () { + () => {}, + }; + closure(); + } +} +"#, + r#" +fn foo() { + { + fn closure() { + match () { + () => {}, + } + } + closure(); + } +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs index d64e9ceda2ef..15f324eff329 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs @@ -2,7 +2,7 @@ use ide_db::{famous_defs::FamousDefs, syntax_helpers::suggest_name}; use syntax::{ AstNode, - ast::{self, HasAttrs, HasLoopBody, edit::IndentLevel, make, syntax_factory::SyntaxFactory}, + ast::{self, HasAttrs, HasLoopBody, edit::IndentLevel, syntax_factory::SyntaxFactory}, syntax_editor::Position, }; @@ -24,8 +24,8 @@ // ``` // fn main() { // let x = vec![1, 2, 3]; -// let mut tmp = x.into_iter(); -// while let Some(v) = tmp.next() { +// let mut iter = x.into_iter(); +// while let Some(v) = iter.next() { // let y = v * 2; // }; // } @@ -57,13 +57,13 @@ pub(crate) fn convert_for_loop_to_while_let( { (expr, Some(make.name_ref(method.as_str()))) } else if let ast::Expr::RefExpr(_) = iterable { - (make::expr_paren(iterable).into(), Some(make.name_ref("into_iter"))) + (make.expr_paren(iterable).into(), Some(make.name_ref("into_iter"))) } else { (iterable, Some(make.name_ref("into_iter"))) }; let iterable = if let Some(method) = method { - make::expr_method_call(iterable, method, make::arg_list([])).into() + make.expr_method_call(iterable, method, make.arg_list([])).into() } else { iterable }; @@ -71,7 +71,7 @@ pub(crate) fn convert_for_loop_to_while_let( let mut new_name = suggest_name::NameGenerator::new_from_scope_locals( ctx.sema.scope(for_loop.syntax()), ); - let tmp_var = new_name.suggest_name("tmp"); + let tmp_var = new_name.suggest_name("iter"); let mut_expr = make.let_stmt( make.ident_pat(false, true, make.name(&tmp_var)).into(), @@ -89,17 +89,18 @@ pub(crate) fn convert_for_loop_to_while_let( for_loop.syntax(), &mut editor, for_loop.attrs().map(|it| it.clone_for_update()), + &make, ); editor.insert( Position::before(for_loop.syntax()), - make::tokens::whitespace(format!("\n{indent}").as_str()), + make.whitespace(format!("\n{indent}").as_str()), ); editor.insert(Position::before(for_loop.syntax()), mut_expr.syntax()); - let opt_pat = make.tuple_struct_pat(make::ext::ident_path("Some"), [pat]); + let opt_pat = make.tuple_struct_pat(make.ident_path("Some"), [pat]); let iter_next_expr = make.expr_method_call( - make.expr_path(make::ext::ident_path(&tmp_var)), + make.expr_path(make.ident_path(&tmp_var)), make.name_ref("next"), make.arg_list([]), ); @@ -187,8 +188,8 @@ fn main() { r" fn main() { let mut x = vec![1, 2, 3]; - let mut tmp = x.into_iter(); - while let Some(v) = tmp.next() { + let mut iter = x.into_iter(); + while let Some(v) = iter.next() { v *= 2; }; }", @@ -210,8 +211,8 @@ fn main() { r" fn main() { let mut x = vec![1, 2, 3]; - let mut tmp = x.into_iter(); - 'a: while let Some(v) = tmp.next() { + let mut iter = x.into_iter(); + 'a: while let Some(v) = iter.next() { v *= 2; break 'a; }; @@ -235,10 +236,10 @@ fn main() { r" fn main() { let mut x = vec![1, 2, 3]; - let mut tmp = x.into_iter(); + let mut iter = x.into_iter(); #[allow(unused)] #[deny(unsafe_code)] - while let Some(v) = tmp.next() { + while let Some(v) = iter.next() { v *= 2; }; }", @@ -274,8 +275,8 @@ fn next(&mut self) -> Option { } fn main() { - let mut tmp = 0..92; - while let Some(x) = tmp.next() { + let mut iter = 0..92; + while let Some(x) = iter.next() { print!("{}", x); } }"#, @@ -329,8 +330,8 @@ fn iter_mut(&mut self) -> Repeat { repeat(92) } fn main() { let x = S; - let mut tmp = x.iter(); - while let Some(v) = tmp.next() { + let mut iter = x.iter(); + while let Some(v) = iter.next() { let a = v * 2; } } @@ -355,8 +356,8 @@ fn main() { struct NoIterMethod; fn main() { let x = NoIterMethod; - let mut tmp = (&x).into_iter(); - while let Some(v) = tmp.next() { + let mut iter = (&x).into_iter(); + while let Some(v) = iter.next() { let a = v * 2; } } @@ -381,8 +382,8 @@ fn main() { struct NoIterMethod; fn main() { let x = NoIterMethod; - let mut tmp = (&mut x).into_iter(); - while let Some(v) = tmp.next() { + let mut iter = (&mut x).into_iter(); + while let Some(v) = iter.next() { let a = v * 2; } } @@ -422,8 +423,8 @@ fn iter_mut(&mut self) -> Repeat { repeat(92) } fn main() { let x = S; - let mut tmp = x.iter_mut(); - while let Some(v) = tmp.next() { + let mut iter = x.iter_mut(); + while let Some(v) = iter.next() { let a = v * 2; } } @@ -447,8 +448,8 @@ fn main() { fn main() { let mut x = vec![1, 2, 3]; let y = &mut x; - let mut tmp = y.into_iter(); - while let Some(v) = tmp.next() { + let mut iter = y.into_iter(); + while let Some(v) = iter.next() { *v *= 2; } }", @@ -470,8 +471,8 @@ fn main() { "#, r#" fn main() { - let mut tmp = core::iter::repeat(92).take(1); - while let Some(a) = tmp.next() { + let mut iter = core::iter::repeat(92).take(1); + while let Some(a) = iter.next() { println!("{}", a); } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index 6a74d214512f..66ccd2a4e409 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -1,6 +1,6 @@ use ide_db::{famous_defs::FamousDefs, traits::resolve_target_trait}; use syntax::ast::edit::IndentLevel; -use syntax::ast::{self, AstNode, HasGenericArgs, HasName, make}; +use syntax::ast::{self, AstNode, HasGenericArgs, HasName, syntax_factory::SyntaxFactory}; use syntax::syntax_editor::{Element, Position}; use crate::{AssistContext, AssistId, Assists}; @@ -74,36 +74,25 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> "Convert From to TryFrom", impl_.syntax().text_range(), |builder| { + let make = SyntaxFactory::with_mappings(); let mut editor = builder.make_editor(impl_.syntax()); - editor.replace( - trait_ty.syntax(), - make::ty(&format!("TryFrom<{from_type}>")).syntax().clone_for_update(), - ); + + editor.replace(trait_ty.syntax(), make.ty(&format!("TryFrom<{from_type}>")).syntax()); editor.replace( from_fn_return_type.syntax(), - make::ty("Result").syntax().clone_for_update(), - ); - editor - .replace(from_fn_name.syntax(), make::name("try_from").syntax().clone_for_update()); - editor.replace( - tail_expr.syntax(), - wrap_ok(tail_expr.clone()).syntax().clone_for_update(), + make.ty("Result").syntax(), ); + editor.replace(from_fn_name.syntax(), make.name("try_from").syntax()); + editor.replace(tail_expr.syntax(), wrap_ok(&make, tail_expr.clone()).syntax()); for r in return_exprs { - let t = r.expr().unwrap_or_else(make::ext::expr_unit); - editor.replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update()); + let t = r.expr().unwrap_or_else(|| make.expr_unit()); + editor.replace(t.syntax(), wrap_ok(&make, t.clone()).syntax()); } - let error_type = ast::AssocItem::TypeAlias(make::ty_alias( - None, - "Error", - None, - None, - None, - Some((make::ty_unit(), None)), - )) - .clone_for_update(); + let error_type_alias = + make.ty_alias(None, "Error", None, None, None, Some((make.ty("()"), None))); + let error_type = ast::AssocItem::TypeAlias(error_type_alias); if let Some(cap) = ctx.config.snippet_cap && let ast::AssocItem::TypeAlias(type_alias) = &error_type @@ -117,22 +106,19 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> editor.insert_all( Position::after(associated_l_curly), vec![ - make::tokens::whitespace(&format!("\n{indent}")).syntax_element(), + make.whitespace(&format!("\n{indent}")).syntax_element(), error_type.syntax().syntax_element(), - make::tokens::whitespace("\n").syntax_element(), + make.whitespace("\n").syntax_element(), ], ); + editor.add_mappings(make.finish_with_mappings()); builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) } -fn wrap_ok(expr: ast::Expr) -> ast::Expr { - make::expr_call( - make::expr_path(make::ext::ident_path("Ok")), - make::arg_list(std::iter::once(expr)), - ) - .into() +fn wrap_ok(make: &SyntaxFactory, expr: ast::Expr) -> ast::Expr { + make.expr_call(make.expr_path(make.path_from_text("Ok")), make.arg_list([expr])).into() } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index e518c39dabc2..aaf727058cf1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -1,14 +1,18 @@ use either::Either; use ide_db::{defs::Definition, search::FileReference}; -use itertools::Itertools; use syntax::{ - SyntaxKind, - ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility}, + NodeOrToken, SyntaxKind, SyntaxNode, T, + algo::next_non_trivia_token, + ast::{ + self, AstNode, HasAttrs, HasGenericParams, HasVisibility, syntax_factory::SyntaxFactory, + }, match_ast, - syntax_editor::{Position, SyntaxEditor}, + syntax_editor::{Element, Position, SyntaxEditor}, }; -use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder}; +use crate::{ + AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::cover_edit_range, +}; // Assist: convert_named_struct_to_tuple_struct // @@ -81,17 +85,17 @@ pub(crate) fn convert_named_struct_to_tuple_struct( AssistId::refactor_rewrite("convert_named_struct_to_tuple_struct"), "Convert to tuple struct", strukt_or_variant.syntax().text_range(), - |edit| { - edit_field_references(ctx, edit, record_fields.fields()); - edit_struct_references(ctx, edit, strukt_def); - edit_struct_def(ctx, edit, &strukt_or_variant, record_fields); + |builder| { + edit_field_references(ctx, builder, record_fields.fields()); + edit_struct_references(ctx, builder, strukt_def); + edit_struct_def(ctx, builder, &strukt_or_variant, record_fields); }, ) } fn edit_struct_def( ctx: &AssistContext<'_>, - edit: &mut SourceChangeBuilder, + builder: &mut SourceChangeBuilder, strukt: &Either, record_fields: ast::RecordFieldList, ) { @@ -108,24 +112,23 @@ fn edit_struct_def( let field = ast::TupleField::cast(field_syntax)?; Some(field) }); - let tuple_fields = ast::make::tuple_field_list(tuple_fields); - let record_fields_text_range = record_fields.syntax().text_range(); - edit.edit_file(ctx.vfs_file_id()); - edit.replace(record_fields_text_range, tuple_fields.syntax().text()); + let make = SyntaxFactory::without_mappings(); + let mut edit = builder.make_editor(strukt.syntax()); + let tuple_fields = make.tuple_field_list(tuple_fields); + + let mut elements = vec![tuple_fields.syntax().clone().into()]; if let Either::Left(strukt) = strukt { if let Some(w) = strukt.where_clause() { - let mut where_clause = w.to_string(); - if where_clause.ends_with(',') { - where_clause.pop(); - } - where_clause.push(';'); + edit.delete(w.syntax()); - edit.delete(w.syntax().text_range()); - edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text()); - edit.insert(record_fields_text_range.end(), where_clause); - edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text()); + elements.extend([ + make.whitespace("\n").into(), + remove_trailing_comma(w).into(), + make.token(T![;]).into(), + make.whitespace("\n").into(), + ]); if let Some(tok) = strukt .generic_param_list() @@ -133,45 +136,51 @@ fn edit_struct_def( .and_then(|tok| tok.next_token()) .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE) { - edit.delete(tok.text_range()); + edit.delete(tok); } } else { - edit.insert(record_fields_text_range.end(), ";"); + elements.push(make.token(T![;]).into()); } } + edit.replace_with_many(record_fields.syntax(), elements); if let Some(tok) = record_fields .l_curly_token() .and_then(|tok| tok.prev_token()) .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE) { - edit.delete(tok.text_range()) + edit.delete(tok) } + + builder.add_file_edits(ctx.vfs_file_id(), edit); } fn edit_struct_references( ctx: &AssistContext<'_>, - edit: &mut SourceChangeBuilder, - strukt: Either, + builder: &mut SourceChangeBuilder, + strukt: Either, ) { let strukt_def = match strukt { Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)), - Either::Right(v) => Definition::Variant(v), + Either::Right(v) => Definition::EnumVariant(v), }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); for (file_id, refs) in usages { - edit.edit_file(file_id.file_id(ctx.db())); + let source = ctx.sema.parse(file_id); + let mut edit = builder.make_editor(source.syntax()); for r in refs { - process_struct_name_reference(ctx, r, edit); + process_struct_name_reference(ctx, r, &mut edit, &source); } + builder.add_file_edits(file_id.file_id(ctx.db()), edit); } } fn process_struct_name_reference( ctx: &AssistContext<'_>, r: FileReference, - edit: &mut SourceChangeBuilder, + edit: &mut SyntaxEditor, + source: &ast::SourceFile, ) -> Option<()> { // First check if it's the last semgnet of a path that directly belongs to a record // expression/pattern. @@ -192,36 +201,26 @@ fn process_struct_name_reference( match_ast! { match parent { ast::RecordPat(record_struct_pat) => { - // When we failed to get the original range for the whole struct expression node, + // When we failed to get the original range for the whole struct pattern node, // we can't provide any reasonable edit. Leave it untouched. - let file_range = ctx.sema.original_range_opt(record_struct_pat.syntax())?; - edit.replace( - file_range.range, - ast::make::tuple_struct_pat( - record_struct_pat.path()?, - record_struct_pat - .record_pat_field_list()? - .fields() - .filter_map(|pat| pat.pat()) - .chain(record_struct_pat.record_pat_field_list()? - .rest_pat() - .map(Into::into)) - ) - .to_string() + record_to_tuple_struct_like( + ctx, + source, + edit, + record_struct_pat.record_pat_field_list()?, + |it| it.fields().filter_map(|it| it.name_ref()), ); }, ast::RecordExpr(record_expr) => { - // When we failed to get the original range for the whole struct pattern node, + // When we failed to get the original range for the whole struct expression node, // we can't provide any reasonable edit. Leave it untouched. - let file_range = ctx.sema.original_range_opt(record_expr.syntax())?; - let path = record_expr.path()?; - let args = record_expr - .record_expr_field_list()? - .fields() - .filter_map(|f| f.expr()) - .join(", "); - - edit.replace(file_range.range, format!("{path}({args})")); + record_to_tuple_struct_like( + ctx, + source, + edit, + record_expr.record_expr_field_list()?, + |it| it.fields().filter_map(|it| it.name_ref()), + ); }, _ => {} } @@ -230,11 +229,67 @@ fn process_struct_name_reference( Some(()) } +fn record_to_tuple_struct_like( + ctx: &AssistContext<'_>, + source: &ast::SourceFile, + edit: &mut SyntaxEditor, + field_list: T, + fields: impl FnOnce(&T) -> I, +) -> Option<()> +where + T: AstNode, + I: IntoIterator, +{ + let make = SyntaxFactory::without_mappings(); + let orig = ctx.sema.original_range_opt(field_list.syntax())?; + let list_range = cover_edit_range(source.syntax(), orig.range); + + let l_curly = match list_range.start() { + NodeOrToken::Node(node) => node.first_token()?, + NodeOrToken::Token(t) => t.clone(), + }; + let r_curly = match list_range.end() { + NodeOrToken::Node(node) => node.last_token()?, + NodeOrToken::Token(t) => t.clone(), + }; + + if l_curly.kind() == T!['{'] { + delete_whitespace(edit, l_curly.prev_token()); + delete_whitespace(edit, l_curly.next_token()); + edit.replace(l_curly, make.token(T!['('])); + } + if r_curly.kind() == T!['}'] { + delete_whitespace(edit, r_curly.prev_token()); + edit.replace(r_curly, make.token(T![')'])); + } + + for name_ref in fields(&field_list) { + let Some(orig) = ctx.sema.original_range_opt(name_ref.syntax()) else { continue }; + let name_range = cover_edit_range(source.syntax(), orig.range); + + if let Some(colon) = next_non_trivia_token(name_range.end().clone()) + && colon.kind() == T![:] + { + edit.delete(&colon); + edit.delete_all(name_range); + + if let Some(next) = next_non_trivia_token(colon.clone()) + && next.kind() != T!['}'] + { + // Avoid overlapping delete whitespace on `{ field: }` + delete_whitespace(edit, colon.next_token()); + } + } + } + Some(()) +} + fn edit_field_references( ctx: &AssistContext<'_>, - edit: &mut SourceChangeBuilder, + builder: &mut SourceChangeBuilder, fields: impl Iterator, ) { + let make = SyntaxFactory::without_mappings(); for (index, field) in fields.enumerate() { let field = match ctx.sema.to_def(&field) { Some(it) => it, @@ -243,19 +298,46 @@ fn edit_field_references( let def = Definition::Field(field); let usages = def.usages(&ctx.sema).all(); for (file_id, refs) in usages { - edit.edit_file(file_id.file_id(ctx.db())); + let source = ctx.sema.parse(file_id); + let mut edit = builder.make_editor(source.syntax()); + for r in refs { if let Some(name_ref) = r.name.as_name_ref() { // Only edit the field reference if it's part of a `.field` access if name_ref.syntax().parent().and_then(ast::FieldExpr::cast).is_some() { - edit.replace(r.range, index.to_string()); + edit.replace_all( + cover_edit_range(source.syntax(), r.range), + vec![make.name_ref(&index.to_string()).syntax().clone().into()], + ); } } } + + builder.add_file_edits(file_id.file_id(ctx.db()), edit); } } } +fn delete_whitespace(edit: &mut SyntaxEditor, whitespace: Option) { + let Some(whitespace) = whitespace else { return }; + let NodeOrToken::Token(token) = whitespace.syntax_element() else { return }; + + if token.kind() == SyntaxKind::WHITESPACE && !token.text().contains('\n') { + edit.delete(token); + } +} + +fn remove_trailing_comma(w: ast::WhereClause) -> SyntaxNode { + let w = w.syntax().clone_subtree(); + let mut editor = SyntaxEditor::new(w.clone()); + if let Some(last) = w.last_child_or_token() + && last.kind() == T![,] + { + editor.delete(last); + } + editor.finish().new_root().clone() +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -677,6 +759,102 @@ struct Wrap(T) ); } + #[test] + fn convert_constructor_expr_uses_self() { + // regression test for #21595 + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct $0Foo { field1: u32 } +impl Foo { + fn clone(&self) -> Self { + Self { field1: self.field1 } + } +}"#, + r#" +struct Foo(u32); +impl Foo { + fn clone(&self) -> Self { + Self(self.0) + } +}"#, + ); + + check_assist( + convert_named_struct_to_tuple_struct, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} +struct $0Foo { field1: u32 } +impl Foo { + fn clone(&self) -> Self { + id!(Self { field1: self.field1 }) + } +}"#, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} +struct Foo(u32); +impl Foo { + fn clone(&self) -> Self { + id!(Self(self.0)) + } +}"#, + ); + } + + #[test] + fn convert_pat_uses_self() { + // regression test for #21595 + check_assist( + convert_named_struct_to_tuple_struct, + r#" +enum Foo { + $0Value { field: &'static Foo }, + Nil, +} +fn foo(foo: &Foo) { + if let Foo::Value { field: Foo::Value { field } } = foo {} +}"#, + r#" +enum Foo { + Value(&'static Foo), + Nil, +} +fn foo(foo: &Foo) { + if let Foo::Value(Foo::Value(field)) = foo {} +}"#, + ); + + check_assist( + convert_named_struct_to_tuple_struct, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} +enum Foo { + $0Value { field: &'static Foo }, + Nil, +} +fn foo(foo: &Foo) { + if let id!(Foo::Value { field: Foo::Value { field } }) = foo {} +}"#, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} +enum Foo { + Value(&'static Foo), + Nil, +} +fn foo(foo: &Foo) { + if let id!(Foo::Value(Foo::Value(field))) = foo {} +}"#, + ); + } + #[test] fn not_applicable_other_than_record_variant() { check_assist_not_applicable( @@ -1042,7 +1220,9 @@ macro_rules! id { fn test() { id! { - let s = Struct(42); + let s = Struct( + 42, + ); let Struct(value) = s; let Struct(inner) = s; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index dc51bf4b5b8c..db4591679220 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -10,14 +10,14 @@ ast::{ self, edit::{AstNodeEdit, IndentLevel}, - make, + syntax_factory::SyntaxFactory, }, }; use crate::{ AssistId, assist_context::{AssistContext, Assists}, - utils::{invert_boolean_expression_legacy, is_never_block}, + utils::{invert_boolean_expression, is_never_block}, }; // Assist: convert_to_guarded_return @@ -69,6 +69,7 @@ fn if_expr_to_guarded_return( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { + let make = SyntaxFactory::without_mappings(); let else_block = match if_expr.else_branch() { Some(ast::ElseBranch::Block(block_expr)) if is_never_block(&ctx.sema, &block_expr) => { Some(block_expr) @@ -88,7 +89,7 @@ fn if_expr_to_guarded_return( return None; } - let let_chains = flat_let_chain(cond); + let let_chains = flat_let_chain(cond, &make); let then_branch = if_expr.then_branch()?; let then_block = then_branch.stmt_list()?; @@ -110,7 +111,8 @@ fn if_expr_to_guarded_return( let early_expression = else_block .or_else(|| { - early_expression(parent_container, &ctx.sema).map(ast::make::tail_only_block_expr) + early_expression(parent_container, &ctx.sema, &make) + .map(ast::make::tail_only_block_expr) })? .reset_indent(); @@ -133,6 +135,7 @@ fn if_expr_to_guarded_return( "Convert to guarded return", target, |edit| { + let make = SyntaxFactory::without_mappings(); let if_indent_level = IndentLevel::from_node(if_expr.syntax()); let replacement = let_chains.into_iter().map(|expr| { if let ast::Expr::LetExpr(let_expr) = &expr @@ -140,15 +143,15 @@ fn if_expr_to_guarded_return( { // If-let. let let_else_stmt = - make::let_else_stmt(pat, None, expr, early_expression.clone()); + make.let_else_stmt(pat, None, expr, early_expression.clone()); let let_else_stmt = let_else_stmt.indent(if_indent_level); let_else_stmt.syntax().clone() } else { // If. let new_expr = { - let then_branch = clean_stmt_block(&early_expression); - let cond = invert_boolean_expression_legacy(expr); - make::expr_if(cond, then_branch, None).indent(if_indent_level) + let then_branch = clean_stmt_block(&early_expression, &make); + let cond = invert_boolean_expression(&make, expr); + make.expr_if(cond, then_branch, None).indent(if_indent_level) }; new_expr.syntax().clone() } @@ -159,7 +162,7 @@ fn if_expr_to_guarded_return( .enumerate() .flat_map(|(i, node)| { (i != 0) - .then(|| make::tokens::whitespace(newline).into()) + .then(|| make.whitespace(newline).into()) .into_iter() .chain(node.children_with_tokens()) }) @@ -201,12 +204,13 @@ fn let_stmt_to_guarded_return( let happy_pattern = try_enum.happy_pattern(pat); let target = let_stmt.syntax().text_range(); + let make = SyntaxFactory::without_mappings(); let early_expression: ast::Expr = { let parent_block = let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; let parent_container = parent_block.syntax().parent()?; - early_expression(parent_container, &ctx.sema)? + early_expression(parent_container, &ctx.sema, &make)? }; acc.add( @@ -215,9 +219,10 @@ fn let_stmt_to_guarded_return( target, |edit| { let let_indent_level = IndentLevel::from_node(let_stmt.syntax()); + let make = SyntaxFactory::without_mappings(); let replacement = { - let let_else_stmt = make::let_else_stmt( + let let_else_stmt = make.let_else_stmt( happy_pattern, let_stmt.ty(), expr.reset_indent(), @@ -228,6 +233,7 @@ fn let_stmt_to_guarded_return( }; let mut editor = edit.make_editor(let_stmt.syntax()); editor.replace(let_stmt.syntax(), replacement); + editor.add_mappings(make.finish_with_mappings()); edit.add_file_edits(ctx.vfs_file_id(), editor); }, ) @@ -236,38 +242,39 @@ fn let_stmt_to_guarded_return( fn early_expression( parent_container: SyntaxNode, sema: &Semantics<'_, RootDatabase>, + make: &SyntaxFactory, ) -> Option { let return_none_expr = || { - let none_expr = make::expr_path(make::ext::ident_path("None")); - make::expr_return(Some(none_expr)) + let none_expr = make.expr_path(make.ident_path("None")); + make.expr_return(Some(none_expr)) }; if let Some(fn_) = ast::Fn::cast(parent_container.clone()) && let Some(fn_def) = sema.to_def(&fn_) && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &fn_def.ret_type(sema.db)) { - return Some(return_none_expr()); + return Some(return_none_expr().into()); } if let Some(body) = ast::ClosureExpr::cast(parent_container.clone()).and_then(|it| it.body()) && let Some(ret_ty) = sema.type_of_expr(&body).map(TypeInfo::original) && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &ret_ty) { - return Some(return_none_expr()); + return Some(return_none_expr().into()); } Some(match parent_container.kind() { - WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None), - FN | CLOSURE_EXPR => make::expr_return(None), + WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make.expr_continue(None).into(), + FN | CLOSURE_EXPR => make.expr_return(None).into(), _ => return None, }) } -fn flat_let_chain(mut expr: ast::Expr) -> Vec { +fn flat_let_chain(mut expr: ast::Expr, make: &SyntaxFactory) -> Vec { let mut chains = vec![]; let mut reduce_cond = |rhs| { if !matches!(rhs, ast::Expr::LetExpr(_)) && let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_))) { - chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last)); + chains.push(make.expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last)); } else { chains.push(rhs); } @@ -286,12 +293,12 @@ fn flat_let_chain(mut expr: ast::Expr) -> Vec { chains } -fn clean_stmt_block(block: &ast::BlockExpr) -> ast::BlockExpr { +fn clean_stmt_block(block: &ast::BlockExpr, make: &SyntaxFactory) -> ast::BlockExpr { if block.statements().next().is_none() && let Some(tail_expr) = block.tail_expr() && block.modifier().is_none() { - make::block_expr(once(make::expr_stmt(tail_expr).into()), None) + make.block_expr(once(make.expr_stmt(tail_expr).into()), None) } else { block.clone() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index f8b9bb68db81..ae41e6c015ce 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -1,17 +1,21 @@ use either::Either; -use hir::FileRangeWrapper; -use ide_db::defs::{Definition, NameRefClass}; -use std::ops::RangeInclusive; +use ide_db::{ + defs::{Definition, NameRefClass}, + search::FileReference, +}; use syntax::{ - SyntaxElement, SyntaxKind, SyntaxNode, T, TextSize, + SyntaxKind, T, ast::{ - self, AstNode, HasAttrs, HasGenericParams, HasVisibility, syntax_factory::SyntaxFactory, + self, AstNode, HasArgList, HasAttrs, HasGenericParams, HasVisibility, + syntax_factory::SyntaxFactory, }, match_ast, syntax_editor::{Element, Position, SyntaxEditor}, }; -use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder}; +use crate::{ + AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::cover_edit_range, +}; // Assist: convert_tuple_struct_to_named_struct // @@ -138,102 +142,130 @@ fn edit_struct_def( fn edit_struct_references( ctx: &AssistContext<'_>, edit: &mut SourceChangeBuilder, - strukt: Either, + strukt: Either, names: &[ast::Name], ) { let strukt_def = match strukt { Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)), - Either::Right(v) => Definition::Variant(v), + Either::Right(v) => Definition::EnumVariant(v), }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); - let edit_node = |node: SyntaxNode| -> Option { - let make = SyntaxFactory::without_mappings(); - match_ast! { - match node { - ast::TupleStructPat(tuple_struct_pat) => { - Some(make.record_pat_with_fields( - tuple_struct_pat.path()?, - generate_record_pat_list(&tuple_struct_pat, names), - ).syntax().clone()) - }, - // for tuple struct creations like Foo(42) - ast::CallExpr(call_expr) => { - let path = call_expr.syntax().descendants().find_map(ast::PathExpr::cast).and_then(|expr| expr.path())?; - - // this also includes method calls like Foo::new(42), we should skip them - if let Some(name_ref) = path.segment().and_then(|s| s.name_ref()) { - match NameRefClass::classify(&ctx.sema, &name_ref) { - Some(NameRefClass::Definition(Definition::SelfType(_), _)) => {}, - Some(NameRefClass::Definition(def, _)) if def == strukt_def => {}, - _ => return None, - }; - } - - let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?; - Some( - make.record_expr( - path, - ast::make::record_expr_field_list(arg_list.args().zip(names).map( - |(expr, name)| { - ast::make::record_expr_field( - ast::make::name_ref(&name.to_string()), - Some(expr), - ) - }, - )), - ).syntax().clone() - ) - }, - _ => None, - } - } - }; - for (file_id, refs) in usages { let source = ctx.sema.parse(file_id); - let source = source.syntax(); + let mut editor = edit.make_editor(source.syntax()); - let mut editor = edit.make_editor(source); - for r in refs.iter().rev() { - if let Some((old_node, new_node)) = r - .name - .syntax() - .ancestors() - .find_map(|node| Some((node.clone(), edit_node(node.clone())?))) - { - if let Some(old_node) = ctx.sema.original_syntax_node_rooted(&old_node) { - editor.replace(old_node, new_node); - } else { - let FileRangeWrapper { file_id: _, range } = ctx.sema.original_range(&old_node); - let parent = source.covering_element(range); - match parent { - SyntaxElement::Token(token) => { - editor.replace(token, new_node.syntax_element()); - } - SyntaxElement::Node(parent_node) => { - // replace the part of macro - // ``` - // foo!(a, Test::A(0)); - // ^^^^^^^^^^^^^^^ // parent_node - // ^^^^^^^^^^ // replace_range - // ``` - let start = parent_node - .children_with_tokens() - .find(|t| t.text_range().contains(range.start())); - let end = parent_node - .children_with_tokens() - .find(|t| t.text_range().contains(range.end() - TextSize::new(1))); - if let (Some(start), Some(end)) = (start, end) { - let replace_range = RangeInclusive::new(start, end); - editor.replace_all(replace_range, vec![new_node.into()]); - } - } + for r in refs { + process_struct_name_reference(ctx, r, &mut editor, &source, &strukt_def, names); + } + + edit.add_file_edits(file_id.file_id(ctx.db()), editor); + } +} + +fn process_struct_name_reference( + ctx: &AssistContext<'_>, + r: FileReference, + editor: &mut SyntaxEditor, + source: &ast::SourceFile, + strukt_def: &Definition, + names: &[ast::Name], +) -> Option<()> { + let make = SyntaxFactory::without_mappings(); + let name_ref = r.name.as_name_ref()?; + let path_segment = name_ref.syntax().parent().and_then(ast::PathSegment::cast)?; + let full_path = path_segment.syntax().parent().and_then(ast::Path::cast)?.top_path(); + + if full_path.segment()?.name_ref()? != *name_ref { + // `name_ref` isn't the last segment of the path, so `full_path` doesn't point to the + // struct we want to edit. + return None; + } + + let parent = full_path.syntax().parent()?; + match_ast! { + match parent { + ast::TupleStructPat(tuple_struct_pat) => { + let range = ctx.sema.original_range_opt(tuple_struct_pat.syntax())?.range; + let new = make.record_pat_with_fields( + full_path, + generate_record_pat_list(&tuple_struct_pat, names), + ); + editor.replace_all(cover_edit_range(source.syntax(), range), vec![new.syntax().clone().into()]); + }, + ast::PathExpr(path_expr) => { + let call_expr = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; + + // this also includes method calls like Foo::new(42), we should skip them + match NameRefClass::classify(&ctx.sema, name_ref) { + Some(NameRefClass::Definition(Definition::SelfType(_), _)) => {}, + Some(NameRefClass::Definition(def, _)) if def == *strukt_def => {}, + _ => return None, + } + + let arg_list = call_expr.arg_list()?; + let mut first_insert = vec![]; + for (expr, name) in arg_list.args().zip(names) { + let range = ctx.sema.original_range_opt(expr.syntax())?.range; + let place = cover_edit_range(source.syntax(), range); + let elements = vec![ + make.name_ref(&name.text()).syntax().clone().into(), + make.token(T![:]).into(), + make.whitespace(" ").into(), + ]; + if first_insert.is_empty() { + // XXX: SyntaxEditor cannot insert after deleted element + first_insert = elements; + } else { + editor.insert_all(Position::before(place.start()), elements); } } - } + process_delimiter(ctx, source, editor, &arg_list, first_insert); + }, + _ => {} } - edit.add_file_edits(file_id.file_id(ctx.db()), editor); + } + Some(()) +} + +fn process_delimiter( + ctx: &AssistContext<'_>, + source: &ast::SourceFile, + editor: &mut SyntaxEditor, + list: &impl AstNode, + first_insert: Vec, +) { + let Some(range) = ctx.sema.original_range_opt(list.syntax()) else { return }; + let place = cover_edit_range(source.syntax(), range.range); + + let l_paren = match place.start() { + syntax::NodeOrToken::Node(node) => node.first_token(), + syntax::NodeOrToken::Token(t) => Some(t.clone()), + }; + let r_paren = match place.end() { + syntax::NodeOrToken::Node(node) => node.last_token(), + syntax::NodeOrToken::Token(t) => Some(t.clone()), + }; + + let make = SyntaxFactory::without_mappings(); + if let Some(l_paren) = l_paren + && l_paren.kind() == T!['('] + { + let mut open_delim = vec![ + make.whitespace(" ").into(), + make.token(T!['{']).into(), + make.whitespace(" ").into(), + ]; + open_delim.extend(first_insert); + editor.replace_with_many(l_paren, open_delim); + } + if let Some(r_paren) = r_paren + && r_paren.kind() == T![')'] + { + editor.replace_with_many( + r_paren, + vec![make.whitespace(" ").into(), make.token(T!['}']).into()], + ); } } @@ -252,13 +284,15 @@ fn edit_field_references( let usages = def.usages(&ctx.sema).all(); for (file_id, refs) in usages { let source = ctx.sema.parse(file_id); - let source = source.syntax(); - let mut editor = edit.make_editor(source); + let mut editor = edit.make_editor(source.syntax()); for r in refs { if let Some(name_ref) = r.name.as_name_ref() - && let Some(original) = ctx.sema.original_ast_node(name_ref.clone()) + && let Some(original) = ctx.sema.original_range_opt(name_ref.syntax()) { - editor.replace(original.syntax(), name.syntax()); + editor.replace_all( + cover_edit_range(source.syntax(), original.range), + vec![name.syntax().clone().into()], + ); } } edit.add_file_edits(file_id.file_id(ctx.db()), editor); @@ -739,6 +773,64 @@ struct Wrap "#, ); } + + #[test] + fn convert_expr_uses_self() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} +struct T$0(u8); +fn test(t: T) { + T(t.0); + id!(T(t.0)); +}"#, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} +struct T { field1: u8 } +fn test(t: T) { + T { field1: t.field1 }; + id!(T { field1: t.field1 }); +}"#, + ); + } + + #[test] + #[ignore = "FIXME overlap edits in nested uses self"] + fn convert_pat_uses_self() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} +enum T { + $0Value(&'static T), + Nil, +} +fn test(t: T) { + if let T::Value(T::Value(t)) = t {} + if let id!(T::Value(T::Value(t))) = t {} +}"#, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} +enum T { + Value { field1: &'static T }, + Nil, +} +fn test(t: T) { + if let T::Value { field1: T::Value { field1: t } } = t {} + if let id!(T::Value { field1: T::Value { field1: t } }) = t {} +}"#, + ); + } + #[test] fn not_applicable_other_than_tuple_variant() { check_assist_not_applicable( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs index 9fd8b4b3159e..f8215d6723d3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs @@ -6,7 +6,7 @@ ast::{ self, HasLoopBody, edit::{AstNodeEdit, IndentLevel}, - make, + syntax_factory::SyntaxFactory, }, syntax_editor::{Element, Position}, }; @@ -14,7 +14,7 @@ use crate::{ AssistId, assist_context::{AssistContext, Assists}, - utils::invert_boolean_expression_legacy, + utils::invert_boolean_expression, }; // Assist: convert_while_to_loop @@ -52,44 +52,47 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) "Convert while to loop", target, |builder| { + let make = SyntaxFactory::without_mappings(); let mut edit = builder.make_editor(while_expr.syntax()); let while_indent_level = IndentLevel::from_node(while_expr.syntax()); - let break_block = make::block_expr( - iter::once(make::expr_stmt(make::expr_break(None, None)).into()), - None, - ) - .indent(IndentLevel(1)); + let break_block = make + .block_expr( + iter::once(make.expr_stmt(make.expr_break(None, None).into()).into()), + None, + ) + .indent(IndentLevel(1)); edit.replace_all( while_kw.syntax_element()..=while_cond.syntax().syntax_element(), - vec![make::token(T![loop]).syntax_element()], + vec![make.token(T![loop]).syntax_element()], ); if is_pattern_cond(while_cond.clone()) { let then_branch = while_body.reset_indent().indent(IndentLevel(1)); - let if_expr = make::expr_if(while_cond, then_branch, Some(break_block.into())); - let stmts = iter::once(make::expr_stmt(if_expr.into()).into()); - let block_expr = make::block_expr(stmts, None); + let if_expr = make.expr_if(while_cond, then_branch, Some(break_block.into())); + let stmts = iter::once(make.expr_stmt(if_expr.into()).into()); + let block_expr = make.block_expr(stmts, None); edit.replace(while_body.syntax(), block_expr.indent(while_indent_level).syntax()); } else { - let if_cond = invert_boolean_expression_legacy(while_cond); - let if_expr = make::expr_if(if_cond, break_block, None).indent(while_indent_level); + let if_cond = invert_boolean_expression(&make, while_cond); + let if_expr = make.expr_if(if_cond, break_block, None).indent(while_indent_level); if !while_body.syntax().text().contains_char('\n') { edit.insert( Position::after(&l_curly), - make::tokens::whitespace(&format!("\n{while_indent_level}")), + make.whitespace(&format!("\n{while_indent_level}")), ); } edit.insert_all( Position::after(&l_curly), vec![ - make::tokens::whitespace(&format!("\n{}", while_indent_level + 1)).into(), + make.whitespace(&format!("\n{}", while_indent_level + 1)).into(), if_expr.syntax().syntax_element(), ], ); }; + edit.add_mappings(make.finish_with_mappings()); builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 4c4cee1d7811..ec4a83b642c0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -17,7 +17,7 @@ use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, - utils::ref_field_expr::determine_ref_and_parens, + utils::{cover_edit_range, ref_field_expr::determine_ref_and_parens}, }; // Assist: destructure_struct_binding @@ -358,6 +358,7 @@ fn update_usages( data: &StructEditData, field_names: &FxHashMap, ) { + let source = ctx.source_file().syntax(); let make = SyntaxFactory::with_mappings(); let edits = data .usages @@ -366,7 +367,9 @@ fn update_usages( .collect_vec(); editor.add_mappings(make.finish_with_mappings()); for (old, new) in edits { - editor.replace(old, new); + if let Some(range) = ctx.sema.original_range_opt(&old) { + editor.replace_all(cover_edit_range(source, range.range), vec![new.into()]); + } } } @@ -381,23 +384,20 @@ fn build_usage_edit( Some(field_expr) => Some({ let field_name: SmolStr = field_expr.name_ref()?.to_string().into(); let new_field_name = field_names.get(&field_name)?; - let new_expr = ast::make::expr_path(ast::make::ext::ident_path(new_field_name)); + let new_expr = make.expr_path(make.ident_path(new_field_name)); // If struct binding is a reference, we might need to deref field usages if data.is_ref { let (replace_expr, ref_data) = determine_ref_and_parens(ctx, &field_expr); - ( - replace_expr.syntax().clone_for_update(), - ref_data.wrap_expr(new_expr).syntax().clone_for_update(), - ) + (replace_expr.syntax().clone(), ref_data.wrap_expr(new_expr, make).syntax().clone()) } else { - (field_expr.syntax().clone(), new_expr.syntax().clone_for_update()) + (field_expr.syntax().clone(), new_expr.syntax().clone()) } }), None => Some(( usage.name.syntax().as_node().unwrap().clone(), make.expr_macro( - ast::make::ext::ident_path("todo"), + make.ident_path("todo"), make.token_tree(syntax::SyntaxKind::L_PAREN, []), ) .syntax() @@ -1009,4 +1009,33 @@ fn main($0foo: dep::Foo) {} "#, ) } + + #[test] + fn record_struct_usage_in_macro_call() { + // exact repro from #20716: struct field access inside write! must not panic + check_assist( + destructure_struct_binding, + r#" +//- minicore: write, fmt +use core::fmt::Write; +struct Foo { y: i8 } + +fn main() { + let mut s = String::new(); + let $0x = Foo { y: 8 }; + write!(s, "{}", x.y).unwrap(); +} +"#, + r#" +use core::fmt::Write; +struct Foo { y: i8 } + +fn main() { + let mut s = String::new(); + let Foo { y } = Foo { y: 8 }; + write!(s, "{}", y).unwrap(); +} +"#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index d51a3a26a3c7..23c11b258c1a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -14,7 +14,7 @@ use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, - utils::ref_field_expr::determine_ref_and_parens, + utils::{cover_edit_range, ref_field_expr::determine_ref_and_parens}, }; // Assist: destructure_tuple_binding @@ -98,7 +98,9 @@ fn destructure_tuple_edit_impl( assignment_edit.apply(&mut syntax_editor, &syntax_factory); if let Some(usages_edit) = current_file_usages_edit { - usages_edit.into_iter().for_each(|usage_edit| usage_edit.apply(edit, &mut syntax_editor)) + usages_edit + .into_iter() + .for_each(|usage_edit| usage_edit.apply(ctx, edit, &mut syntax_editor)) } syntax_editor.add_mappings(syntax_factory.finish_with_mappings()); @@ -311,14 +313,25 @@ enum EditTupleUsage { } impl EditTupleUsage { - fn apply(self, edit: &mut SourceChangeBuilder, syntax_editor: &mut SyntaxEditor) { + fn apply( + self, + ctx: &AssistContext<'_>, + edit: &mut SourceChangeBuilder, + syntax_editor: &mut SyntaxEditor, + ) { match self { EditTupleUsage::NoIndex(range) => { edit.insert(range.start(), "/*"); edit.insert(range.end(), "*/"); } EditTupleUsage::ReplaceExpr(target_expr, replace_with) => { - syntax_editor.replace(target_expr.syntax(), replace_with.syntax()) + if let Some(range) = ctx.sema.original_range_opt(target_expr.syntax()) { + let source = ctx.source_file().syntax(); + syntax_editor.replace_all( + cover_edit_range(source, range.range), + vec![replace_with.syntax().clone().into()], + ); + } } } } @@ -349,24 +362,6 @@ fn detect_tuple_index(usage: &FileReference, data: &TupleData) -> Option range of `field_expr` in applied macro, NOT range in actual file! - if field_expr.syntax().ancestors().any(|a| ast::MacroStmts::can_cast(a.kind())) { - cov_mark::hit!(destructure_tuple_macro_call); - - // issue: cannot differentiate between tuple index passed into macro or tuple index as result of macro: - // ```rust - // macro_rules! m { - // ($t1:expr, $t2:expr) => { $t1; $t2.0 } - // } - // let t = (1,2); - // m!(t.0, t) - // ``` - // -> 2 tuple index usages detected! - // - // -> only handle `t` - return None; - } - Some(TupleIndex { index: idx, field_expr }) } else { // tuple index out of range @@ -1437,7 +1432,6 @@ mod in_macro_call { #[test] fn detect_macro_call() { - cov_mark::check!(destructure_tuple_macro_call); check_in_place_assist( r#" macro_rules! m { @@ -1456,7 +1450,7 @@ macro_rules! m { fn main() { let ($0_0, _1) = (1,2); - m!(/*t*/.0); + m!(_0); } "#, ) @@ -1548,7 +1542,6 @@ fn main() { m!(t.0); } "#, - // FIXME: replace `t.0` with `_0` (cannot detect range of tuple index in macro call) r#" macro_rules! m { ($e:expr) => { "foo"; $e }; @@ -1556,10 +1549,9 @@ macro_rules! m { fn main() { let ($0_0, _1) = (1,2); - m!(/*t*/.0); + m!(_0); } "#, - // FIXME: replace `t.0` with `_0` r#" macro_rules! m { ($e:expr) => { "foo"; $e }; @@ -1567,7 +1559,7 @@ macro_rules! m { fn main() { let t @ ($0_0, _1) = (1,2); - m!(t.0); + m!(_0); } "#, ) @@ -1586,7 +1578,6 @@ fn main() { m!((t).0); } "#, - // FIXME: replace `(t).0` with `_0` r#" macro_rules! m { ($e:expr) => { "foo"; $e }; @@ -1594,10 +1585,9 @@ macro_rules! m { fn main() { let ($0_0, _1) = (1,2); - m!((/*t*/).0); + m!(_0); } "#, - // FIXME: replace `(t).0` with `_0` r#" macro_rules! m { ($e:expr) => { "foo"; $e }; @@ -1605,7 +1595,7 @@ macro_rules! m { fn main() { let t @ ($0_0, _1) = (1,2); - m!((t).0); + m!(_0); } "#, ) @@ -1653,7 +1643,6 @@ fn main() { m!(t, t.0); } "#, - // FIXME: replace `t.0` in macro call (not IN macro) with `_0` r#" macro_rules! m { ($t:expr, $i:expr) => { $t.0 + $i }; @@ -1661,10 +1650,9 @@ macro_rules! m { fn main() { let ($0_0, _1) = (1,2); - m!(/*t*/, /*t*/.0); + m!(t, _0); } "#, - // FIXME: replace `t.0` in macro call with `_0` r#" macro_rules! m { ($t:expr, $i:expr) => { $t.0 + $i }; @@ -1672,13 +1660,41 @@ macro_rules! m { fn main() { let t @ ($0_0, _1) = (1,2); - m!(t, t.0); + m!(t, _0); } "#, ) } } + mod in_macro_expr { + use super::assist::*; + + // exact repro from #20716: tuple index inside write! must not panic + #[test] + fn tuple_index_in_write_macro() { + check_in_place_assist( + r#" +//- minicore: write, fmt +use core::fmt::Write; +fn main() { + let mut s = String::new(); + let $0x = (2i32, 3i32); + write!(s, "{}", x.0).unwrap(); +} +"#, + r#" +use core::fmt::Write; +fn main() { + let mut s = String::new(); + let ($0_0, _1) = (2i32, 3i32); + write!(s, "{}", _0).unwrap(); +} +"#, + ) + } + } + mod refs { use super::assist::*; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs index 9976e34e730c..865dc862215f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs @@ -1,15 +1,11 @@ use std::iter; -use ide_db::{ - assists::{AssistId, ExprFillDefaultMode}, - ty_filter::TryEnum, -}; +use ide_db::{assists::AssistId, ty_filter::TryEnum}; use syntax::{ AstNode, T, ast::{ self, edit::{AstNodeEdit, IndentLevel}, - make, syntax_factory::SyntaxFactory, }, }; @@ -68,41 +64,39 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op AssistId::refactor_rewrite("desugar_try_expr_match"), "Replace try expression with match", target, - |edit| { + |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(try_expr.syntax()); + let sad_pat = match try_enum { - TryEnum::Option => make::path_pat(make::ext::ident_path("None")), - TryEnum::Result => make::tuple_struct_pat( - make::ext::ident_path("Err"), - iter::once(make::path_pat(make::ext::ident_path("err"))), - ) - .into(), - }; - let sad_expr = match try_enum { - TryEnum::Option => { - make::expr_return(Some(make::expr_path(make::ext::ident_path("None")))) - } - TryEnum::Result => make::expr_return(Some( - make::expr_call( - make::expr_path(make::ext::ident_path("Err")), - make::arg_list(iter::once(make::expr_path(make::ext::ident_path("err")))), + TryEnum::Option => make.path_pat(make.ident_path("None")), + TryEnum::Result => make + .tuple_struct_pat( + make.ident_path("Err"), + iter::once(make.path_pat(make.ident_path("err"))), ) .into(), - )), }; + let sad_expr = make.expr_return(Some(sad_expr(try_enum, &make, || { + make.expr_path(make.ident_path("err")) + }))); - let happy_arm = make::match_arm( - try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()), + let happy_arm = make.match_arm( + try_enum.happy_pattern(make.ident_pat(false, false, make.name("it")).into()), None, - make::expr_path(make::ext::ident_path("it")), + make.expr_path(make.ident_path("it")), ); - let sad_arm = make::match_arm(sad_pat, None, sad_expr); + let sad_arm = make.match_arm(sad_pat, None, sad_expr.into()); - let match_arm_list = make::match_arm_list([happy_arm, sad_arm]); + let match_arm_list = make.match_arm_list([happy_arm, sad_arm]); - let expr_match = make::expr_match(expr.clone(), match_arm_list) + let expr_match = make + .expr_match(expr.clone(), match_arm_list) .indent(IndentLevel::from_node(try_expr.syntax())); - edit.replace_ast::(try_expr.clone().into(), expr_match.into()); + editor.replace(try_expr.syntax(), expr_match.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ); @@ -119,48 +113,18 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let mut editor = builder.make_editor(let_stmt.syntax()); let indent_level = IndentLevel::from_node(let_stmt.syntax()); + let fill_expr = || crate::utils::expr_fill_default(ctx.config); let new_let_stmt = make.let_else_stmt( try_enum.happy_pattern(pat), - let_stmt.ty(), + let_stmt.ty().map(|ty| match try_enum { + TryEnum::Option => make.ty_option(ty).into(), + TryEnum::Result => make.ty_result(ty, make.ty_infer().into()).into(), + }), expr, make.block_expr( iter::once( make.expr_stmt( - make.expr_return(Some(match try_enum { - TryEnum::Option => make.expr_path(make.ident_path("None")), - TryEnum::Result => make - .expr_call( - make.expr_path(make.ident_path("Err")), - make.arg_list(iter::once( - match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make - .expr_macro( - make.ident_path("todo"), - make.token_tree( - syntax::SyntaxKind::L_PAREN, - [], - ), - ) - .into(), - ExprFillDefaultMode::Underscore => { - make.expr_underscore().into() - } - ExprFillDefaultMode::Default => make - .expr_macro( - make.ident_path("todo"), - make.token_tree( - syntax::SyntaxKind::L_PAREN, - [], - ), - ) - .into(), - }, - )), - ) - .into(), - })) - .indent(indent_level + 1) - .into(), + make.expr_return(Some(sad_expr(try_enum, &make, fill_expr))).into(), ) .into(), ), @@ -177,6 +141,15 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op Some(()) } +fn sad_expr(try_enum: TryEnum, make: &SyntaxFactory, err: impl Fn() -> ast::Expr) -> ast::Expr { + match try_enum { + TryEnum::Option => make.expr_path(make.ident_path("None")), + TryEnum::Result => make + .expr_call(make.expr_path(make.ident_path("Err")), make.arg_list(iter::once(err()))) + .into(), + } +} + #[cfg(test)] mod tests { use super::*; @@ -273,6 +246,48 @@ fn test() { let Ok(pat) = Ok(true) else { return Err(todo!()); }; +} + "#, + "Replace try expression with let else", + ); + } + + #[test] + fn test_desugar_try_expr_option_let_else_with_type() { + check_assist_by_label( + desugar_try_expr, + r#" +//- minicore: try, option +fn test() { + let pat: bool = Some(true)$0?; +} + "#, + r#" +fn test() { + let Some(pat): Option = Some(true) else { + return None; + }; +} + "#, + "Replace try expression with let else", + ); + } + + #[test] + fn test_desugar_try_expr_result_let_else_with_type() { + check_assist_by_label( + desugar_try_expr, + r#" +//- minicore: try, result +fn test() { + let pat: bool = Ok(true)$0?; +} + "#, + r#" +fn test() { + let Ok(pat): Result = Ok(true) else { + return Err(todo!()); + }; } "#, "Replace try expression with let else", diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs index 7eca4d3f2a09..6c5c21bfc90f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -317,7 +317,7 @@ fn find_refs_in_mod( .into_iter() .map(|v| Ref { visible_name: v.name(ctx.db()), - def: Definition::Variant(v), + def: Definition::EnumVariant(v), is_pub: true, }) .collect(), @@ -379,7 +379,7 @@ fn find_imported_defs(ctx: &AssistContext<'_>, use_item: Use) -> Vec | Definition::Module(_) | Definition::Function(_) | Definition::Adt(_) - | Definition::Variant(_) + | Definition::EnumVariant(_) | Definition::Const(_) | Definition::Static(_) | Definition::Trait(_) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs index 867ac4851864..a7e78dfc9c94 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -102,7 +102,7 @@ fn expand_tuple_struct_rest_pattern( let fields = match ctx.sema.type_of_pat(&pat.clone().into())?.original.as_adt()? { hir::Adt::Struct(s) if s.kind(ctx.sema.db) == StructKind::Tuple => s.fields(ctx.sema.db), hir::Adt::Enum(_) => match ctx.sema.resolve_path(&path)? { - PathResolution::Def(hir::ModuleDef::Variant(v)) + PathResolution::Def(hir::ModuleDef::EnumVariant(v)) if v.kind(ctx.sema.db) == StructKind::Tuple => { v.fields(ctx.sema.db) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs index 61af2de6ec68..35e8baa18aca 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs @@ -8,7 +8,7 @@ AstNode, AstToken, NodeOrToken, SyntaxKind::WHITESPACE, SyntaxToken, T, - ast::{self, TokenTree, make, syntax_factory::SyntaxFactory}, + ast::{self, TokenTree, syntax_factory::SyntaxFactory}, }; // Assist: extract_expressions_from_format_string @@ -57,6 +57,7 @@ pub(crate) fn extract_expressions_from_format_string( "Extract format expressions", tt.syntax().text_range(), |edit| { + let make = SyntaxFactory::without_mappings(); // Extract existing arguments in macro let mut raw_tokens = tt.token_trees_and_tokens().skip(1).collect_vec(); let format_string_index = format_str_index(&raw_tokens, &fmt_string); @@ -94,14 +95,14 @@ pub(crate) fn extract_expressions_from_format_string( let mut new_tt_bits = raw_tokens; let mut placeholder_indexes = vec![]; - new_tt_bits.push(NodeOrToken::Token(make::tokens::literal(&new_fmt))); + new_tt_bits.push(NodeOrToken::Token(make.expr_literal(&new_fmt).token().clone())); for arg in extracted_args { if matches!(arg, Arg::Expr(_) | Arg::Placeholder) { // insert ", " before each arg new_tt_bits.extend_from_slice(&[ - NodeOrToken::Token(make::token(T![,])), - NodeOrToken::Token(make::tokens::single_space()), + NodeOrToken::Token(make.token(T![,])), + NodeOrToken::Token(make.whitespace(" ")), ]); } @@ -109,7 +110,7 @@ pub(crate) fn extract_expressions_from_format_string( Arg::Expr(s) => { // insert arg let expr = ast::Expr::parse(&s, ctx.edition()).syntax_node(); - let mut expr_tt = utils::tt_from_syntax(expr); + let mut expr_tt = utils::tt_from_syntax(expr, &make); new_tt_bits.append(&mut expr_tt); } Arg::Placeholder => { @@ -120,7 +121,7 @@ pub(crate) fn extract_expressions_from_format_string( } None => { placeholder_indexes.push(new_tt_bits.len()); - new_tt_bits.push(NodeOrToken::Token(make::token(T![_]))); + new_tt_bits.push(NodeOrToken::Token(make.token(T![_]))); } } } @@ -129,7 +130,6 @@ pub(crate) fn extract_expressions_from_format_string( } // Insert new args - let make = SyntaxFactory::with_mappings(); let new_tt = make.token_tree(tt_delimiter, new_tt_bits); let mut editor = edit.make_editor(tt.syntax()); editor.replace(tt.syntax(), new_tt.syntax()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index a17ae4885e62..dcbeaefa21f4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -728,7 +728,7 @@ macro_rules! check_item { } Definition::Function(x) => check_item!(x), Definition::Adt(x) => check_item!(x), - Definition::Variant(x) => check_item!(x), + Definition::EnumVariant(x) => check_item!(x), Definition::Const(x) => check_item!(x), Definition::Static(x) => check_item!(x), Definition::Trait(x) => check_item!(x), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 386652a42292..4c46a51bef58 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -1,7 +1,7 @@ use std::iter; use either::Either; -use hir::{HasCrate, Module, ModuleDef, Name, Variant}; +use hir::{EnumVariant, HasCrate, Module, ModuleDef, Name}; use ide_db::{ FxHashSet, RootDatabase, defs::Definition, @@ -16,9 +16,7 @@ SyntaxKind::*, SyntaxNode, T, ast::{ - self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, - edit::{AstNodeEdit, IndentLevel}, - make, + self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make, }, match_ast, ted, }; @@ -63,7 +61,7 @@ pub(crate) fn extract_struct_from_enum_variant( let edition = enum_hir.krate(ctx.db()).edition(ctx.db()); let variant_hir_name = variant_hir.name(ctx.db()); let enum_module_def = ModuleDef::from(enum_hir); - let usages = Definition::Variant(variant_hir).usages(&ctx.sema).all(); + let usages = Definition::EnumVariant(variant_hir).usages(&ctx.sema).all(); let mut visited_modules_set = FxHashSet::default(); let current_module = enum_hir.module(ctx.db()); @@ -163,7 +161,7 @@ fn extract_field_list_if_applicable( } } -fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Variant) -> bool { +fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &EnumVariant) -> bool { variant .parent_enum(db) .module(db) @@ -175,7 +173,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va def, ModuleDef::Module(_) | ModuleDef::Adt(_) - | ModuleDef::Variant(_) + | ModuleDef::EnumVariant(_) | ModuleDef::Trait(_) | ModuleDef::TypeAlias(_) | ModuleDef::BuiltinType(_) @@ -290,7 +288,6 @@ fn create_struct_def( field_list.clone().into() } }; - let field_list = field_list.indent(IndentLevel::single()); let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index 769bbd976a26..e4fdac27f47f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -2,7 +2,10 @@ use hir::HirDisplay; use ide_db::syntax_helpers::node_ext::walk_ty; use syntax::{ - ast::{self, AstNode, HasGenericArgs, HasGenericParams, HasName, edit::IndentLevel, make}, + ast::{ + self, AstNode, HasGenericArgs, HasGenericParams, HasName, edit::IndentLevel, + syntax_factory::SyntaxFactory, + }, syntax_editor, }; @@ -43,10 +46,9 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> let resolved_ty = ctx.sema.resolve_type(&ty)?; let resolved_ty = if !resolved_ty.contains_unknown() { let module = ctx.sema.scope(ty.syntax())?.module(); - let resolved_ty = resolved_ty.display_source_code(ctx.db(), module.into(), false).ok()?; - make::ty(&resolved_ty) + resolved_ty.display_source_code(ctx.db(), module.into(), false).ok()? } else { - ty.clone() + ty.to_string() }; acc.add( @@ -55,6 +57,9 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> target, |builder| { let mut edit = builder.make_editor(node); + let make = SyntaxFactory::without_mappings(); + + let resolved_ty = make.ty(&resolved_ty); let mut known_generics = match item.generic_param_list() { Some(it) => it.generic_params().collect(), @@ -68,22 +73,20 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> } let generics = collect_used_generics(&ty, &known_generics); let generic_params = - generics.map(|it| make::generic_param_list(it.into_iter().cloned())); + generics.map(|it| make.generic_param_list(it.into_iter().cloned())); // Replace original type with the alias let ty_args = generic_params.as_ref().map(|it| it.to_generic_args().generic_args()); let new_ty = if let Some(ty_args) = ty_args { - make::generic_ty_path_segment(make::name_ref("Type"), ty_args) + make.generic_ty_path_segment(make.name_ref("Type"), ty_args) } else { - make::path_segment(make::name_ref("Type")) - } - .clone_for_update(); + make.path_segment(make.name_ref("Type")) + }; edit.replace(ty.syntax(), new_ty.syntax()); // Insert new alias let ty_alias = - make::ty_alias(None, "Type", generic_params, None, None, Some((resolved_ty, None))) - .clone_for_update(); + make.ty_alias(None, "Type", generic_params, None, None, Some((resolved_ty, None))); if let Some(cap) = ctx.config.snippet_cap && let Some(name) = ty_alias.name() @@ -96,7 +99,7 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> syntax_editor::Position::before(node), vec![ ty_alias.syntax().clone().into(), - make::tokens::whitespace(&format!("\n\n{indent}")).into(), + make.whitespace(&format!("\n\n{indent}")).into(), ], ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 7c6018414217..e5ce02cf5357 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -9,7 +9,6 @@ ast::{ self, AstNode, edit::{AstNodeEdit, IndentLevel}, - make, syntax_factory::SyntaxFactory, }, syntax_editor::Position, @@ -75,7 +74,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op .next() .and_then(ast::Expr::cast) { - expr.syntax().ancestors().find_map(valid_target_expr)?.syntax().clone() + expr.syntax().ancestors().find_map(valid_target_expr(ctx))?.syntax().clone() } else { return None; } @@ -96,7 +95,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let to_extract = node .descendants() .take_while(|it| range.contains_range(it.text_range())) - .find_map(valid_target_expr)?; + .find_map(valid_target_expr(ctx))?; let ty = ctx.sema.type_of_expr(&to_extract).map(TypeInfo::adjusted); if matches!(&ty, Some(ty_info) if ty_info.is_unit()) { @@ -176,7 +175,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let mut editor = edit.make_editor(&expr_replace); let pat_name = make.name(&var_name); - let name_expr = make.expr_path(make::ext::ident_path(&var_name)); + let name_expr = make.expr_path(make.ident_path(&var_name)); if let Some(cap) = ctx.config.snippet_cap { let tabstop = edit.make_tabstop_before(cap); @@ -233,7 +232,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op Position::before(place), vec![ new_stmt.syntax().clone().into(), - make::tokens::whitespace(&trailing_ws).into(), + make.whitespace(&trailing_ws).into(), ], ); @@ -283,14 +282,19 @@ fn peel_parens(mut expr: ast::Expr) -> ast::Expr { /// Check whether the node is a valid expression which can be extracted to a variable. /// In general that's true for any expression, but in some cases that would produce invalid code. -fn valid_target_expr(node: SyntaxNode) -> Option { - match node.kind() { - SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None, +fn valid_target_expr(ctx: &AssistContext<'_>) -> impl Fn(SyntaxNode) -> Option { + |node| match node.kind() { + SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None, SyntaxKind::BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()), SyntaxKind::RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()), SyntaxKind::BLOCK_EXPR => { ast::BlockExpr::cast(node).filter(|it| it.is_standalone()).map(ast::Expr::from) } + SyntaxKind::PATH_EXPR => { + let path_expr = ast::PathExpr::cast(node)?; + let path_resolution = ctx.sema.resolve_path(&path_expr.path()?)?; + like_const_value(ctx, path_resolution).then_some(path_expr.into()) + } _ => ast::Expr::cast(node), } } @@ -455,6 +459,31 @@ fn from(to_extract: &ast::Expr, kind: &ExtractionKind) -> Option { } } +fn like_const_value(ctx: &AssistContext<'_>, path_resolution: hir::PathResolution) -> bool { + let db = ctx.db(); + let adt_like_const_value = |adt: Option| matches!(adt, Some(hir::Adt::Struct(s)) if s.kind(db) == hir::StructKind::Unit); + match path_resolution { + hir::PathResolution::Def(def) => match def { + hir::ModuleDef::Adt(adt) => adt_like_const_value(Some(adt)), + hir::ModuleDef::EnumVariant(variant) => variant.kind(db) == hir::StructKind::Unit, + hir::ModuleDef::TypeAlias(ty) => adt_like_const_value(ty.ty(db).as_adt()), + hir::ModuleDef::Const(_) | hir::ModuleDef::Static(_) => true, + hir::ModuleDef::Trait(_) + | hir::ModuleDef::BuiltinType(_) + | hir::ModuleDef::Macro(_) + | hir::ModuleDef::Module(_) => false, + hir::ModuleDef::Function(_) => false, // no extract named function + }, + hir::PathResolution::SelfType(ty) => adt_like_const_value(ty.self_ty(db).as_adt()), + hir::PathResolution::ConstParam(_) => true, + hir::PathResolution::Local(_) + | hir::PathResolution::TypeParam(_) + | hir::PathResolution::BuiltinAttr(_) + | hir::PathResolution::ToolModule(_) + | hir::PathResolution::DeriveHelper(_) => false, + } +} + #[cfg(test)] mod tests { // NOTE: We use check_assist_by_label, but not check_assist_not_applicable_by_label @@ -1747,6 +1776,27 @@ fn main() { ); } + #[test] + fn extract_non_local_path_expr() { + check_assist_by_label( + extract_variable, + r#" +struct Foo; +fn foo() -> Foo { + $0Foo$0 +} +"#, + r#" +struct Foo; +fn foo() -> Foo { + let $0foo = Foo; + foo +} +"#, + "Extract into variable", + ); + } + #[test] fn extract_var_for_return_not_applicable() { check_assist_not_applicable(extract_variable, "fn foo() { $0return$0; } "); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs index 5134b98f1b2f..440f2d5f17ca 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs @@ -173,7 +173,7 @@ fn offset_target_and_file_id( // FIXME hir::ModuleDef::Macro(_) => return None, // Enum variants can't be private, we can't modify builtin types - hir::ModuleDef::Variant(_) | hir::ModuleDef::BuiltinType(_) => return None, + hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None, }; Some((offset, target, target_file, target_name)) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index b0fa9e6b3ebb..e022a27e519a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -5,15 +5,15 @@ use hir::{HasCrate, Semantics}; use ide_db::{ RootDatabase, - assists::{AssistId, AssistKind, ExprFillDefaultMode}, + assists::{AssistId, AssistKind}, famous_defs::FamousDefs, syntax_helpers::suggest_name, }; use syntax::{ AstNode, ast::{ - self, AssocItem, BlockExpr, GenericParam, HasAttrs, HasGenericParams, HasName, - HasTypeBounds, HasVisibility, edit::AstNodeEdit, make, + self, AssocItem, GenericParam, HasAttrs, HasGenericParams, HasName, HasTypeBounds, + HasVisibility, edit::AstNodeEdit, make, }, syntax_editor::Position, }; @@ -269,7 +269,7 @@ fn todo_fn(f: &ast::Fn, config: &AssistConfig) -> ast::Fn { f.generic_param_list(), f.where_clause(), params, - default_block(config), + make::block_expr(None, Some(crate::utils::expr_fill_default(config))), f.ret_type(), f.async_token().is_some(), f.const_token().is_some(), @@ -278,15 +278,6 @@ fn todo_fn(f: &ast::Fn, config: &AssistConfig) -> ast::Fn { ) } -fn default_block(config: &AssistConfig) -> BlockExpr { - let expr = match config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }; - make::block_expr(None, Some(expr)) -} - fn cfg_attrs(node: &impl HasAttrs) -> impl Iterator { node.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs index 48400d436aa6..2d92bf514622 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs @@ -1,8 +1,12 @@ use ide_db::famous_defs::FamousDefs; -use stdx::format_to; use syntax::{ AstNode, - ast::{self, HasGenericParams, HasName, HasTypeBounds, Impl, make}, + ast::{ + self, HasGenericParams, HasName, HasTypeBounds, Impl, + edit::{AstNodeEdit, IndentLevel}, + syntax_factory::SyntaxFactory, + }, + syntax_editor::Position, }; use crate::{ @@ -62,29 +66,32 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<' return None; } - let insert_location = impl_.syntax().text_range(); + let target = impl_.syntax().text_range(); acc.add( AssistId::generate("generate_default_from_new"), "Generate a Default impl from a new fn", - insert_location, + target, move |builder| { - let default_code = " fn default() -> Self { - Self::new() - }"; - let code = generate_trait_impl_text_from_impl(&impl_, self_ty, "Default", default_code); - builder.insert(insert_location.end(), code); + let make = SyntaxFactory::without_mappings(); + let default_impl = generate_default_impl(&make, &impl_, self_ty); + let indent = IndentLevel::from_node(impl_.syntax()); + let default_impl = default_impl.indent(indent); + + let mut editor = builder.make_editor(impl_.syntax()); + editor.insert_all( + Position::after(impl_.syntax()), + vec![ + make.whitespace(&format!("\n\n{indent}")).into(), + default_impl.syntax().clone().into(), + ], + ); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) } -// FIXME: based on from utils::generate_impl_text_inner -fn generate_trait_impl_text_from_impl( - impl_: &ast::Impl, - self_ty: ast::Type, - trait_text: &str, - code: &str, -) -> String { +fn generate_default_impl(make: &SyntaxFactory, impl_: &ast::Impl, self_ty: ast::Type) -> ast::Impl { let generic_params = impl_.generic_param_list().map(|generic_params| { let lifetime_params = generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam); @@ -92,40 +99,59 @@ fn generate_trait_impl_text_from_impl( // remove defaults since they can't be specified in impls let param = match param { ast::TypeOrConstParam::Type(param) => { - let param = make::type_param(param.name()?, param.type_bound_list()); + let param = make.type_param(param.name()?, param.type_bound_list()); ast::GenericParam::TypeParam(param) } ast::TypeOrConstParam::Const(param) => { - let param = make::const_param(param.name()?, param.ty()?); + let param = make.const_param(param.name()?, param.ty()?); ast::GenericParam::ConstParam(param) } }; Some(param) }); - make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params)) + make.generic_param_list(itertools::chain(lifetime_params, ty_or_const_params)) }); - let mut buf = String::with_capacity(code.len()); - buf.push_str("\n\n"); + let trait_ty: ast::Type = make.ty_path(make.ident_path("Default")).into(); - // `impl{generic_params} {trait_text} for {impl_.self_ty()}` - buf.push_str("impl"); - if let Some(generic_params) = &generic_params { - format_to!(buf, "{generic_params}") - } - format_to!(buf, " {trait_text} for {self_ty}"); + let self_new_path = make.path_concat(make.ident_path("Self"), make.ident_path("new")); + let self_new_call = + make.expr_call(make.expr_path(self_new_path), make.arg_list(std::iter::empty())); + let fn_body = make.block_expr(std::iter::empty(), Some(self_new_call.into())); + let self_ty_ret: ast::Type = make.ty_path(make.ident_path("Self")).into(); + let default_fn = make + .fn_( + [], + None, + make.name("default"), + None, + None, + make.param_list(None, std::iter::empty()), + fn_body, + Some(make.ret_type(self_ty_ret)), + false, + false, + false, + false, + ) + .indent(1.into()); + let body = make.assoc_item_list(Some(ast::AssocItem::from(default_fn))); - match impl_.where_clause() { - Some(where_clause) => { - format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}"); - } - None => { - format_to!(buf, " {{\n{code}\n}}"); - } - } - - buf + make.impl_trait( + [], + false, + None, + None, + generic_params, + None, + false, + trait_ty, + self_ty, + None, + impl_.where_clause(), + Some(body), + ) } fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool { @@ -628,12 +654,12 @@ pub fn new() -> Self { } } -impl Default for Example { - fn default() -> Self { - Self::new() + impl Default for Example { + fn default() -> Self { + Self::new() + } } } -} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs index c1eb1a74ecde..63033c7d5e39 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -4,7 +4,7 @@ ast::{ self, AstNode, HasGenericParams, HasName, HasVisibility as _, edit::{AstNodeEdit, IndentLevel}, - make, + syntax_factory::SyntaxFactory, }, syntax_editor::Position, }; @@ -100,7 +100,6 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { continue; }; - let field = make::ext::field_from_idents(["self", &field_name])?; acc.add_group( &GroupLabel("Generate delegate methods…".to_owned()), @@ -108,10 +107,14 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' format!("Generate delegate for `{field_name}.{name}()`",), target, |edit| { + let make = SyntaxFactory::without_mappings(); + let field = make + .field_from_idents(["self", &field_name]) + .expect("always be a valid expression"); // Create the function let method_source = match ctx.sema.source(method) { Some(source) => { - let v = source.value.clone_for_update(); + let v = source.value; let source_scope = ctx.sema.scope(v.syntax()); let target_scope = ctx.sema.scope(strukt.syntax()); if let (Some(s), Some(t)) = (source_scope, target_scope) { @@ -132,42 +135,42 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let is_unsafe = method_source.unsafe_token().is_some(); let is_gen = method_source.gen_token().is_some(); - let fn_name = make::name(&name); + let fn_name = make.name(&name); let type_params = method_source.generic_param_list(); let where_clause = method_source.where_clause(); let params = - method_source.param_list().unwrap_or_else(|| make::param_list(None, [])); + method_source.param_list().unwrap_or_else(|| make.param_list(None, [])); // compute the `body` let arg_list = method_source .param_list() - .map(convert_param_list_to_arg_list) - .unwrap_or_else(|| make::arg_list([])); + .map(|v| convert_param_list_to_arg_list(v, &make)) + .unwrap_or_else(|| make.arg_list([])); - let tail_expr = - make::expr_method_call(field, make::name_ref(&name), arg_list).into(); + let tail_expr = make.expr_method_call(field, make.name_ref(&name), arg_list).into(); let tail_expr_finished = - if is_async { make::expr_await(tail_expr) } else { tail_expr }; - let body = make::block_expr([], Some(tail_expr_finished)); + if is_async { make.expr_await(tail_expr).into() } else { tail_expr }; + let body = make.block_expr([], Some(tail_expr_finished)); let ret_type = method_source.ret_type(); - let f = make::fn_( - None, - vis, - fn_name, - type_params, - where_clause, - params, - body, - ret_type, - is_async, - is_const, - is_unsafe, - is_gen, - ) - .indent(IndentLevel(1)); + let f = make + .fn_( + None, + vis, + fn_name, + type_params, + where_clause, + params, + body, + ret_type, + is_async, + is_const, + is_unsafe, + is_gen, + ) + .indent(IndentLevel(1)); let item = ast::AssocItem::Fn(f.clone()); let mut editor = edit.make_editor(strukt.syntax()); @@ -179,7 +182,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' Some(item) } None => { - let assoc_item_list = make::assoc_item_list(Some(vec![item])); + let assoc_item_list = make.assoc_item_list(vec![item]); editor.insert( Position::last_child_of(impl_def.syntax()), assoc_item_list.syntax(), @@ -192,17 +195,16 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let ty_params = strukt.generic_param_list(); let ty_args = ty_params.as_ref().map(|it| it.to_generic_args()); let where_clause = strukt.where_clause(); - let assoc_item_list = make::assoc_item_list(Some(vec![item])); + let assoc_item_list = make.assoc_item_list(vec![item]); - let impl_def = make::impl_( + let impl_def = make.impl_( None, ty_params, ty_args, - make::ty_path(make::ext::ident_path(name)), + syntax::ast::Type::PathType(make.ty_path(make.ident_path(name))), where_clause, Some(assoc_item_list), - ) - .clone_for_update(); + ); // Fixup impl_def indentation let indent = strukt.indent_level(); @@ -213,7 +215,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' editor.insert_all( Position::after(strukt.syntax()), vec![ - make::tokens::whitespace(&format!("\n\n{indent}")).into(), + make.whitespace(&format!("\n\n{indent}")).into(), impl_def.syntax().clone().into(), ], ); @@ -227,6 +229,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let tabstop = edit.make_tabstop_before(cap); editor.add_annotation(fn_.syntax(), tabstop); } + editor.add_mappings(make.finish_with_mappings()); edit.add_file_edits(ctx.vfs_file_id(), editor); }, )?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 921f04f2a56b..f703e4dc4ab2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -782,7 +782,7 @@ fn func_assoc_item( }; // Build argument list with self expression prepended - let other_args = convert_param_list_to_arg_list(l); + let other_args = convert_param_list_to_arg_list(l, &make); let all_args: Vec = std::iter::once(tail_expr_self).chain(other_args.args()).collect(); let args = make.arg_list(all_args); @@ -790,13 +790,13 @@ fn func_assoc_item( make.expr_call(make.expr_path(qualified_path), args).into() } None => make - .expr_call(make.expr_path(qualified_path), convert_param_list_to_arg_list(l)) + .expr_call(make.expr_path(qualified_path), convert_param_list_to_arg_list(l, &make)) .into(), }, None => make .expr_call( make.expr_path(qualified_path), - convert_param_list_to_arg_list(make.param_list(None, Vec::new())), + convert_param_list_to_arg_list(make.param_list(None, Vec::new()), &make), ) .into(), }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs index 494c87e6d136..5534dc1cd304 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs @@ -1,16 +1,15 @@ -use std::fmt::Display; - use hir::{ModPath, ModuleDef}; -use ide_db::{RootDatabase, famous_defs::FamousDefs}; +use ide_db::{FileId, RootDatabase, famous_defs::FamousDefs}; use syntax::{ - AstNode, Edition, SyntaxNode, - ast::{self, HasName}, + Edition, + ast::{self, AstNode, HasName, edit::AstNodeEdit, syntax_factory::SyntaxFactory}, + syntax_editor::Position, }; use crate::{ AssistId, assist_context::{AssistContext, Assists, SourceChangeBuilder}, - utils::generate_trait_impl_text_intransitive, + utils::generate_trait_impl_intransitive_with_item, }; // Assist: generate_deref @@ -64,6 +63,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let field_type = field.ty()?; let field_name = field.name()?; let target = field.syntax().text_range(); + let file_id = ctx.vfs_file_id(); acc.add( AssistId::generate("generate_deref"), format!("Generate `{deref_type_to_generate:?}` impl using `{field_name}`"), @@ -72,9 +72,10 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( generate_edit( ctx.db(), edit, + file_id, strukt, - field_type.syntax(), - field_name.syntax(), + field_type, + &field_name.to_string(), deref_type_to_generate, trait_path, module.krate(ctx.db()).edition(ctx.db()), @@ -105,6 +106,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() let field_type = field.ty()?; let target = field.syntax().text_range(); + let file_id = ctx.vfs_file_id(); acc.add( AssistId::generate("generate_deref"), format!("Generate `{deref_type_to_generate:?}` impl using `{field}`"), @@ -113,9 +115,10 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() generate_edit( ctx.db(), edit, + file_id, strukt, - field_type.syntax(), - field_list_index, + field_type, + &field_list_index.to_string(), deref_type_to_generate, trait_path, module.krate(ctx.db()).edition(ctx.db()), @@ -127,35 +130,81 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() fn generate_edit( db: &RootDatabase, edit: &mut SourceChangeBuilder, + file_id: FileId, strukt: ast::Struct, - field_type_syntax: &SyntaxNode, - field_name: impl Display, + field_type: ast::Type, + field_name: &str, deref_type: DerefType, trait_path: ModPath, edition: Edition, ) { - let start_offset = strukt.syntax().text_range().end(); - let impl_code = match deref_type { - DerefType::Deref => format!( - r#" type Target = {field_type_syntax}; + let make = SyntaxFactory::with_mappings(); + let strukt_adt = ast::Adt::Struct(strukt.clone()); + let trait_ty = make.ty(&trait_path.display(db, edition).to_string()); - fn deref(&self) -> &Self::Target {{ - &self.{field_name} - }}"#, - ), - DerefType::DerefMut => format!( - r#" fn deref_mut(&mut self) -> &mut Self::Target {{ - &mut self.{field_name} - }}"#, - ), + let assoc_items: Vec = match deref_type { + DerefType::Deref => { + let target_alias = + make.ty_alias([], "Target", None, None, None, Some((field_type, None))); + let ret_ty = + make.ty_ref(make.ty_path(make.path_from_text("Self::Target")).into(), false); + let field_expr = make.expr_field(make.expr_path(make.ident_path("self")), field_name); + let body = make.block_expr([], Some(make.expr_ref(field_expr.into(), false))); + let fn_ = make + .fn_( + [], + None, + make.name("deref"), + None, + None, + make.param_list(Some(make.self_param()), []), + body, + Some(make.ret_type(ret_ty)), + false, + false, + false, + false, + ) + .indent(1.into()); + vec![ast::AssocItem::TypeAlias(target_alias), ast::AssocItem::Fn(fn_)] + } + DerefType::DerefMut => { + let ret_ty = + make.ty_ref(make.ty_path(make.path_from_text("Self::Target")).into(), true); + let field_expr = make.expr_field(make.expr_path(make.ident_path("self")), field_name); + let body = make.block_expr([], Some(make.expr_ref(field_expr.into(), true))); + let fn_ = make + .fn_( + [], + None, + make.name("deref_mut"), + None, + None, + make.param_list(Some(make.mut_self_param()), []), + body, + Some(make.ret_type(ret_ty)), + false, + false, + false, + false, + ) + .indent(1.into()); + vec![ast::AssocItem::Fn(fn_)] + } }; - let strukt_adt = ast::Adt::Struct(strukt); - let deref_impl = generate_trait_impl_text_intransitive( - &strukt_adt, - &trait_path.display(db, edition).to_string(), - &impl_code, + + let body = make.assoc_item_list(assoc_items); + let indent = strukt.indent_level(); + let impl_ = generate_trait_impl_intransitive_with_item(&make, &strukt_adt, trait_ty, body) + .indent(indent); + + let mut editor = edit.make_editor(strukt.syntax()); + editor.insert_all( + Position::after(strukt.syntax()), + vec![make.whitespace(&format!("\n\n{indent}")).into(), impl_.syntax().clone().into()], ); - edit.insert(start_offset, deref_impl); + editor.add_mappings(make.finish_with_mappings()); + edit.add_file_edits(file_id, editor); } fn existing_deref_impl( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs index 7fd94b4bedc8..6bcbd9b0ccc2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs @@ -2,7 +2,7 @@ use ide_db::assists::{AssistId, GroupLabel}; use syntax::{ AstNode, - ast::{self, HasGenericParams, HasName, edit::IndentLevel, make}, + ast::{self, HasGenericParams, HasName, edit::IndentLevel, syntax_factory::SyntaxFactory}, syntax_editor, }; @@ -56,6 +56,7 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) func_node.syntax().text_range(), |builder| { let mut edit = builder.make_editor(func); + let make = SyntaxFactory::without_mappings(); let alias_name = format!("{}Fn", stdx::to_camel_case(&name.to_string())); @@ -68,24 +69,24 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) let is_mut = self_ty.is_mutable_reference(); if let Some(adt) = self_ty.strip_references().as_adt() { - let inner_type = make::ty(adt.name(ctx.db()).as_str()); + let inner_type = make.ty(adt.name(ctx.db()).as_str()); let ast_self_ty = - if is_ref { make::ty_ref(inner_type, is_mut) } else { inner_type }; + if is_ref { make.ty_ref(inner_type, is_mut) } else { inner_type }; - fn_params_vec.push(make::unnamed_param(ast_self_ty)); + fn_params_vec.push(make.unnamed_param(ast_self_ty)); } } fn_params_vec.extend(param_list.params().filter_map(|p| match style { ParamStyle::Named => Some(p), - ParamStyle::Unnamed => p.ty().map(make::unnamed_param), + ParamStyle::Unnamed => p.ty().map(|ty| make.unnamed_param(ty)), })); let generic_params = func_node.generic_param_list(); let is_unsafe = func_node.unsafe_token().is_some(); - let ty = make::ty_fn_ptr( + let ty = make.ty_fn_ptr( is_unsafe, func_node.abi(), fn_params_vec.into_iter(), @@ -93,22 +94,21 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ); // Insert new alias - let ty_alias = make::ty_alias( + let ty_alias = make.ty_alias( None, &alias_name, generic_params, None, None, Some((ast::Type::FnPtrType(ty), None)), - ) - .clone_for_update(); + ); let indent = IndentLevel::from_node(insertion_node); edit.insert_all( syntax_editor::Position::before(insertion_node), vec![ ty_alias.syntax().clone().into(), - make::tokens::whitespace(&format!("\n\n{indent}")).into(), + make.whitespace(&format!("\n\n{indent}")).into(), ], ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs index 24f271ded80b..1adb3f4fe49a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs @@ -1,10 +1,11 @@ use hir::next_solver::{DbInterner, TypingMode}; use ide_db::{RootDatabase, famous_defs::FamousDefs}; -use syntax::ast::{self, AstNode, HasName}; +use syntax::ast::{self, AstNode, HasName, edit::AstNodeEdit, syntax_factory::SyntaxFactory}; +use syntax::syntax_editor::Position; use crate::{ AssistContext, AssistId, Assists, - utils::{generate_trait_impl_text_intransitive, is_selected}, + utils::{generate_trait_impl_intransitive_with_item, is_selected}, }; // Assist: generate_from_impl_for_enum @@ -33,39 +34,72 @@ pub(crate) fn generate_from_impl_for_enum( let variants = selected_variants(ctx, &variant)?; let target = variant.syntax().text_range(); + let file_id = ctx.vfs_file_id(); acc.add( AssistId::generate("generate_from_impl_for_enum"), "Generate `From` impl for this enum variant(s)", target, |edit| { - let start_offset = variant.parent_enum().syntax().text_range().end(); - let from_impl = variants - .into_iter() - .map(|variant_info| { - let from_trait = format!("From<{}>", variant_info.ty); - let impl_code = generate_impl_code(variant_info); - generate_trait_impl_text_intransitive(&adt, &from_trait, &impl_code) - }) - .collect::(); - edit.insert(start_offset, from_impl); + let make = SyntaxFactory::with_mappings(); + let indent = adt.indent_level(); + let mut elements = Vec::new(); + + for variant_info in variants { + let impl_ = build_from_impl(&make, &adt, variant_info).indent(indent); + elements.push(make.whitespace(&format!("\n\n{indent}")).into()); + elements.push(impl_.syntax().clone().into()); + } + + let mut editor = edit.make_editor(adt.syntax()); + editor.insert_all(Position::after(adt.syntax()), elements); + editor.add_mappings(make.finish_with_mappings()); + edit.add_file_edits(file_id, editor); }, ) } -fn generate_impl_code(VariantInfo { name, field_name, ty }: VariantInfo) -> String { - if let Some(field) = field_name { - format!( - r#" fn from({field}: {ty}) -> Self {{ - Self::{name} {{ {field} }} - }}"# - ) +fn build_from_impl(make: &SyntaxFactory, adt: &ast::Adt, variant_info: VariantInfo) -> ast::Impl { + let VariantInfo { name, field_name, ty } = variant_info; + let trait_ty = make.ty(&format!("From<{ty}>")); + let ret_ty = make.ret_type(make.ty_path(make.ident_path("Self")).into()); + + let (params, body_expr) = if let Some(field) = field_name { + let field_str = field.to_string(); + let param = make.param(make.ident_pat(false, false, make.name(&field_str)).into(), ty); + let field_item = make.record_expr_field(make.name_ref(&field_str), None); + let record = make.record_expr( + make.path_from_text(&format!("Self::{name}")), + make.record_expr_field_list([field_item]), + ); + (make.param_list(None, [param]), ast::Expr::from(record)) } else { - format!( - r#" fn from(v: {ty}) -> Self {{ - Self::{name}(v) - }}"# + let param = make.param(make.ident_pat(false, false, make.name("v")).into(), ty); + let call = make.expr_call( + make.expr_path(make.path_from_text(&format!("Self::{name}"))), + make.arg_list([make.expr_path(make.ident_path("v"))]), + ); + (make.param_list(None, [param]), ast::Expr::from(call)) + }; + + let from_fn = make + .fn_( + [], + None, + make.name("from"), + None, + None, + params, + make.block_expr([], Some(body_expr)), + Some(ret_ty), + false, + false, + false, + false, ) - } + .indent(1.into()); + + let body = make.assoc_item_list([ast::AssocItem::Fn(from_fn)]); + generate_trait_impl_intransitive_with_item(make, adt, trait_ty, body) } struct VariantInfo { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index f62eccaf1952..fbf6241e43a3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -4,7 +4,6 @@ }; use ide_db::{ FileId, FxHashMap, FxHashSet, RootDatabase, SnippetCap, - assists::ExprFillDefaultMode, defs::{Definition, NameRefClass}, famous_defs::FamousDefs, helpers::is_editable_crate, @@ -24,7 +23,7 @@ use crate::{ AssistContext, AssistId, Assists, - utils::{convert_reference_type, find_struct_impl}, + utils::{convert_reference_type, expr_fill_default, find_struct_impl}, }; // Assist: generate_function @@ -286,11 +285,7 @@ fn from_call( target_module, &mut necessary_generic_params, ); - let placeholder_expr = match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }; + let placeholder_expr = expr_fill_default(ctx.config); fn_body = make::block_expr(vec![], Some(placeholder_expr)); }; @@ -345,11 +340,7 @@ fn from_method_call( let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; - let placeholder_expr = match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }; + let placeholder_expr = expr_fill_default(ctx.config); let fn_body = make::block_expr(vec![], Some(placeholder_expr)); Some(Self { @@ -465,11 +456,7 @@ fn make_fn_body_as_new_function( let adt_info = adt_info.as_ref()?; let path_self = make::ext::ident_path("Self"); - let placeholder_expr = match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }; + let placeholder_expr = expr_fill_default(ctx.config); let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() { match strukt.kind(ctx.db()) { StructKind::Record => { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs index 92a654743b58..62ffd3d9656b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -218,14 +218,14 @@ fn generate_getter_from_info( ctx: &AssistContext<'_>, info: &AssistInfo, record_field_info: &RecordFieldInfo, - syntax_factory: &SyntaxFactory, + make: &SyntaxFactory, ) -> ast::Fn { let (ty, body) = if matches!(info.assist_type, AssistType::MutGet) { - let self_expr = syntax_factory.expr_path(syntax_factory.ident_path("self")); + let self_expr = make.expr_path(make.ident_path("self")); ( - syntax_factory.ty_ref(record_field_info.field_ty.clone(), true), - syntax_factory.expr_ref( - syntax_factory.expr_field(self_expr, &record_field_info.field_name.text()).into(), + make.ty_ref(record_field_info.field_ty.clone(), true), + make.expr_ref( + make.expr_field(self_expr, &record_field_info.field_name.text()).into(), true, ), ) @@ -239,21 +239,20 @@ fn generate_getter_from_info( .map(|conversion| { cov_mark::hit!(convert_reference_type); ( - conversion.convert_type(ctx.db(), module), - conversion.getter(record_field_info.field_name.to_string()), + conversion.convert_type_with_factory(make, ctx.db(), module), + conversion.getter(make, record_field_info.field_name.to_string()), ) }) })() .unwrap_or_else(|| { ( - syntax_factory.ty_ref(record_field_info.field_ty.clone(), false), - syntax_factory.expr_ref( - syntax_factory - .expr_field( - syntax_factory.expr_path(syntax_factory.ident_path("self")), - &record_field_info.field_name.text(), - ) - .into(), + make.ty_ref(record_field_info.field_ty.clone(), false), + make.expr_ref( + make.expr_field( + make.expr_path(make.ident_path("self")), + &record_field_info.field_name.text(), + ) + .into(), false, ), ) @@ -261,18 +260,18 @@ fn generate_getter_from_info( }; let self_param = if matches!(info.assist_type, AssistType::MutGet) { - syntax_factory.mut_self_param() + make.mut_self_param() } else { - syntax_factory.self_param() + make.self_param() }; let strukt = &info.strukt; - let fn_name = syntax_factory.name(&record_field_info.fn_name); - let params = syntax_factory.param_list(Some(self_param), []); - let ret_type = Some(syntax_factory.ret_type(ty)); - let body = syntax_factory.block_expr([], Some(body)); + let fn_name = make.name(&record_field_info.fn_name); + let params = make.param_list(Some(self_param), []); + let ret_type = Some(make.ret_type(ty)); + let body = make.block_expr([], Some(body)); - syntax_factory.fn_( + make.fn_( None, strukt.visibility(), fn_name, @@ -291,32 +290,29 @@ fn generate_getter_from_info( fn generate_setter_from_info( info: &AssistInfo, record_field_info: &RecordFieldInfo, - syntax_factory: &SyntaxFactory, + make: &SyntaxFactory, ) -> ast::Fn { let strukt = &info.strukt; let field_name = &record_field_info.fn_name; - let fn_name = syntax_factory.name(&format!("set_{field_name}")); + let fn_name = make.name(&format!("set_{field_name}")); let field_ty = &record_field_info.field_ty; // Make the param list // `(&mut self, $field_name: $field_ty)` - let field_param = syntax_factory.param( - syntax_factory.ident_pat(false, false, syntax_factory.name(field_name)).into(), - field_ty.clone(), - ); - let params = syntax_factory.param_list(Some(syntax_factory.mut_self_param()), [field_param]); + let field_param = + make.param(make.ident_pat(false, false, make.name(field_name)).into(), field_ty.clone()); + let params = make.param_list(Some(make.mut_self_param()), [field_param]); // Make the assignment body // `self.$field_name = $field_name` - let self_expr = syntax_factory.expr_path(syntax_factory.ident_path("self")); - let lhs = syntax_factory.expr_field(self_expr, field_name); - let rhs = syntax_factory.expr_path(syntax_factory.ident_path(field_name)); - let assign_stmt = - syntax_factory.expr_stmt(syntax_factory.expr_assignment(lhs.into(), rhs).into()); - let body = syntax_factory.block_expr([assign_stmt.into()], None); + let self_expr = make.expr_path(make.ident_path("self")); + let lhs = make.expr_field(self_expr, field_name); + let rhs = make.expr_path(make.ident_path(field_name)); + let assign_stmt = make.expr_stmt(make.expr_assignment(lhs.into(), rhs).into()); + let body = make.block_expr([assign_stmt.into()], None); // Make the setter fn - syntax_factory.fn_( + make.fn_( None, strukt.visibility(), fn_name, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index bbd42481ef0f..2d1235792dcf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -1,15 +1,21 @@ use syntax::{ - ast::{self, AstNode, HasGenericParams, HasName, edit::AstNodeEdit, make}, + ast::{ + self, AstNode, HasGenericParams, HasName, edit::AstNodeEdit, syntax_factory::SyntaxFactory, + }, syntax_editor::{Position, SyntaxEditor}, }; use crate::{ AssistContext, AssistId, Assists, - utils::{self, DefaultMethods, IgnoreAssocItems}, + utils::{ + self, DefaultMethods, IgnoreAssocItems, generate_impl_with_factory, + generate_trait_impl_intransitive, + }, }; fn insert_impl( editor: &mut SyntaxEditor, + make: &SyntaxFactory, impl_: &ast::Impl, nominal: &impl AstNodeEdit, ) -> ast::Impl { @@ -20,7 +26,7 @@ fn insert_impl( Position::after(nominal.syntax()), vec![ // Add a blank line after the ADT, and indentation for the impl to match the ADT - make::tokens::whitespace(&format!("\n\n{indent}")).into(), + make.whitespace(&format!("\n\n{indent}")).into(), impl_.syntax().clone().into(), ], ); @@ -59,12 +65,13 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio format!("Generate impl for `{name}`"), target, |edit| { + let make = SyntaxFactory::with_mappings(); // Generate the impl - let impl_ = utils::generate_impl(&nominal); + let impl_ = generate_impl_with_factory(&make, &nominal); let mut editor = edit.make_editor(nominal.syntax()); - let impl_ = insert_impl(&mut editor, &impl_, &nominal); + let impl_ = insert_impl(&mut editor, &make, &impl_, &nominal); // Add a tabstop after the left curly brace if let Some(cap) = ctx.config.snippet_cap && let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) @@ -73,6 +80,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio editor.add_annotation(l_curly, tabstop); } + editor.add_mappings(make.finish_with_mappings()); edit.add_file_edits(ctx.vfs_file_id(), editor); }, ) @@ -109,12 +117,13 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> format!("Generate trait impl for `{name}`"), target, |edit| { + let make = SyntaxFactory::with_mappings(); // Generate the impl - let impl_ = utils::generate_trait_impl_intransitive(&nominal, make::ty_placeholder()); + let impl_ = generate_trait_impl_intransitive(&make, &nominal, make.ty_placeholder()); let mut editor = edit.make_editor(nominal.syntax()); - let impl_ = insert_impl(&mut editor, &impl_, &nominal); + let impl_ = insert_impl(&mut editor, &make, &impl_, &nominal); // Make the trait type a placeholder snippet if let Some(cap) = ctx.config.snippet_cap { if let Some(trait_) = impl_.trait_() { @@ -128,6 +137,7 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> } } + editor.add_mappings(make.finish_with_mappings()); edit.add_file_edits(ctx.vfs_file_id(), editor); }, ) @@ -166,9 +176,10 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> format!("Generate `{name}` impl for type"), target, |edit| { + let make = SyntaxFactory::with_mappings(); let mut editor = edit.make_editor(trait_.syntax()); - let holder_arg = ast::GenericArg::TypeArg(make::type_arg(make::ty_placeholder())); + let holder_arg = ast::GenericArg::TypeArg(make.type_arg(make.ty_placeholder())); let missing_items = utils::filter_assoc_items( &ctx.sema, &hir_trait.items(ctx.db()), @@ -177,11 +188,11 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> ); let trait_gen_args = trait_.generic_param_list().map(|list| { - make::generic_arg_list(list.generic_params().map(|_| holder_arg.clone())) + make.generic_arg_list(list.generic_params().map(|_| holder_arg.clone()), false) }); let make_impl_ = |body| { - make::impl_trait( + make.impl_trait( None, trait_.unsafe_token().is_some(), None, @@ -189,13 +200,12 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> None, None, false, - make::ty(&name.text()), - make::ty_placeholder(), + make.ty(&name.text()), + make.ty_placeholder(), None, None, body, ) - .clone_for_update() }; let impl_ = if missing_items.is_empty() { @@ -210,11 +220,12 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> &impl_, &target_scope, ); - let assoc_item_list = make::assoc_item_list(Some(assoc_items)); + let assoc_item_list = make.assoc_item_list(assoc_items); make_impl_(Some(assoc_item_list)) }; - let impl_ = insert_impl(&mut editor, &impl_, &trait_); + let impl_ = insert_impl(&mut editor, &make, &impl_, &trait_); + editor.add_mappings(make.finish_with_mappings()); if let Some(cap) = ctx.config.snippet_cap { if let Some(generics) = impl_.trait_().and_then(|it| it.generic_arg_list()) { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs index 793211a27b47..301d13c09584 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs @@ -3,7 +3,10 @@ use_trivial_constructor::use_trivial_constructor, }; use syntax::{ - ast::{self, AstNode, HasName, HasVisibility, StructKind, edit::AstNodeEdit, make}, + ast::{ + self, AstNode, HasName, HasVisibility, StructKind, edit::AstNodeEdit, + syntax_factory::SyntaxFactory, + }, syntax_editor::Position, }; @@ -36,6 +39,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let strukt = ctx.find_node_at_offset::()?; + let make = SyntaxFactory::without_mappings(); let field_list = match strukt.kind() { StructKind::Record(named) => { named.fields().filter_map(|f| Some((f.name()?, f.ty()?))).collect::>() @@ -55,7 +59,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option Some(name) => name, None => name_generator.suggest_name(&format!("_{i}")), }; - Some((make::name(name.as_str()), f.ty()?)) + Some((make.name(name.as_str()), f.ty()?)) }) .collect::>() } @@ -70,6 +74,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let target = strukt.syntax().text_range(); acc.add(AssistId::generate("generate_new"), "Generate `new`", target, |builder| { + let make = SyntaxFactory::with_mappings(); let trivial_constructors = field_list .iter() .map(|(name, ty)| { @@ -95,63 +100,63 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option edition, )?; - Some((make::name_ref(&name.text()), Some(expr))) + Some((make.name_ref(&name.text()), Some(expr))) }) .collect::>(); let params = field_list.iter().enumerate().filter_map(|(i, (name, ty))| { if trivial_constructors[i].is_none() { - Some(make::param(make::ident_pat(false, false, name.clone()).into(), ty.clone())) + Some(make.param(make.ident_pat(false, false, name.clone()).into(), ty.clone())) } else { None } }); - let params = make::param_list(None, params); + let params = make.param_list(None, params); let fields = field_list.iter().enumerate().map(|(i, (name, _))| { if let Some(constructor) = trivial_constructors[i].clone() { constructor } else { - (make::name_ref(&name.text()), None) + (make.name_ref(&name.text()), None) } }); let tail_expr: ast::Expr = match strukt.kind() { StructKind::Record(_) => { - let fields = fields.map(|(name, expr)| make::record_expr_field(name, expr)); - let fields = make::record_expr_field_list(fields); - make::record_expr(make::ext::ident_path("Self"), fields).into() + let fields = fields.map(|(name, expr)| make.record_expr_field(name, expr)); + let fields = make.record_expr_field_list(fields); + make.record_expr(make.ident_path("Self"), fields).into() } StructKind::Tuple(_) => { let args = fields.map(|(arg, expr)| { - let arg = || make::expr_path(make::path_unqualified(make::path_segment(arg))); + let arg = || make.expr_path(make.path_unqualified(make.path_segment(arg))); expr.unwrap_or_else(arg) }); - let arg_list = make::arg_list(args); - make::expr_call(make::expr_path(make::ext::ident_path("Self")), arg_list).into() + let arg_list = make.arg_list(args); + make.expr_call(make.expr_path(make.ident_path("Self")), arg_list).into() } StructKind::Unit => unreachable!(), }; - let body = make::block_expr(None, tail_expr.into()); + let body = make.block_expr(None, tail_expr.into()); - let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self"))); + let ret_type = make.ret_type(make.ty_path(make.ident_path("Self")).into()); - let fn_ = make::fn_( - None, - strukt.visibility(), - make::name("new"), - None, - None, - params, - body, - Some(ret_type), - false, - false, - false, - false, - ) - .clone_for_update() - .indent(1.into()); + let fn_ = make + .fn_( + [], + strukt.visibility(), + make.name("new"), + None, + None, + params, + body, + Some(ret_type), + false, + false, + false, + false, + ) + .indent(1.into()); let mut editor = builder.make_editor(strukt.syntax()); @@ -164,32 +169,30 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option editor.insert_all( Position::after(l_curly), vec![ - make::tokens::whitespace(&format!("\n{}", impl_def.indent_level() + 1)) - .into(), + make.whitespace(&format!("\n{}", impl_def.indent_level() + 1)).into(), fn_.syntax().clone().into(), - make::tokens::whitespace("\n").into(), + make.whitespace("\n").into(), ], ); fn_.syntax().clone() } else { - let items = vec![ast::AssocItem::Fn(fn_)]; - let list = make::assoc_item_list(Some(items)); + let list = make.assoc_item_list([ast::AssocItem::Fn(fn_)]); editor.insert(Position::after(impl_def.syntax()), list.syntax()); list.syntax().clone() } } else { // Generate a new impl to add the method to let indent_level = strukt.indent_level(); - let body = vec![ast::AssocItem::Fn(fn_)]; - let list = make::assoc_item_list(Some(body)); - let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list)) - .indent(strukt.indent_level()); + let list = make.assoc_item_list([ast::AssocItem::Fn(fn_)]); + let impl_def = + generate_impl_with_item(&make, &ast::Adt::Struct(strukt.clone()), Some(list)) + .indent(strukt.indent_level()); // Insert it after the adt editor.insert_all( Position::after(strukt.syntax()), vec![ - make::tokens::whitespace(&format!("\n\n{indent_level}")).into(), + make.whitespace(&format!("\n\n{indent_level}")).into(), impl_def.syntax().clone().into(), ], ); @@ -233,6 +236,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option } } + editor.add_mappings(make.finish_with_mappings()); builder.add_file_edits(ctx.vfs_file_id(), editor); }) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs index 8bc4d50cf6af..1286abe3565e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs @@ -1,8 +1,10 @@ use crate::assist_context::{AssistContext, Assists}; use ide_db::assists::AssistId; use syntax::{ - AstNode, SyntaxKind, T, - ast::{self, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make}, + AstNode, AstToken, SyntaxKind, T, + ast::{ + self, HasDocComments, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make, + }, syntax_editor::{Position, SyntaxEditor}, }; @@ -45,7 +47,7 @@ // }; // } // -// trait ${0:NewTrait} { +// trait ${0:Create} { // // Used as an associated constant. // const CONST_ASSOC: usize = N * 4; // @@ -54,7 +56,7 @@ // const_maker! {i32, 7} // } // -// impl ${0:NewTrait} for Foo { +// impl ${0:Create} for Foo { // // Used as an associated constant. // const CONST_ASSOC: usize = N * 4; // @@ -107,7 +109,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ }; let trait_ast = make::trait_( false, - "NewTrait", + &trait_name(&impl_assoc_items).text(), impl_ast.generic_param_list(), impl_ast.where_clause(), trait_items, @@ -133,6 +135,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ let mut editor = builder.make_editor(impl_ast.syntax()); impl_assoc_items.assoc_items().for_each(|item| { remove_items_visibility(&mut editor, &item); + remove_doc_comments(&mut editor, &item); }); editor.insert_all(Position::before(impl_name.syntax()), elements); @@ -160,6 +163,18 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ Some(()) } +fn trait_name(items: &ast::AssocItemList) -> ast::Name { + let mut fn_names = items + .assoc_items() + .filter_map(|x| if let ast::AssocItem::Fn(f) = x { f.name() } else { None }); + fn_names + .next() + .and_then(|name| { + fn_names.next().is_none().then(|| make::name(&stdx::to_camel_case(&name.text()))) + }) + .unwrap_or_else(|| make::name("NewTrait")) +} + /// `E0449` Trait items always share the visibility of their trait fn remove_items_visibility(editor: &mut SyntaxEditor, item: &ast::AssocItem) { if let Some(has_vis) = ast::AnyHasVisibility::cast(item.syntax().clone()) { @@ -175,6 +190,17 @@ fn remove_items_visibility(editor: &mut SyntaxEditor, item: &ast::AssocItem) { } } +fn remove_doc_comments(editor: &mut SyntaxEditor, item: &ast::AssocItem) { + for doc in item.doc_comments() { + if let Some(next) = doc.syntax().next_token() + && next.kind() == SyntaxKind::WHITESPACE + { + editor.delete(next); + } + editor.delete(doc.syntax()); + } +} + fn strip_body(editor: &mut SyntaxEditor, item: &ast::AssocItem) { if let ast::AssocItem::Fn(f) = item && let Some(body) = f.body() @@ -226,11 +252,47 @@ fn add(&mut self, x: f64) { r#" struct Foo(f64); -trait NewTrait { +trait Add { fn add(&mut self, x: f64); } -impl NewTrait for Foo { +impl Add for Foo { + fn add(&mut self, x: f64) { + self.0 += x; + } +}"#, + ) + } + + #[test] + fn test_remove_doc_comments() { + check_assist_no_snippet_cap( + generate_trait_from_impl, + r#" +struct Foo(f64); + +impl F$0oo { + /// Add `x` + /// + /// # Examples + #[cfg(true)] + fn add(&mut self, x: f64) { + self.0 += x; + } +}"#, + r#" +struct Foo(f64); + +trait Add { + /// Add `x` + /// + /// # Examples + #[cfg(true)] + fn add(&mut self, x: f64); +} + +impl Add for Foo { + #[cfg(true)] fn add(&mut self, x: f64) { self.0 += x; } @@ -339,11 +401,11 @@ pub fn a_func() -> Option<()> { r#" struct Foo; -trait NewTrait { +trait AFunc { fn a_func() -> Option<()>; } -impl NewTrait for Foo { +impl AFunc for Foo { fn a_func() -> Option<()> { Some(()) } @@ -373,17 +435,39 @@ fn foo() {} }"#, r#" mod a { - trait NewTrait { + trait Foo { fn foo(); } - impl NewTrait for S { + impl Foo for S { fn foo() {} } }"#, ) } + #[test] + fn test_multi_fn_impl_not_suggest_trait_name() { + check_assist_no_snippet_cap( + generate_trait_from_impl, + r#" +impl S$0 { + fn foo() {} + fn bar() {} +}"#, + r#" +trait NewTrait { + fn foo(); + fn bar(); +} + +impl NewTrait for S { + fn foo() {} + fn bar() {} +}"#, + ) + } + #[test] fn test_snippet_cap_is_some() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs index 5d4bdc6ec76c..f55ef4229e58 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs @@ -1,3 +1,4 @@ +use either::{Either, for_both}; use hir::{PathResolution, Semantics}; use ide_db::{ EditionedFileId, RootDatabase, @@ -5,8 +6,9 @@ search::{FileReference, FileReferenceNode, UsageSearchResult}, }; use syntax::{ - SyntaxElement, TextRange, + Direction, TextRange, ast::{self, AstNode, AstToken, HasName, syntax_factory::SyntaxFactory}, + syntax_editor::{Element, SyntaxEditor}, }; use crate::{ @@ -36,12 +38,15 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>) let InlineData { let_stmt, delete_let, references, target } = if let Some(path_expr) = ctx.find_node_at_offset::() { inline_usage(&ctx.sema, path_expr, range, file_id) - } else if let Some(let_stmt) = ctx.find_node_at_offset::() { + } else if let Some(let_stmt) = ctx.find_node_at_offset() { inline_let(&ctx.sema, let_stmt, range, file_id) } else { None }?; - let initializer_expr = let_stmt.initializer()?; + let initializer_expr = match &let_stmt { + either::Either::Left(it) => it.initializer()?, + either::Either::Right(it) => it.expr()?, + }; let wrap_in_parens = references .into_iter() @@ -81,13 +86,15 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>) let mut editor = builder.make_editor(&target); if delete_let { editor.delete(let_stmt.syntax()); - if let Some(whitespace) = let_stmt - .syntax() - .next_sibling_or_token() - .and_then(SyntaxElement::into_token) - .and_then(ast::Whitespace::cast) + + if let Some(bin_expr) = let_stmt.syntax().parent().and_then(ast::BinExpr::cast) + && let Some(op_token) = bin_expr.op_token() { - editor.delete(whitespace.syntax()); + editor.delete(&op_token); + remove_whitespace(op_token, Direction::Prev, &mut editor); + remove_whitespace(let_stmt.syntax(), Direction::Prev, &mut editor); + } else { + remove_whitespace(let_stmt.syntax(), Direction::Next, &mut editor); } } @@ -116,7 +123,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>) } struct InlineData { - let_stmt: ast::LetStmt, + let_stmt: Either, delete_let: bool, target: ast::NameOrNameRef, references: Vec, @@ -124,11 +131,11 @@ struct InlineData { fn inline_let( sema: &Semantics<'_, RootDatabase>, - let_stmt: ast::LetStmt, + let_stmt: Either, range: TextRange, file_id: EditionedFileId, ) -> Option { - let bind_pat = match let_stmt.pat()? { + let bind_pat = match for_both!(&let_stmt, it => it.pat())? { ast::Pat::IdentPat(pat) => pat, _ => return None, }; @@ -187,7 +194,7 @@ fn inline_usage( let bind_pat = source.as_ident_pat()?; - let let_stmt = ast::LetStmt::cast(bind_pat.syntax().parent()?)?; + let let_stmt = AstNode::cast(bind_pat.syntax().parent()?)?; let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all(); let mut references = references.remove(&file_id)?; @@ -197,6 +204,23 @@ fn inline_usage( Some(InlineData { let_stmt, delete_let, target: ast::NameOrNameRef::NameRef(name), references }) } +fn remove_whitespace(elem: impl Element, dir: Direction, editor: &mut SyntaxEditor) { + let token = match elem.syntax_element() { + syntax::NodeOrToken::Node(node) => match dir { + Direction::Next => node.last_token(), + Direction::Prev => node.first_token(), + }, + syntax::NodeOrToken::Token(t) => Some(t), + }; + let next_token = match dir { + Direction::Next => token.and_then(|it| it.next_token()), + Direction::Prev => token.and_then(|it| it.prev_token()), + }; + if let Some(whitespace) = next_token.and_then(ast::Whitespace::cast) { + editor.delete(whitespace.syntax()); + } +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -404,6 +428,38 @@ fn foo() { ); } + #[test] + fn test_inline_let_expr() { + check_assist( + inline_local_variable, + r" +fn bar(a: usize) {} +fn foo() { + if let a$0 = 1 + && true + { + a + 1; + if a > 10 {} + while a > 10 {} + let b = a * 10; + bar(a); + } +}", + r" +fn bar(a: usize) {} +fn foo() { + if true + { + 1 + 1; + if 1 > 10 {} + while 1 > 10 {} + let b = 1 * 10; + bar(1); + } +}", + ); + } + #[test] fn test_not_inline_mut_variable() { cov_mark::check!(test_not_inline_mut_variable); @@ -816,6 +872,70 @@ fn f() { ); } + #[test] + fn let_expr_works_on_local_usage() { + check_assist( + inline_local_variable, + r#" +fn f() { + if let xyz = 0 + && true + { + xyz$0; + } +} +"#, + r#" +fn f() { + if true + { + 0; + } +} +"#, + ); + + check_assist( + inline_local_variable, + r#" +fn f() { + if let xyz = true + && xyz$0 + { + } +} +"#, + r#" +fn f() { + if true + { + } +} +"#, + ); + + check_assist( + inline_local_variable, + r#" +fn f() { + if true + && let xyz = 0 + { + xyz$0; + } +} +"#, + r#" +fn f() { + if true + { + 0; + } +} +"#, + ); + } + #[test] fn does_not_remove_let_when_multiple_usages() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs index c7a48f3261a9..f3ebe6107819 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -12,7 +12,7 @@ use syntax::ast::syntax_factory::SyntaxFactory; use syntax::syntax_editor::SyntaxEditor; use syntax::{ - AstNode, NodeOrToken, SyntaxNode, + AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, ast::{self, HasGenericParams, HasName}, }; @@ -322,12 +322,42 @@ fn create_replacement( if let Some(old_lifetime) = ast::Lifetime::cast(syntax.clone()) { if let Some(new_lifetime) = lifetime_map.0.get(&old_lifetime.to_string()) { if new_lifetime.text() == "'_" { - removals.push(NodeOrToken::Node(syntax.clone())); + // Check if this lifetime is inside a LifetimeArg (in angle brackets) + if let Some(lifetime_arg) = + old_lifetime.syntax().parent().and_then(ast::LifetimeArg::cast) + { + // Remove LifetimeArg and associated comma/whitespace + let lifetime_arg_syntax = lifetime_arg.syntax(); + removals.push(NodeOrToken::Node(lifetime_arg_syntax.clone())); - if let Some(ws) = syntax.next_sibling_or_token() { - removals.push(ws.clone()); + // Remove comma and whitespace (look forward then backward) + let comma_and_ws: Vec<_> = lifetime_arg_syntax + .siblings_with_tokens(syntax::Direction::Next) + .skip(1) + .take_while(|it| it.as_token().is_some()) + .take_while_inclusive(|it| it.kind() == T![,]) + .collect(); + + if comma_and_ws.iter().any(|it| it.kind() == T![,]) { + removals.extend(comma_and_ws); + } else { + // No comma after, try before + let comma_and_ws: Vec<_> = lifetime_arg_syntax + .siblings_with_tokens(syntax::Direction::Prev) + .skip(1) + .take_while(|it| it.as_token().is_some()) + .take_while_inclusive(|it| it.kind() == T![,]) + .collect(); + removals.extend(comma_and_ws); + } + continue; + } + removals.push(NodeOrToken::Node(syntax.clone())); + if let Some(ws) = syntax.next_sibling_or_token() + && ws.kind() == SyntaxKind::WHITESPACE + { + removals.push(ws); } - continue; } @@ -349,6 +379,34 @@ fn create_replacement( } } + // Deduplicate removals to avoid intersecting changes + removals.sort_by_key(|n| n.text_range().start()); + removals.dedup(); + + // Remove GenericArgList entirely if all its args are being removed (avoids empty angle brackets) + let generic_arg_lists_to_check: Vec<_> = + updated_concrete_type.descendants().filter_map(ast::GenericArgList::cast).collect(); + + for generic_arg_list in generic_arg_lists_to_check { + let will_be_empty = generic_arg_list.generic_args().all(|arg| match arg { + ast::GenericArg::LifetimeArg(lt_arg) => removals.iter().any(|removal| { + if let NodeOrToken::Node(node) = removal { node == lt_arg.syntax() } else { false } + }), + _ => false, + }); + + if will_be_empty && generic_arg_list.generic_args().next().is_some() { + removals.retain(|removal| { + if let NodeOrToken::Node(node) = removal { + !node.ancestors().any(|anc| anc == *generic_arg_list.syntax()) + } else { + true + } + }); + removals.push(NodeOrToken::Node(generic_arg_list.syntax().clone())); + } + } + for (old, new) in replacements { editor.replace(old, new); } @@ -946,6 +1004,48 @@ trait Tr { ); } + #[test] + fn inline_types_with_lifetime() { + check_assist( + inline_type_alias_uses, + r#" +struct A<'a, 'b>(pub &'a mut &'b mut ()); + +type $0T<'a, 'b> = A<'a, 'b>; + +fn foo(_: T) {} +"#, + r#" +struct A<'a, 'b>(pub &'a mut &'b mut ()); + + + +fn foo(_: A) {} +"#, + ); + } + + #[test] + fn mixed_lifetime_and_type_args() { + check_assist( + inline_type_alias, + r#" +type Foo<'a, T> = Bar<'a, T>; +struct Bar<'a, T>(&'a T); +fn main() { + let a: $0Foo; +} +"#, + r#" +type Foo<'a, T> = Bar<'a, T>; +struct Bar<'a, T>(&'a T); +fn main() { + let a: Bar; +} +"#, + ); + } + mod inline_type_alias_uses { use crate::{handlers::inline_type_alias::inline_type_alias_uses, tests::check_assist}; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs index bf82d8df9b58..c8cb7bb60f69 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs @@ -1,13 +1,13 @@ use ide_db::syntax_helpers::node_ext::is_pattern_cond; use syntax::{ T, - ast::{self, AstNode}, + ast::{self, AstNode, syntax_factory::SyntaxFactory}, }; use crate::{ AssistId, assist_context::{AssistContext, Assists}, - utils::invert_boolean_expression_legacy, + utils::invert_boolean_expression, }; // Assist: invert_if @@ -50,7 +50,8 @@ pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() }; acc.add(AssistId::refactor_rewrite("invert_if"), "Invert if", if_range, |edit| { - let flip_cond = invert_boolean_expression_legacy(cond.clone()); + let make = SyntaxFactory::without_mappings(); + let flip_cond = invert_boolean_expression(&make, cond.clone()); edit.replace_ast(cond, flip_cond); let else_node = else_block.syntax(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index 9ba73d23dd24..42bc05811fd1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -49,8 +49,9 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio SyntaxElement::Node(n) => n, SyntaxElement::Token(t) => t.parent()?, }; - let mut selected_nodes = - parent_node.children().filter(|it| selection_range.contains_range(it.text_range())); + let mut selected_nodes = parent_node.children().filter(|it| { + selection_range.intersect(it.text_range()).is_some_and(|it| !it.is_empty()) + }); let first_selected = selected_nodes.next()?; let edits = match_ast! { @@ -677,6 +678,25 @@ fn merge_selection_uses() { ); } + #[test] + fn merge_partial_selection_uses() { + cov_mark::check!(merge_with_selected_use_item_neighbors); + check_assist( + merge_imports, + r" +use std::fmt::Error; +$0use std::fmt::Display; +use std::fmt::Debug; +use std::fmt::Write; +use$0 std::fmt::Result; +", + r" +use std::fmt::Error; +use std::fmt::{Debug, Display, Result, Write}; +", + ); + } + #[test] fn merge_selection_use_trees() { cov_mark::check!(merge_with_selected_use_tree_neighbors); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs index 08170f81b283..6e84af5f9129 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs @@ -160,8 +160,11 @@ fn recurse<'db>( } } ast::Pat::IdentPat(ident_pat) => { - if let Some(name) = ident_pat.name() { + if let Some(name) = ident_pat.name() + && ctx.sema.to_def(ident_pat).is_some() + { let pat_type = ctx.sema.type_of_binding_in_pat(ident_pat); + map.insert(name.text().to_string(), pat_type); } } @@ -212,6 +215,40 @@ fn main() { ); } + #[test] + fn merge_match_arms_ambiguous_ident_patterns() { + check_assist( + merge_match_arms, + r#" +#[derive(Debug)] +enum X { A, B, C } +use X::*; + +fn main() { + let x = A; + let y = match x { + A => { 1i32$0 } + B => { 1i32 } + C => { 2i32 } + } +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } +use X::*; + +fn main() { + let x = A; + let y = match x { + A | B => { 1i32 }, + C => { 2i32 } + } +} +"#, + ); + } + #[test] fn merge_match_arms_multiple_patterns() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs index e5425abab097..79b8bd5d3d48 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs @@ -1,11 +1,8 @@ use either::Either; use syntax::{ - ast::{ - self, AstNode, HasName, HasTypeBounds, - edit_in_place::{GenericParamsOwnerEdit, Removable}, - make, - }, + ast::{self, AstNode, HasName, HasTypeBounds, syntax_factory::SyntaxFactory}, match_ast, + syntax_editor::{GetOrCreateWhereClause, Removable}, }; use crate::{AssistContext, AssistId, Assists}; @@ -47,18 +44,23 @@ pub(crate) fn move_bounds_to_where_clause( AssistId::refactor_rewrite("move_bounds_to_where_clause"), "Move to where clause", target, - |edit| { - let type_param_list = edit.make_mut(type_param_list); - let parent = edit.make_syntax_mut(parent); + |builder| { + let mut edit = builder.make_editor(&parent); + let make = SyntaxFactory::without_mappings(); - let where_clause: ast::WhereClause = match_ast! { - match parent { - ast::Fn(it) => it.get_or_create_where_clause(), - ast::Trait(it) => it.get_or_create_where_clause(), - ast::Impl(it) => it.get_or_create_where_clause(), - ast::Enum(it) => it.get_or_create_where_clause(), - ast::Struct(it) => it.get_or_create_where_clause(), - ast::TypeAlias(it) => it.get_or_create_where_clause(), + let new_preds: Vec = type_param_list + .generic_params() + .filter_map(|param| build_predicate(param, &make)) + .collect(); + + match_ast! { + match (&parent) { + ast::Fn(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()), + ast::Trait(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()), + ast::Impl(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()), + ast::Enum(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()), + ast::Struct(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()), + ast::TypeAlias(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()), _ => return, } }; @@ -70,25 +72,22 @@ pub(crate) fn move_bounds_to_where_clause( ast::GenericParam::ConstParam(_) => continue, }; if let Some(tbl) = param.type_bound_list() { - if let Some(predicate) = build_predicate(generic_param) { - where_clause.add_predicate(predicate) - } - tbl.remove() + tbl.remove(&mut edit); } } + + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } -fn build_predicate(param: ast::GenericParam) -> Option { +fn build_predicate(param: ast::GenericParam, make: &SyntaxFactory) -> Option { let target = match ¶m { - ast::GenericParam::TypeParam(t) => { - Either::Right(make::ty_path(make::ext::ident_path(&t.name()?.to_string()))) - } + ast::GenericParam::TypeParam(t) => Either::Right(make.ty(&t.name()?.to_string())), ast::GenericParam::LifetimeParam(l) => Either::Left(l.lifetime()?), ast::GenericParam::ConstParam(_) => return None, }; - let predicate = make::where_pred( + let predicate = make.where_pred( target, match param { ast::GenericParam::TypeParam(t) => t.type_bound_list()?, @@ -97,7 +96,7 @@ fn build_predicate(param: ast::GenericParam) -> Option { } .bounds(), ); - Some(predicate.clone_for_update()) + Some(predicate) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs index b4c347ff36a7..80587372e516 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs @@ -3,7 +3,7 @@ SyntaxKind::WHITESPACE, TextRange, ast::{ - AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make, + AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, prec::ExprPrecedence, syntax_factory::SyntaxFactory, }, syntax_editor::Element, @@ -53,14 +53,15 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>) let space_after_arrow = match_arm.fat_arrow_token()?.next_sibling_or_token(); let arm_expr = match_arm.expr()?; + let make = SyntaxFactory::without_mappings(); let if_branch = chain([&match_arm], &rest_arms) .rfold(None, |else_branch, arm| { if let Some(guard) = arm.guard() { - let then_branch = crate::utils::wrap_block(&arm.expr()?); + let then_branch = crate::utils::wrap_block(&arm.expr()?, &make); let guard_condition = guard.condition()?.reset_indent(); - Some(make::expr_if(guard_condition, then_branch, else_branch).into()) + Some(make.expr_if(guard_condition, then_branch, else_branch).into()) } else { - arm.expr().map(|it| crate::utils::wrap_block(&it).into()) + arm.expr().map(|it| crate::utils::wrap_block(&it, &make).into()) } })? .indent(arm_expr.indent_level()); @@ -84,7 +85,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>) if let Some(element) = space_after_arrow && element.kind() == WHITESPACE { - edit.replace(element, make::tokens::single_space()); + edit.replace(element, make.whitespace(" ")); } edit.delete(guard.syntax()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs index 495a84d62b07..8b9e6570e917 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -1,6 +1,6 @@ use hir::{AsAssocItem, AssocItem, AssocItemContainer, ItemInNs, ModuleDef, db::HirDatabase}; use ide_db::assists::AssistId; -use syntax::{AstNode, ast}; +use syntax::{AstNode, ast, ast::syntax_factory::SyntaxFactory}; use crate::{ assist_context::{AssistContext, Assists}, @@ -52,19 +52,25 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> cfg, )?; - let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call); + let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call.clone(), resolved_call); acc.add( AssistId::refactor_rewrite("qualify_method_call"), format!("Qualify `{ident}` method call"), range, |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(call.syntax()); qualify_candidate.qualify( - |replace_with: String| builder.replace(range, replace_with), + |_| {}, + &mut editor, + &make, &receiver_path, item_in_ns, current_edition, - ) + ); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ); Some(()) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs index b3cf2969650a..c059f758c47e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs @@ -11,7 +11,8 @@ use syntax::ast::HasGenericArgs; use syntax::{ AstNode, ast, - ast::{HasArgList, make}, + ast::{HasArgList, syntax_factory::SyntaxFactory}, + syntax_editor::SyntaxEditor, }; use crate::{ @@ -54,25 +55,25 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let qualify_candidate = match candidate { ImportCandidate::Path(candidate) if !candidate.qualifier.is_empty() => { cov_mark::hit!(qualify_path_qualifier_start); - let path = ast::Path::cast(syntax_under_caret)?; + let path = ast::Path::cast(syntax_under_caret.clone())?; let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) } ImportCandidate::Path(_) => { cov_mark::hit!(qualify_path_unqualified_name); - let path = ast::Path::cast(syntax_under_caret)?; + let path = ast::Path::cast(syntax_under_caret.clone())?; let generics = path.segment()?.generic_arg_list(); QualifyCandidate::UnqualifiedName(generics) } ImportCandidate::TraitAssocItem(_) => { cov_mark::hit!(qualify_path_trait_assoc_item); - let path = ast::Path::cast(syntax_under_caret)?; + let path = ast::Path::cast(syntax_under_caret.clone())?; let (qualifier, segment) = (path.qualifier()?, path.segment()?); QualifyCandidate::TraitAssocItem(qualifier, segment) } ImportCandidate::TraitMethod(_) => { cov_mark::hit!(qualify_path_trait_method); - let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?; + let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret.clone())?; QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr) } }; @@ -101,12 +102,18 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option label(ctx.db(), candidate, &import, current_edition), range, |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(&syntax_under_caret); qualify_candidate.qualify( |replace_with: String| builder.replace(range, replace_with), + &mut editor, + &make, &import.import_path, import.item_to_import, current_edition, - ) + ); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ); } @@ -124,6 +131,8 @@ impl QualifyCandidate<'_> { pub(crate) fn qualify( &self, mut replacer: impl FnMut(String), + editor: &mut SyntaxEditor, + make: &SyntaxFactory, import: &hir::ModPath, item: hir::ItemInNs, edition: Edition, @@ -142,10 +151,10 @@ pub(crate) fn qualify( replacer(format!("<{qualifier} as {import}>::{segment}")); } QualifyCandidate::TraitMethod(db, mcall_expr) => { - Self::qualify_trait_method(db, mcall_expr, replacer, import, item); + Self::qualify_trait_method(db, mcall_expr, editor, make, import, item); } QualifyCandidate::ImplMethod(db, mcall_expr, hir_fn) => { - Self::qualify_fn_call(db, mcall_expr, replacer, import, hir_fn); + Self::qualify_fn_call(db, mcall_expr, editor, make, import, hir_fn); } } } @@ -153,7 +162,8 @@ pub(crate) fn qualify( fn qualify_fn_call( db: &RootDatabase, mcall_expr: &ast::MethodCallExpr, - mut replacer: impl FnMut(String), + editor: &mut SyntaxEditor, + make: &SyntaxFactory, import: ast::Path, hir_fn: &hir::Function, ) -> Option<()> { @@ -165,15 +175,17 @@ fn qualify_fn_call( if let Some(self_access) = hir_fn.self_param(db).map(|sp| sp.access(db)) { let receiver = match self_access { - hir::Access::Shared => make::expr_ref(receiver, false), - hir::Access::Exclusive => make::expr_ref(receiver, true), + hir::Access::Shared => make.expr_ref(receiver, false), + hir::Access::Exclusive => make.expr_ref(receiver, true), hir::Access::Owned => receiver, }; let arg_list = match arg_list { - Some(args) => make::arg_list(iter::once(receiver).chain(args)), - None => make::arg_list(iter::once(receiver)), + Some(args) => make.arg_list(iter::once(receiver).chain(args)), + None => make.arg_list(iter::once(receiver)), }; - replacer(format!("{import}::{method_name}{generics}{arg_list}")); + let call_path = make.path_from_text(&format!("{import}::{method_name}{generics}")); + let call_expr = make.expr_call(make.expr_path(call_path), arg_list); + editor.replace(mcall_expr.syntax(), call_expr.syntax()); } Some(()) } @@ -181,14 +193,15 @@ fn qualify_fn_call( fn qualify_trait_method( db: &RootDatabase, mcall_expr: &ast::MethodCallExpr, - replacer: impl FnMut(String), + editor: &mut SyntaxEditor, + make: &SyntaxFactory, import: ast::Path, item: hir::ItemInNs, ) -> Option<()> { let trait_method_name = mcall_expr.name_ref()?; let trait_ = item_as_trait(db, item)?; let method = find_trait_method(db, trait_, &trait_method_name)?; - Self::qualify_fn_call(db, mcall_expr, replacer, import, &method) + Self::qualify_fn_call(db, mcall_expr, editor, make, import, &method) } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 7c024263b4a8..f54f7a02d2b3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -4,7 +4,7 @@ use syntax::{ SyntaxKind::WHITESPACE, T, - ast::{self, AstNode, HasName, make}, + ast::{self, AstNode, HasName, syntax_factory::SyntaxFactory}, syntax_editor::{Position, SyntaxEditor}, }; @@ -12,8 +12,8 @@ AssistConfig, AssistId, assist_context::{AssistContext, Assists}, utils::{ - DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items, - gen_trait_fn_body, generate_trait_impl, + DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl_with_factory, + filter_assoc_items, gen_trait_fn_body, generate_trait_impl, }, }; @@ -127,6 +127,7 @@ fn add_assist( let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`"); acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| { + let make = SyntaxFactory::without_mappings(); let insert_after = Position::after(adt.syntax()); let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false); let impl_def = impl_def_from_trait( @@ -142,7 +143,7 @@ fn add_assist( let mut editor = builder.make_editor(attr.syntax()); update_attribute(&mut editor, old_derives, old_tree, old_trait_path, attr); - let trait_path = make::ty_path(replace_trait_path.clone()); + let trait_path = make.ty_path(replace_trait_path.clone()).into(); let (impl_def, first_assoc_item) = if let Some(impl_def) = impl_def { ( @@ -150,7 +151,7 @@ fn add_assist( impl_def.assoc_item_list().and_then(|list| list.assoc_items().next()), ) } else { - (generate_trait_impl(impl_is_unsafe, adt, trait_path), None) + (generate_trait_impl(&make, impl_is_unsafe, adt, trait_path), None) }; if let Some(cap) = ctx.config.snippet_cap { @@ -174,7 +175,7 @@ fn add_assist( editor.insert_all( insert_after, - vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()], + vec![make.whitespace("\n\n").into(), impl_def.syntax().clone().into()], ); builder.add_file_edits(ctx.vfs_file_id(), editor); }) @@ -205,10 +206,19 @@ fn impl_def_from_trait( if trait_items.is_empty() { return None; } - let impl_def = generate_trait_impl(impl_is_unsafe, adt, make::ty_path(trait_path.clone())); + let make = SyntaxFactory::without_mappings(); + let trait_ty = make.ty_path(trait_path.clone()).into(); + let impl_def = generate_trait_impl(&make, impl_is_unsafe, adt, trait_ty); - let assoc_items = - add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope); + let assoc_items = add_trait_assoc_items_to_impl_with_factory( + &make, + sema, + config, + &trait_items, + trait_, + &impl_def, + &target_scope, + ); let assoc_item_list = if let Some((first, other)) = assoc_items.split_first().map(|(first, other)| (first.clone_subtree(), other)) { @@ -222,12 +232,12 @@ fn impl_def_from_trait( } else { Some(first.clone()) }; - let items = first_item.into_iter().chain(other.iter().cloned()).collect(); - make::assoc_item_list(Some(items)) + let items: Vec = + first_item.into_iter().chain(other.iter().cloned()).collect(); + make.assoc_item_list(items) } else { - make::assoc_item_list(None) - } - .clone_for_update(); + make.assoc_item_list_empty() + }; let impl_def = impl_def.clone_subtree(); let mut editor = SyntaxEditor::new(impl_def.syntax().clone()); @@ -243,6 +253,7 @@ fn update_attribute( old_trait_path: &ast::Path, attr: &ast::Attr, ) { + let make = SyntaxFactory::without_mappings(); let new_derives = old_derives .iter() .filter(|t| t.to_string() != old_trait_path.to_string()) @@ -257,13 +268,13 @@ fn update_attribute( .collect::>() }); // ...which are interspersed with ", " - let tt = Itertools::intersperse(tt, vec![make::token(T![,]), make::tokens::single_space()]); + let tt = Itertools::intersperse(tt, vec![make.token(T![,]), make.whitespace(" ")]); // ...wrap them into the appropriate `NodeOrToken` variant let tt = tt.flatten().map(syntax::NodeOrToken::Token); // ...and make them into a flat list of tokens let tt = tt.collect::>(); - let new_tree = make::token_tree(T!['('], tt).clone_for_update(); + let new_tree = make.token_tree(T!['('], tt); editor.replace(old_tree.syntax(), new_tree.syntax()); } else { // Remove the attr and any trailing whitespace diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs index d22e951b5dab..38d8c38ef23d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -1,8 +1,11 @@ use either::Either; use ide_db::syntax_helpers::suggest_name; -use syntax::ast::{self, AstNode, HasArgList, syntax_factory::SyntaxFactory}; +use syntax::ast::{self, AstNode, HasArgList, prec::ExprPrecedence, syntax_factory::SyntaxFactory}; -use crate::{AssistContext, AssistId, Assists, utils::cover_let_chain}; +use crate::{ + AssistContext, AssistId, Assists, + utils::{cover_let_chain, wrap_paren, wrap_paren_in_call}, +}; // Assist: replace_is_some_with_if_let_some // @@ -39,6 +42,7 @@ pub(crate) fn replace_is_method_with_if_let_method( match method_kind { "is_some" | "is_ok" => { let receiver = call_expr.receiver()?; + let make = SyntaxFactory::with_mappings(); let mut name_generator = suggest_name::NameGenerator::new_from_scope_locals( ctx.sema.scope(has_cond.syntax()), @@ -48,7 +52,7 @@ pub(crate) fn replace_is_method_with_if_let_method( } else { name_generator.for_variable(&receiver, &ctx.sema) }; - let (pat, predicate) = method_predicate(&call_expr).unzip(); + let (pat, predicate) = method_predicate(&call_expr, &var_name, &make); let (assist_id, message, text) = if method_kind == "is_some" { ("replace_is_some_with_if_let_some", "Replace `is_some` with `let Some`", "Some") @@ -61,13 +65,9 @@ pub(crate) fn replace_is_method_with_if_let_method( message, call_expr.syntax().text_range(), |edit| { - let make = SyntaxFactory::with_mappings(); let mut editor = edit.make_editor(call_expr.syntax()); - let var_pat = pat.unwrap_or_else(|| { - make.ident_pat(false, false, make.name(&var_name)).into() - }); - let pat = make.tuple_struct_pat(make.ident_path(text), [var_pat]).into(); + let pat = make.tuple_struct_pat(make.ident_path(text), [pat]).into(); let let_expr = make.expr_let(pat, receiver); if let Some(cap) = ctx.config.snippet_cap @@ -81,6 +81,7 @@ pub(crate) fn replace_is_method_with_if_let_method( let new_expr = if let Some(predicate) = predicate { let op = ast::BinaryOp::LogicOp(ast::LogicOp::And); + let predicate = wrap_paren(predicate, &make, ExprPrecedence::LAnd); make.expr_bin(let_expr.into(), op, predicate).into() } else { ast::Expr::from(let_expr) @@ -96,14 +97,23 @@ pub(crate) fn replace_is_method_with_if_let_method( } } -fn method_predicate(call_expr: &ast::MethodCallExpr) -> Option<(ast::Pat, ast::Expr)> { - let argument = call_expr.arg_list()?.args().next()?; - match argument { - ast::Expr::ClosureExpr(it) => { - let pat = it.param_list()?.params().next()?.pat()?; - Some((pat, it.body()?)) - } - _ => None, +fn method_predicate( + call_expr: &ast::MethodCallExpr, + name: &str, + make: &SyntaxFactory, +) -> (ast::Pat, Option) { + let argument = call_expr.arg_list().and_then(|it| it.args().next()); + if let Some(ast::Expr::ClosureExpr(it)) = argument.clone() + && let Some(pat) = it.param_list().and_then(|it| it.params().next()?.pat()) + { + (pat, it.body()) + } else { + let pat = make.ident_pat(false, false, make.name(name)); + let expr = argument.map(|expr| { + let arg_list = make.arg_list([make.expr_path(make.ident_path(name))]); + make.expr_call(wrap_paren_in_call(expr, make), arg_list).into() + }); + (pat.into(), expr) } } @@ -232,6 +242,54 @@ fn main() { let x = Some(1); if let Some(it) = x && it != 3 {} } +"#, + ); + + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + if x.is_som$0e_and(|it| it != 3 || it > 10) {} +} +"#, + r#" +fn main() { + let x = Some(1); + if let Some(it) = x && (it != 3 || it > 10) {} +} +"#, + ); + + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + if x.is_som$0e_and(predicate) {} +} +"#, + r#" +fn main() { + let x = Some(1); + if let Some(x1) = x && predicate(x1) {} +} +"#, + ); + + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + if x.is_som$0e_and(func.f) {} +} +"#, + r#" +fn main() { + let x = Some(1); + if let Some(x1) = x && (func.f)(x1) {} +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs index 5587f1b59c54..6ff5f0bbd30c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs @@ -86,8 +86,8 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_> } fn let_expr_needs_paren(expr: &ast::Expr) -> bool { - let fake_expr_let = - ast::make::expr_let(ast::make::tuple_pat(None).into(), ast::make::ext::expr_unit()); + let make = SyntaxFactory::without_mappings(); + let fake_expr_let = make.expr_let(make.tuple_pat(None).into(), make.expr_unit()); let Some(fake_expr) = fake_expr_let.expr() else { stdx::never!(); return false; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs index 6ca3e26ca018..6e4dd8cb73a6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs @@ -2,10 +2,10 @@ use ide_db::{RootDatabase, assists::AssistId, defs::Definition}; use syntax::{ AstNode, - ast::{self, Expr, HasArgList, make}, + ast::{self, Expr, HasArgList, make, syntax_factory::SyntaxFactory}, }; -use crate::{AssistContext, Assists}; +use crate::{AssistContext, Assists, utils::wrap_paren_in_call}; // Assist: replace_with_lazy_method // @@ -177,11 +177,7 @@ fn into_call(param: &Expr, sema: &Semantics<'_, RootDatabase>) -> Expr { } })() .unwrap_or_else(|| { - let callable = if needs_parens_in_call(param) { - make::expr_paren(param.clone()).into() - } else { - param.clone() - }; + let callable = wrap_paren_in_call(param.clone(), &SyntaxFactory::without_mappings()); make::expr_call(callable, make::arg_list(Vec::new())).into() }) } @@ -200,12 +196,6 @@ fn ends_is(name: &str, end: &str) -> bool { name.strip_suffix(end).is_some_and(|s| s.is_empty() || s.ends_with('_')) } -fn needs_parens_in_call(param: &Expr) -> bool { - let call = make::expr_call(make::ext::expr_unit(), make::arg_list(Vec::new())); - let callable = call.expr().expect("invalid make call"); - param.needs_parens_in_place_of(call.syntax(), callable.syntax()) -} - #[cfg(test)] mod tests { use crate::tests::check_assist; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs index df7057835c34..018642a04723 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs @@ -5,9 +5,10 @@ defs::Definition, search::{SearchScope, UsageSearchResult}, }; +use syntax::ast::syntax_factory::SyntaxFactory; use syntax::{ AstNode, - ast::{self, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, PathType, make}, + ast::{self, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, PathType}, match_ast, }; @@ -72,6 +73,7 @@ pub(crate) fn replace_named_generic_with_impl( target, |edit| { let mut editor = edit.make_editor(type_param.syntax()); + let make = SyntaxFactory::without_mappings(); // remove trait from generic param list if let Some(generic_params) = fn_.generic_param_list() { @@ -83,17 +85,14 @@ pub(crate) fn replace_named_generic_with_impl( if params.is_empty() { editor.delete(generic_params.syntax()); } else { - let new_generic_param_list = make::generic_param_list(params); - editor.replace( - generic_params.syntax(), - new_generic_param_list.syntax().clone_for_update(), - ); + let new_generic_param_list = make.generic_param_list(params); + editor.replace(generic_params.syntax(), new_generic_param_list.syntax()); } } - let new_bounds = make::impl_trait_type(type_bound_list); + let new_bounds = make.impl_trait_type(type_bound_list); for path_type in path_types_to_replace.iter().rev() { - editor.replace(path_type.syntax(), new_bounds.clone_for_update().syntax()); + editor.replace(path_type.syntax(), new_bounds.syntax()); } edit.add_file_edits(ctx.vfs_file_id(), editor); }, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index 009fc077ce6c..cdf20586ef15 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -102,7 +102,7 @@ fn target_path(ctx: &AssistContext<'_>, mut original_path: ast::Path) -> Option< } match ctx.sema.resolve_path(&original_path)? { - PathResolution::Def(ModuleDef::Variant(_)) if on_first => original_path.qualifier(), + PathResolution::Def(ModuleDef::EnumVariant(_)) if on_first => original_path.qualifier(), PathResolution::Def(def) if def.as_assoc_item(ctx.db()).is_some() => { on_first.then_some(original_path.qualifier()?) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs index 7b0f2dc65a78..c4c03d3e35f5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -38,11 +38,18 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O } let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?; let match_arm_body = match_arm.expr()?; + let pats_after = pipe_token + .siblings_with_tokens(Direction::Next) + .filter_map(|it| ast::Pat::cast(it.into_node()?)) + .collect::>(); // We don't need to check for leading pipe because it is directly under `MatchArm` // without `OrPat`. let new_parent = match_arm.syntax().parent()?; + if pats_after.is_empty() { + return None; + } acc.add( AssistId::refactor_rewrite("unmerge_match_arm"), @@ -51,10 +58,6 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O |edit| { let make = SyntaxFactory::with_mappings(); let mut editor = edit.make_editor(&new_parent); - let pats_after = pipe_token - .siblings_with_tokens(Direction::Next) - .filter_map(|it| ast::Pat::cast(it.into_node()?)) - .collect::>(); // It is guaranteed that `pats_after` has at least one element let new_pat = if pats_after.len() == 1 { pats_after[0].clone() @@ -190,6 +193,21 @@ fn main() { ); } + #[test] + fn unmerge_match_arm_trailing_pipe() { + check_assist_not_applicable( + unmerge_match_arm, + r#" +fn main() { + let y = match 0 { + 0 |$0 => { 1i32 } + 1 => { 2i32 } + }; +} +"#, + ); + } + #[test] fn unmerge_match_arm_multiple_pipes() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs index a58b1da621c7..ef395791e251 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -1,8 +1,5 @@ use hir::AsAssocItem; -use syntax::{ - TextRange, - ast::{self, AstNode, HasArgList, prec::ExprPrecedence}, -}; +use syntax::ast::{self, AstNode, HasArgList, prec::ExprPrecedence, syntax_factory::SyntaxFactory}; use crate::{AssistContext, AssistId, Assists}; @@ -36,10 +33,7 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) } let args = call.arg_list()?; - let l_paren = args.l_paren_token()?; - let mut args_iter = args.args(); - let first_arg = args_iter.next()?; - let second_arg = args_iter.next(); + let first_arg = args.args().next()?; let qualifier = path.qualifier()?; let method_name = path.segment()?.name_ref()?; @@ -51,43 +45,33 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) return None; } - // `core::ops::Add::add(` -> `` - let delete_path = - TextRange::new(path.syntax().text_range().start(), l_paren.text_range().end()); - - // Parens around `expr` if needed - let parens = first_arg.precedence().needs_parentheses_in(ExprPrecedence::Postfix).then(|| { - let range = first_arg.syntax().text_range(); - (range.start(), range.end()) - }); - - // `, ` -> `.add(` - let replace_comma = TextRange::new( - first_arg.syntax().text_range().end(), - second_arg - .map(|a| a.syntax().text_range().start()) - .unwrap_or_else(|| first_arg.syntax().text_range().end()), - ); - acc.add( AssistId::refactor_rewrite("unqualify_method_call"), "Unqualify method call", call.syntax().text_range(), - |edit| { - edit.delete(delete_path); - if let Some((open, close)) = parens { - edit.insert(open, "("); - edit.insert(close, ")"); - } - edit.replace(replace_comma, format!(".{method_name}(")); + |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(call.syntax()); + + let new_arg_list = make.arg_list(args.args().skip(1)); + let receiver = if first_arg.precedence().needs_parentheses_in(ExprPrecedence::Postfix) { + ast::Expr::from(make.expr_paren(first_arg.clone())) + } else { + first_arg.clone() + }; + let method_call = make.expr_method_call(receiver, method_name, new_arg_list); + + editor.replace(call.syntax(), method_call.syntax()); if let Some(fun) = fun.as_assoc_item(ctx.db()) && let Some(trait_) = fun.container_or_implemented_trait(ctx.db()) && !scope.can_use_trait_methods(trait_) { - // Only add an import for trait methods that are not already imported. - add_import(qualifier, ctx, edit); + add_import(qualifier, ctx, &make, &mut editor); } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) } @@ -95,7 +79,8 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) fn add_import( qualifier: ast::Path, ctx: &AssistContext<'_>, - edit: &mut ide_db::source_change::SourceChangeBuilder, + make: &SyntaxFactory, + editor: &mut syntax::syntax_editor::SyntaxEditor, ) { if let Some(path_segment) = qualifier.segment() { // for `` @@ -122,8 +107,13 @@ fn add_import( ); if let Some(scope) = scope { - let scope = edit.make_import_scope_mut(scope); - ide_db::imports::insert_use::insert_use(&scope, import, &ctx.config.insert_use); + ide_db::imports::insert_use::insert_use_with_editor( + &scope, + import, + &ctx.config.insert_use, + editor, + make, + ); } } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs index e4f5e3523bd2..e029d7884fd5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs @@ -45,6 +45,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option ast::LoopExpr(it) => it.syntax().clone(), ast::WhileExpr(it) => it.syntax().clone(), ast::MatchArm(it) => it.parent_match().syntax().clone(), + ast::LetElse(it) => it.syntax().parent()?, ast::LetStmt(it) => { replacement = wrap_let(&it, replacement); prefer_container = Some(it.syntax().clone()); @@ -556,6 +557,40 @@ fn main() { ); } + #[test] + fn simple_let_else() { + check_assist( + unwrap_block, + r#" +fn main() { + let Some(2) = None else {$0 + return; + }; +} +"#, + r#" +fn main() { + return; +} +"#, + ); + check_assist( + unwrap_block, + r#" +fn main() { + let Some(2) = None else {$0 + return + }; +} +"#, + r#" +fn main() { + return +} +"#, + ); + } + #[test] fn unwrap_match_arm() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs index 46f3e85e1234..e03274bbb3c9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs @@ -1,3 +1,6 @@ +use std::iter; + +use either::Either; use syntax::{ AstNode, T, ast::{self, edit::AstNodeEdit}, @@ -24,11 +27,16 @@ // ``` pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let let_kw = ctx.find_token_syntax_at_offset(T![let])?; - let let_stmt = let_kw.parent().and_then(ast::LetStmt::cast)?; - let indent_level = let_stmt.indent_level().0 as usize; - let pat = let_stmt.pat()?; - let ty = let_stmt.ty(); - let init = let_stmt.initializer()?; + let let_stmt = let_kw.parent().and_then(Either::::cast)?; + let mut indent_level = let_stmt.indent_level(); + let pat = either::for_both!(&let_stmt, it => it.pat())?; + let (ty, init, prefix, suffix) = match &let_stmt { + Either::Left(let_stmt) => (let_stmt.ty(), let_stmt.initializer()?, "", ";"), + Either::Right(let_expr) => { + indent_level += 1; + (None, let_expr.expr()?, "&& ", "") + } + }; // This only applies for tuple patterns, types, and initializers. let tuple_pat = match pat { @@ -60,25 +68,19 @@ pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option "Unwrap tuple", let_kw.text_range(), |edit| { - let indents = " ".repeat(indent_level); + let mut decls = String::new(); // If there is an ascribed type, insert that type for each declaration, // otherwise, omit that type. - if let Some(tys) = tuple_ty { - let mut zipped_decls = String::new(); - for (pat, ty, expr) in - itertools::izip!(tuple_pat.fields(), tys.fields(), tuple_init.fields()) - { - zipped_decls.push_str(&format!("{indents}let {pat}: {ty} = {expr};\n")) - } - edit.replace(parent.text_range(), zipped_decls.trim()); - } else { - let mut zipped_decls = String::new(); - for (pat, expr) in itertools::izip!(tuple_pat.fields(), tuple_init.fields()) { - zipped_decls.push_str(&format!("{indents}let {pat} = {expr};\n")); - } - edit.replace(parent.text_range(), zipped_decls.trim()); + let tys = + tuple_ty.into_iter().flat_map(|it| it.fields().map(Some)).chain(iter::repeat(None)); + for (pat, ty, expr) in itertools::izip!(tuple_pat.fields(), tys, tuple_init.fields()) { + let ty = ty.map_or_else(String::new, |ty| format!(": {ty}")); + decls.push_str(&format!("{prefix}let {pat}{ty} = {expr}{suffix}\n{indent_level}")) } + + let s = decls.trim(); + edit.replace(parent.text_range(), s.strip_prefix(prefix).unwrap_or(s)); }, ) } @@ -123,6 +125,28 @@ fn main() { ); } + #[test] + fn unwrap_tuples_in_let_expr() { + check_assist( + unwrap_tuple, + r#" +fn main() { + if $0let (foo, bar) = ("Foo", "Bar") { + code(); + } +} +"#, + r#" +fn main() { + if let foo = "Foo" + && let bar = "Bar" { + code(); + } +} +"#, + ); + } + #[test] fn unwrap_tuple_with_types() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs index 7d5740b748be..36df4af31d5e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs @@ -2,7 +2,7 @@ use itertools::Itertools; use syntax::{ NodeOrToken, SyntaxToken, T, TextRange, algo, - ast::{self, AstNode, make, syntax_factory::SyntaxFactory}, + ast::{self, AstNode, edit::AstNodeEdit, make, syntax_factory::SyntaxFactory}, }; use crate::{AssistContext, AssistId, Assists}; @@ -27,7 +27,7 @@ enum WrapUnwrapOption { WrapDerive { derive: TextRange, attr: ast::Attr }, - WrapAttr(ast::Attr), + WrapAttr(Vec), } /// Attempts to get the derive attribute from a derive attribute list @@ -102,9 +102,9 @@ fn attempt_get_derive(attr: ast::Attr, ident: SyntaxToken) -> WrapUnwrapOption { if ident.parent().and_then(ast::TokenTree::cast).is_none() || !attr.simple_name().map(|v| v.eq("derive")).unwrap_or_default() { - WrapUnwrapOption::WrapAttr(attr) + WrapUnwrapOption::WrapAttr(vec![attr]) } else { - attempt_attr().unwrap_or(WrapUnwrapOption::WrapAttr(attr)) + attempt_attr().unwrap_or_else(|| WrapUnwrapOption::WrapAttr(vec![attr])) } } pub(crate) fn wrap_unwrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { @@ -118,13 +118,27 @@ pub(crate) fn wrap_unwrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>) - Some(attempt_get_derive(attr, ident)) } - (Some(attr), _) => Some(WrapUnwrapOption::WrapAttr(attr)), + (Some(attr), _) => Some(WrapUnwrapOption::WrapAttr(vec![attr])), _ => None, } } else { let covering_element = ctx.covering_element(); match covering_element { - NodeOrToken::Node(node) => ast::Attr::cast(node).map(WrapUnwrapOption::WrapAttr), + NodeOrToken::Node(node) => { + if let Some(attr) = ast::Attr::cast(node.clone()) { + Some(WrapUnwrapOption::WrapAttr(vec![attr])) + } else { + let attrs = node + .children() + .filter(|it| it.text_range().intersect(ctx.selection_trimmed()).is_some()) + .map(ast::Attr::cast) + .collect::>>()?; + if attrs.is_empty() { + return None; + } + Some(WrapUnwrapOption::WrapAttr(attrs)) + } + } NodeOrToken::Token(ident) if ident.kind() == syntax::T![ident] => { let attr = ident.parent_ancestors().find_map(ast::Attr::cast)?; Some(attempt_get_derive(attr, ident)) @@ -133,10 +147,12 @@ pub(crate) fn wrap_unwrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>) - } }?; match option { - WrapUnwrapOption::WrapAttr(attr) if attr.simple_name().as_deref() == Some("cfg_attr") => { - unwrap_cfg_attr(acc, attr) - } - WrapUnwrapOption::WrapAttr(attr) => wrap_cfg_attr(acc, ctx, attr), + WrapUnwrapOption::WrapAttr(attrs) => match &attrs[..] { + [attr] if attr.simple_name().as_deref() == Some("cfg_attr") => { + unwrap_cfg_attr(acc, attrs.into_iter().next().unwrap()) + } + _ => wrap_cfg_attrs(acc, ctx, attrs), + }, WrapUnwrapOption::WrapDerive { derive, attr } => wrap_derive(acc, ctx, attr, derive), } } @@ -220,40 +236,51 @@ fn wrap_derive( ); Some(()) } -fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) -> Option<()> { - let range = attr.syntax().text_range(); - let path = attr.path()?; +fn wrap_cfg_attrs(acc: &mut Assists, ctx: &AssistContext<'_>, attrs: Vec) -> Option<()> { + let (first_attr, last_attr) = (attrs.first()?, attrs.last()?); + let range = first_attr.syntax().text_range().cover(last_attr.syntax().text_range()); + let path_attrs = + attrs.iter().map(|attr| Some((attr.path()?, attr.clone()))).collect::>>()?; let handle_source_change = |edit: &mut SourceChangeBuilder| { let make = SyntaxFactory::with_mappings(); - let mut editor = edit.make_editor(attr.syntax()); - let mut raw_tokens = - vec![NodeOrToken::Token(make.token(T![,])), NodeOrToken::Token(make.whitespace(" "))]; - path.syntax().descendants_with_tokens().for_each(|it| { - if let NodeOrToken::Token(token) = it { - raw_tokens.push(NodeOrToken::Token(token)); - } - }); - if let Some(meta) = attr.meta() { - if let (Some(eq), Some(expr)) = (meta.eq_token(), meta.expr()) { - raw_tokens.push(NodeOrToken::Token(make.whitespace(" "))); - raw_tokens.push(NodeOrToken::Token(eq)); - raw_tokens.push(NodeOrToken::Token(make.whitespace(" "))); + let mut editor = edit.make_editor(first_attr.syntax()); + let mut raw_tokens = vec![]; + for (path, attr) in path_attrs { + raw_tokens.extend([ + NodeOrToken::Token(make.token(T![,])), + NodeOrToken::Token(make.whitespace(" ")), + ]); + path.syntax().descendants_with_tokens().for_each(|it| { + if let NodeOrToken::Token(token) = it { + raw_tokens.push(NodeOrToken::Token(token)); + } + }); + if let Some(meta) = attr.meta() { + if let (Some(eq), Some(expr)) = (meta.eq_token(), meta.expr()) { + raw_tokens.push(NodeOrToken::Token(make.whitespace(" "))); + raw_tokens.push(NodeOrToken::Token(eq)); + raw_tokens.push(NodeOrToken::Token(make.whitespace(" "))); - expr.syntax().descendants_with_tokens().for_each(|it| { - if let NodeOrToken::Token(token) = it { - raw_tokens.push(NodeOrToken::Token(token)); - } - }); - } else if let Some(tt) = meta.token_tree() { - raw_tokens.extend(tt.token_trees_and_tokens()); + expr.syntax().descendants_with_tokens().for_each(|it| { + if let NodeOrToken::Token(token) = it { + raw_tokens.push(NodeOrToken::Token(token)); + } + }); + } else if let Some(tt) = meta.token_tree() { + raw_tokens.extend(tt.token_trees_and_tokens()); + } } } let meta = make.meta_token_tree(make.ident_path("cfg_attr"), make.token_tree(T!['('], raw_tokens)); - let cfg_attr = - if attr.excl_token().is_some() { make.attr_inner(meta) } else { make.attr_outer(meta) }; + let cfg_attr = if first_attr.excl_token().is_some() { + make.attr_inner(meta) + } else { + make.attr_outer(meta) + }; - editor.replace(attr.syntax(), cfg_attr.syntax()); + let syntax_range = first_attr.syntax().clone().into()..=last_attr.syntax().clone().into(); + editor.replace_all(syntax_range, vec![cfg_attr.syntax().clone().into()]); if let Some(snippet_cap) = ctx.config.snippet_cap && let Some(first_meta) = @@ -332,7 +359,8 @@ fn unwrap_cfg_attr(acc: &mut Assists, attr: ast::Attr) -> Option<()> { return None; } let handle_source_change = |f: &mut SourceChangeBuilder| { - let inner_attrs = inner_attrs.iter().map(|it| it.to_string()).join("\n"); + let inner_attrs = + inner_attrs.iter().map(|it| it.to_string()).join(&format!("\n{}", attr.indent_level())); f.replace(range, inner_attrs); }; acc.add( @@ -414,6 +442,42 @@ pub struct Test { } "#, ); + check_assist( + wrap_unwrap_cfg_attr, + r#" + pub struct Test { + #[other_attr] + $0#[foo] + #[bar]$0 + #[other_attr] + test: u32, + } + "#, + r#" + pub struct Test { + #[other_attr] + #[cfg_attr($0, foo, bar)] + #[other_attr] + test: u32, + } + "#, + ); + check_assist( + wrap_unwrap_cfg_attr, + r#" + pub struct Test { + #[cfg_attr(debug_assertions$0, foo, bar)] + test: u32, + } + "#, + r#" + pub struct Test { + #[foo] + #[bar] + test: u32, + } + "#, + ); } #[test] fn to_from_eq_attr() { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 30405090002a..66d5cf834f17 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -507,8 +507,8 @@ fn main() { r#####" fn main() { let x = vec![1, 2, 3]; - let mut tmp = x.into_iter(); - while let Some(v) = tmp.next() { + let mut iter = x.into_iter(); + while let Some(v) = iter.next() { let y = v * 2; }; } @@ -2282,7 +2282,7 @@ macro_rules! const_maker { }; } -trait ${0:NewTrait} { +trait ${0:Create} { // Used as an associated constant. const CONST_ASSOC: usize = N * 4; @@ -2291,7 +2291,7 @@ trait ${0:NewTrait} { const_maker! {i32, 7} } -impl ${0:NewTrait} for Foo { +impl ${0:Create} for Foo { // Used as an associated constant. const CONST_ASSOC: usize = N * 4; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index b4055e77ccf8..10057f868152 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -25,6 +25,7 @@ edit::{AstNodeEdit, IndentLevel}, edit_in_place::AttrsOwnerEdit, make, + prec::ExprPrecedence, syntax_factory::SyntaxFactory, }, syntax_editor::{Element, Removable, SyntaxEditor}, @@ -86,17 +87,31 @@ pub fn extract_trivial_expression(block_expr: &ast::BlockExpr) -> Option ast::BlockExpr { +pub(crate) fn wrap_block(expr: &ast::Expr, make: &SyntaxFactory) -> ast::BlockExpr { if let ast::Expr::BlockExpr(block) = expr && let Some(first) = block.syntax().first_token() && first.kind() == T!['{'] { block.reset_indent() } else { - make::block_expr(None, Some(expr.reset_indent().indent(1.into()))) + make.block_expr(None, Some(expr.reset_indent().indent(1.into()))) } } +pub(crate) fn wrap_paren(expr: ast::Expr, make: &SyntaxFactory, prec: ExprPrecedence) -> ast::Expr { + if expr.precedence().needs_parentheses_in(prec) { make.expr_paren(expr).into() } else { expr } +} + +pub(crate) fn wrap_paren_in_call(expr: ast::Expr, make: &SyntaxFactory) -> ast::Expr { + if needs_parens_in_call(make, &expr) { make.expr_paren(expr).into() } else { expr } +} + +fn needs_parens_in_call(make: &SyntaxFactory, param: &ast::Expr) -> bool { + let call = make.expr_call(make.expr_unit(), make.arg_list(Vec::new())); + let callable = call.expr().expect("invalid make call"); + param.needs_parens_in_place_of(call.syntax(), callable.syntax()) +} + /// This is a method with a heuristics to support test methods annotated with custom test annotations, such as /// `#[test_case(...)]`, `#[tokio::test]` and similar. /// Also a regular `#[test]` annotation is supported. @@ -188,6 +203,9 @@ fn has_def_name(item: &InFile) -> bool { /// [`filter_assoc_items()`]), clones each item for update and applies path transformation to it, /// then inserts into `impl_`. Returns the modified `impl_` and the first associated item that got /// inserted. +/// +/// Legacy: prefer [`add_trait_assoc_items_to_impl_with_factory`] when a [`SyntaxFactory`] is +/// available. #[must_use] pub fn add_trait_assoc_items_to_impl( sema: &Semantics<'_, RootDatabase>, @@ -233,15 +251,79 @@ pub fn add_trait_assoc_items_to_impl( .filter_map(|item| match item { ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { let fn_ = fn_.clone_subtree(); - let new_body = &make::block_expr( - None, - Some(match config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }), - ); - let new_body = AstNodeEdit::indent(new_body, IndentLevel::single()); + let new_body = make::block_expr(None, Some(expr_fill_default(config))); + let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone()); + fn_.replace_or_insert_body(&mut fn_editor, new_body.clone_for_update()); + let new_fn_ = fn_editor.finish().new_root().clone(); + ast::AssocItem::cast(new_fn_) + } + ast::AssocItem::TypeAlias(type_alias) => { + let type_alias = type_alias.clone_subtree(); + if let Some(type_bound_list) = type_alias.type_bound_list() { + let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone()); + type_bound_list.remove(&mut type_alias_editor); + let type_alias = type_alias_editor.finish().new_root().clone(); + ast::AssocItem::cast(type_alias) + } else { + Some(ast::AssocItem::TypeAlias(type_alias)) + } + } + item => Some(item), + }) + .map(|item| AstNodeEdit::indent(&item, new_indent_level)) + .collect() +} + +/// [`SyntaxFactory`]-based variant of [`add_trait_assoc_items_to_impl`]. +#[must_use] +pub fn add_trait_assoc_items_to_impl_with_factory( + make: &SyntaxFactory, + sema: &Semantics<'_, RootDatabase>, + config: &AssistConfig, + original_items: &[InFile], + trait_: hir::Trait, + impl_: &ast::Impl, + target_scope: &hir::SemanticsScope<'_>, +) -> Vec { + let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; + original_items + .iter() + .map(|InFile { file_id, value: original_item }| { + let mut cloned_item = { + if let Some(macro_file) = file_id.macro_file() { + let span_map = sema.db.expansion_span_map(macro_file); + let item_prettified = prettify_macro_expansion( + sema.db, + original_item.syntax().clone(), + &span_map, + target_scope.krate().into(), + ); + if let Some(formatted) = ast::AssocItem::cast(item_prettified) { + return formatted; + } else { + stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`"); + } + } + original_item + } + .reset_indent(); + + if let Some(source_scope) = sema.scope(original_item.syntax()) { + let transform = + PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone()); + cloned_item = ast::AssocItem::cast(transform.apply(cloned_item.syntax())).unwrap(); + } + cloned_item.remove_attrs_and_docs(); + cloned_item + }) + .filter_map(|item| match item { + ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { + let fn_ = fn_.clone_subtree(); + let fill_expr: ast::Expr = match config.expr_fill_default { + ExprFillDefaultMode::Todo | ExprFillDefaultMode::Default => make.expr_todo(), + ExprFillDefaultMode::Underscore => make.expr_underscore().into(), + }; + let new_body = make.block_expr(None::, Some(fill_expr)); let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone()); fn_.replace_or_insert_body(&mut fn_editor, new_body); let new_fn_ = fn_editor.finish().new_root().clone(); @@ -275,11 +357,6 @@ pub(crate) fn invert_boolean_expression(make: &SyntaxFactory, expr: ast::Expr) - invert_special_case(make, &expr).unwrap_or_else(|| make.expr_prefix(T![!], expr).into()) } -// FIXME: Migrate usages of this function to the above function and remove this. -pub(crate) fn invert_boolean_expression_legacy(expr: ast::Expr) -> ast::Expr { - invert_special_case_legacy(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr).into()) -} - fn invert_special_case(make: &SyntaxFactory, expr: &ast::Expr) -> Option { match expr { ast::Expr::BinExpr(bin) => { @@ -343,62 +420,11 @@ fn invert_special_case(make: &SyntaxFactory, expr: &ast::Expr) -> Option Option { - match expr { - ast::Expr::BinExpr(bin) => { - let bin = bin.clone_subtree(); - let op_token = bin.op_token()?; - let rev_token = match op_token.kind() { - T![==] => T![!=], - T![!=] => T![==], - T![<] => T![>=], - T![<=] => T![>], - T![>] => T![<=], - T![>=] => T![<], - // Parenthesize other expressions before prefixing `!` - _ => { - return Some( - make::expr_prefix(T![!], make::expr_paren(expr.clone()).into()).into(), - ); - } - }; - let mut bin_editor = SyntaxEditor::new(bin.syntax().clone()); - bin_editor.replace(op_token, make::token(rev_token)); - ast::Expr::cast(bin_editor.finish().new_root().clone()) - } - ast::Expr::MethodCallExpr(mce) => { - let receiver = mce.receiver()?; - let method = mce.name_ref()?; - let arg_list = mce.arg_list()?; - - let method = match method.text().as_str() { - "is_some" => "is_none", - "is_none" => "is_some", - "is_ok" => "is_err", - "is_err" => "is_ok", - _ => return None, - }; - Some(make::expr_method_call(receiver, make::name_ref(method), arg_list).into()) - } - ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::UnaryOp::Not => match pe.expr()? { - ast::Expr::ParenExpr(parexpr) => parexpr.expr(), - _ => pe.expr(), - }, - ast::Expr::Literal(lit) => match lit.kind() { - ast::LiteralKind::Bool(b) => match b { - true => Some(ast::Expr::Literal(make::expr_literal("false"))), - false => Some(ast::Expr::Literal(make::expr_literal("true"))), - }, - _ => None, - }, - _ => None, - } -} - pub(crate) fn insert_attributes( before: impl Element, edit: &mut SyntaxEditor, attrs: impl IntoIterator, + make: &SyntaxFactory, ) { let mut attrs = attrs.into_iter().peekable(); if attrs.peek().is_none() { @@ -410,9 +436,7 @@ pub(crate) fn insert_attributes( edit.insert_all( syntax::syntax_editor::Position::before(elem), attrs - .flat_map(|attr| { - [attr.syntax().clone().into(), make::tokens::whitespace(&whitespace).into()] - }) + .flat_map(|attr| [attr.syntax().clone().into(), make.whitespace(&whitespace).into()]) .collect(), ); } @@ -508,6 +532,15 @@ fn check_pat_variant_nested_or_literal_with_depth( } } +pub(crate) fn expr_fill_default(config: &AssistConfig) -> ast::Expr { + let make = SyntaxFactory::without_mappings(); + match config.expr_fill_default { + ExprFillDefaultMode::Todo => make.expr_todo(), + ExprFillDefaultMode::Underscore => make.expr_underscore().into(), + ExprFillDefaultMode::Default => make.expr_todo(), + } +} + // Uses a syntax-driven approach to find any impl blocks for the struct that // exist within the module/file // @@ -596,29 +629,6 @@ pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String { generate_impl_text_inner(adt, None, true, code) } -/// Generates the surrounding `impl for Type { }` including type -/// and lifetime parameters, with `` appended to `impl`'s generic parameters' bounds. -/// -/// This is useful for traits like `PartialEq`, since `impl PartialEq for U` often requires `T: PartialEq`. -// FIXME: migrate remaining uses to `generate_trait_impl` -#[allow(dead_code)] -pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String { - generate_impl_text_inner(adt, Some(trait_text), true, code) -} - -/// Generates the surrounding `impl for Type { }` including type -/// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is. -/// -/// This is useful for traits like `From`, since `impl From for U` doesn't require `T: From`. -// FIXME: migrate remaining uses to `generate_trait_impl_intransitive` -pub(crate) fn generate_trait_impl_text_intransitive( - adt: &ast::Adt, - trait_text: &str, - code: &str, -) -> String { - generate_impl_text_inner(adt, Some(trait_text), false, code) -} - fn generate_impl_text_inner( adt: &ast::Adt, trait_text: Option<&str>, @@ -699,10 +709,15 @@ fn generate_impl_text_inner( /// Generates the corresponding `impl Type {}` including type and lifetime /// parameters. pub(crate) fn generate_impl_with_item( + make: &SyntaxFactory, adt: &ast::Adt, body: Option, ) -> ast::Impl { - generate_impl_inner(false, adt, None, true, body) + generate_impl_inner_with_factory(make, false, adt, None, true, body) +} + +pub(crate) fn generate_impl_with_factory(make: &SyntaxFactory, adt: &ast::Adt) -> ast::Impl { + generate_impl_inner_with_factory(make, false, adt, None, true, None) } pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl { @@ -713,16 +728,34 @@ pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl { /// and lifetime parameters, with `` appended to `impl`'s generic parameters' bounds. /// /// This is useful for traits like `PartialEq`, since `impl PartialEq for U` often requires `T: PartialEq`. -pub(crate) fn generate_trait_impl(is_unsafe: bool, adt: &ast::Adt, trait_: ast::Type) -> ast::Impl { - generate_impl_inner(is_unsafe, adt, Some(trait_), true, None) +pub(crate) fn generate_trait_impl( + make: &SyntaxFactory, + is_unsafe: bool, + adt: &ast::Adt, + trait_: ast::Type, +) -> ast::Impl { + generate_impl_inner_with_factory(make, is_unsafe, adt, Some(trait_), true, None) } /// Generates the corresponding `impl for Type {}` including type /// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is. /// /// This is useful for traits like `From`, since `impl From for U` doesn't require `T: From`. -pub(crate) fn generate_trait_impl_intransitive(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl { - generate_impl_inner(false, adt, Some(trait_), false, None) +pub(crate) fn generate_trait_impl_intransitive( + make: &SyntaxFactory, + adt: &ast::Adt, + trait_: ast::Type, +) -> ast::Impl { + generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, None) +} + +pub(crate) fn generate_trait_impl_intransitive_with_item( + make: &SyntaxFactory, + adt: &ast::Adt, + trait_: ast::Type, + body: ast::AssocItemList, +) -> ast::Impl { + generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, Some(body)) } fn generate_impl_inner( @@ -795,6 +828,76 @@ fn generate_impl_inner( .clone_for_update() } +fn generate_impl_inner_with_factory( + make: &SyntaxFactory, + is_unsafe: bool, + adt: &ast::Adt, + trait_: Option, + trait_is_transitive: bool, + body: Option, +) -> ast::Impl { + // Ensure lifetime params are before type & const params + let generic_params = adt.generic_param_list().map(|generic_params| { + let lifetime_params = + generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam); + let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| { + let param = match param { + ast::TypeOrConstParam::Type(param) => { + // remove defaults since they can't be specified in impls + let mut bounds = + param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect()); + if let Some(trait_) = &trait_ { + // Add the current trait to `bounds` if the trait is transitive, + // meaning `impl Trait for U` requires `T: Trait`. + if trait_is_transitive { + bounds.push(make.type_bound(trait_.clone())); + } + }; + // `{ty_param}: {bounds}` + let param = make.type_param(param.name()?, make.type_bound_list(bounds)); + ast::GenericParam::TypeParam(param) + } + ast::TypeOrConstParam::Const(param) => { + // remove defaults since they can't be specified in impls + let param = make.const_param(param.name()?, param.ty()?); + ast::GenericParam::ConstParam(param) + } + }; + Some(param) + }); + + make.generic_param_list(itertools::chain(lifetime_params, ty_or_const_params)) + }); + let generic_args = + generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update()); + let adt_assoc_bounds = + trait_.as_ref().zip(generic_params.as_ref()).and_then(|(trait_, params)| { + generic_param_associated_bounds_with_factory(make, adt, trait_, params) + }); + + let ty: ast::Type = make.ty_path(make.ident_path(&adt.name().unwrap().text())).into(); + + let cfg_attrs = + adt.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")); + match trait_ { + Some(trait_) => make.impl_trait( + cfg_attrs, + is_unsafe, + None, + None, + generic_params, + generic_args, + false, + trait_, + ty, + adt_assoc_bounds, + adt.where_clause(), + body, + ), + None => make.impl_(cfg_attrs, generic_params, generic_args, ty, adt.where_clause(), body), + } +} + fn generic_param_associated_bounds( adt: &ast::Adt, trait_: &ast::Type, @@ -840,6 +943,52 @@ fn generic_param_associated_bounds( trait_where_clause.peek().is_some().then(|| make::where_clause(trait_where_clause)) } +fn generic_param_associated_bounds_with_factory( + make: &SyntaxFactory, + adt: &ast::Adt, + trait_: &ast::Type, + generic_params: &ast::GenericParamList, +) -> Option { + let in_type_params = |name: &ast::NameRef| { + generic_params + .generic_params() + .filter_map(|param| match param { + ast::GenericParam::TypeParam(type_param) => type_param.name(), + _ => None, + }) + .any(|param| param.text() == name.text()) + }; + let adt_body = match adt { + ast::Adt::Enum(e) => e.variant_list().map(|it| it.syntax().clone()), + ast::Adt::Struct(s) => s.field_list().map(|it| it.syntax().clone()), + ast::Adt::Union(u) => u.record_field_list().map(|it| it.syntax().clone()), + }; + let mut trait_where_clause = adt_body + .into_iter() + .flat_map(|it| it.descendants()) + .filter_map(ast::Path::cast) + .filter_map(|path| { + let qualifier = path.qualifier()?.as_single_segment()?; + let qualifier = qualifier + .name_ref() + .or_else(|| match qualifier.type_anchor()?.ty()? { + ast::Type::PathType(path_type) => path_type.path()?.as_single_name_ref(), + _ => None, + }) + .filter(in_type_params)?; + Some((qualifier, path.segment()?.name_ref()?)) + }) + .map(|(qualifier, assoc_name)| { + let segments = [qualifier, assoc_name].map(|nr| make.path_segment(nr)); + let path = make.path_from_segments(segments, false); + let bounds = [make.type_bound(trait_.clone())]; + make.where_pred(either::Either::Right(make.ty_path(path).into()), bounds) + }) + .unique_by(|it| it.syntax().to_string()) + .peekable(); + trait_where_clause.peek().is_some().then(|| make.where_clause(trait_where_clause)) +} + pub(crate) fn add_method_to_adt( builder: &mut SourceChangeBuilder, adt: &ast::Adt, @@ -886,8 +1035,8 @@ enum ReferenceConversionType { } impl<'db> ReferenceConversion<'db> { - pub(crate) fn convert_type(&self, db: &'db dyn HirDatabase, module: hir::Module) -> ast::Type { - let ty = match self.conversion { + fn type_to_string(&self, db: &'db dyn HirDatabase, module: hir::Module) -> String { + match self.conversion { ReferenceConversionType::Copy => self .ty .display_source_code(db, module.into(), true) @@ -937,25 +1086,38 @@ pub(crate) fn convert_type(&self, db: &'db dyn HirDatabase, module: hir::Module) .unwrap_or_else(|_| "_".to_owned()); format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>") } - }; + } + } + pub(crate) fn convert_type(&self, db: &'db dyn HirDatabase, module: hir::Module) -> ast::Type { + let ty = self.type_to_string(db, module); make::ty(&ty) } - pub(crate) fn getter(&self, field_name: String) -> ast::Expr { - let expr = make::expr_field(make::ext::expr_self(), &field_name); + pub(crate) fn convert_type_with_factory( + &self, + make: &SyntaxFactory, + db: &'db dyn HirDatabase, + module: hir::Module, + ) -> ast::Type { + let ty = self.type_to_string(db, module); + make.ty(&ty) + } + + pub(crate) fn getter(&self, make: &SyntaxFactory, field_name: String) -> ast::Expr { + let expr = make.expr_field(make.expr_self(), &field_name); match self.conversion { - ReferenceConversionType::Copy => expr, + ReferenceConversionType::Copy => expr.into(), ReferenceConversionType::AsRefStr | ReferenceConversionType::AsRefSlice | ReferenceConversionType::Dereferenced | ReferenceConversionType::Option | ReferenceConversionType::Result => { if self.impls_deref { - make::expr_ref(expr, false) + make.expr_ref(expr.into(), false) } else { - make::expr_method_call(expr, make::name_ref("as_ref"), make::arg_list([])) + make.expr_method_call(expr.into(), make.name_ref("as_ref"), make.arg_list([])) .into() } } @@ -1095,18 +1257,21 @@ pub(crate) fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRa /// Convert a list of function params to a list of arguments that can be passed /// into a function call. -pub(crate) fn convert_param_list_to_arg_list(list: ast::ParamList) -> ast::ArgList { +pub(crate) fn convert_param_list_to_arg_list( + list: ast::ParamList, + make: &SyntaxFactory, +) -> ast::ArgList { let mut args = vec![]; for param in list.params() { if let Some(ast::Pat::IdentPat(pat)) = param.pat() && let Some(name) = pat.name() { let name = name.to_string(); - let expr = make::expr_path(make::ext::ident_path(&name)); + let expr = make.expr_path(make.ident_path(&name)); args.push(expr); } } - make::arg_list(args) + make.arg_list(args) } /// Calculate the number of hashes required for a raw string containing `s` @@ -1191,7 +1356,10 @@ pub(crate) fn replace_record_field_expr( /// Creates a token tree list from a syntax node, creating the needed delimited sub token trees. /// Assumes that the input syntax node is a valid syntax tree. -pub(crate) fn tt_from_syntax(node: SyntaxNode) -> Vec> { +pub(crate) fn tt_from_syntax( + node: SyntaxNode, + make: &SyntaxFactory, +) -> Vec> { let mut tt_stack = vec![(None, vec![])]; for element in node.descendants_with_tokens() { @@ -1219,7 +1387,7 @@ pub(crate) fn tt_from_syntax(node: SyntaxNode) -> Vec { @@ -1254,6 +1422,20 @@ pub(crate) fn cover_let_chain(mut expr: ast::Expr, range: TextRange) -> Option std::ops::RangeInclusive { + let node = match source.covering_element(range) { + NodeOrToken::Node(node) => node, + NodeOrToken::Token(t) => t.parent().unwrap(), + }; + let mut iter = node.children_with_tokens().filter(|it| range.contains_range(it.text_range())); + let first = iter.next().unwrap_or(node.into()); + let last = iter.last().unwrap_or_else(|| first.clone()); + first..=last +} + pub(crate) fn is_selected( it: &impl AstNode, selection: syntax::TextRange, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs index df8ad4111234..fc9bf210e487 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs @@ -5,7 +5,7 @@ //! based on the parent of the existing expression. use syntax::{ AstNode, T, - ast::{self, FieldExpr, MethodCallExpr, make, syntax_factory::SyntaxFactory}, + ast::{self, FieldExpr, MethodCallExpr, syntax_factory::SyntaxFactory}, }; use crate::AssistContext; @@ -119,13 +119,13 @@ pub(crate) struct RefData { impl RefData { /// Derefs `expr` and wraps it in parens if necessary - pub(crate) fn wrap_expr(&self, mut expr: ast::Expr) -> ast::Expr { + pub(crate) fn wrap_expr(&self, mut expr: ast::Expr, make: &SyntaxFactory) -> ast::Expr { if self.needs_deref { - expr = make::expr_prefix(T![*], expr).into(); + expr = make.expr_prefix(T![*], expr).into(); } if self.needs_parentheses { - expr = make::expr_paren(expr).into(); + expr = make.expr_paren(expr).into(); } expr diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 355687b2032b..1fb1fd4e579d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -26,7 +26,7 @@ use std::iter; -use hir::{HasAttrs, Name, ScopeDef, Variant, sym}; +use hir::{EnumVariant, HasAttrs, Name, ScopeDef, sym}; use ide_db::{RootDatabase, SymbolKind, imports::import_assets::LocatedImport}; use syntax::{SmolStr, ToSmolStr, ast}; @@ -426,7 +426,7 @@ pub(crate) fn add_qualified_enum_variant( &mut self, ctx: &CompletionContext<'_>, path_ctx: &PathCompletionCtx<'_>, - variant: hir::Variant, + variant: hir::EnumVariant, path: hir::ModPath, ) { if !ctx.check_stability_and_hidden(variant) { @@ -443,7 +443,7 @@ pub(crate) fn add_enum_variant( &mut self, ctx: &CompletionContext<'_>, path_ctx: &PathCompletionCtx<'_>, - variant: hir::Variant, + variant: hir::EnumVariant, local_name: Option, ) { if !ctx.check_stability_and_hidden(variant) { @@ -569,7 +569,7 @@ pub(crate) fn add_variant_pat( ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, path_ctx: Option<&PathCompletionCtx<'_>>, - variant: hir::Variant, + variant: hir::EnumVariant, local_name: Option, ) { if !ctx.check_stability_and_hidden(variant) { @@ -589,7 +589,7 @@ pub(crate) fn add_qualified_variant_pat( &mut self, ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, - variant: hir::Variant, + variant: hir::EnumVariant, path: hir::ModPath, ) { if !ctx.check_stability_and_hidden(variant) { @@ -644,9 +644,9 @@ fn enum_variants_with_paths( ctx: &CompletionContext<'_>, enum_: hir::Enum, impl_: Option<&ast::Impl>, - cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath), + cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::EnumVariant, hir::ModPath), ) { - let mut process_variant = |variant: Variant| { + let mut process_variant = |variant: EnumVariant| { let self_path = hir::ModPath::from_segments( hir::PathKind::Plain, iter::once(Name::new_symbol_root(sym::Self_)).chain(iter::once(variant.name(ctx.db))), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs index 96dac66b8a19..bd0b69215cf7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs @@ -30,14 +30,27 @@ pub(crate) fn complete_fn_param( _ => return None, }; + let qualifier = param_qualifier(param); let comma_wrapper = comma_wrapper(ctx); let mut add_new_item_to_acc = |label: &str| { - let mk_item = |label: &str, range: TextRange| { - CompletionItem::new(CompletionItemKind::Binding, range, label, ctx.edition) + let label = label.strip_prefix(qualifier.as_str()).unwrap_or(label); + let insert = if label.starts_with('#') { + // FIXME: `#[attr] it: i32` -> `#[attr] mut it: i32` + label.to_smolstr() + } else { + format_smolstr!("{qualifier}{label}") + }; + let mk_item = |insert_text: &str, range: TextRange| { + let mut item = + CompletionItem::new(CompletionItemKind::Binding, range, label, ctx.edition); + if insert_text != label { + item.insert_text(insert_text); + } + item }; let item = match &comma_wrapper { - Some((fmt, range)) => mk_item(&fmt(label), *range), - None => mk_item(label, ctx.source_range()), + Some((fmt, range)) => mk_item(&fmt(&insert), *range), + None => mk_item(&insert, ctx.source_range()), }; // Completion lookup is omitted intentionally here. // See the full discussion: https://github.com/rust-lang/rust-analyzer/issues/12073 @@ -75,9 +88,6 @@ fn fill_fn_params( let mut file_params = FxHashMap::default(); let mut extract_params = |f: ast::Fn| { - if !is_simple_param(current_param) { - return; - } f.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { if let Some(pat) = param.pat() { let whole_param = param.to_smolstr(); @@ -88,6 +98,9 @@ fn fill_fn_params( }; for node in ctx.token.parent_ancestors() { + if !is_simple_param(current_param) { + break; + } match_ast! { match node { ast::SourceFile(it) => it.items().filter_map(|item| match item { @@ -214,3 +227,16 @@ fn is_simple_param(param: &ast::Param) -> bool { .pat() .is_none_or(|pat| matches!(pat, ast::Pat::IdentPat(ident_pat) if ident_pat.pat().is_none())) } + +fn param_qualifier(param: &ast::Param) -> SmolStr { + let mut b = syntax::SmolStrBuilder::new(); + if let Some(ast::Pat::IdentPat(pat)) = param.pat() { + if pat.ref_token().is_some() { + b.push_str("ref "); + } + if pat.mut_token().is_some() { + b.push_str("mut "); + } + } + b.finish() +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs index 6e9328165d95..e7597bf95c80 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs @@ -91,7 +91,7 @@ pub(crate) fn complete_pattern( acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone())); true } - hir::ModuleDef::Variant(variant) + hir::ModuleDef::EnumVariant(variant) if refutable || single_variant_enum(variant.parent_enum(ctx.db)) => { acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone())); @@ -190,7 +190,7 @@ pub(crate) fn complete_pattern_path( let add_completion = match res { ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true, - ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true, + ScopeDef::ModuleDef(hir::ModuleDef::EnumVariant(_)) => true, ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true, ScopeDef::ImplSelfType(_) => true, _ => false, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index ea53aef40c2e..5b91e7c456a5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -16,7 +16,7 @@ use stdx::never; use syntax::{ SmolStr, - SyntaxKind::{EXPR_STMT, STMT_LIST}, + SyntaxKind::{CLOSURE_EXPR, EXPR_STMT, MATCH_ARM, STMT_LIST}, T, TextRange, TextSize, ToSmolStr, ast::{self, AstNode, AstToken}, format_smolstr, match_ast, @@ -66,6 +66,12 @@ pub(crate) fn complete_postfix( Some(it) => it, None => return, }; + let semi = + if expr_ctx.in_block_expr && ctx.token.next_token().is_none_or(|it| it.kind() != T![;]) { + ";" + } else { + "" + }; let cfg = ctx.config.find_path_config(ctx.is_nightly); @@ -151,12 +157,12 @@ pub(crate) fn complete_postfix( .add_to(acc, ctx.db); } _ if matches!(parent.kind(), STMT_LIST | EXPR_STMT) => { - postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) + postfix_snippet("let", "let", &format!("let $0 = {receiver_text}{semi}")) .add_to(acc, ctx.db); - postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) + postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text}{semi}")) .add_to(acc, ctx.db); } - _ if ast::MatchArm::can_cast(parent.kind()) => { + _ if matches!(parent.kind(), MATCH_ARM | CLOSURE_EXPR) => { postfix_snippet( "let", "let", @@ -307,26 +313,12 @@ pub(crate) fn complete_postfix( add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text); } - postfix_snippet( - "return", - "return expr", - &format!( - "return {receiver_text}{semi}", - semi = if expr_ctx.in_block_expr { ";" } else { "" } - ), - ) - .add_to(acc, ctx.db); + postfix_snippet("return", "return expr", &format!("return {receiver_text}{semi}")) + .add_to(acc, ctx.db); if let Some(BreakableKind::Block | BreakableKind::Loop) = expr_ctx.in_breakable { - postfix_snippet( - "break", - "break expr", - &format!( - "break {receiver_text}{semi}", - semi = if expr_ctx.in_block_expr { ";" } else { "" } - ), - ) - .add_to(acc, ctx.db); + postfix_snippet("break", "break expr", &format!("break {receiver_text}{semi}")) + .add_to(acc, ctx.db); } } @@ -371,12 +363,20 @@ fn get_receiver_text( range.range = TextRange::at(range.range.start(), range.range.len() - TextSize::of('.')) } let file_text = sema.db.file_text(range.file_id.file_id(sema.db)); - let mut text = file_text.text(sema.db)[range.range].to_owned(); + let text = file_text.text(sema.db); + let indent_spaces = indent_of_tail_line(&text[TextRange::up_to(range.range.start())]); + let mut text = stdx::dedent_by(indent_spaces, &text[range.range]); // The receiver texts should be interpreted as-is, as they are expected to be // normal Rust expressions. escape_snippet_bits(&mut text); - text + return text; + + fn indent_of_tail_line(text: &str) -> usize { + let tail_line = text.rsplit_once('\n').map_or(text, |(_, s)| s); + let trimmed = tail_line.trim_start_matches(' '); + tail_line.len() - trimmed.len() + } } /// Escapes `\` and `$` so that they don't get interpreted as snippet-specific constructs. @@ -402,6 +402,10 @@ fn receiver_accessor(receiver: &ast::Expr) -> ast::Expr { .unwrap_or_else(|| receiver.clone()) } +/// Given an `initial_element`, tries to expand it to include deref(s), and then references. +/// Returns the expanded expressions, and the added prefix as a string +/// +/// For example, if called with the `42` in `&&mut *42`, would return `(&&mut *42, "&&mut *")`. fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) { let mut resulting_element = initial_element.clone(); let mut prefix = String::new(); @@ -410,11 +414,8 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) { while let Some(parent_deref_element) = resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast) + && parent_deref_element.op_kind() == Some(ast::UnaryOp::Deref) { - if parent_deref_element.op_kind() != Some(ast::UnaryOp::Deref) { - break; - } - found_ref_or_deref = true; resulting_element = ast::Expr::from(parent_deref_element); @@ -663,6 +664,22 @@ fn main() { #[test] fn let_middle_block() { + check_edit( + "let", + r#" +fn main() { + baz.l$0 + res +} +"#, + r#" +fn main() { + let $0 = baz; + res +} +"#, + ); + check( r#" fn main() { @@ -719,6 +736,20 @@ fn main() { #[test] fn let_tail_block() { + check_edit( + "let", + r#" +fn main() { + baz.l$0 +} +"#, + r#" +fn main() { + let $0 = baz; +} +"#, + ); + check( r#" fn main() { @@ -772,6 +803,23 @@ fn main() { ); } + #[test] + fn let_before_semicolon() { + check_edit( + "let", + r#" +fn main() { + baz.l$0; +} +"#, + r#" +fn main() { + let $0 = baz; +} +"#, + ); + } + #[test] fn option_iflet() { check_edit( @@ -965,6 +1013,28 @@ fn main() { ); } + #[test] + fn closure_let_block() { + check_edit( + "let", + r#" +fn main() { + let bar = 2; + let f = || bar.$0; +} +"#, + r#" +fn main() { + let bar = 2; + let f = || { + let $1 = bar; + $0 +}; +} +"#, + ); + } + #[test] fn option_letelse() { check_edit( @@ -1040,6 +1110,7 @@ fn main() { #[test] fn postfix_completion_for_references() { check_edit("dbg", r#"fn main() { &&42.$0 }"#, r#"fn main() { dbg!(&&42) }"#); + check_edit("dbg", r#"fn main() { &&*"hello".$0 }"#, r#"fn main() { dbg!(&&*"hello") }"#); check_edit("refm", r#"fn main() { &&42.$0 }"#, r#"fn main() { &&&mut 42 }"#); check_edit( "ifl", @@ -1198,9 +1269,9 @@ fn main() { fn main() { ControlFlow::Break(match true { - true => "\${1:placeholder}", - false => "\\\$", - }) + true => "\${1:placeholder}", + false => "\\\$", +}) } "#, ); @@ -1440,4 +1511,31 @@ fn foo() { "#, ); } + + #[test] + fn snippet_dedent() { + check_edit( + "let", + r#" +//- minicore: option +fn foo(x: Option, y: Option) { + let _f = || { + x + .and(y) + .map(|it| it+2) + .$0 + }; +} +"#, + r#" +fn foo(x: Option, y: Option) { + let _f = || { + let $0 = x + .and(y) + .map(|it| it+2); + }; +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs index abcf9fca6f29..8ff9c3258e8e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs @@ -23,7 +23,9 @@ pub(crate) fn complete_type_path( ScopeDef::GenericParam(LifetimeParam(_)) => location.complete_lifetimes(), ScopeDef::Label(_) => false, // no values in type places - ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false, + ScopeDef::ModuleDef(Function(_) | EnumVariant(_) | Static(_)) | ScopeDef::Local(_) => { + false + } // unless its a constant in a generic arg list position ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => { location.complete_consts() diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 97afd07b0086..4fd0348156a5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -288,7 +288,7 @@ pub(crate) struct PatternContext { pub(crate) record_pat: Option, pub(crate) impl_or_trait: Option>, /// List of missing variants in a match expr - pub(crate) missing_variants: Vec, + pub(crate) missing_variants: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -527,7 +527,7 @@ pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible { hir::ModuleDef::Module(it) => self.is_visible(it), hir::ModuleDef::Function(it) => self.is_visible(it), hir::ModuleDef::Adt(it) => self.is_visible(it), - hir::ModuleDef::Variant(it) => self.is_visible(it), + hir::ModuleDef::EnumVariant(it) => self.is_visible(it), hir::ModuleDef::Const(it) => self.is_visible(it), hir::ModuleDef::Static(it) => self.is_visible(it), hir::ModuleDef::Trait(it) => self.is_visible(it), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 4b0cc0c7cd98..a3494b964f89 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1,7 +1,7 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; -use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant}; +use hir::{EnumVariant, ExpandResult, InFile, Semantics, Type, TypeInfo}; use ide_db::{ RootDatabase, active_parameter::ActiveParameter, syntax_helpers::node_ext::find_loops, }; @@ -778,6 +778,16 @@ fn expected_type_and_name<'db>( let ty = sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::original); (ty, None) }, + ast::TupleStructPat(it) => { + let fields = it.path().and_then(|path| match sema.resolve_path(&path)? { + hir::PathResolution::Def(hir::ModuleDef::Adt(adt)) => Some(adt.as_struct()?.fields(sema.db)), + hir::PathResolution::Def(hir::ModuleDef::EnumVariant(variant)) => Some(variant.fields(sema.db)), + _ => None, + }); + let nr = it.fields().take_while(|it| it.syntax().text_range().end() <= token.text_range().start()).count(); + let ty = fields.and_then(|fields| Some(fields.get(nr)?.ty(sema.db).to_type(sema.db))); + (ty, None) + }, ast::Fn(it) => { cov_mark::hit!(expected_type_fn_ret_with_leading_char); cov_mark::hit!(expected_type_fn_ret_without_leading_char); @@ -944,10 +954,10 @@ fn classify_name_ref<'db>( let field_expr_handle = |receiver, node| { let receiver = find_opt_node_in_file(original_file, receiver); let receiver_is_ambiguous_float_literal = match &receiver { - Some(ast::Expr::Literal(l)) => matches! { - l.kind(), - ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().is_some_and(|it| it.text().ends_with('.')) - }, + Some(ast::Expr::Literal(l)) => { + matches!(l.kind(), ast::LiteralKind::FloatNumber { .. }) + && l.syntax().last_token().is_some_and(|it| it.text().ends_with('.')) + } _ => false, }; @@ -1139,7 +1149,7 @@ fn classify_name_ref<'db>( hir::ModuleDef::Adt(adt) => { sema.source(adt)?.value.generic_param_list() } - hir::ModuleDef::Variant(variant) => { + hir::ModuleDef::EnumVariant(variant) => { sema.source(variant.parent_enum(sema.db))?.value.generic_param_list() } hir::ModuleDef::Trait(trait_) => { @@ -1815,7 +1825,7 @@ fn pattern_context_for( }); (!variant_already_present).then_some(*variant) - }).collect::>()) + }).collect::>()) }); if let Some(missing_variants_) = missing_variants_opt { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index e97d9720e3f3..94d904932ac5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -287,6 +287,50 @@ fn foo() -> Foo { ); } +#[test] +fn expected_type_tuple_struct_pat() { + check_expected_type_and_name( + r#" +//- minicore: option +struct Foo(Option); +fn foo(x: Foo) -> Foo { + match x { Foo($0) => () } +} +"#, + expect![[r#"ty: Option, name: ?"#]], + ); + + check_expected_type_and_name( + r#" +struct Foo(i32, u32, f32); +fn foo(x: Foo) -> Foo { + match x { Foo($0) => () } +} +"#, + expect![[r#"ty: i32, name: ?"#]], + ); + + check_expected_type_and_name( + r#" +struct Foo(i32, u32, f32); +fn foo(x: Foo) -> Foo { + match x { Foo(num,$0) => () } +} +"#, + expect![[r#"ty: u32, name: ?"#]], + ); + + check_expected_type_and_name( + r#" +struct Foo(i32, u32, f32); +fn foo(x: Foo) -> Foo { + match x { Foo(num,$0,float) => () } +} +"#, + expect![[r#"ty: u32, name: ?"#]], + ); +} + #[test] fn expected_type_if_let_without_leading_char() { cov_mark::check!(expected_type_if_let_without_leading_char); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 765304d8187d..d77e79329541 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -408,7 +408,7 @@ fn render_resolution_path( let ctx = ctx.import_to_add(import_to_add); return render_fn(ctx, path_ctx, Some(local_name), func); } - ScopeDef::ModuleDef(Variant(var)) => { + ScopeDef::ModuleDef(EnumVariant(var)) => { let ctx = ctx.clone().import_to_add(import_to_add.clone()); if let Some(item) = render_variant_lit(ctx, path_ctx, Some(local_name.clone()), var, None) @@ -476,7 +476,7 @@ fn render_resolution_path( } // Filtered out above ScopeDef::ModuleDef( - ModuleDef::Function(_) | ModuleDef::Variant(_) | ModuleDef::Macro(_), + ModuleDef::Function(_) | ModuleDef::EnumVariant(_) | ModuleDef::Macro(_), ) => (), ScopeDef::ModuleDef(ModuleDef::Const(konst)) => set_item_relevance(konst.ty(db)), ScopeDef::ModuleDef(ModuleDef::Static(stat)) => set_item_relevance(stat.ty(db)), @@ -528,7 +528,7 @@ fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { match resolution { ScopeDef::Unknown => CompletionItemKind::UnresolvedReference, ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function), - ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant), + ScopeDef::ModuleDef(EnumVariant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant), ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro), ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module), ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { @@ -559,7 +559,7 @@ fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option it.docs(db), ScopeDef::ModuleDef(Adt(it)) => it.docs(db), - ScopeDef::ModuleDef(Variant(it)) => it.docs(db), + ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(db), ScopeDef::ModuleDef(Const(it)) => it.docs(db), ScopeDef::ModuleDef(Static(it)) => it.docs(db), ScopeDef::ModuleDef(Trait(it)) => it.docs(db), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 475e00dfcf29..dfa30841e7db 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -678,7 +678,7 @@ fn main() { fn complete_fn_param() { // has mut kw check_edit( - "mut bar: u32", + "bar: u32", r#" fn f(foo: (), mut bar: u32) {} fn g(foo: (), mut ba$0) @@ -689,10 +689,35 @@ fn g(foo: (), mut bar: u32) "#, ); - // has type param + // has unmatched mut kw + check_edit( + "bar: u32", + r#" +fn f(foo: (), bar: u32) {} +fn g(foo: (), mut ba$0) +"#, + r#" +fn f(foo: (), bar: u32) {} +fn g(foo: (), mut bar: u32) +"#, + ); + check_edit( "mut bar: u32", r#" +fn f(foo: (), mut bar: u32) {} +fn g(foo: (), ba$0) +"#, + r#" +fn f(foo: (), mut bar: u32) {} +fn g(foo: (), mut bar: u32) +"#, + ); + + // has type param + check_edit( + "bar: u32", + r#" fn g(foo: (), mut ba$0: u32) fn f(foo: (), mut bar: u32) {} "#, @@ -707,7 +732,7 @@ fn f(foo: (), mut bar: u32) {} fn complete_fn_mut_param_add_comma() { // add leading and trailing comma check_edit( - ", mut bar: u32,", + "bar: u32", r#" fn f(foo: (), mut bar: u32) {} fn g(foo: ()mut ba$0 baz: ()) @@ -746,7 +771,7 @@ fn g(foo: (), #[baz = "qux"] mut bar: u32) ); check_edit( - r#", #[baz = "qux"] mut bar: u32"#, + r#"#[baz = "qux"] mut bar: u32"#, r#" fn f(foo: (), #[baz = "qux"] mut bar: u32) {} fn g(foo: ()#[baz = "qux"] mut ba$0) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs index 8b14f05b72b2..6e49af980aea 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs @@ -23,7 +23,7 @@ pub(crate) fn render_variant_lit( ctx: RenderContext<'_>, path_ctx: &PathCompletionCtx<'_>, local_name: Option, - variant: hir::Variant, + variant: hir::EnumVariant, path: Option, ) -> Option { let _p = tracing::info_span!("render_variant_lit").entered(); @@ -150,7 +150,7 @@ fn render( #[derive(Clone, Copy)] enum Variant { Struct(hir::Struct), - EnumVariant(hir::Variant), + EnumVariant(hir::EnumVariant), } impl Variant { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs index 60474a31b4d3..fb35d7b9b671 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs @@ -47,7 +47,7 @@ pub(crate) fn render_variant_pat( ctx: RenderContext<'_>, pattern_ctx: &PatternContext, path_ctx: Option<&PathCompletionCtx<'_>>, - variant: hir::Variant, + variant: hir::EnumVariant, local_name: Option, path: Option<&hir::ModPath>, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs index d6d73da3f140..aaa225642c6f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs @@ -43,7 +43,7 @@ fn bar(file_id: usize) {} fn baz(file$0 id: u32) {} "#, expect![[r#" - bn file_id: usize, + bn file_id: usize kw mut kw ref "#]], diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs index f5a5b76c336a..8bd4c6c46b85 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs @@ -113,7 +113,7 @@ pub fn generic_def_for_node( sema: &Semantics<'_, RootDatabase>, generic_arg_list: &ast::GenericArgList, token: &SyntaxToken, -) -> Option<(hir::GenericDef, usize, bool, Option)> { +) -> Option<(hir::GenericDef, usize, bool, Option)> { let parent = generic_arg_list.syntax().parent()?; let mut variant = None; let def = match_ast! { @@ -125,7 +125,7 @@ pub fn generic_def_for_node( hir::PathResolution::Def(hir::ModuleDef::Function(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => { + hir::PathResolution::Def(hir::ModuleDef::EnumVariant(it)) => { variant = Some(it); it.parent_enum(sema.db).into() }, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 788f9b73fa19..82cff372963a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -14,11 +14,12 @@ use either::Either; use hir::{ Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, - Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, ExternAssocItem, - ExternCrateDecl, Field, Function, GenericDef, GenericParam, GenericSubstitution, HasContainer, - HasVisibility, HirDisplay, Impl, InlineAsmOperand, ItemContainer, Label, Local, Macro, Module, - ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, Trait, - TupleField, TypeAlias, Variant, VariantDef, Visibility, + Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, EnumVariant, + ExpressionStoreOwner, ExternAssocItem, ExternCrateDecl, Field, Function, GenericDef, + GenericParam, GenericSubstitution, HasContainer, HasVisibility, HirDisplay, Impl, + InlineAsmOperand, ItemContainer, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, + Semantics, Static, StaticLifetime, Struct, ToolModule, Trait, TupleField, TypeAlias, Variant, + Visibility, }; use span::Edition; use stdx::{format_to, impl_from}; @@ -38,7 +39,7 @@ pub enum Definition { Crate(Crate), Function(Function), Adt(Adt), - Variant(Variant), + EnumVariant(EnumVariant), Const(Const), Static(Static), Trait(Trait), @@ -85,7 +86,7 @@ pub fn module(&self, db: &RootDatabase) -> Option { Definition::Static(it) => it.module(db), Definition::Trait(it) => it.module(db), Definition::TypeAlias(it) => it.module(db), - Definition::Variant(it) => it.module(db), + Definition::EnumVariant(it) => it.module(db), Definition::SelfType(it) => it.module(db), Definition::Local(it) => it.module(db), Definition::GenericParam(it) => it.module(db), @@ -123,7 +124,7 @@ fn container_to_definition(container: ItemContainer) -> Option { Definition::Static(it) => container_to_definition(it.container(db)), Definition::Trait(it) => container_to_definition(it.container(db)), Definition::TypeAlias(it) => container_to_definition(it.container(db)), - Definition::Variant(it) => Some(Adt::Enum(it.parent_enum(db)).into()), + Definition::EnumVariant(it) => Some(Adt::Enum(it.parent_enum(db)).into()), Definition::SelfType(it) => Some(it.module(db).into()), Definition::Local(it) => it.parent(db).try_into().ok(), Definition::GenericParam(it) => Some(it.parent().into()), @@ -151,7 +152,7 @@ pub fn visibility(&self, db: &RootDatabase) -> Option { Definition::Static(it) => it.visibility(db), Definition::Trait(it) => it.visibility(db), Definition::TypeAlias(it) => it.visibility(db), - Definition::Variant(it) => it.visibility(db), + Definition::EnumVariant(it) => it.visibility(db), Definition::ExternCrateDecl(it) => it.visibility(db), Definition::Macro(it) => it.visibility(db), Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public, @@ -179,7 +180,7 @@ pub fn name(&self, db: &RootDatabase) -> Option { } Definition::Function(it) => it.name(db), Definition::Adt(it) => it.name(db), - Definition::Variant(it) => it.name(db), + Definition::EnumVariant(it) => it.name(db), Definition::Const(it) => it.name(db)?, Definition::Static(it) => it.name(db), Definition::Trait(it) => it.name(db), @@ -227,7 +228,7 @@ pub fn docs_with_rangemap<'db>( Definition::Crate(it) => it.docs_with_rangemap(db), Definition::Function(it) => it.docs_with_rangemap(db), Definition::Adt(it) => it.docs_with_rangemap(db), - Definition::Variant(it) => it.docs_with_rangemap(db), + Definition::EnumVariant(it) => it.docs_with_rangemap(db), Definition::Const(it) => it.docs_with_rangemap(db), Definition::Static(it) => it.docs_with_rangemap(db), Definition::Trait(it) => it.docs_with_rangemap(db), @@ -315,7 +316,7 @@ pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String Definition::Crate(it) => it.display(db, display_target).to_string(), Definition::Function(it) => it.display(db, display_target).to_string(), Definition::Adt(it) => it.display(db, display_target).to_string(), - Definition::Variant(it) => it.display(db, display_target).to_string(), + Definition::EnumVariant(it) => it.display(db, display_target).to_string(), Definition::Const(it) => it.display(db, display_target).to_string(), Definition::Static(it) => it.display(db, display_target).to_string(), Definition::Trait(it) => it.display(db, display_target).to_string(), @@ -556,7 +557,7 @@ pub fn classify( ast::Rename(it) => classify_rename(sema, it)?, ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?), ast::RecordField(it) => Definition::Field(sema.to_def(&it)?), - ast::Variant(it) => Definition::Variant(sema.to_def(&it)?), + ast::Variant(it) => Definition::EnumVariant(sema.to_def(&it)?), ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), ast::AsmOperandNamed(it) => Definition::InlineAsmOperand(sema.to_def(&it)?), @@ -848,7 +849,7 @@ pub fn classify( ast::OffsetOfExpr(_) => { let (def, subst) = sema.resolve_offset_of_field(name_ref)?; let def = match def { - Either::Left(variant) => Definition::Variant(variant), + Either::Left(variant) => Definition::EnumVariant(variant), Either::Right(field) => Definition::Field(field), }; Some(NameRefClass::Definition(def, Some(subst))) @@ -891,7 +892,7 @@ pub fn classify_lifetime( } impl_from!( - Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local, + Field, Module, Function, Adt, EnumVariant, Const, Static, Trait, TypeAlias, BuiltinType, Local, GenericParam, Label, Macro, ExternCrateDecl for Definition ); @@ -967,7 +968,7 @@ fn from(def: ModuleDef) -> Self { ModuleDef::Module(it) => Definition::Module(it), ModuleDef::Function(it) => Definition::Function(it), ModuleDef::Adt(it) => Definition::Adt(it), - ModuleDef::Variant(it) => Definition::Variant(it), + ModuleDef::EnumVariant(it) => Definition::EnumVariant(it), ModuleDef::Const(it) => Definition::Const(it), ModuleDef::Static(it) => Definition::Static(it), ModuleDef::Trait(it) => Definition::Trait(it), @@ -988,8 +989,8 @@ fn from(def: DocLinkDef) -> Self { } } -impl From for Definition { - fn from(def: VariantDef) -> Self { +impl From for Definition { + fn from(def: Variant) -> Self { ModuleDef::from(def).into() } } @@ -1001,7 +1002,7 @@ fn try_from(def: DefWithBody) -> Result { DefWithBody::Function(it) => Ok(it.into()), DefWithBody::Static(it) => Ok(it.into()), DefWithBody::Const(it) => Ok(it.into()), - DefWithBody::Variant(it) => Ok(it.into()), + DefWithBody::EnumVariant(it) => Ok(it.into()), } } } @@ -1020,6 +1021,17 @@ fn from(def: GenericDef) -> Self { } } +impl TryFrom for Definition { + type Error = (); + fn try_from(def: ExpressionStoreOwner) -> Result { + match def { + ExpressionStoreOwner::Body(def_with_body) => def_with_body.try_into(), + ExpressionStoreOwner::Signature(generic_def) => Ok(generic_def.into()), + ExpressionStoreOwner::VariantFields(it) => Ok(it.into()), + } + } +} + impl TryFrom for GenericDef { type Error = (); fn try_from(def: Definition) -> Result { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs index 4c4691cca2ca..407049f4b362 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs @@ -58,8 +58,22 @@ impl HasDocs for hir::$def {} } impl_has_docs![ - Variant, Field, Static, Const, Trait, TypeAlias, Macro, Function, Adt, Module, Impl, Crate, - AssocItem, Struct, Union, Enum, + EnumVariant, + Field, + Static, + Const, + Trait, + TypeAlias, + Macro, + Function, + Adt, + Module, + Impl, + Crate, + AssocItem, + Struct, + Union, + Enum, ]; impl HasDocs for hir::ExternCrateDecl { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index dedc12aa653f..9e6d58600888 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -11576,9 +11576,9 @@ pub union GenericUnion { // Unions with non-`Copy` fields are unstable. label: "try_blocks", description: r##"# `try_blocks` -The tracking issue for this feature is: [#31436] +The tracking issue for this feature is: [#154391] -[#31436]: https://github.com/rust-lang/rust/issues/31436 +[#154391]: https://github.com/rust-lang/rust/issues/154391 ------------------------ @@ -11590,14 +11590,14 @@ pub union GenericUnion { // Unions with non-`Copy` fields are unstable. use std::num::ParseIntError; -let result: Result = try { +let result = try { "1".parse::()? + "2".parse::()? + "3".parse::()? }; assert_eq!(result, Ok(6)); -let result: Result = try { +let result = try { "1".parse::()? + "foo".parse::()? + "3".parse::()? diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 023b32b36195..cde0705d8ac2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -312,7 +312,7 @@ impl SymbolKind { pub fn from_module_def(db: &dyn HirDatabase, it: hir::ModuleDef) -> Self { match it { hir::ModuleDef::Const(..) => SymbolKind::Const, - hir::ModuleDef::Variant(..) => SymbolKind::Variant, + hir::ModuleDef::EnumVariant(..) => SymbolKind::Variant, hir::ModuleDef::Function(..) => SymbolKind::Function, hir::ModuleDef::Macro(mac) if mac.is_proc_macro() => SymbolKind::ProcMacro, hir::ModuleDef::Macro(..) => SymbolKind::Macro, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 01a326a0dc63..508f841340b1 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -580,7 +580,7 @@ fn transform_ident_pat( } } - if let hir::ModuleDef::Variant(v) = def + if let hir::ModuleDef::EnumVariant(v) = def && v.kind(self.source_scope.db) != hir::StructKind::Unit { return None; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs index 015b06e8e0b2..d264428212cb 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs @@ -4,7 +4,7 @@ //! various caches, it's not really advanced at the moment. use std::panic::AssertUnwindSafe; -use hir::{Symbol, db::DefDatabase}; +use hir::{Symbol, import_map::ImportMap}; use rustc_hash::FxHashMap; use salsa::{Cancelled, Database}; @@ -123,7 +123,7 @@ enum ParallelPrimeCacheWorkerProgress { Ok::<_, crossbeam_channel::SendError<_>>(()) }; let handle_import_map = |crate_id| { - let cancelled = Cancelled::catch(|| _ = db.import_map(crate_id)); + let cancelled = Cancelled::catch(|| _ = ImportMap::of(&db, crate_id)); match cancelled { Ok(()) => { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index b03a5b6efb6a..b18ed69d80fe 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -170,7 +170,7 @@ pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option name_range(it, sema).and_then(syn_ctx_is_root), hir::Adt::Enum(it) => name_range(it, sema).and_then(syn_ctx_is_root), }, - Definition::Variant(it) => name_range(it, sema).and_then(syn_ctx_is_root), + Definition::EnumVariant(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Const(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Static(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Trait(it) => name_range(it, sema).and_then(syn_ctx_is_root), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index 4196a13aa3fa..25acb47f7b4c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -10,9 +10,9 @@ use base_db::{RootQueryDb, SourceDatabase}; use either::Either; use hir::{ - Adt, AsAssocItem, DefWithBody, EditionedFileId, FileRange, FileRangeWrapper, HasAttrs, - HasContainer, HasSource, InFile, InFileWrapper, InRealFile, InlineAsmOperand, ItemContainer, - ModuleSource, PathResolution, Semantics, Visibility, + Adt, AsAssocItem, DefWithBody, EditionedFileId, ExpressionStoreOwner, FileRange, + FileRangeWrapper, HasAttrs, HasContainer, HasSource, InFile, InFileWrapper, InRealFile, + InlineAsmOperand, ItemContainer, ModuleSource, PathResolution, Semantics, Visibility, }; use memchr::memmem::Finder; use parser::SyntaxKind; @@ -169,7 +169,7 @@ fn crate_graph(db: &RootDatabase) -> SearchScope { entries.extend( source_root .iter() - .map(|id| (EditionedFileId::new(db, id, crate_data.edition, krate), None)), + .map(|id| (EditionedFileId::new(db, id, crate_data.edition), None)), ); } SearchScope { entries } @@ -183,9 +183,11 @@ fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope { let source_root = db.file_source_root(root_file).source_root_id(db); let source_root = db.source_root(source_root).source_root(db); - entries.extend(source_root.iter().map(|id| { - (EditionedFileId::new(db, id, rev_dep.edition(db), rev_dep.into()), None) - })); + entries.extend( + source_root + .iter() + .map(|id| (EditionedFileId::new(db, id, rev_dep.edition(db)), None)), + ); } SearchScope { entries } } @@ -199,7 +201,7 @@ fn krate(db: &RootDatabase, of: hir::Crate) -> SearchScope { SearchScope { entries: source_root .iter() - .map(|id| (EditionedFileId::new(db, id, of.edition(db), of.into()), None)) + .map(|id| (EditionedFileId::new(db, id, of.edition(db)), None)) .collect(), } } @@ -308,10 +310,26 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { if let Definition::Local(var) = self { let def = match var.parent(db) { - DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + ExpressionStoreOwner::Body(def) => match def { + DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), + DefWithBody::EnumVariant(v) => v.source(db).map(|src| src.syntax().cloned()), + }, + ExpressionStoreOwner::Signature(def) => match def { + hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Adt(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Trait(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::TypeAlias(it) => { + it.source(db).map(|src| src.syntax().cloned()) + } + hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Static(it) => it.source(db).map(|src| src.syntax().cloned()), + }, + ExpressionStoreOwner::VariantFields(it) => { + it.source(db).map(|src| src.syntax().cloned()) + } }; return match def { Some(def) => SearchScope::file_range( @@ -323,10 +341,26 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { if let Definition::InlineAsmOperand(op) = self { let def = match op.parent(db) { - DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + ExpressionStoreOwner::Body(def) => match def { + DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), + DefWithBody::EnumVariant(v) => v.source(db).map(|src| src.syntax().cloned()), + }, + ExpressionStoreOwner::Signature(def) => match def { + hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Adt(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Trait(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::TypeAlias(it) => { + it.source(db).map(|src| src.syntax().cloned()) + } + hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Static(it) => it.source(db).map(|src| src.syntax().cloned()), + }, + ExpressionStoreOwner::VariantFields(it) => { + it.source(db).map(|src| src.syntax().cloned()) + } }; return match def { Some(def) => SearchScope::file_range( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 5d1e876ea298..3a785fbe80a0 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -89,6 +89,12 @@ /// /// assert_eq!(generator.suggest_name("b2"), "b2"); /// assert_eq!(generator.suggest_name("b"), "b3"); +/// +/// // Multi-byte UTF-8 identifiers (e.g. CJK) are handled correctly +/// assert_eq!(generator.suggest_name("日本語"), "日本語"); +/// assert_eq!(generator.suggest_name("日本語"), "日本語1"); +/// assert_eq!(generator.suggest_name("données3"), "données3"); +/// assert_eq!(generator.suggest_name("données"), "données4"); /// ``` #[derive(Debug, Default)] pub struct NameGenerator { @@ -262,11 +268,15 @@ fn insert(&mut self, name: &str) { /// Remove the numeric suffix from the name /// /// # Examples - /// `a1b2c3` -> `a1b2c` + /// `a1b2c3` -> (`a1b2c`, Some(3)) fn split_numeric_suffix(name: &str) -> (&str, Option) { let pos = name.rfind(|c: char| !c.is_numeric()).expect("Name cannot be empty or all-numeric"); - let (prefix, suffix) = name.split_at(pos + 1); + // `rfind` returns the byte offset of the matched character, which may be + // multi-byte (e.g. CJK identifiers). Use `ceil_char_boundary` to advance + // past the full character to the next valid split point. + let split = name.ceil_char_boundary(pos + 1); + let (prefix, suffix) = name.split_at(split); (prefix, suffix.parse().ok()) } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt index 0c28c312f83b..fc98ebb06921 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt @@ -2,7 +2,7 @@ ( Module { id: ModuleIdLt { - [salsa id]: Id(3800), + [salsa id]: Id(3400), }, }, [ diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 4b588572d328..02a023038a61 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -2,14 +2,14 @@ ( Module { id: ModuleIdLt { - [salsa id]: Id(3800), + [salsa id]: Id(3400), }, }, [ FileSymbol { name: "A", - def: Variant( - Variant { + def: EnumVariant( + EnumVariant { id: EnumVariantId( 7c00, ), @@ -80,8 +80,8 @@ }, FileSymbol { name: "B", - def: Variant( - Variant { + def: EnumVariant( + EnumVariant { id: EnumVariantId( 7c01, ), @@ -671,7 +671,7 @@ def: Module( Module { id: ModuleIdLt { - [salsa id]: Id(3801), + [salsa id]: Id(3401), }, }, ), @@ -706,7 +706,7 @@ def: Module( Module { id: ModuleIdLt { - [salsa id]: Id(3802), + [salsa id]: Id(3402), }, }, ), @@ -998,7 +998,7 @@ ( Module { id: ModuleIdLt { - [salsa id]: Id(3801), + [salsa id]: Id(3401), }, }, [ @@ -1044,7 +1044,7 @@ ( Module { id: ModuleIdLt { - [salsa id]: Id(3802), + [salsa id]: Id(3402), }, }, [ diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt index 87f0c7d9a817..aff1d56c56a3 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt @@ -5,7 +5,7 @@ Struct( Struct { id: StructId( - 3c00, + 4000, ), }, ), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt index e96aa889ba06..bf5d81cfb149 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt @@ -5,7 +5,7 @@ Struct( Struct { id: StructId( - 3c00, + 4000, ), }, ), @@ -42,7 +42,7 @@ Struct( Struct { id: StructId( - 3c00, + 4000, ), }, ), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs index 7200e7fbe5ae..60bdc2d82c16 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs @@ -130,7 +130,8 @@ pub(crate) fn position( database.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); - let file_id = EditionedFileId::from_span_guess_origin(&database, file_id); + + let file_id = EditionedFileId::from_span_file_id(&database, file_id); let offset = range_or_offset.expect_offset(); (database, FilePosition { file_id, offset }) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index c47449f2593d..5410f8b58a9a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -262,6 +262,48 @@ struct SomeStruct { SomeField: u8 } ); } + #[test] + fn incorrect_union_names() { + check_diagnostics( + r#" +union non_camel_case_name { field: u8 } + // ^^^^^^^^^^^^^^^^^^^ 💡 warn: Union `non_camel_case_name` should have UpperCamelCase name, e.g. `NonCamelCaseName` + +union SCREAMING_CASE { field: u8 } + // ^^^^^^^^^^^^^^ 💡 warn: Union `SCREAMING_CASE` should have UpperCamelCase name, e.g. `ScreamingCase` +"#, + ); + } + + #[test] + fn no_diagnostic_for_camel_cased_acronyms_in_union_name() { + check_diagnostics( + r#" +union AABB { field: u8 } +"#, + ); + } + + #[test] + fn no_diagnostic_for_repr_c_union() { + check_diagnostics( + r#" +#[repr(C)] +union my_union { field: u8 } +"#, + ); + } + + #[test] + fn incorrect_union_field() { + check_diagnostics( + r#" +union SomeUnion { SomeField: u8 } + // ^^^^^^^^^ 💡 warn: Field `SomeField` should have snake_case name, e.g. `some_field` +"#, + ); + } + #[test] fn incorrect_enum_names() { check_diagnostics( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs index 894e044642cc..25220704e04d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs @@ -220,6 +220,23 @@ fn enum_type_alias_default_param() { fn main() { let _ = Result::<()>::Ok(()); +} + "#, + ); + } + + #[test] + fn type_as_trait_does_not_count() { + check_diagnostics( + r#" +pub trait Lock { + fn new(b: T) -> Self; +} +pub trait LockChoice { + type Lock: Lock; +} +fn f() { + ::Lock::new(()); } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index d5f25dfaf208..050d5477f62c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -588,14 +588,14 @@ fn test_fn() { fn test_fill_struct_fields_default() { check_fix( r#" -//- minicore: default, option +//- minicore: default, option, slice struct TestWithDefault(usize); impl Default for TestWithDefault { pub fn default() -> Self { Self(0) } } -struct TestStruct { one: i32, two: TestWithDefault } +struct TestStruct { one: i32, two: TestWithDefault, r: &'static [i32] } fn test_fn() { let s = TestStruct{ $0 }; @@ -608,10 +608,10 @@ pub fn default() -> Self { Self(0) } } -struct TestStruct { one: i32, two: TestWithDefault } +struct TestStruct { one: i32, two: TestWithDefault, r: &'static [i32] } fn test_fn() { - let s = TestStruct{ one: 0, two: TestWithDefault::default() }; + let s = TestStruct{ one: 0, two: TestWithDefault::default(), r: <&'static [i32]>::default() }; } ", ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs index 5cb710b66b5f..b10cdaa14ee6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs @@ -115,4 +115,20 @@ struct A<'a, T> { "#, ); } + + // FIXME: Ideally, should emit generic default forbidden as well + #[test] + fn regression_16280() { + check_diagnostics( + r#" +trait Traitor<'a, const M: Traitor = Traitor> { + fn crash(&self) -> Traitor { + // ^^^^^^^ error: missing lifetime specifier + // ^^^^^^^ error: missing lifetime specifier + Traitor + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index bcfe3a8aa5ce..944622bb1d58 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -64,20 +64,20 @@ fn missing_record_expr_field_fixes( let module; let def_file_id; let record_fields = match def_id { - hir::VariantDef::Struct(s) => { + hir::Variant::Struct(s) => { module = s.module(sema.db); let source = s.source(sema.db)?; def_file_id = source.file_id; let fields = source.value.field_list()?; record_field_list(fields)? } - hir::VariantDef::Union(u) => { + hir::Variant::Union(u) => { module = u.module(sema.db); let source = u.source(sema.db)?; def_file_id = source.file_id; source.value.record_field_list()? } - hir::VariantDef::Variant(e) => { + hir::Variant::EnumVariant(e) => { module = e.module(sema.db); let source = e.source(sema.db)?; def_file_id = source.file_id; @@ -97,25 +97,37 @@ fn missing_record_expr_field_fixes( make::ty(&new_field_type.display_source_code(sema.db, module.into(), true).ok()?), ); - let last_field = record_fields.fields().last()?; - let last_field_syntax = last_field.syntax(); - let indent = IndentLevel::from_node(last_field_syntax); + let (indent, offset, postfix, needs_comma) = + if let Some(last_field) = record_fields.fields().last() { + let indent = IndentLevel::from_node(last_field.syntax()); + let offset = last_field.syntax().text_range().end(); + let needs_comma = !last_field.to_string().ends_with(','); + (indent, offset, String::new(), needs_comma) + } else { + let indent = IndentLevel::from_node(record_fields.syntax()); + let offset = record_fields.l_curly_token()?.text_range().end(); + let postfix = if record_fields.syntax().text().contains_char('\n') { + ",".into() + } else { + format!(",\n{indent}") + }; + (indent + 1, offset, postfix, false) + }; let mut new_field = new_field.to_string(); // FIXME: check submodule instead of FileId - if usage_file_id != def_file_id && !matches!(def_id, hir::VariantDef::Variant(_)) { + if usage_file_id != def_file_id && !matches!(def_id, hir::Variant::EnumVariant(_)) { new_field = format!("pub(crate) {new_field}"); } - new_field = format!("\n{indent}{new_field}"); + new_field = format!("\n{indent}{new_field}{postfix}"); - let needs_comma = !last_field_syntax.to_string().ends_with(','); if needs_comma { new_field = format!(",{new_field}"); } let source_change = SourceChange::from_text_edit( def_file_id.file_id(sema.db), - TextEdit::insert(last_field_syntax.text_range().end(), new_field), + TextEdit::insert(offset, new_field), ); return Some(vec![fix( @@ -334,6 +346,44 @@ struct Foo { ) } + #[test] + fn test_add_field_from_usage_with_empty_struct() { + check_fix( + r" +fn main() { + Foo { bar$0: false }; +} +struct Foo {} +", + r" +fn main() { + Foo { bar: false }; +} +struct Foo { + bar: bool, +} +", + ); + + check_fix( + r" +fn main() { + Foo { bar$0: false }; +} +struct Foo { +} +", + r" +fn main() { + Foo { bar: false }; +} +struct Foo { + bar: bool, +} +", + ); + } + #[test] fn test_add_field_in_other_file_from_usage() { check_fix( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs index c86ecd2f03b9..bc10e82854f5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs @@ -1,4 +1,11 @@ -use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; +use either::Either; +use hir::Semantics; +use ide_db::text_edit::TextEdit; +use ide_db::ty_filter::TryEnum; +use ide_db::{RootDatabase, source_change::SourceChange}; +use syntax::{AstNode, ast}; + +use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix}; // Diagnostic: non-exhaustive-let // @@ -15,11 +22,74 @@ pub(crate) fn non_exhaustive_let( d.pat.map(Into::into), ) .stable() + .with_fixes(fixes(&ctx.sema, d)) +} + +fn fixes(sema: &Semantics<'_, RootDatabase>, d: &hir::NonExhaustiveLet) -> Option> { + let root = sema.parse_or_expand(d.pat.file_id); + let pat = d.pat.value.to_node(&root); + let let_stmt = ast::LetStmt::cast(pat.syntax().parent()?)?; + let early_node = + sema.ancestors_with_macros(let_stmt.syntax().clone()).find_map(AstNode::cast)?; + let early_text = early_text(sema, &early_node); + + if let_stmt.let_else().is_some() { + return None; + } + let hir::FileRangeWrapper { file_id, range } = sema.original_range_opt(let_stmt.syntax())?; + let insert_offset = if let Some(semicolon) = let_stmt.semicolon_token() + && let Some(token) = sema.parse(file_id).syntax().token_at_offset(range.end()).left_biased() + && token.kind() == semicolon.kind() + { + token.text_range().start() + } else { + range.end() + }; + let semicolon = if let_stmt.semicolon_token().is_none() { ";" } else { "" }; + let else_block = format!(" else {{ {early_text} }}{semicolon}"); + let file_id = file_id.file_id(sema.db); + + let source_change = + SourceChange::from_text_edit(file_id, TextEdit::insert(insert_offset, else_block)); + let target = sema.original_range(let_stmt.syntax()).range; + Some(vec![fix("add_let_else_block", "Add let-else block", source_change, target)]) +} + +fn early_text( + sema: &Semantics<'_, RootDatabase>, + early_node: &Either>, +) -> &'static str { + match early_node { + Either::Left(_any_loop) => "continue", + Either::Right(Either::Left(fn_)) => sema + .to_def(fn_) + .map(|fn_def| fn_def.ret_type(sema.db)) + .map(|ty| return_text(&ty, sema)) + .unwrap_or("return"), + Either::Right(Either::Right(closure)) => closure + .body() + .and_then(|expr| sema.type_of_expr(&expr)) + .map(|ty| return_text(&ty.adjusted(), sema)) + .unwrap_or("return"), + } +} + +fn return_text(ty: &hir::Type<'_>, sema: &Semantics<'_, RootDatabase>) -> &'static str { + if ty.is_unit() { + "return" + } else if let Some(try_enum) = TryEnum::from_ty(sema, ty) { + match try_enum { + TryEnum::Option => "return None", + TryEnum::Result => "return Err($0)", + } + } else { + "return $0" + } } #[cfg(test)] mod tests { - use crate::tests::check_diagnostics; + use crate::tests::{check_diagnostics, check_fix}; #[test] fn option_nonexhaustive() { @@ -28,7 +98,7 @@ fn option_nonexhaustive() { //- minicore: option fn main() { let None = Some(5); - //^^^^ error: non-exhaustive pattern: `Some(_)` not covered + //^^^^ 💡 error: non-exhaustive pattern: `Some(_)` not covered } "#, ); @@ -54,7 +124,7 @@ fn option_nonexhaustive_inside_blocks() { fn main() { '_a: { let None = Some(5); - //^^^^ error: non-exhaustive pattern: `Some(_)` not covered + //^^^^ 💡 error: non-exhaustive pattern: `Some(_)` not covered } } "#, @@ -66,7 +136,7 @@ fn main() { fn main() { let _ = async { let None = Some(5); - //^^^^ error: non-exhaustive pattern: `Some(_)` not covered + //^^^^ 💡 error: non-exhaustive pattern: `Some(_)` not covered }; } "#, @@ -78,7 +148,7 @@ fn main() { fn main() { unsafe { let None = Some(5); - //^^^^ error: non-exhaustive pattern: `Some(_)` not covered + //^^^^ 💡 error: non-exhaustive pattern: `Some(_)` not covered } } "#, @@ -101,7 +171,7 @@ fn test(x: Result) { //- minicore: result fn test(x: Result) { let Ok(_y) = x; - //^^^^^^ error: non-exhaustive pattern: `Err(_)` not covered + //^^^^^^ 💡 error: non-exhaustive pattern: `Err(_)` not covered } "#, ); @@ -132,6 +202,136 @@ fn foo(v: Enum<()>) { ); } + #[test] + fn fix_return_in_loop() { + check_fix( + r#" +//- minicore: option +fn foo() { + while cond { + let None$0 = Some(5); + } +} +"#, + r#" +fn foo() { + while cond { + let None = Some(5) else { continue }; + } +} +"#, + ); + } + + #[test] + fn fix_return_in_fn() { + check_fix( + r#" +//- minicore: option +fn foo() { + let None$0 = Some(5); +} +"#, + r#" +fn foo() { + let None = Some(5) else { return }; +} +"#, + ); + } + + #[test] + fn fix_return_in_macro_expanded() { + check_fix( + r#" +//- minicore: option +macro_rules! identity { ($($t:tt)*) => { $($t)* }; } +fn foo() { + identity! { + let None$0 = Some(5); + } +} +"#, + r#" +macro_rules! identity { ($($t:tt)*) => { $($t)* }; } +fn foo() { + identity! { + let None = Some(5) else { return }; + } +} +"#, + ); + } + + #[test] + fn fix_return_in_incomplete_let() { + check_fix( + r#" +//- minicore: option +fn foo() { + let None$0 = Some(5) +} +"#, + r#" +fn foo() { + let None = Some(5) else { return }; +} +"#, + ); + } + + #[test] + fn fix_return_in_closure() { + check_fix( + r#" +//- minicore: option +fn foo() -> Option<()> { + let _f = || { + let None$0 = Some(5); + }; +} +"#, + r#" +fn foo() -> Option<()> { + let _f = || { + let None = Some(5) else { return }; + }; +} +"#, + ); + } + + #[test] + fn fix_return_try_in_fn() { + check_fix( + r#" +//- minicore: option +fn foo() -> Option<()> { + let None$0 = Some(5); +} +"#, + r#" +fn foo() -> Option<()> { + let None = Some(5) else { return None }; +} +"#, + ); + + check_fix( + r#" +//- minicore: option, result +fn foo() -> Result<(), i32> { + let None$0 = Some(5); +} +"#, + r#" +fn foo() -> Result<(), i32> { + let None = Some(5) else { return Err($0) }; +} +"#, + ); + } + #[test] fn regression_20259() { check_diagnostics( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs index 7dc5b5b45e5f..04f48ae3db17 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs @@ -48,7 +48,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option block diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index cb3aac3717f8..f4054610f2bd 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -6,6 +6,7 @@ source_change::SourceChangeBuilder, }; use syntax::ToSmolStr; +use syntax::ast::edit::AstNodeEdit; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -23,6 +24,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( let default_range = d.impl_.syntax_node_ptr().text_range(); let trait_name = d.trait_.name(db).display_no_db(ctx.edition).to_smolstr(); + let indent_level = d.trait_.source(db).map_or(0, |it| it.value.indent_level().0) + 1; let (redundant_item_name, diagnostic_range, redundant_item_def) = match assoc_item { hir::AssocItem::Function(id) => { @@ -30,7 +32,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( ( format!("`fn {redundant_assoc_item_name}`"), function.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), - format!("\n {};", function.display(db, ctx.display_target)), + format!("\n{};", function.display(db, ctx.display_target)), ) } hir::AssocItem::Const(id) => { @@ -38,7 +40,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( ( format!("`const {redundant_assoc_item_name}`"), constant.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), - format!("\n {};", constant.display(db, ctx.display_target)), + format!("\n{};", constant.display(db, ctx.display_target)), ) } hir::AssocItem::TypeAlias(id) => { @@ -46,10 +48,8 @@ pub(crate) fn trait_impl_redundant_assoc_item( ( format!("`type {redundant_assoc_item_name}`"), type_alias.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), - format!( - "\n type {};", - type_alias.name(ctx.sema.db).display_no_db(ctx.edition).to_smolstr() - ), + // FIXME cannot generate generic parameter and bounds + format!("\ntype {};", type_alias.name(ctx.sema.db).display_no_db(ctx.edition)), ) } }; @@ -65,7 +65,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( .with_fixes(quickfix_for_redundant_assoc_item( ctx, d, - redundant_item_def, + stdx::indent_string(&redundant_item_def, indent_level), diagnostic_range, )) } @@ -191,6 +191,89 @@ impl Marker for Foo { ) } + #[test] + fn quickfix_indentations() { + check_fix( + r#" +mod indent { + trait Marker { + fn boo(); + } + struct Foo; + impl Marker for Foo { + fn$0 bar(_a: i32, _b: T) -> String {} + fn boo() {} + } +} + "#, + r#" +mod indent { + trait Marker { + fn bar(_a: i32, _b: T) -> String + where + T: Copy,; + fn boo(); + } + struct Foo; + impl Marker for Foo { + fn bar(_a: i32, _b: T) -> String {} + fn boo() {} + } +} + "#, + ); + + check_fix( + r#" +mod indent { + trait Marker { + fn foo () {} + } + struct Foo; + impl Marker for Foo { + const FLAG: bool$0 = false; + } +} + "#, + r#" +mod indent { + trait Marker { + const FLAG: bool; + fn foo () {} + } + struct Foo; + impl Marker for Foo { + const FLAG: bool = false; + } +} + "#, + ); + + check_fix( + r#" +mod indent { + trait Marker { + } + struct Foo; + impl Marker for Foo { + type T = i32;$0 + } +} + "#, + r#" +mod indent { + trait Marker { + type T; + } + struct Foo; + impl Marker for Foo { + type T = i32; + } +} + "#, + ); + } + #[test] fn quickfix_dont_work() { check_no_fix( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 577c582a2080..fd1674e2a47b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -442,4 +442,30 @@ fn rdtscp() -> u64 { }"#, ); } + + #[test] + fn asm_sym_with_macro_expr_fragment() { + // Regression test for issue #21582 + // When `$e:expr` captures a path and is used in `sym $e`, the path gets + // wrapped in parentheses during macro expansion due to invisible delimiters. + // This should not cause false positive typed-hole errors. + check_diagnostics( + r#" +//- minicore: asm +macro_rules! m { + ($e:expr) => { + core::arch::asm!("/*{f}*/", f = sym $e, out("ax") _) + }; +} + +fn generic() {} + +fn main() { + unsafe { + m!(generic::); + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs index de26879c2959..181cc74a51d4 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs @@ -17,7 +17,7 @@ pub fn ssr_from_comment( frange: FileRange, ) -> Option<(MatchFinder<'_>, TextRange)> { let comment = { - let file_id = EditionedFileId::current_edition_guess_origin(db, frange.file_id); + let file_id = EditionedFileId::current_edition(db, frange.file_id); let file = db.parse(file_id); file.tree().syntax().token_at_offset(frange.range.start()).find_map(ast::Comment::cast) diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index d854c1c45044..33bed9501a39 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -219,7 +219,7 @@ pub(crate) fn resolve_doc_path_for_def( Definition::Crate(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Adt(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), - Definition::Variant(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), + Definition::EnumVariant(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Static(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Trait(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), @@ -678,7 +678,7 @@ fn filename_and_frag_for_def( Definition::Function(f) => { format!("fn.{}.html", f.name(db).as_str()) } - Definition::Variant(ev) => { + Definition::EnumVariant(ev) => { let def = Definition::Adt(ev.parent_enum(db).into()); let (_, file, _) = filename_and_frag_for_def(db, def)?; return Some((def, file, Some(format!("variant.{}", ev.name(db).as_str())))); @@ -703,9 +703,9 @@ fn filename_and_frag_for_def( }, Definition::Field(field) => { let def = match field.parent_def(db) { - hir::VariantDef::Struct(it) => Definition::Adt(it.into()), - hir::VariantDef::Union(it) => Definition::Adt(it.into()), - hir::VariantDef::Variant(it) => Definition::Variant(it), + hir::Variant::Struct(it) => Definition::Adt(it.into()), + hir::Variant::Union(it) => Definition::Adt(it.into()), + hir::Variant::EnumVariant(it) => Definition::EnumVariant(it), }; let (_, file, _) = filename_and_frag_for_def(db, def)?; return Some((def, file, Some(format!("structfield.{}", field.name(db).as_str())))); diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index a61a6c677f65..509c55a31e58 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -113,7 +113,7 @@ fn node_to_def<'db>( ast::Struct(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Struct(def)))), ast::Union(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Union(def)))), ast::Enum(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Enum(def)))), - ast::Variant(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Variant(def))), + ast::Variant(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::EnumVariant(def))), ast::Trait(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Trait(def))), ast::Static(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Static(def))), ast::Const(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Const(def))), diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index cf5f137cdd03..af78e9a40c9f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -5,7 +5,7 @@ use hir::{ Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DisplayTarget, DropGlue, DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError, - MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef, + MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, Variant, db::ExpandDatabase, }; use ide_db::{ @@ -366,14 +366,14 @@ fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) - let parent_name = parent.name(db); let parent_name = parent_name.display(db, edition).to_string(); return match parent { - VariantDef::Variant(variant) => { + Variant::EnumVariant(variant) => { let enum_name = variant.parent_enum(db).name(db); Some(format!("{}::{parent_name}", enum_name.display(db, edition))) } _ => Some(parent_name), }; } - Definition::Variant(e) => Some(e.parent_enum(db).name(db)), + Definition::EnumVariant(e) => Some(e.parent_enum(db).name(db)), Definition::GenericParam(generic_param) => match generic_param.parent() { hir::GenericDef::Adt(it) => Some(it.name(db)), hir::GenericDef::Trait(it) => Some(it.name(db)), @@ -470,7 +470,7 @@ pub(super) fn definition( Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => { adt.display_limited(db, config.max_fields_count, display_target).to_string() } - Definition::Variant(variant) => { + Definition::EnumVariant(variant) => { variant.display_limited(db, config.max_fields_count, display_target).to_string() } Definition::Adt(adt @ Adt::Enum(_)) => { @@ -499,7 +499,7 @@ pub(super) fn definition( }; let docs = def.docs_with_rangemap(db, famous_defs, display_target); let value = || match def { - Definition::Variant(it) => { + Definition::EnumVariant(it) => { if !it.parent_enum(db).is_data_carrying(db) { match it.eval(db) { Ok(it) => { @@ -596,7 +596,7 @@ pub(super) fn definition( |_| { let var_def = it.parent_def(db); match var_def { - hir::VariantDef::Struct(s) => { + hir::Variant::Struct(s) => { Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it)) } _ => None, @@ -627,7 +627,7 @@ pub(super) fn definition( |_| None, |_| None, ), - Definition::Variant(it) => render_memory_layout( + Definition::EnumVariant(it) => render_memory_layout( config.memory_layout, || it.layout(db), |_| None, @@ -710,7 +710,7 @@ pub(super) fn definition( has_dtor: Some(enum_drop_glue > fields_drop_glue), } } - Definition::Variant(variant) => { + Definition::EnumVariant(variant) => { let fields_drop_glue = variant .fields(db) .iter() diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index 5b9267126f8a..e845faec565f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -46,7 +46,7 @@ fn variant_hints( enum_: &ast::Enum, variant: &ast::Variant, ) -> Option<()> { - if variant.expr().is_some() { + if variant.const_arg().is_some() { return None; } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index e5e4c899ec03..3af529e8c56d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -7,7 +7,7 @@ //! ``` use hir::{ DefWithBody, - db::{DefDatabase as _, HirDatabase as _}, + db::HirDatabase as _, mir::{MirSpan, TerminatorKind}, }; use ide_db::{FileRange, famous_defs::FamousDefs}; @@ -35,7 +35,7 @@ pub(super) fn hints( let def: DefWithBody = def.into(); let def = def.try_into().ok()?; - let (hir, source_map) = sema.db.body_with_source_map(def); + let (hir, source_map) = hir::Body::with_source_map(sema.db, def); let mir = sema.db.mir_body(def).ok()?; diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index f1e62a5ab8ac..08588bbed090 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -374,7 +374,7 @@ fn is_adt_constructor_similar_to_param_name( hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => { Some(to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name) } - hir::PathResolution::Def(hir::ModuleDef::Function(_) | hir::ModuleDef::Variant(_)) => { + hir::PathResolution::Def(hir::ModuleDef::Function(_) | hir::ModuleDef::EnumVariant(_)) => { if to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name { return Some(true); } diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 930eaf2262d9..81a771fec89e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -339,8 +339,7 @@ pub fn file_text(&self, file_id: FileId) -> Cancellable> { pub fn parse(&self, file_id: FileId) -> Cancellable { // FIXME edition self.with_db(|db| { - let editioned_file_id_wrapper = - EditionedFileId::current_edition_guess_origin(&self.db, file_id); + let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id); db.parse(editioned_file_id_wrapper).tree() }) @@ -369,7 +368,7 @@ pub fn extend_selection(&self, frange: FileRange) -> Cancellable { /// supported). pub fn matching_brace(&self, position: FilePosition) -> Cancellable> { self.with_db(|db| { - let file_id = EditionedFileId::current_edition_guess_origin(&self.db, position.file_id); + let file_id = EditionedFileId::current_edition(&self.db, position.file_id); let parse = db.parse(file_id); let file = parse.tree(); matching_brace::matching_brace(&file, position.offset) @@ -430,7 +429,7 @@ pub fn expand_macro(&self, position: FilePosition) -> Cancellable Cancellable { self.with_db(|db| { let editioned_file_id_wrapper = - EditionedFileId::current_edition_guess_origin(&self.db, frange.file_id); + EditionedFileId::current_edition(&self.db, frange.file_id); let parse = db.parse(editioned_file_id_wrapper); join_lines::join_lines(config, &parse.tree(), frange.range) }) @@ -471,8 +470,7 @@ pub fn file_structure( ) -> Cancellable> { // FIXME: Edition self.with_db(|db| { - let editioned_file_id_wrapper = - EditionedFileId::current_edition_guess_origin(&self.db, file_id); + let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id); let source_file = db.parse(editioned_file_id_wrapper).tree(); file_structure::file_structure(&source_file, config) }) @@ -503,8 +501,7 @@ pub fn inlay_hints_resolve( /// Returns the set of folding ranges. pub fn folding_ranges(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| { - let editioned_file_id_wrapper = - EditionedFileId::current_edition_guess_origin(&self.db, file_id); + let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id); folding_ranges::folding_ranges(&db.parse(editioned_file_id_wrapper).tree()) }) diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 1c1389ca7a15..335e1b5b13ca 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -205,7 +205,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati Definition::Adt(Adt::Struct(..)) => Struct, Definition::Adt(Adt::Union(..)) => Union, Definition::Adt(Adt::Enum(..)) => Enum, - Definition::Variant(..) => EnumMember, + Definition::EnumVariant(..) => EnumMember, Definition::Const(..) => Constant, Definition::Static(..) => StaticVariable, Definition::Trait(..) => Trait, diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 185df92e2d39..92020321f453 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -276,7 +276,7 @@ fn try_to_nav( Some(it.display(db, display_target).to_string()) } hir::ModuleDef::Adt(it) => Some(it.display(db, display_target).to_string()), - hir::ModuleDef::Variant(it) => { + hir::ModuleDef::EnumVariant(it) => { Some(it.display(db, display_target).to_string()) } hir::ModuleDef::Const(it) => { @@ -319,7 +319,7 @@ fn try_to_nav( Definition::GenericParam(it) => it.try_to_nav(sema), Definition::Function(it) => it.try_to_nav(sema), Definition::Adt(it) => it.try_to_nav(sema), - Definition::Variant(it) => it.try_to_nav(sema), + Definition::EnumVariant(it) => it.try_to_nav(sema), Definition::Const(it) => it.try_to_nav(sema), Definition::Static(it) => it.try_to_nav(sema), Definition::Trait(it) => it.try_to_nav(sema), @@ -347,7 +347,7 @@ fn try_to_nav( hir::ModuleDef::Module(it) => Some(it.to_nav(sema.db)), hir::ModuleDef::Function(it) => it.try_to_nav(sema), hir::ModuleDef::Adt(it) => it.try_to_nav(sema), - hir::ModuleDef::Variant(it) => it.try_to_nav(sema), + hir::ModuleDef::EnumVariant(it) => it.try_to_nav(sema), hir::ModuleDef::Const(it) => it.try_to_nav(sema), hir::ModuleDef::Static(it) => it.try_to_nav(sema), hir::ModuleDef::Trait(it) => it.try_to_nav(sema), @@ -406,7 +406,7 @@ fn container_name(self, db: &RootDatabase) -> Option { container_name(db, self) } } -impl ToNavFromAst for hir::Variant { +impl ToNavFromAst for hir::EnumVariant { const KIND: SymbolKind = SymbolKind::Variant; } impl ToNavFromAst for hir::Union { diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 102eb91b74f7..9392651c1794 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -299,7 +299,7 @@ fn retain_adt_literal_usages( }); usages.references.retain(|_, it| !it.is_empty()); } - Definition::Adt(_) | Definition::Variant(_) => { + Definition::Adt(_) | Definition::EnumVariant(_) => { refs.for_each(|it| { it.retain(|reference| reference.name.as_name_ref().is_some_and(is_lit_name_ref)) }); @@ -377,7 +377,7 @@ fn is_enum_lit_name_ref( let path_is_variant_of_enum = |path: ast::Path| { matches!( sema.resolve_path(&path), - Some(PathResolution::Def(hir::ModuleDef::Variant(variant))) + Some(PathResolution::Def(hir::ModuleDef::EnumVariant(variant))) if variant.parent_enum(sema.db) == enum_ ) }; @@ -1151,10 +1151,7 @@ pub fn quux$0() {} check_with_scope( code, Some(&mut |db| { - SearchScope::single_file(EditionedFileId::current_edition_guess_origin( - db, - FileId::from_raw(2), - )) + SearchScope::single_file(EditionedFileId::current_edition(db, FileId::from_raw(2))) }), expect![[r#" quux Function FileId(0) 19..35 26..30 diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index ae19e7750968..900a885a64de 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -480,7 +480,7 @@ fn rename_to_self( } let fn_def = match local.parent(sema.db) { - hir::DefWithBody::Function(func) => func, + hir::ExpressionStoreOwner::Body(hir::DefWithBody::Function(func)) => func, _ => bail!("Cannot rename local to self outside of function"), }; @@ -743,7 +743,7 @@ fn rename_self_to_param( } let fn_def = match local.parent(sema.db) { - hir::DefWithBody::Function(func) => func, + hir::ExpressionStoreOwner::Body(hir::DefWithBody::Function(func)) => func, _ => bail!("Cannot rename local to self outside of function"), }; diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 42efa7142b50..a0a6a245592c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -494,7 +494,7 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op Definition::Module(it) => it.attrs(db), Definition::Function(it) => it.attrs(db), Definition::Adt(it) => it.attrs(db), - Definition::Variant(it) => it.attrs(db), + Definition::EnumVariant(it) => it.attrs(db), Definition::Const(it) => it.attrs(db), Definition::Static(it) => it.attrs(db), Definition::Trait(it) => it.attrs(db), diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 9ab07565e9ef..9eb01b12f2bd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -497,7 +497,7 @@ fn signature_help_for_tuple_struct_pat( }; let db = sema.db; - let fields: Vec<_> = if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { + let fields: Vec<_> = if let PathResolution::Def(ModuleDef::EnumVariant(variant)) = path_res { let en = variant.parent_enum(db); res.doc = en.docs(db).map(Documentation::into_owned); @@ -623,7 +623,7 @@ fn signature_help_for_record_<'db>( let db = sema.db; let path_res = sema.resolve_path(path)?; - if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { + if let PathResolution::Def(ModuleDef::EnumVariant(variant)) = path_res { fields = variant.fields(db); let en = variant.parent_enum(db); @@ -1975,8 +1975,8 @@ trait Sub: Super + Super { fn f() -> impl Sub<$0 "#, expect![[r#" - trait Sub - ^^^^^^^^^ ----------- + trait Sub + ^^^^^^^^^^^ --------- "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index ce1df6a1e7dc..217b13b4ef95 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -14,7 +14,9 @@ use std::ops::ControlFlow; use either::Either; -use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Semantics}; +use hir::{ + DefWithBody, EditionedFileId, ExpressionStoreOwner, InFile, InRealFile, MacroKind, Semantics, +}; use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind}; use syntax::{ AstNode, AstToken, NodeOrToken, @@ -256,8 +258,8 @@ fn item(&self) -> &ast::Item { let mut inside_attribute = false; // FIXME: accommodate range highlighting - let mut body_stack: Vec> = vec![]; - let mut per_body_cache: FxHashMap> = FxHashMap::default(); + let mut body_stack: Vec> = vec![]; + let mut per_body_cache: FxHashMap> = FxHashMap::default(); // Walk all nodes, keeping track of whether we are inside a macro or not. // If in macro, expand it first and highlight the expanded code. @@ -288,19 +290,18 @@ fn item(&self) -> &ast::Item { inside_attribute = false } Enter(NodeOrToken::Node(node)) => { + // FIXME: ExpressionStore signatures and variant fields + // Maybe we can re-use child container stuff here if let Some(item) = >::cast(node.clone()) { match item { Either::Left(item) => { match &item { - ast::Item::Fn(it) => { - body_stack.push(sema.to_def(it).map(Into::into)) - } - ast::Item::Const(it) => { - body_stack.push(sema.to_def(it).map(Into::into)) - } - ast::Item::Static(it) => { - body_stack.push(sema.to_def(it).map(Into::into)) - } + ast::Item::Fn(it) => body_stack + .push(sema.to_def(it).map(DefWithBody::from).map(Into::into)), + ast::Item::Const(it) => body_stack + .push(sema.to_def(it).map(DefWithBody::from).map(Into::into)), + ast::Item::Static(it) => body_stack + .push(sema.to_def(it).map(DefWithBody::from).map(Into::into)), _ => (), } @@ -329,7 +330,9 @@ fn item(&self) -> &ast::Item { } } } - Either::Right(it) => body_stack.push(sema.to_def(&it).map(Into::into)), + Either::Right(it) => { + body_stack.push(sema.to_def(&it).map(DefWithBody::from).map(Into::into)) + } } } } @@ -392,11 +395,11 @@ fn item(&self) -> &ast::Item { let descended = descend_token(sema, InRealFile::new(file_id, token)); let body = match &descended.value { NodeOrToken::Node(n) => { - sema.body_for(InFile::new(descended.file_id, n.syntax())) - } - NodeOrToken::Token(t) => { - t.parent().and_then(|it| sema.body_for(InFile::new(descended.file_id, &it))) + sema.store_owner_for(InFile::new(descended.file_id, n.syntax())) } + NodeOrToken::Token(t) => t + .parent() + .and_then(|it| sema.store_owner_for(InFile::new(descended.file_id, &it))), }; (descended, body) } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index a94bbc9f041d..0e101ab235f5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -538,7 +538,7 @@ pub(super) fn highlight_def( (Highlight::new(h), Some(adt.attrs(sema.db))) } - Definition::Variant(variant) => { + Definition::EnumVariant(variant) => { (Highlight::new(HlTag::Symbol(SymbolKind::Variant)), Some(variant.attrs(sema.db))) } Definition::Const(konst) => { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index 291333f09cf8..74a8d93dfe82 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -209,7 +209,7 @@ fn module_def_to_hl_tag(db: &dyn HirDatabase, def: Definition) -> HlTag { Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct, Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum, Definition::Adt(hir::Adt::Union(_)) => SymbolKind::Union, - Definition::Variant(_) => SymbolKind::Variant, + Definition::EnumVariant(_) => SymbolKind::Variant, Definition::Const(_) => SymbolKind::Const, Definition::Static(_) => SymbolKind::Static, Definition::Trait(_) => SymbolKind::Trait, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index c6dbc435c0e8..1184739cc258 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -105,7 +105,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd loop {} } -fn const_param<const FOO: usize>() -> usize { +fn const_param<const FOO: usize>() -> usize where [(); FOO]: Sized { const_param::<{ FOO }>(); FOO } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index c6aebd0b0cd1..aecd1d3fdb56 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -210,7 +210,7 @@ fn never() -> ! { loop {} } -fn const_param() -> usize { +fn const_param() -> usize where [(); FOO]: Sized { const_param::<{ FOO }>(); FOO } diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index f8b0dbfe6282..e8b0c92dcb20 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -17,10 +17,7 @@ use either::Either; use hir::EditionedFileId; -use ide_db::{ - FilePosition, RootDatabase, - base_db::{RootQueryDb, SourceDatabase}, -}; +use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb}; use span::Edition; use std::iter; @@ -74,15 +71,11 @@ pub(crate) fn on_char_typed( return None; } let edition = db - .source_root_crates(db.file_source_root(position.file_id).source_root_id(db)) + .relevant_crates(position.file_id) .first() - .map_or(Edition::CURRENT, |crates| crates.data(db).edition); - // FIXME: We are hitting the database here, if we are unlucky this call might block momentarily - // causing the editor to feel sluggish! We need to make this bail if it would block too long? - let editioned_file_id_wrapper = EditionedFileId::from_span_guess_origin( - db, - span::EditionedFileId::new(position.file_id, edition), - ); + .copied() + .map_or(Edition::CURRENT, |krate| krate.data(db).edition); + let editioned_file_id_wrapper = EditionedFileId::new(db, position.file_id, edition); let file = &db.parse(editioned_file_id_wrapper); let char_matches_position = file.tree().syntax().text().char_at(position.offset) == Some(char_typed); diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs index 76a2802d294c..fdc583a15cc7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs @@ -51,7 +51,7 @@ // ![On Enter](https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif) pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option { let editioned_file_id_wrapper = - ide_db::base_db::EditionedFileId::current_edition_guess_origin(db, position.file_id); + ide_db::base_db::EditionedFileId::current_edition(db, position.file_id); let parse = db.parse(editioned_file_id_wrapper); let file = parse.tree(); let token = file.syntax().token_at_offset(position.offset).left_biased()?; diff --git a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs index e1a7e4e6ab23..8d84eba7ab65 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs @@ -10,6 +10,9 @@ // | VS Code | **rust-analyzer: Debug ItemTree** | pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String { let sema = Semantics::new(db); + let Some(krate) = sema.first_crate(file_id) else { + return String::new(); + }; let file_id = sema.attach_first_edition(file_id); - db.file_item_tree(file_id.into()).pretty_print(db, file_id.edition(db)) + db.file_item_tree(file_id.into(), krate.into()).pretty_print(db, file_id.edition(db)) } diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml index ad73c191c047..39320ebd1cfe 100644 --- a/src/tools/rust-analyzer/crates/intern/Cargo.toml +++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml @@ -22,3 +22,6 @@ rayon.workspace = true [lints] workspace = true + +[features] +prevent-gc = [] diff --git a/src/tools/rust-analyzer/crates/intern/src/gc.rs b/src/tools/rust-analyzer/crates/intern/src/gc.rs index 937de26831e2..f4e8f75e7194 100644 --- a/src/tools/rust-analyzer/crates/intern/src/gc.rs +++ b/src/tools/rust-analyzer/crates/intern/src/gc.rs @@ -110,6 +110,10 @@ pub fn add_slice_storage(&mut self) { /// the added storages must form a DAG. /// - [`GcInternedVisit`] and [`GcInternedSliceVisit`] must mark all values reachable from the node. pub unsafe fn collect(mut self) { + if cfg!(feature = "prevent-gc") { + return; + } + let total_nodes = self.storages.iter().map(|storage| storage.len()).sum(); self.alive.clear(); self.alive.reserve(total_nodes); diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index b8ce3a8da4a2..8753eab43a8c 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -42,6 +42,7 @@ pub struct LoadCargoConfig { pub load_out_dirs_from_check: bool, pub with_proc_macro_server: ProcMacroServerChoice, pub prefill_caches: bool, + pub num_worker_threads: usize, pub proc_macro_processes: usize, } @@ -197,7 +198,7 @@ pub fn load_workspace_into_db( ); if load_config.prefill_caches { - prime_caches::parallel_prime_caches(db, 1, &|_| ()); + prime_caches::parallel_prime_caches(db, load_config.num_worker_threads, &|_| ()); } Ok((vfs, proc_macro_server.and_then(Result::ok))) @@ -638,7 +639,7 @@ fn expand( current_span = Span { range: resolved.range, anchor: SpanAnchor { - file_id: resolved.file_id.editioned_file_id(db), + file_id: resolved.file_id.span_file_id(db), ast_id: span::ROOT_ERASED_FILE_AST_ID, }, ctx: current_ctx, @@ -652,7 +653,7 @@ fn expand( let resolved = db.resolve_span(current_span); Ok(SubResponse::SpanSourceResult { - file_id: resolved.file_id.editioned_file_id(db).as_u32(), + file_id: resolved.file_id.span_file_id(db).as_u32(), ast_id: span::ROOT_ERASED_FILE_AST_ID.into_raw(), start: u32::from(resolved.range.start()), end: u32::from(resolved.range.end()), @@ -684,7 +685,7 @@ fn expand( .text_range(); let parent_span = Some(ParentSpan { - file_id: editioned_file_id.editioned_file_id(db).as_u32(), + file_id: editioned_file_id.span_file_id(db).as_u32(), ast_id: span::ROOT_ERASED_FILE_AST_ID.into_raw(), start: u32::from(range.start()), end: u32::from(range.end()), @@ -744,16 +745,26 @@ mod tests { #[test] fn test_loading_rust_analyzer() { - let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); + let cargo_toml_path = Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .parent() + .unwrap() + .join("Cargo.toml"); + let cargo_toml_path = AbsPathBuf::assert_utf8(cargo_toml_path); + let manifest = ProjectManifest::from_manifest_file(cargo_toml_path).unwrap(); + let cargo_config = CargoConfig { set_test: true, ..CargoConfig::default() }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: false, with_proc_macro_server: ProcMacroServerChoice::None, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; + let workspace = ProjectWorkspace::load(manifest, &cargo_config, &|_| {}).unwrap(); let (db, _vfs, _proc_macro) = - load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {}).unwrap(); + load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config).unwrap(); let n_crates = db.all_crates().len(); // RA has quite a few crates, but the exact count doesn't matter diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index b75474ee2b86..3214fd90f29a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -407,8 +407,18 @@ pub(crate) fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option) { // test variant_discriminant // enum E { X(i32) = 10 } if p.eat(T![=]) { + let m = p.start(); expressions::expr(p); + m.complete(p, CONST_ARG); } m.complete(p, VARIANT); } else { @@ -139,7 +141,9 @@ fn record_field(p: &mut Parser<'_>) { // test record_field_default_values // struct S { f: f32 = 0.0 } if p.eat(T![=]) { + let m = p.start(); expressions::expr(p); + m.complete(p, CONST_ARG); } m.complete(p, RECORD_FIELD); } else { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 9f919f6cea42..4c001104fe52 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -25,6 +25,8 @@ fn arb_self_types() { #[test] fn asm_label() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_label.rs"); } #[test] + fn asm_sym_paren() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_sym_paren.rs"); } + #[test] fn assoc_const_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_const_eq.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_sym_paren.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_sym_paren.rast new file mode 100644 index 000000000000..d189f63f2afc --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_sym_paren.rast @@ -0,0 +1,49 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + ASM_EXPR + BUILTIN_KW "builtin" + POUND "#" + ASM_KW "asm" + L_PAREN "(" + LITERAL + STRING "\"\"" + COMMA "," + WHITESPACE " " + ASM_OPERAND_NAMED + NAME + IDENT "f" + WHITESPACE " " + EQ "=" + WHITESPACE " " + ASM_SYM + SYM_KW "sym" + WHITESPACE " " + L_PAREN "(" + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "foo" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "bar" + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_sym_paren.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_sym_paren.rs new file mode 100644 index 000000000000..7b2f80704c85 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_sym_paren.rs @@ -0,0 +1,3 @@ +fn foo() { + builtin#asm("", f = sym (foo::bar)); +} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast index 33088f2cabf3..e53b886bbff8 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast @@ -21,8 +21,9 @@ SOURCE_FILE WHITESPACE " " EQ "=" WHITESPACE " " - LITERAL - FLOAT_NUMBER "0.0" + CONST_ARG + LITERAL + FLOAT_NUMBER "0.0" WHITESPACE " " R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast index 9f0c5a76108d..3494085e88fa 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast @@ -23,8 +23,9 @@ SOURCE_FILE WHITESPACE " " EQ "=" WHITESPACE " " - LITERAL - INT_NUMBER "10" + CONST_ARG + LITERAL + INT_NUMBER "10" WHITESPACE " " R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast index dd47e3aa47ad..51837e5372a7 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast @@ -78,8 +78,9 @@ SOURCE_FILE WHITESPACE " " EQ "=" WHITESPACE " " - LITERAL - INT_NUMBER "92" + CONST_ARG + LITERAL + INT_NUMBER "92" COMMA "," WHITESPACE "\n " VARIANT diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 734cb4ecc169..0bdc379cb626 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -328,7 +328,7 @@ fn apply( let prev_working_dir = std::env::current_dir().ok(); if let Err(err) = std::env::set_current_dir(dir) { eprintln!( - "Failed to set the current working dir to {}. Error: {err:?}", + "Failed to change the current working dir to {}. Error: {err:?}", dir.display() ) } @@ -370,7 +370,7 @@ fn drop(&mut self) { && let Err(err) = std::env::set_current_dir(dir) { eprintln!( - "Failed to set the current working dir to {}. Error: {:?}", + "Failed to change the current working dir back to {}. Error: {:?}", dir.display(), err ) diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs index 9b9111012b54..4ea136afbb45 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs @@ -365,9 +365,27 @@ pub enum RunnableKind { /// May include {test_id} which will get the test clicked on by the user. TestOne, + /// Run tests matching a pattern (in RA, usually a path::to::module::of::tests) + /// May include {label} which will get the label from the `build` section of a crate. + /// May include {test_pattern} which will get the test module clicked on by the user. + TestMod, + + /// Run a single doctest + /// May include {label} which will get the label from the `build` section of a crate. + /// May include {test_id} which will get the doctest clicked on by the user. + DocTestOne, + + /// Run a single benchmark + /// May include {label} which will get the label from the `build` section of a crate. + /// May include {bench_id} which will get the benchmark clicked on by the user. + BenchOne, + /// Template for checking a target, emitting rustc JSON diagnostics. /// May include {label} which will get the label from the `build` section of a crate. Flycheck, + + /// For forwards-compatibility, i.e. old rust-analyzer binary with newer workspace discovery tools + Unknown, } #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] @@ -380,6 +398,8 @@ pub struct ProjectJsonData { crates: Vec, #[serde(default)] runnables: Vec, + // + // New fields should be Option or #[serde(default)]. This applies to most of this datastructure. } #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Default)] @@ -453,32 +473,40 @@ enum EditionData { } #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -pub struct BuildData { +struct BuildData { label: String, build_file: Utf8PathBuf, target_kind: TargetKindData, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct RunnableData { - pub program: String, - pub args: Vec, - pub cwd: Utf8PathBuf, - pub kind: RunnableKindData, +struct RunnableData { + program: String, + args: Vec, + cwd: Utf8PathBuf, + kind: RunnableKindData, } #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub enum RunnableKindData { +enum RunnableKindData { Flycheck, Check, Run, TestOne, + TestMod, + DocTestOne, + BenchOne, + + /// For forwards-compatibility, i.e. old rust-analyzer binary with newer workspace discovery tools + #[allow(unused)] + #[serde(other)] + Unknown, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub enum TargetKindData { +enum TargetKindData { Bin, /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...). Lib, @@ -541,7 +569,11 @@ fn from(data: RunnableKindData) -> Self { RunnableKindData::Check => RunnableKind::Check, RunnableKindData::Run => RunnableKind::Run, RunnableKindData::TestOne => RunnableKind::TestOne, + RunnableKindData::TestMod => RunnableKind::TestMod, + RunnableKindData::DocTestOne => RunnableKind::DocTestOne, + RunnableKindData::BenchOne => RunnableKind::BenchOne, RunnableKindData::Flycheck => RunnableKind::Flycheck, + RunnableKindData::Unknown => RunnableKind::Unknown, } } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index a03ed562e1be..395cea6f76e6 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -192,6 +192,12 @@ fn rust_project_hello_world_project_model() { ); } +#[test] +fn rust_project_labeled_project_model() { + // This just needs to parse. + _ = load_rust_project("labeled-project.json"); +} + #[test] fn rust_project_cfg_groups() { let (crate_graph, _proc_macros) = load_rust_project("cfg-groups.json"); diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/labeled-project.json b/src/tools/rust-analyzer/crates/project-model/test_data/labeled-project.json new file mode 100644 index 000000000000..5c0e1f33979e --- /dev/null +++ b/src/tools/rust-analyzer/crates/project-model/test_data/labeled-project.json @@ -0,0 +1,37 @@ +{ + "sysroot_src": null, + "crates": [ + { + "display_name": "hello_world", + "root_module": "$ROOT$src/lib.rs", + "edition": "2018", + "deps": [], + "is_workspace_member": true, + "build": { + "label": "//:hello_world", + "build_file": "$ROOT$BUILD", + "target_kind": "bin" + } + } + ], + "runnables": [ + { + "kind": "run", + "program": "bazel", + "args": ["run", "{label}"], + "cwd": "$ROOT$" + }, + { + "kind": "flycheck", + "program": "$ROOT$custom-flychecker.sh", + "args": ["{label}"], + "cwd": "$ROOT$" + }, + { + "kind": "we-ignore-unknown-runnable-kinds-for-forwards-compatibility", + "program": "abc", + "args": ["{label}"], + "cwd": "$ROOT$" + } + ] +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index d1283ca59e8c..beb83a8173a0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -94,6 +94,8 @@ test-utils.workspace = true test-fixture.workspace = true syntax-bridge.workspace = true +intern = { path = "../intern", features = ["prevent-gc"] } + [features] jemalloc = ["jemallocator", "profile/jemalloc"] force-always-assert = ["stdx/force-always-assert"] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 1995d3889891..74828cba02ed 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -10,15 +10,15 @@ use cfg::{CfgAtom, CfgDiff}; use hir::{ - Adt, AssocItem, Crate, DefWithBody, FindPathConfig, HasCrate, HasSource, HirDisplay, ModuleDef, - Name, crate_lang_items, + Adt, AssocItem, Crate, DefWithBody, FindPathConfig, GenericDef, HasCrate, HasSource, + HirDisplay, ModuleDef, Name, Variant, VariantId, crate_lang_items, db::{DefDatabase, ExpandDatabase, HirDatabase}, next_solver::{DbInterner, GenericArgs}, }; use hir_def::{ - SyntheticSyntax, - expr_store::BodySourceMap, - hir::{ExprId, PatId}, + DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, + expr_store::{Body, BodySourceMap, ExpressionStore}, + hir::{ExprId, PatId, generics::GenericParams}, }; use hir_ty::InferenceResult; use ide::{ @@ -91,6 +91,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { } }, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; @@ -126,8 +127,8 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { let source_roots = krates .iter() .cloned() - .map(|krate| db.file_source_root(krate.root_file(db)).source_root_id(db)) - .unique(); + .map(|krate| (db.file_source_root(krate.root_file(db)).source_root_id(db), krate)) + .unique_by(|(source_root_id, _)| *source_root_id); let mut dep_loc = 0; let mut workspace_loc = 0; @@ -137,7 +138,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { let mut workspace_item_stats = PrettyItemStats::default(); let mut dep_item_stats = PrettyItemStats::default(); - for source_root_id in source_roots { + for (source_root_id, krate) in source_roots { let source_root = db.source_root(source_root_id).source_root(db); for file_id in source_root.iter() { if let Some(p) = source_root.path_for_file(&file_id) @@ -148,7 +149,8 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { let length = db.file_text(file_id).text(db).lines().count(); let item_stats = db .file_item_tree( - EditionedFileId::current_edition_guess_origin(db, file_id).into(), + EditionedFileId::current_edition(db, file_id).into(), + krate.into(), ) .item_tree_stats() .into(); @@ -160,7 +162,8 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { let length = db.file_text(file_id).text(db).lines().count(); let item_stats = db .file_item_tree( - EditionedFileId::current_edition_guess_origin(db, file_id).into(), + EditionedFileId::current_edition(db, file_id).into(), + krate.into(), ) .item_tree_stats() .into(); @@ -226,6 +229,8 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { eprint!(" crates: {num_crates}"); let mut num_decls = 0; let mut bodies = Vec::new(); + let mut signatures = Vec::new(); + let mut variants = Vec::new(); let mut adts = Vec::new(); let mut file_ids = Vec::new(); @@ -243,10 +248,15 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { match decl { ModuleDef::Function(f) => bodies.push(DefWithBody::from(f)), ModuleDef::Adt(a) => { - if let Adt::Enum(e) = a { - for v in e.variants(db) { - bodies.push(DefWithBody::from(v)); + match a { + Adt::Enum(e) => { + for v in e.variants(db) { + bodies.push(DefWithBody::from(v)); + variants.push(Variant::EnumVariant(v)); + } } + Adt::Struct(it) => variants.push(Variant::Struct(it)), + Adt::Union(it) => variants.push(Variant::Union(it)), } adts.push(a) } @@ -264,24 +274,32 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { }, _ => (), }; + if let Some(g) = decl.as_generic_def() { + signatures.push(g); + } } for impl_def in module.impl_defs(db) { + signatures.push(impl_def.into()); for item in impl_def.items(db) { num_decls += 1; match item { - AssocItem::Function(f) => bodies.push(DefWithBody::from(f)), + AssocItem::Function(f) => { + bodies.push(DefWithBody::from(f)); + signatures.push(f.into()) + } AssocItem::Const(c) => { bodies.push(DefWithBody::from(c)); + signatures.push(c.into()); } - _ => (), + AssocItem::TypeAlias(t) => signatures.push(t.into()), } } } } } eprintln!( - ", mods: {}, decls: {num_decls}, bodies: {}, adts: {}, consts: {}", + ", mods: {}, decls: {num_decls}, bodies: {}, adts: {}, consts: {}, signatures: {}, variants: {}", visited_modules.len(), bodies.len(), adts.len(), @@ -289,6 +307,8 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { .iter() .filter(|it| matches!(it, DefWithBody::Const(_) | DefWithBody::Static(_))) .count(), + signatures.len(), + variants.len() ); eprintln!(" Workspace:"); @@ -324,15 +344,15 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { } if !self.skip_lowering { - self.run_body_lowering(db, &vfs, &bodies, verbosity); + self.run_body_lowering(db, &vfs, &bodies, &signatures, &variants, verbosity); } if !self.skip_inference { - self.run_inference(db, &vfs, &bodies, verbosity); + self.run_inference(db, &vfs, &bodies, &signatures, &variants, verbosity); } if !self.skip_mir_stats { - self.run_mir_lowering(db, &bodies, verbosity); + self.run_mir_lowering(db, &bodies, &signatures, &variants, verbosity); } if !self.skip_data_layout { @@ -340,7 +360,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { } if !self.skip_const_eval { - self.run_const_eval(db, &bodies, verbosity); + self.run_const_eval(db, &bodies, &signatures, &variants, verbosity); } }); @@ -381,7 +401,7 @@ fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbo let mut fail = 0; for &a in adts { let interner = DbInterner::new_no_crate(db); - let generic_params = db.generic_params(a.into()); + let generic_params = GenericParams::of(db, a.into()); if generic_params.iter_type_or_consts().next().is_some() || generic_params.iter_lt().next().is_some() { @@ -393,7 +413,7 @@ fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbo hir_def::AdtId::from(a), GenericArgs::empty(interner).store(), hir_ty::ParamEnvAndCrate { - param_env: db.trait_environment(a.into()), + param_env: db.trait_environment(GenericDefId::from(a).into()), krate: a.krate(db).into(), } .store(), @@ -413,7 +433,14 @@ fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbo report_metric("data layout time", data_layout_time.time.as_millis() as u64, "ms"); } - fn run_const_eval(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { + fn run_const_eval( + &self, + db: &RootDatabase, + bodies: &[DefWithBody], + _signatures: &[GenericDef], + _variants: &[Variant], + verbosity: Verbosity, + ) { let len = bodies .iter() .filter(|body| matches!(body, DefWithBody::Const(_) | DefWithBody::Static(_))) @@ -428,7 +455,9 @@ fn run_const_eval(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: V let mut all = 0; let mut fail = 0; for &b in bodies { - bar.set_message(move || format!("const eval: {}", full_name(db, b, b.module(db)))); + bar.set_message(move || { + format!("const eval: {}", full_name(db, || b.name(db), b.module(db))) + }); let res = match b { DefWithBody::Const(c) => c.eval(db), DefWithBody::Static(s) => s.eval(db), @@ -492,7 +521,7 @@ struct Acc { let mut sw = self.stop_watch(); for &file_id in file_ids { - let file_id = file_id.editioned_file_id(db); + let file_id = file_id.span_file_id(db); let sema = hir::Semantics::new(db); let display_target = match sema.first_crate(file_id.file_id()) { Some(krate) => krate.to_display_target(sema.db), @@ -684,7 +713,14 @@ fn trim(s: &str) -> String { bar.finish_and_clear(); } - fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { + fn run_mir_lowering( + &self, + db: &RootDatabase, + bodies: &[DefWithBody], + _signatures: &[GenericDef], + _variants: &[Variant], + verbosity: Verbosity, + ) { let mut bar = match verbosity { Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), @@ -695,14 +731,14 @@ fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: let mut fail = 0; for &body in bodies { bar.set_message(move || { - format!("mir lowering: {}", full_name(db, body, body.module(db))) + format!("mir lowering: {}", full_name(db, || body.name(db), body.module(db))) }); bar.inc(1); - if matches!(body, DefWithBody::Variant(_)) { + if matches!(body, DefWithBody::EnumVariant(_)) { continue; } let module = body.module(db); - if !self.should_process(db, body, module) { + if !self.should_process(db, || body.name(db), module) { continue; } @@ -740,6 +776,8 @@ fn run_inference( db: &RootDatabase, vfs: &Vfs, bodies: &[DefWithBody], + signatures: &[GenericDef], + variants: &[Variant], verbosity: Verbosity, ) { let mut bar = match verbosity { @@ -750,12 +788,31 @@ fn run_inference( if self.parallel { let mut inference_sw = self.stop_watch(); - let bodies = bodies.iter().filter_map(|&body| body.try_into().ok()).collect::>(); + let bodies = bodies + .iter() + .filter_map(|&body| body.try_into().ok()) + .collect::>(); bodies .par_iter() .map_with(db.clone(), |snap, &body| { - snap.body(body); - InferenceResult::for_body(snap, body); + InferenceResult::of(snap, body); + }) + .count(); + let signatures = signatures + .iter() + .filter_map(|&signatures| signatures.try_into().ok()) + .collect::>(); + signatures + .par_iter() + .map_with(db.clone(), |snap, &signatures| { + InferenceResult::of(snap, signatures); + }) + .count(); + let variants = variants.iter().copied().map(Into::into).collect::>(); + variants + .par_iter() + .map_with(db.clone(), |snap, &variants| { + InferenceResult::of(snap, variants); }) .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); @@ -779,7 +836,7 @@ fn run_inference( let display_target = module.krate(db).to_display_target(db); if let Some(only_name) = self.only.as_deref() && name.display(db, Edition::LATEST).to_string() != only_name - && full_name(db, body_id, module) != only_name + && full_name(db, || body_id.name(db), module) != only_name { continue; } @@ -789,7 +846,9 @@ fn run_inference( DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::EnumVariant(it) => { + it.source(db).map(|it| it.syntax().cloned()) + } }; if let Some(src) = source { let original_file = src.file_id.original_file(db); @@ -797,33 +856,44 @@ fn run_inference( let syntax_range = src.text_range(); format!( "processing: {} ({} {:?})", - full_name(db, body_id, module), + full_name(db, || body_id.name(db), module), path, syntax_range ) } else { - format!("processing: {}", full_name(db, body_id, module)) + format!("processing: {}", full_name(db, || body_id.name(db), module)) } } else { - format!("processing: {}", full_name(db, body_id, module)) + format!("processing: {}", full_name(db, || body_id.name(db), module)) } }; if verbosity.is_spammy() { bar.println(msg()); } bar.set_message(msg); - let body = db.body(body_def_id); + let body = Body::of(db, body_def_id); let inference_result = - catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_def_id))); + catch_unwind(AssertUnwindSafe(|| InferenceResult::of(db, body_def_id))); let inference_result = match inference_result { Ok(inference_result) => inference_result, Err(p) => { if let Some(s) = p.downcast_ref::<&str>() { - eprintln!("infer panicked for {}: {}", full_name(db, body_id, module), s); + eprintln!( + "infer panicked for {}: {}", + full_name(db, || body_id.name(db), module), + s + ); } else if let Some(s) = p.downcast_ref::() { - eprintln!("infer panicked for {}: {}", full_name(db, body_id, module), s); + eprintln!( + "infer panicked for {}: {}", + full_name(db, || body_id.name(db), module), + s + ); } else { - eprintln!("infer panicked for {}", full_name(db, body_id, module)); + eprintln!( + "infer panicked for {}", + full_name(db, || body_id.name(db), module) + ); } panics += 1; bar.inc(1); @@ -831,7 +901,7 @@ fn run_inference( } }; // This query is LRU'd, so actually calling it will skew the timing results. - let sm = || db.body_with_source_map(body_def_id).1; + let sm = || &Body::with_source_map(db, body_def_id).1; // region:expressions let (previous_exprs, previous_unknown, previous_partially_unknown) = @@ -842,7 +912,7 @@ fn run_inference( let unknown_or_partial = if ty.is_ty_error() { num_exprs_unknown += 1; if verbosity.is_spammy() { - if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm(), expr_id) + if let Some((path, start, end)) = expr_syntax_range(db, vfs, sm(), expr_id) { bar.println(format!( "{} {}:{}-{}:{}: Unknown type", @@ -869,7 +939,7 @@ fn run_inference( }; if self.only.is_some() && verbosity.is_spammy() { // in super-verbose mode for just one function, we print every single expression - if let Some((_, start, end)) = expr_syntax_range(db, vfs, &sm(), expr_id) { + if let Some((_, start, end)) = expr_syntax_range(db, vfs, sm(), expr_id) { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, @@ -888,14 +958,14 @@ fn run_inference( if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, - location_csv_expr(db, vfs, &sm(), expr_id), + location_csv_expr(db, vfs, sm(), expr_id), ty.display(db, display_target) ); } if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { num_expr_type_mismatches += 1; if verbosity.is_verbose() { - if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm(), expr_id) + if let Some((path, start, end)) = expr_syntax_range(db, vfs, sm(), expr_id) { bar.println(format!( "{} {}:{}-{}:{}: Expected {}, got {}", @@ -919,7 +989,7 @@ fn run_inference( if self.output == Some(OutputFormat::Csv) { println!( r#"{},mismatch,"{}","{}""#, - location_csv_expr(db, vfs, &sm(), expr_id), + location_csv_expr(db, vfs, sm(), expr_id), mismatch.expected.as_ref().display(db, display_target), mismatch.actual.as_ref().display(db, display_target) ); @@ -929,7 +999,7 @@ fn run_inference( if verbosity.is_spammy() { bar.println(format!( "In {}: {} exprs, {} unknown, {} partial", - full_name(db, body_id, module), + full_name(db, || body_id.name(db), module), num_exprs - previous_exprs, num_exprs_unknown - previous_unknown, num_exprs_partially_unknown - previous_partially_unknown @@ -946,7 +1016,7 @@ fn run_inference( let unknown_or_partial = if ty.is_ty_error() { num_pats_unknown += 1; if verbosity.is_spammy() { - if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm(), pat_id) { + if let Some((path, start, end)) = pat_syntax_range(db, vfs, sm(), pat_id) { bar.println(format!( "{} {}:{}-{}:{}: Unknown type", path, @@ -972,7 +1042,7 @@ fn run_inference( }; if self.only.is_some() && verbosity.is_spammy() { // in super-verbose mode for just one function, we print every single pattern - if let Some((_, start, end)) = pat_syntax_range(db, vfs, &sm(), pat_id) { + if let Some((_, start, end)) = pat_syntax_range(db, vfs, sm(), pat_id) { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, @@ -991,14 +1061,14 @@ fn run_inference( if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, - location_csv_pat(db, vfs, &sm(), pat_id), + location_csv_pat(db, vfs, sm(), pat_id), ty.display(db, display_target) ); } if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat_id) { num_pat_type_mismatches += 1; if verbosity.is_verbose() { - if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm(), pat_id) { + if let Some((path, start, end)) = pat_syntax_range(db, vfs, sm(), pat_id) { bar.println(format!( "{} {}:{}-{}:{}: Expected {}, got {}", path, @@ -1021,7 +1091,7 @@ fn run_inference( if self.output == Some(OutputFormat::Csv) { println!( r#"{},mismatch,"{}","{}""#, - location_csv_pat(db, vfs, &sm(), pat_id), + location_csv_pat(db, vfs, sm(), pat_id), mismatch.expected.as_ref().display(db, display_target), mismatch.actual.as_ref().display(db, display_target) ); @@ -1031,7 +1101,7 @@ fn run_inference( if verbosity.is_spammy() { bar.println(format!( "In {}: {} pats, {} unknown, {} partial", - full_name(db, body_id, module), + full_name(db, || body_id.name(db), module), num_pats - previous_pats, num_pats_unknown - previous_unknown, num_pats_partially_unknown - previous_partially_unknown @@ -1075,20 +1145,104 @@ fn run_body_lowering( db: &RootDatabase, vfs: &Vfs, bodies: &[DefWithBody], + signatures: &[GenericDef], + variants: &[Variant], verbosity: Verbosity, ) { let mut bar = match verbosity { Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), _ if self.output.is_some() => ProgressReport::hidden(), - _ => ProgressReport::new(bodies.len()), + _ => ProgressReport::new(bodies.len() + signatures.len() + variants.len()), }; let mut sw = self.stop_watch(); bar.tick(); + for &signature in signatures { + let Ok(signature_id) = signature.try_into() else { continue }; + let module = signature.module(db); + if !self.should_process(db, || signature.name(db), module) { + continue; + } + let msg = move || { + if verbosity.is_verbose() { + let source = match signature { + GenericDef::Function(it) => it.source(db).map(|it| it.syntax().cloned()), + GenericDef::Static(it) => it.source(db).map(|it| it.syntax().cloned()), + GenericDef::Const(it) => it.source(db).map(|it| it.syntax().cloned()), + GenericDef::Adt(adt) => adt.source(db).map(|it| it.syntax().cloned()), + GenericDef::Trait(it) => it.source(db).map(|it| it.syntax().cloned()), + GenericDef::TypeAlias(type_alias) => { + type_alias.source(db).map(|it| it.syntax().cloned()) + } + GenericDef::Impl(it) => it.source(db).map(|it| it.syntax().cloned()), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file.file_id(db)); + let syntax_range = src.text_range(); + format!( + "processing: {} ({} {:?})", + full_name(db, || signature.name(db), module), + path, + syntax_range + ) + } else { + format!("processing: {}", full_name(db, || signature.name(db), module)) + } + } else { + format!("processing: {}", full_name(db, || signature.name(db), module)) + } + }; + if verbosity.is_spammy() { + bar.println(msg()); + } + bar.set_message(msg); + ExpressionStore::of(db, ExpressionStoreOwnerId::Signature(signature_id)); + bar.inc(1); + } + + for &variant in variants { + let variant_id = variant.into(); + let module = variant.module(db); + if !self.should_process(db, || Some(variant.name(db)), module) { + continue; + } + let msg = move || { + if verbosity.is_verbose() { + let source = match variant { + Variant::EnumVariant(it) => it.source(db).map(|it| it.syntax().cloned()), + Variant::Struct(it) => it.source(db).map(|it| it.syntax().cloned()), + Variant::Union(it) => it.source(db).map(|it| it.syntax().cloned()), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file.file_id(db)); + let syntax_range = src.text_range(); + format!( + "processing: {} ({} {:?})", + full_name(db, || Some(variant.name(db)), module), + path, + syntax_range + ) + } else { + format!("processing: {}", full_name(db, || Some(variant.name(db)), module)) + } + } else { + format!("processing: {}", full_name(db, || Some(variant.name(db)), module)) + } + }; + if verbosity.is_spammy() { + bar.println(msg()); + } + bar.set_message(msg); + ExpressionStore::of(db, ExpressionStoreOwnerId::VariantFields(variant_id)); + bar.inc(1); + } + for &body_id in bodies { let Ok(body_def_id) = body_id.try_into() else { continue }; let module = body_id.module(db); - if !self.should_process(db, body_id, module) { + if !self.should_process(db, || body_id.name(db), module) { continue; } let msg = move || { @@ -1097,7 +1251,9 @@ fn run_body_lowering( DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::EnumVariant(it) => { + it.source(db).map(|it| it.syntax().cloned()) + } }; if let Some(src) = source { let original_file = src.file_id.original_file(db); @@ -1105,28 +1261,28 @@ fn run_body_lowering( let syntax_range = src.text_range(); format!( "processing: {} ({} {:?})", - full_name(db, body_id, module), + full_name(db, || body_id.name(db), module), path, syntax_range ) } else { - format!("processing: {}", full_name(db, body_id, module)) + format!("processing: {}", full_name(db, || body_id.name(db), module)) } } else { - format!("processing: {}", full_name(db, body_id, module)) + format!("processing: {}", full_name(db, || body_id.name(db), module)) } }; if verbosity.is_spammy() { bar.println(msg()); } bar.set_message(msg); - db.body(body_def_id); + Body::of(db, body_def_id); bar.inc(1); } bar.finish_and_clear(); let body_lowering_time = sw.elapsed(); - eprintln!("{:<20} {}", "Body lowering:", body_lowering_time); + eprintln!("{:<20} {}", "Expression Store Lowering:", body_lowering_time); report_metric("body lowering time", body_lowering_time.time.as_millis() as u64, "ms"); } @@ -1280,12 +1436,17 @@ fn run_ide_things( eprintln!("{:<20} {} ({} files)", "IDE:", ide_time, file_ids.len()); } - fn should_process(&self, db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> bool { + fn should_process( + &self, + db: &RootDatabase, + name_fn: impl Fn() -> Option, + module: hir::Module, + ) -> bool { if let Some(only_name) = self.only.as_deref() { - let name = body_id.name(db).unwrap_or_else(Name::missing); + let name = name_fn().unwrap_or_else(Name::missing); if name.display(db, Edition::LATEST).to_string() != only_name - && full_name(db, body_id, module) != only_name + && full_name(db, name_fn, module) != only_name { return false; } @@ -1298,7 +1459,7 @@ fn stop_watch(&self) -> StopWatch { } } -fn full_name(db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> String { +fn full_name(db: &RootDatabase, name: impl Fn() -> Option, module: hir::Module) -> String { module .krate(db) .display_name(db) @@ -1310,7 +1471,7 @@ fn full_name(db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> St .into_iter() .filter_map(|it| it.name(db)) .rev() - .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) + .chain(Some(name().unwrap_or_else(Name::missing))) .map(|it| it.display(db, Edition::LATEST).to_string()), ) .join("::") diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index 575c77f8428c..efbaad3c4936 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -41,6 +41,7 @@ fn run_(self) -> anyhow::Result<()> { load_out_dirs_from_check: !self.disable_build_scripts, with_proc_macro_server, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; let (db, _vfs, _proc_macro) = diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index c52206018138..03849938f598 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -40,6 +40,8 @@ cmd parse { /// Suppress printing. optional --no-dump + /// Output as JSON. + optional --json } /// Parse stdin and print the list of symbols. @@ -189,6 +191,9 @@ /// Exclude code from vendored libraries from the resulting index. optional --exclude-vendored-libraries + + /// The number of worker threads for cache priming. Defaults to the number of physical cores. + optional --num-threads num_threads: usize } } } @@ -233,6 +238,7 @@ pub struct LspServer { #[derive(Debug)] pub struct Parse { pub no_dump: bool, + pub json: bool, } #[derive(Debug)] @@ -257,8 +263,8 @@ pub struct AnalysisStats { pub disable_build_scripts: bool, pub disable_proc_macros: bool, pub proc_macro_srv: Option, - pub skip_lowering: bool, pub skip_lang_items: bool, + pub skip_lowering: bool, pub skip_inference: bool, pub skip_mir_stats: bool, pub skip_data_layout: bool, @@ -335,6 +341,7 @@ pub struct Scip { pub output: Option, pub config_path: Option, pub exclude_vendored_libraries: bool, + pub num_threads: Option, } impl RustAnalyzer { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs index e5e238db6361..3950a581fd77 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs @@ -293,6 +293,7 @@ pub fn run( load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; let path = AbsPathBuf::assert_utf8(env::current_dir()?.join(self.path)); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs index 85ec95409ae7..aa1b659d8bcd 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs @@ -1,18 +1,101 @@ //! Read Rust code on stdin, print syntax tree on stdout. use ide::Edition; -use syntax::{AstNode, SourceFile}; +use ide_db::line_index::LineIndex; +use serde::Serialize; +use syntax::{AstNode, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken}; use crate::cli::{flags, read_stdin}; +#[derive(Serialize)] +struct JsonNode { + kind: String, + #[serde(rename = "type")] + node_type: &'static str, + start: [u32; 3], + end: [u32; 3], + #[serde(skip_serializing_if = "Option::is_none")] + text: Option, + #[serde(skip_serializing_if = "Option::is_none")] + children: Option>, +} + +fn pos(line_index: &LineIndex, offset: syntax::TextSize) -> [u32; 3] { + let offset_u32 = u32::from(offset); + let line_col = line_index.line_col(offset); + [offset_u32, line_col.line, line_col.col] +} + impl flags::Parse { pub fn run(self) -> anyhow::Result<()> { let _p = tracing::info_span!("flags::Parse::run").entered(); let text = read_stdin()?; + let line_index = LineIndex::new(&text); let file = SourceFile::parse(&text, Edition::CURRENT).tree(); + if !self.no_dump { - println!("{:#?}", file.syntax()); + if self.json { + let json_tree = node_to_json(NodeOrToken::Node(file.syntax().clone()), &line_index); + println!("{}", serde_json::to_string(&json_tree)?); + } else { + println!("{:#?}", file.syntax()); + } } + std::mem::forget(file); Ok(()) } } + +fn node_to_json(node: NodeOrToken, line_index: &LineIndex) -> JsonNode { + let range = node.text_range(); + let kind = format!("{:?}", node.kind()); + + match node { + NodeOrToken::Node(n) => { + let children: Vec<_> = + n.children_with_tokens().map(|it| node_to_json(it, line_index)).collect(); + JsonNode { + kind, + node_type: "Node", + start: pos(line_index, range.start()), + end: pos(line_index, range.end()), + text: None, + children: Some(children), + } + } + NodeOrToken::Token(t) => JsonNode { + kind, + node_type: "Token", + start: pos(line_index, range.start()), + end: pos(line_index, range.end()), + text: Some(t.text().to_owned()), + children: None, + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cli::flags; + + #[test] + fn test_parse_json_output() { + let text = "fn main() {}".to_owned(); + let flags = flags::Parse { json: true, no_dump: false }; + let line_index = LineIndex::new(&text); + + let file = SourceFile::parse(&text, Edition::CURRENT).tree(); + + let output = if flags.json { + let json_tree = node_to_json(NodeOrToken::Node(file.syntax().clone()), &line_index); + serde_json::to_string(&json_tree).unwrap() + } else { + format!("{:#?}", file.syntax()) + }; + + assert!(output.contains(r#""kind":"SOURCE_FILE""#)); + assert!(output.contains(r#""text":"main""#)); + assert!(output.contains(r#""start":[0,0,0]"#)); + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs index d5da6791797b..beedcfae4ed8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs @@ -38,6 +38,7 @@ pub fn run(self) -> anyhow::Result<()> { // we want to ensure that this command, not `load_workspace_at`, // is responsible for that work. prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: config.proc_macro_num_processes(), }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs index d4a56d773e7d..e8c88cadf6f0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs @@ -23,6 +23,7 @@ pub fn run(self) -> Result<()> { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; let (ref db, _vfs, _proc_macro) = diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index e8c6c5f4d4f7..49f28352b6cf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -103,6 +103,7 @@ fn new() -> Result { load_out_dirs_from_check: false, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; let (db, _vfs, _proc_macro) = diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index ed0476697c9c..ef6d4399e663 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -52,6 +52,7 @@ pub fn run(self) -> anyhow::Result<()> { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: true, + num_worker_threads: self.num_threads.unwrap_or_else(num_cpus::get_physical), proc_macro_processes: config.proc_macro_num_processes(), }; let cargo_config = config.cargo(None); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs index 5c69bda723fb..7b00aebbfc4a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs @@ -20,6 +20,7 @@ pub fn run(self) -> anyhow::Result<()> { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; let (ref db, vfs, _proc_macro) = load_workspace_at( @@ -57,6 +58,7 @@ pub fn run(self) -> anyhow::Result<()> { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; let (ref db, _vfs, _proc_macro) = load_workspace_at( @@ -74,7 +76,7 @@ pub fn run(self) -> anyhow::Result<()> { let sr = db.source_root(root).source_root(db); for file_id in sr.iter() { for debug_info in match_finder.debug_where_text_equal( - EditionedFileId::current_edition_guess_origin(db, file_id), + EditionedFileId::current_edition(db, file_id), debug_snippet, ) { println!("{debug_info:#?}"); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs index 49c6fcb91ebf..2d9b870f4de8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs @@ -44,6 +44,7 @@ fn run_(self) -> anyhow::Result<()> { load_out_dirs_from_check: !self.disable_build_scripts, with_proc_macro_server, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: config.proc_macro_num_processes(), }; let (db, vfs, _proc_macro) = diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 0dda7f3cc276..2ccd85f0e34e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -948,18 +948,18 @@ pub enum MaxSubstitutionLength { /// Override the command used for bench runnables. /// The first element of the array should be the program to execute (for example, `cargo`). /// - /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically + /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically /// replace the package name, target option (such as `--bin` or `--example`), the target name and - /// the test name (name of test function or test mod path). + /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`). runnables_bench_overrideCommand: Option> = None, /// Command to be executed instead of 'cargo' for runnables. runnables_command: Option = None, /// Override the command used for bench runnables. /// The first element of the array should be the program to execute (for example, `cargo`). /// - /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically + /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically /// replace the package name, target option (such as `--bin` or `--example`), the target name and - /// the test name (name of test function or test mod path). + /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`). runnables_doctest_overrideCommand: Option> = None, /// Additional arguments to be passed to cargo for runnables such as /// tests or binaries. For example, it may be `--release`. @@ -977,9 +977,9 @@ pub enum MaxSubstitutionLength { /// Override the command used for test runnables. /// The first element of the array should be the program to execute (for example, `cargo`). /// - /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically + /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically /// replace the package name, target option (such as `--bin` or `--example`), the target name and - /// the test name (name of test function or test mod path). + /// the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`). runnables_test_overrideCommand: Option> = None, /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index cdaf944bbad4..c41696bf3f6a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -1021,7 +1021,7 @@ fn from_eof(&self) -> Option { } } -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] #[serde(untagged)] enum JsonMessage { Cargo(cargo_metadata::Message), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index 138310b78f62..09b6794e4f43 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -295,8 +295,9 @@ pub(crate) fn handle_did_change_watched_files( for change in params.changes.iter().unique_by(|&it| &it.uri) { if let Ok(path) = from_proto::abs_path(&change.uri) { if !trigger_flycheck { + // Trigger if no workspaces contain this file. trigger_flycheck = - state.config.workspace_roots().iter().any(|root| !path.starts_with(root)); + state.config.workspace_roots().iter().all(|root| !path.starts_with(root)); } state.loader.handle.invalidate(path); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index d16ca2fb48ac..6a74b8a54deb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -53,6 +53,7 @@ fn integrated_highlighting_benchmark() { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: false, + num_worker_threads: 1, proc_macro_processes: 1, }; @@ -122,6 +123,7 @@ fn integrated_completion_benchmark() { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: true, + num_worker_threads: 1, proc_macro_processes: 1, }; @@ -324,6 +326,7 @@ fn integrated_diagnostics_benchmark() { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, prefill_caches: true, + num_worker_threads: 1, proc_macro_processes: 1, }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 64decc9e0db6..7c494de6f73d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -92,7 +92,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Event::DeferredTask(_) => write!(f, "Event::DeferredTask"), Event::TestResult(_) => write!(f, "Event::TestResult"), Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"), - Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"), + Event::FetchWorkspaces(_) => write!(f, "Event::FetchWorkspaces"), } } } @@ -1178,6 +1178,8 @@ fn handle_flycheck_msg(&mut self, message: FlycheckMessage, cargo_finished: &mut } => self.diagnostics.clear_check_older_than_for_package(id, package_id, generation), FlycheckMessage::Progress { id, progress } => { let format_with_id = |user_facing_command: String| { + // When we're running multiple flychecks, we have to include a disambiguator in + // the title, or the editor complains. Note that this is a user-facing string. if self.flycheck.len() == 1 { user_facing_command } else { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs index b8d9acc02a32..8be061cacfa8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs @@ -6,7 +6,7 @@ use cfg::{CfgAtom, CfgExpr}; use hir::sym; use ide::{Cancellable, Crate, FileId, RunnableKind, TestId}; -use project_model::project_json::Runnable; +use project_model::project_json::{self, Runnable}; use project_model::{CargoFeatures, ManifestPath, TargetKind}; use rustc_hash::FxHashSet; use triomphe::Arc; @@ -72,48 +72,51 @@ pub(crate) struct ProjectJsonTargetSpec { } impl ProjectJsonTargetSpec { + fn find_replace_runnable( + &self, + kind: project_json::RunnableKind, + replacer: &dyn Fn(&Self, &str) -> String, + ) -> Option { + for runnable in &self.shell_runnables { + if runnable.kind == kind { + let mut runnable = runnable.clone(); + + let replaced_args: Vec<_> = + runnable.args.iter().map(|arg| replacer(self, arg)).collect(); + runnable.args = replaced_args; + + return Some(runnable); + } + } + + None + } + pub(crate) fn runnable_args(&self, kind: &RunnableKind) -> Option { match kind { - RunnableKind::Bin => { - for runnable in &self.shell_runnables { - if matches!(runnable.kind, project_model::project_json::RunnableKind::Run) { - let mut runnable = runnable.clone(); - - let replaced_args: Vec<_> = runnable - .args - .iter() - .map(|arg| arg.replace("{label}", &self.label)) - .collect(); - runnable.args = replaced_args; - - return Some(runnable); - } - } - - None - } + RunnableKind::Bin => self + .find_replace_runnable(project_json::RunnableKind::Run, &|this, arg| { + arg.replace("{label}", &this.label) + }), RunnableKind::Test { test_id, .. } => { - for runnable in &self.shell_runnables { - if matches!(runnable.kind, project_model::project_json::RunnableKind::TestOne) { - let mut runnable = runnable.clone(); - - let replaced_args: Vec<_> = runnable - .args - .iter() - .map(|arg| arg.replace("{test_id}", &test_id.to_string())) - .map(|arg| arg.replace("{label}", &self.label)) - .collect(); - runnable.args = replaced_args; - - return Some(runnable); - } - } - - None + self.find_replace_runnable(project_json::RunnableKind::Run, &|this, arg| { + arg.replace("{label}", &this.label).replace("{test_id}", &test_id.to_string()) + }) + } + RunnableKind::TestMod { path } => self + .find_replace_runnable(project_json::RunnableKind::TestMod, &|this, arg| { + arg.replace("{label}", &this.label).replace("{test_pattern}", path) + }), + RunnableKind::Bench { test_id } => { + self.find_replace_runnable(project_json::RunnableKind::BenchOne, &|this, arg| { + arg.replace("{label}", &this.label).replace("{bench_id}", &test_id.to_string()) + }) + } + RunnableKind::DocTest { test_id } => { + self.find_replace_runnable(project_json::RunnableKind::DocTestOne, &|this, arg| { + arg.replace("{label}", &this.label).replace("{test_id}", &test_id.to_string()) + }) } - RunnableKind::TestMod { .. } => None, - RunnableKind::Bench { .. } => None, - RunnableKind::DocTest { .. } => None, } } } @@ -129,38 +132,21 @@ pub(crate) fn runnable_args( let extra_test_binary_args = config.extra_test_binary_args; let mut cargo_args = Vec::new(); - let mut executable_args = Vec::new(); + let executable_args = Self::executable_args_for(kind, extra_test_binary_args); match kind { - RunnableKind::Test { test_id, attr } => { + RunnableKind::Test { .. } => { cargo_args.push(config.test_command); - executable_args.push(test_id.to_string()); - if let TestId::Path(_) = test_id { - executable_args.push("--exact".to_owned()); - } - executable_args.extend(extra_test_binary_args); - if attr.ignore { - executable_args.push("--ignored".to_owned()); - } } - RunnableKind::TestMod { path } => { + RunnableKind::TestMod { .. } => { cargo_args.push(config.test_command); - executable_args.push(path.clone()); - executable_args.extend(extra_test_binary_args); } - RunnableKind::Bench { test_id } => { + RunnableKind::Bench { .. } => { cargo_args.push(config.bench_command); - executable_args.push(test_id.to_string()); - if let TestId::Path(_) = test_id { - executable_args.push("--exact".to_owned()); - } - executable_args.extend(extra_test_binary_args); } - RunnableKind::DocTest { test_id } => { + RunnableKind::DocTest { .. } => { cargo_args.push("test".to_owned()); cargo_args.push("--doc".to_owned()); - executable_args.push(test_id.to_string()); - executable_args.extend(extra_test_binary_args); } RunnableKind::Bin => { let subcommand = match spec { @@ -253,16 +239,70 @@ pub(crate) fn override_command( TargetKind::BuildScript | TargetKind::Other => "", }; + let target = |kind, target| match kind { + TargetKind::Bin | TargetKind::Test | TargetKind::Bench | TargetKind::Example => target, + _ => "", + }; + let replace_placeholders = |arg: String| match &spec { Some(spec) => arg .replace("${package}", &spec.package) .replace("${target_arg}", target_arg(spec.target_kind)) - .replace("${target}", &spec.target) + .replace("${target}", target(spec.target_kind, &spec.target)) .replace("${test_name}", &test_name), _ => arg, }; - args.map(|args| args.into_iter().map(replace_placeholders).collect()) + let extra_test_binary_args = config.extra_test_binary_args; + let executable_args = Self::executable_args_for(kind, extra_test_binary_args); + + args.map(|mut args| { + let exec_args_idx = args.iter().position(|a| a == "${executable_args}"); + + if let Some(idx) = exec_args_idx { + args.splice(idx..idx + 1, executable_args); + } + + args.into_iter().map(replace_placeholders).filter(|a| !a.trim().is_empty()).collect() + }) + } + + fn executable_args_for( + kind: &RunnableKind, + extra_test_binary_args: impl IntoIterator, + ) -> Vec { + let mut executable_args = Vec::new(); + + match kind { + RunnableKind::Test { test_id, attr } => { + executable_args.push(test_id.to_string()); + if let TestId::Path(_) = test_id { + executable_args.push("--exact".to_owned()); + } + executable_args.extend(extra_test_binary_args); + if attr.ignore { + executable_args.push("--ignored".to_owned()); + } + } + RunnableKind::TestMod { path } => { + executable_args.push(path.clone()); + executable_args.extend(extra_test_binary_args); + } + RunnableKind::Bench { test_id } => { + executable_args.push(test_id.to_string()); + if let TestId::Path(_) = test_id { + executable_args.push("--exact".to_owned()); + } + executable_args.extend(extra_test_binary_args); + } + RunnableKind::DocTest { test_id } => { + executable_args.push(test_id.to_string()); + executable_args.extend(extra_test_binary_args); + } + RunnableKind::Bin => {} + } + + executable_args } pub(crate) fn push_to(self, buf: &mut Vec, kind: &RunnableKind) { diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index f52604e13917..f6500a9b4dbe 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -206,6 +206,11 @@ fn kind(self) -> u32 { self.0 >> (HASH_BITS + INDEX_BITS) } + #[inline] + pub fn is_root(self) -> bool { + self.kind() == ErasedFileAstIdKind::Root as u32 + } + fn ast_id_for( node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap, @@ -220,14 +225,16 @@ fn ast_id_for( .or_else(|| asm_expr_ast_id(node, index_map)) } - fn should_alloc(node: &SyntaxNode) -> bool { + fn should_alloc(node: &SyntaxNode) -> Option { let kind = node.kind(); should_alloc_has_name(kind) - || should_alloc_assoc_item(kind) - || ast::ExternBlock::can_cast(kind) - || ast::Use::can_cast(kind) - || ast::Impl::can_cast(kind) - || ast::AsmExpr::can_cast(kind) + .or_else(|| should_alloc_assoc_item(kind)) + .or_else(|| { + ast::ExternBlock::can_cast(kind).then_some(ErasedFileAstIdKind::ExternBlock) + }) + .or_else(|| ast::Use::can_cast(kind).then_some(ErasedFileAstIdKind::Use)) + .or_else(|| ast::Impl::can_cast(kind).then_some(ErasedFileAstIdKind::Impl)) + .or_else(|| ast::AsmExpr::can_cast(kind).then_some(ErasedFileAstIdKind::AsmExpr)) } #[inline] @@ -478,8 +485,8 @@ fn has_name_ast_id(node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap) - } } - fn should_alloc_has_name(kind: SyntaxKind) -> bool { - false $( || ast::$ident::can_cast(kind) )* + fn should_alloc_has_name(kind: SyntaxKind) -> Option { + $( if ast::$ident::can_cast(kind) { Some(ErasedFileAstIdKind::$ident) } else )* { None } } }; } @@ -528,8 +535,8 @@ fn assoc_item_ast_id( } } - fn should_alloc_assoc_item(kind: SyntaxKind) -> bool { - false $( || ast::$ident::can_cast(kind) )* + fn should_alloc_assoc_item(kind: SyntaxKind) -> Option { + $( if ast::$ident::can_cast(kind) { Some(ErasedFileAstIdKind::$ident) } else )* { None } } }; } @@ -612,22 +619,49 @@ pub fn from_source(node: &SyntaxNode) -> AstIdMap { syntax::WalkEvent::Enter(node) => { if ast::BlockExpr::can_cast(node.kind()) { blocks.push((node, ContainsItems::No)); - } else if ErasedFileAstId::should_alloc(&node) { + } else if let Some(kind) = ErasedFileAstId::should_alloc(&node) { // Allocate blocks on-demand, only if they have items. // We don't associate items with blocks, only with items, since block IDs can be quite unstable. // FIXME: Is this the correct thing to do? Macro calls might actually be more incremental if // associated with blocks (not sure). Either way it's not a big deal. + let is_item = matches!( + kind, + ErasedFileAstIdKind::Enum + | ErasedFileAstIdKind::Struct + | ErasedFileAstIdKind::Union + | ErasedFileAstIdKind::ExternCrate + | ErasedFileAstIdKind::MacroDef + | ErasedFileAstIdKind::MacroRules + | ErasedFileAstIdKind::Module + | ErasedFileAstIdKind::Static + | ErasedFileAstIdKind::Trait + | ErasedFileAstIdKind::Const + | ErasedFileAstIdKind::Fn + | ErasedFileAstIdKind::TypeAlias + | ErasedFileAstIdKind::ExternBlock + | ErasedFileAstIdKind::Use + | ErasedFileAstIdKind::Impl + ); if let Some(( last_block_node, already_allocated @ ContainsItems::No, )) = blocks.last_mut() + && (is_item + || (kind == ErasedFileAstIdKind::MacroCall && { + let mut anc = node.ancestors(); + _ = anc.next(); + anc.next().is_some_and(|it| { + it.kind() == SyntaxKind::MACRO_EXPR + }) && anc.next().is_some_and(|it| { + it.kind() == SyntaxKind::EXPR_STMT + || it.kind() == SyntaxKind::STMT_LIST + }) + })) { - let block_ast_id = block_expr_ast_id( - last_block_node, - &mut index_map, - parent_of(parent_idx, &res), - ) - .expect("not a BlockExpr"); + let parent = parent_of(parent_idx, &res); + let block_ast_id = + block_expr_ast_id(last_block_node, &mut index_map, parent) + .expect("not a BlockExpr"); res.arena .alloc((SyntaxNodePtr::new(last_block_node), block_ast_id)); *already_allocated = ContainsItems::Yes; @@ -645,8 +679,9 @@ pub fn from_source(node: &SyntaxNode) -> AstIdMap { } syntax::WalkEvent::Leave(node) => { if ast::BlockExpr::can_cast(node.kind()) { - assert_eq!( - blocks.pop().map(|it| it.0), + let block = blocks.pop(); + debug_assert_eq!( + block.map(|it| it.0), Some(node), "left a BlockExpr we never entered" ); diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index 7ab26b189065..275e0e5ac8db 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -1,5 +1,6 @@ //! Missing batteries for standard libraries. +use std::borrow::Cow; use std::io as sio; use std::process::Command; use std::{cmp::Ordering, ops, time::Instant}; @@ -221,12 +222,7 @@ pub fn trim_indent(mut text: &str) -> String { if text.starts_with('\n') { text = &text[1..]; } - let indent = text - .lines() - .filter(|it| !it.trim().is_empty()) - .map(|it| it.len() - it.trim_start().len()) - .min() - .unwrap_or(0); + let indent = indent_of(text); text.split_inclusive('\n') .map( |line| { @@ -236,6 +232,43 @@ pub fn trim_indent(mut text: &str) -> String { .collect() } +#[must_use] +fn indent_of(text: &str) -> usize { + text.lines() + .filter(|it| !it.trim().is_empty()) + .map(|it| it.len() - it.trim_start().len()) + .min() + .unwrap_or(0) +} + +#[must_use] +pub fn dedent_by(spaces: usize, text: &str) -> String { + text.split_inclusive('\n') + .map(|line| { + let trimmed = line.trim_start_matches(' '); + if line.len() - trimmed.len() <= spaces { trimmed } else { &line[spaces..] } + }) + .collect() +} + +/// Indent non empty lines, including the first line +#[must_use] +pub fn indent_string(s: &str, indent_level: u8) -> String { + if indent_level == 0 || s.is_empty() { + return s.to_owned(); + } + let indent_str = " ".repeat(indent_level as usize); + s.split_inclusive("\n") + .map(|line| { + if line.trim_end().is_empty() { + Cow::Borrowed(line) + } else { + format!("{indent_str}{line}").into() + } + }) + .collect() +} + pub fn equal_range_by(slice: &[T], mut key: F) -> ops::Range where F: FnMut(&T) -> Ordering, @@ -366,6 +399,37 @@ fn main() { ); } + #[test] + fn test_dedent() { + assert_eq!(dedent_by(0, ""), ""); + assert_eq!(dedent_by(1, ""), ""); + assert_eq!(dedent_by(2, ""), ""); + assert_eq!(dedent_by(0, "foo"), "foo"); + assert_eq!(dedent_by(2, "foo"), "foo"); + assert_eq!(dedent_by(2, " foo"), "foo"); + assert_eq!(dedent_by(2, " foo"), " foo"); + assert_eq!(dedent_by(2, " foo\nbar"), " foo\nbar"); + assert_eq!(dedent_by(2, "foo\n bar"), "foo\n bar"); + assert_eq!(dedent_by(2, "foo\n\n bar"), "foo\n\n bar"); + assert_eq!(dedent_by(2, "foo\n.\n bar"), "foo\n.\n bar"); + assert_eq!(dedent_by(2, "foo\n .\n bar"), "foo\n.\n bar"); + assert_eq!(dedent_by(2, "foo\n .\n bar"), "foo\n .\n bar"); + } + + #[test] + fn test_indent_of() { + assert_eq!(indent_of(""), 0); + assert_eq!(indent_of(" "), 0); + assert_eq!(indent_of(" x"), 1); + assert_eq!(indent_of(" x\n"), 1); + assert_eq!(indent_of(" x\ny"), 0); + assert_eq!(indent_of(" x\n y"), 1); + assert_eq!(indent_of(" x\n y"), 1); + assert_eq!(indent_of(" x\n y"), 2); + assert_eq!(indent_of(" x\n y\n"), 2); + assert_eq!(indent_of(" x\n\n y\n"), 2); + } + #[test] fn test_replace() { #[track_caller] diff --git a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml index b2f238efc025..41db3ddcc550 100644 --- a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml @@ -23,6 +23,3 @@ path = "fuzz_targets/parser.rs" [[bin]] name = "reparse" path = "fuzz_targets/reparse.rs" - -[lints] -workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 544053408f73..3113fc74308b 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -245,7 +245,7 @@ RecordFieldList = RecordField = Attr* Visibility? 'unsafe'? - Name ':' Type ('=' Expr)? + Name ':' Type ('=' default_val:ConstArg)? TupleFieldList = '(' fields:(TupleField (',' TupleField)* ','?)? ')' @@ -268,7 +268,7 @@ VariantList = Variant = Attr* Visibility? - Name FieldList? ('=' Expr)? + Name FieldList? ('=' ConstArg)? Union = Attr* Visibility? diff --git a/src/tools/rust-analyzer/crates/syntax/src/algo.rs b/src/tools/rust-analyzer/crates/syntax/src/algo.rs index 3ab9c902625f..c679921b3f65 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/algo.rs @@ -132,3 +132,19 @@ pub fn previous_non_trivia_token(e: impl Into) -> Option) -> Option { + let mut token = match e.into() { + SyntaxElement::Node(n) => n.last_token()?, + SyntaxElement::Token(t) => t, + } + .next_token(); + while let Some(inner) = token { + if !inner.kind().is_trivia() { + return Some(inner); + } else { + token = inner.next_token(); + } + } + None +} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index 9b30642fe4b0..b706d7f722f4 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -43,8 +43,14 @@ fn add(self, rhs: u8) -> IndentLevel { } } +impl ops::AddAssign for IndentLevel { + fn add_assign(&mut self, rhs: u8) { + self.0 += rhs; + } +} + impl IndentLevel { - pub fn single() -> IndentLevel { + pub fn zero() -> IndentLevel { IndentLevel(0) } pub fn is_zero(&self) -> bool { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 2b7dc5cd76ab..7f59ae421382 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -591,7 +591,7 @@ pub fn add_item(&self, item: ast::AssocItem) { normalize_ws_between_braces(self.syntax()); (IndentLevel::from_token(&l_curly) + 1, ted::Position::after(&l_curly), "\n") } - None => (IndentLevel::single(), ted::Position::last_child_of(self.syntax()), "\n"), + None => (IndentLevel::zero(), ted::Position::last_child_of(self.syntax()), "\n"), }, }; let elements: Vec = vec![ diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index c4e72eafa793..7334de0fd96f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1337,7 +1337,7 @@ impl ast::HasName for RecordField {} impl ast::HasVisibility for RecordField {} impl RecordField { #[inline] - pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn default_val(&self) -> Option { support::child(&self.syntax) } #[inline] pub fn ty(&self) -> Option { support::child(&self.syntax) } #[inline] @@ -1896,7 +1896,7 @@ impl ast::HasName for Variant {} impl ast::HasVisibility for Variant {} impl Variant { #[inline] - pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn const_arg(&self) -> Option { support::child(&self.syntax) } #[inline] pub fn field_list(&self) -> Option { support::child(&self.syntax) } #[inline] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index f5d1d009a579..00971569a2ef 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -74,10 +74,18 @@ pub fn expr_underscore() -> ast::Expr { expr_from_text("_") } pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{ty}::default()")) + if !ty.needs_angles_in_path() { + expr_from_text(&format!("{ty}::default()")) + } else { + expr_from_text(&format!("<{ty}>::default()")) + } } pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{ty}::new()")) + if !ty.needs_angles_in_path() { + expr_from_text(&format!("{ty}::new()")) + } else { + expr_from_text(&format!("<{ty}>::new()")) + } } pub fn expr_self() -> ast::Expr { expr_from_text("self") diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 76cfea9d5bc6..63e4608d0f63 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -717,6 +717,10 @@ pub fn generic_arg_list(&self) -> Option { None } } + + pub fn needs_angles_in_path(&self) -> bool { + !matches!(self, ast::Type::PathType(_)) || self.generic_arg_list().is_some() + } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 27182191c3da..44114a780295 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -1,9 +1,11 @@ //! Wrappers over [`make`] constructors +use either::Either; + use crate::{ AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, ast::{ self, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, - HasTypeBounds, HasVisibility, RangeItem, make, + HasTypeBounds, HasVisibility, Lifetime, Param, RangeItem, make, }, syntax_editor::SyntaxMappingBuilder, }; @@ -19,6 +21,18 @@ pub fn name_ref(&self, name: &str) -> ast::NameRef { make::name_ref(name).clone_for_update() } + pub fn name_ref_self_ty(&self) -> ast::NameRef { + make::name_ref_self_ty().clone_for_update() + } + + pub fn expr_todo(&self) -> ast::Expr { + make::ext::expr_todo().clone_for_update() + } + + pub fn expr_self(&self) -> ast::Expr { + make::ext::expr_self().clone_for_update() + } + pub fn lifetime(&self, text: &str) -> ast::Lifetime { make::lifetime(text).clone_for_update() } @@ -49,6 +63,26 @@ pub fn ty_path(&self, path: ast::Path) -> ast::PathType { ast } + pub fn type_bound(&self, bound: ast::Type) -> ast::TypeBound { + make::type_bound(bound).clone_for_update() + } + + pub fn type_bound_list( + &self, + bounds: impl IntoIterator, + ) -> Option { + let (bounds, input) = iterator_input(bounds); + let ast = make::type_bound_list(bounds)?.clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.bounds().map(|b| b.syntax().clone())); + builder.finish(&mut mapping); + } + + Some(ast) + } + pub fn type_param( &self, name: ast::Name, @@ -94,7 +128,139 @@ pub fn struct_( generic_param_list: Option, field_list: ast::FieldList, ) -> ast::Struct { - make::struct_(visibility, strukt_name, generic_param_list, field_list).clone_for_update() + let ast = make::struct_( + visibility.clone(), + strukt_name.clone(), + generic_param_list.clone(), + field_list.clone(), + ) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(visibility) = visibility { + builder.map_node( + visibility.syntax().clone(), + ast.visibility().unwrap().syntax().clone(), + ); + } + builder.map_node(strukt_name.syntax().clone(), ast.name().unwrap().syntax().clone()); + if let Some(generic_param_list) = generic_param_list { + builder.map_node( + generic_param_list.syntax().clone(), + ast.generic_param_list().unwrap().syntax().clone(), + ); + } + builder + .map_node(field_list.syntax().clone(), ast.field_list().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn unnamed_param(&self, ty: ast::Type) -> ast::Param { + let ast = make::unnamed_param(ty.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn ty_fn_ptr>( + &self, + is_unsafe: bool, + abi: Option, + params: I, + ret_type: Option, + ) -> ast::FnPtrType { + let (params, params_input) = iterator_input(params); + let ast = make::ty_fn_ptr(is_unsafe, abi.clone(), params.into_iter(), ret_type.clone()) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(abi) = abi { + builder.map_node(abi.syntax().clone(), ast.abi().unwrap().syntax().clone()); + } + builder.map_children( + params_input, + ast.param_list().unwrap().params().map(|p| p.syntax().clone()), + ); + if let Some(ret_type) = ret_type { + builder + .map_node(ret_type.syntax().clone(), ast.ret_type().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn where_pred( + &self, + path: Either, + bounds: impl IntoIterator, + ) -> ast::WherePred { + let (bounds, bounds_input) = iterator_input(bounds); + let ast = make::where_pred(path.clone(), bounds).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + match &path { + Either::Left(lifetime) => { + builder.map_node( + lifetime.syntax().clone(), + ast.lifetime().unwrap().syntax().clone(), + ); + } + Either::Right(ty) => { + builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone()); + } + } + if let Some(type_bound_list) = ast.type_bound_list() { + builder.map_children( + bounds_input, + type_bound_list.bounds().map(|b| b.syntax().clone()), + ); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn where_clause( + &self, + predicates: impl IntoIterator, + ) -> ast::WhereClause { + let (predicates, input) = iterator_input(predicates); + let ast = make::where_clause(predicates).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.predicates().map(|p| p.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + + pub fn impl_trait_type(&self, bounds: ast::TypeBoundList) -> ast::ImplTraitType { + let ast = make::impl_trait_type(bounds.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder + .map_node(bounds.syntax().clone(), ast.type_bound_list().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast } pub fn expr_field(&self, receiver: ast::Expr, field: &str) -> ast::FieldExpr { @@ -287,6 +453,64 @@ pub fn path_segment(&self, name_ref: ast::NameRef) -> ast::PathSegment { ast } + pub fn generic_ty_path_segment( + &self, + name_ref: ast::NameRef, + generic_args: impl IntoIterator, + ) -> ast::PathSegment { + let (generic_args, input) = iterator_input(generic_args); + let ast = make::generic_ty_path_segment(name_ref.clone(), generic_args).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone()); + builder.map_children( + input, + ast.generic_arg_list().unwrap().generic_args().map(|a| a.syntax().clone()), + ); + builder.finish(&mut mapping); + } + + ast + } + + pub fn tail_only_block_expr(&self, tail_expr: ast::Expr) -> ast::BlockExpr { + let ast = make::tail_only_block_expr(tail_expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let stmt_list = ast.stmt_list().unwrap(); + let mut builder = SyntaxMappingBuilder::new(stmt_list.syntax().clone()); + builder.map_node( + tail_expr.syntax().clone(), + stmt_list.tail_expr().unwrap().syntax().clone(), + ); + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_bin_op(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr { + let ast::Expr::BinExpr(ast) = + make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(lhs.syntax().clone(), ast.lhs().unwrap().syntax().clone()); + builder.map_node(rhs.syntax().clone(), ast.rhs().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast.into() + } + + pub fn ty_placeholder(&self) -> ast::Type { + make::ty_placeholder().clone_for_update() + } + pub fn path_segment_generics( &self, name_ref: ast::NameRef, @@ -317,7 +541,23 @@ pub fn use_( visibility: Option, use_tree: ast::UseTree, ) -> ast::Use { - make::use_(attrs, visibility, use_tree).clone_for_update() + let (attrs, attrs_input) = iterator_input(attrs); + let ast = make::use_(attrs, visibility.clone(), use_tree.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone())); + if let Some(visibility) = visibility { + builder.map_node( + visibility.syntax().clone(), + ast.visibility().unwrap().syntax().clone(), + ); + } + builder.map_node(use_tree.syntax().clone(), ast.use_tree().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast } pub fn use_tree( @@ -327,7 +567,25 @@ pub fn use_tree( alias: Option, add_star: bool, ) -> ast::UseTree { - make::use_tree(path, use_tree_list, alias, add_star).clone_for_update() + let ast = make::use_tree(path.clone(), use_tree_list.clone(), alias.clone(), add_star) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone()); + if let Some(use_tree_list) = use_tree_list { + builder.map_node( + use_tree_list.syntax().clone(), + ast.use_tree_list().unwrap().syntax().clone(), + ); + } + if let Some(alias) = alias { + builder.map_node(alias.syntax().clone(), ast.rename().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast } pub fn path_unqualified(&self, segment: ast::PathSegment) -> ast::Path { @@ -828,10 +1086,6 @@ pub fn expr_underscore(&self) -> ast::UnderscoreExpr { unreachable!() }; - if let Some(mut mapping) = self.mappings() { - SyntaxMappingBuilder::new(ast.syntax().clone()).finish(&mut mapping); - } - ast } @@ -1220,6 +1474,22 @@ pub fn record_expr( ast } + pub fn record_expr_field_list( + &self, + fields: impl IntoIterator, + ) -> ast::RecordExprFieldList { + let (fields, input) = iterator_input(fields); + let ast = make::record_expr_field_list(fields).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.fields().map(|f| f.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn record_expr_field( &self, name: ast::NameRef, @@ -1230,7 +1500,20 @@ pub fn record_expr_field( if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); - builder.map_node(name.syntax().clone(), ast.name_ref().unwrap().syntax().clone()); + if let Some(ast_name_ref) = ast.name_ref() { + // NameRef is a direct child + builder.map_node(name.syntax().clone(), ast_name_ref.syntax().clone()); + } else { + // NameRef is nested inside PathExpr > Path > PathSegment. + // map_node requires the output to be a direct child of the builder's parent, so + // we need a separate builder scoped to PathSegment. + let ast::Expr::PathExpr(path_expr) = ast.expr().unwrap() else { unreachable!() }; + let path_segment = path_expr.path().unwrap().segment().unwrap(); + let inner_name_ref = path_segment.name_ref().unwrap(); + let mut inner_builder = SyntaxMappingBuilder::new(path_segment.syntax().clone()); + inner_builder.map_node(name.syntax().clone(), inner_name_ref.syntax().clone()); + inner_builder.finish(&mut mapping); + } if let Some(expr) = expr { builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); } @@ -1435,8 +1718,10 @@ pub fn variant( } if let Some(discriminant) = discriminant { - builder - .map_node(discriminant.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.map_node( + discriminant.syntax().clone(), + ast.const_arg().unwrap().syntax().clone(), + ); } builder.finish(&mut mapping); @@ -1529,6 +1814,10 @@ pub fn assoc_item_list( ast } + pub fn assoc_item_list_empty(&self) -> ast::AssocItemList { + make::assoc_item_list(None).clone_for_update() + } + pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr { let ast = make::attr_outer(meta.clone()).clone_for_update(); @@ -1697,6 +1986,65 @@ pub fn ty_ref(&self, ty: ast::Type, is_mut: bool) -> ast::Type { } ast } + + pub fn field_from_idents<'a>( + &self, + parts: impl std::iter::IntoIterator, + ) -> Option { + make::ext::field_from_idents(parts) + } + + pub fn expr_await(&self, expr: ast::Expr) -> ast::AwaitExpr { + let ast::Expr::AwaitExpr(ast) = make::expr_await(expr.clone()).clone_for_update() else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_break(&self, label: Option, expr: Option) -> ast::BreakExpr { + let ast::Expr::BreakExpr(ast) = + make::expr_break(label.clone(), expr.clone()).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(label) = label { + builder.map_node(label.syntax().clone(), ast.lifetime().unwrap().syntax().clone()); + } + if let Some(expr) = expr { + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_continue(&self, label: Option) -> ast::ContinueExpr { + let ast::Expr::ContinueExpr(ast) = make::expr_continue(label.clone()).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(label) = label { + builder.map_node(label.syntax().clone(), ast.lifetime().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } } // `ext` constructors diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 5683d891be7a..e6937e4d0f8a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -20,7 +20,7 @@ mod edits; mod mapping; -pub use edits::Removable; +pub use edits::{GetOrCreateWhereClause, Removable}; pub use mapping::{SyntaxMapping, SyntaxMappingBuilder}; #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs index 9090f7c9eb14..44f0a8038eca 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -10,6 +10,107 @@ syntax_editor::{Position, SyntaxEditor}, }; +pub trait GetOrCreateWhereClause: ast::HasGenericParams { + fn where_clause_position(&self) -> Option; + + fn get_or_create_where_clause( + &self, + editor: &mut SyntaxEditor, + make: &SyntaxFactory, + new_preds: impl Iterator, + ) { + let existing = self.where_clause(); + let all_preds: Vec<_> = + existing.iter().flat_map(|wc| wc.predicates()).chain(new_preds).collect(); + let new_where = make.where_clause(all_preds); + + if let Some(existing) = &existing { + editor.replace(existing.syntax(), new_where.syntax()); + } else if let Some(pos) = self.where_clause_position() { + editor.insert_all( + pos, + vec![make.whitespace(" ").into(), new_where.syntax().clone().into()], + ); + } + } +} + +impl GetOrCreateWhereClause for ast::Fn { + fn where_clause_position(&self) -> Option { + if let Some(ty) = self.ret_type() { + Some(Position::after(ty.syntax())) + } else if let Some(param_list) = self.param_list() { + Some(Position::after(param_list.syntax())) + } else { + Some(Position::last_child_of(self.syntax())) + } + } +} + +impl GetOrCreateWhereClause for ast::Impl { + fn where_clause_position(&self) -> Option { + if let Some(ty) = self.self_ty() { + Some(Position::after(ty.syntax())) + } else { + Some(Position::last_child_of(self.syntax())) + } + } +} + +impl GetOrCreateWhereClause for ast::Trait { + fn where_clause_position(&self) -> Option { + if let Some(gpl) = self.generic_param_list() { + Some(Position::after(gpl.syntax())) + } else if let Some(name) = self.name() { + Some(Position::after(name.syntax())) + } else { + Some(Position::last_child_of(self.syntax())) + } + } +} + +impl GetOrCreateWhereClause for ast::TypeAlias { + fn where_clause_position(&self) -> Option { + if let Some(gpl) = self.generic_param_list() { + Some(Position::after(gpl.syntax())) + } else if let Some(name) = self.name() { + Some(Position::after(name.syntax())) + } else { + Some(Position::last_child_of(self.syntax())) + } + } +} + +impl GetOrCreateWhereClause for ast::Struct { + fn where_clause_position(&self) -> Option { + let tfl = self.field_list().and_then(|fl| match fl { + ast::FieldList::RecordFieldList(_) => None, + ast::FieldList::TupleFieldList(it) => Some(it), + }); + if let Some(tfl) = tfl { + Some(Position::after(tfl.syntax())) + } else if let Some(gpl) = self.generic_param_list() { + Some(Position::after(gpl.syntax())) + } else if let Some(name) = self.name() { + Some(Position::after(name.syntax())) + } else { + Some(Position::last_child_of(self.syntax())) + } + } +} + +impl GetOrCreateWhereClause for ast::Enum { + fn where_clause_position(&self) -> Option { + if let Some(gpl) = self.generic_param_list() { + Some(Position::after(gpl.syntax())) + } else if let Some(name) = self.name() { + Some(Position::after(name.syntax())) + } else { + Some(Position::last_child_of(self.syntax())) + } + } +} + impl SyntaxEditor { /// Adds a new generic param to the function using `SyntaxEditor` pub fn add_generic_param(&mut self, function: &Fn, new_param: GenericParam) { @@ -109,7 +210,7 @@ pub fn add_items(&self, editor: &mut SyntaxEditor, items: Vec) { normalize_ws_between_braces(editor, self.syntax()); (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n") } - None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"), + None => (IndentLevel::zero(), Position::last_child_of(self.syntax()), "\n"), }, }; @@ -141,7 +242,7 @@ pub fn add_variant(&self, editor: &mut SyntaxEditor, variant: &ast::Variant) { normalize_ws_between_braces(editor, self.syntax()); (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly)) } - None => (IndentLevel::single(), Position::last_child_of(self.syntax())), + None => (IndentLevel::zero(), Position::last_child_of(self.syntax())), }, }; let elements: Vec = vec![ diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index ca68edd88c05..e271c32c8626 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -149,8 +149,8 @@ fn with_single_file( let fixture = ChangeFixture::parse(ra_fixture); fixture.change.apply(&mut db); assert_eq!(fixture.files.len(), 1, "Multiple file found in the fixture"); - let file = EditionedFileId::from_span_guess_origin(&db, fixture.files[0]); - (db, file) + let file_id = EditionedFileId::from_span_file_id(&db, fixture.files[0]); + (db, file_id) } /// See the trait documentation for more information on fixtures. @@ -165,7 +165,7 @@ fn with_many_files( let files = fixture .files .into_iter() - .map(|file| EditionedFileId::from_span_guess_origin(&db, file)) + .map(|file| EditionedFileId::from_span_file_id(&db, file)) .collect(); (db, files) } @@ -222,7 +222,7 @@ fn with_range_or_offset( let (file_id, range_or_offset) = fixture .file_position .expect("Could not find file position in fixture. Did you forget to add an `$0`?"); - let file_id = EditionedFileId::from_span_guess_origin(&db, file_id); + let file_id = EditionedFileId::from_span_file_id(&db, file_id); (db, file_id, range_or_offset) } diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index c34475bbdf01..86fb08073253 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -1503,6 +1503,19 @@ pub fn len(&self) -> usize { loop {} } } + + // region:default + impl const Default for &[T] { + fn default() -> Self { + &[] + } + } + impl const Default for &mut [T] { + fn default() -> Self { + &mut [] + } + } + // endregion:default } // endregion:slice diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs index c6393cc6922a..428b19c50b9d 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs @@ -208,6 +208,22 @@ fn run(mut self, inbox: Receiver) { ) }) .filter_map(|path| -> Option<(AbsPathBuf, Option>)> { + // Ignore events for files/directories that we're not watching. + if !(self.watched_file_entries.contains(&path) + || self + .watched_dir_entries + .iter() + .any(|dir| dir.contains_file(&path))) + { + return None; + } + + // For removed files, fs::metadata() will return Err, but + // we still want to update the VFS. + if matches!(event.kind, EventKind::Remove(_)) { + return Some((path, None)); + } + let meta = fs::metadata(&path).ok()?; if meta.file_type().is_dir() && self @@ -223,15 +239,6 @@ fn run(mut self, inbox: Receiver) { return None; } - if !(self.watched_file_entries.contains(&path) - || self - .watched_dir_entries - .iter() - .any(|dir| dir.contains_file(&path))) - { - return None; - } - let contents = read(&path); Some((path, contents)) }) @@ -317,7 +324,7 @@ fn load_entry( fn watch(&mut self, path: &Path) { if let Some((watcher, _)) = &mut self.watcher { - log_notify_error(watcher.watch(path, RecursiveMode::NonRecursive)); + log_notify_error(watcher.watch(path, RecursiveMode::Recursive)); } } diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 8460c2c7d0cf..35fba5accdbb 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -1380,9 +1380,9 @@ Default: `null` Override the command used for bench runnables. The first element of the array should be the program to execute (for example, `cargo`). -Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically +Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically replace the package name, target option (such as `--bin` or `--example`), the target name and -the test name (name of test function or test mod path). +the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`). ## rust-analyzer.runnables.command {#runnables.command} @@ -1399,9 +1399,9 @@ Default: `null` Override the command used for bench runnables. The first element of the array should be the program to execute (for example, `cargo`). -Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically +Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically replace the package name, target option (such as `--bin` or `--example`), the target name and -the test name (name of test function or test mod path). +the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`). ## rust-analyzer.runnables.extraArgs {#runnables.extraArgs} @@ -1444,9 +1444,9 @@ Default: `null` Override the command used for test runnables. The first element of the array should be the program to execute (for example, `cargo`). -Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically +Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically replace the package name, target option (such as `--bin` or `--example`), the target name and -the test name (name of test function or test mod path). +the arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`). ## rust-analyzer.rustc.source {#rustc.source} diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index be0bdc8d55bb..b51dc4d1320d 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -738,9 +738,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -799,9 +799,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -1817,9 +1817,9 @@ ] }, "node_modules/@vscode/vsce/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -2060,9 +2060,9 @@ "license": "BSD-2-Clause" }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -3416,9 +3416,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -3697,9 +3697,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -3895,9 +3895,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4822,9 +4822,9 @@ } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -5463,9 +5463,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -6719,9 +6719,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", - "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", "dev": true, "license": "MIT", "engines": { diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index fc20597e8876..1dd513c9de40 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2865,7 +2865,7 @@ "title": "Runnables", "properties": { "rust-analyzer.runnables.bench.overrideCommand": { - "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).", + "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).", "default": null, "type": [ "null", @@ -2894,7 +2894,7 @@ "title": "Runnables", "properties": { "rust-analyzer.runnables.doctest.overrideCommand": { - "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).", + "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).", "default": null, "type": [ "null", @@ -2948,7 +2948,7 @@ "title": "Runnables", "properties": { "rust-analyzer.runnables.test.overrideCommand": { - "markdownDescription": "Override the command used for test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).", + "markdownDescription": "Override the command used for test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${executable_args}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe arguments passed to test binary args (includes `rust-analyzer.runnables.extraTestBinaryArgs`).", "default": null, "type": [ "null", diff --git a/src/tools/rust-analyzer/lib/smol_str/src/borsh.rs b/src/tools/rust-analyzer/lib/smol_str/src/borsh.rs index b684a4910c96..44ae513ed444 100644 --- a/src/tools/rust-analyzer/lib/smol_str/src/borsh.rs +++ b/src/tools/rust-analyzer/lib/smol_str/src/borsh.rs @@ -16,7 +16,7 @@ impl BorshDeserialize for SmolStr { #[inline] fn deserialize_reader(reader: &mut R) -> borsh::io::Result { let len = u32::deserialize_reader(reader)?; - if (len as usize) < INLINE_CAP { + if (len as usize) <= INLINE_CAP { let mut buf = [0u8; INLINE_CAP]; reader.read_exact(&mut buf[..len as usize])?; _ = core::str::from_utf8(&buf[..len as usize]).map_err(|err| { @@ -29,9 +29,8 @@ fn deserialize_reader(reader: &mut R) -> borsh::io::Result { })) } else { // u8::vec_from_reader always returns Some on success in current implementation - let vec = u8::vec_from_reader(len, reader)?.ok_or_else(|| { - Error::new(ErrorKind::Other, "u8::vec_from_reader unexpectedly returned None") - })?; + let vec = u8::vec_from_reader(len, reader)? + .ok_or_else(|| Error::other("u8::vec_from_reader unexpectedly returned None"))?; Ok(SmolStr::from(String::from_utf8(vec).map_err(|err| { let msg = err.to_string(); Error::new(ErrorKind::InvalidData, msg) diff --git a/src/tools/rust-analyzer/lib/smol_str/src/lib.rs b/src/tools/rust-analyzer/lib/smol_str/src/lib.rs index 0d1f01a32b5a..55ede286c245 100644 --- a/src/tools/rust-analyzer/lib/smol_str/src/lib.rs +++ b/src/tools/rust-analyzer/lib/smol_str/src/lib.rs @@ -34,13 +34,17 @@ pub struct SmolStr(Repr); impl SmolStr { + /// The maximum byte length of a string that can be stored inline + /// without heap allocation. + pub const INLINE_CAP: usize = INLINE_CAP; + /// Constructs an inline variant of `SmolStr`. /// /// This never allocates. /// /// # Panics /// - /// Panics if `text.len() > 23`. + /// Panics if `text.len() > `[`SmolStr::INLINE_CAP`]. #[inline] pub const fn new_inline(text: &str) -> SmolStr { assert!(text.len() <= INLINE_CAP); // avoids bounds checks in loop @@ -100,6 +104,24 @@ pub fn is_empty(&self) -> bool { pub const fn is_heap_allocated(&self) -> bool { matches!(self.0, Repr::Heap(..)) } + + /// Constructs a `SmolStr` from a byte slice, returning an error if the slice is not valid + /// UTF-8. + #[inline] + pub fn from_utf8(bytes: &[u8]) -> Result { + core::str::from_utf8(bytes).map(SmolStr::new) + } + + /// Constructs a `SmolStr` from a byte slice without checking that the bytes are valid UTF-8. + /// + /// # Safety + /// + /// `bytes` must be valid UTF-8. + #[inline] + pub unsafe fn from_utf8_unchecked(bytes: &[u8]) -> SmolStr { + // SAFETY: caller guarantees bytes are valid UTF-8 + SmolStr::new(unsafe { core::str::from_utf8_unchecked(bytes) }) + } } impl Clone for SmolStr { @@ -116,7 +138,10 @@ fn cold_clone(v: &SmolStr) -> SmolStr { return cold_clone(self); } - // SAFETY: We verified that the payload of `Repr` is a POD + // SAFETY: The non-heap variants (`Repr::Inline` and `Repr::Static`) contain only + // `Copy` data (a `[u8; 23]` + `InlineSize` enum, or a `&'static str` fat pointer) + // and carry no drop glue, so a raw `ptr::read` bitwise copy is sound. + // The heap variant (`Repr::Heap`) is excluded above. unsafe { core::ptr::read(self as *const SmolStr) } } } @@ -142,7 +167,12 @@ fn deref(&self) -> &str { impl Eq for SmolStr {} impl PartialEq for SmolStr { fn eq(&self, other: &SmolStr) -> bool { - self.0.ptr_eq(&other.0) || self.as_str() == other.as_str() + match (&self.0, &other.0) { + (Repr::Inline { len: l_len, buf: l_buf }, Repr::Inline { len: r_len, buf: r_buf }) => { + l_len == r_len && l_buf == r_buf + } + _ => self.as_str() == other.as_str(), + } } } @@ -215,6 +245,48 @@ fn partial_cmp(&self, other: &SmolStr) -> Option { } } +impl PartialOrd for SmolStr { + fn partial_cmp(&self, other: &str) -> Option { + Some(self.as_str().cmp(other)) + } +} + +impl<'a> PartialOrd<&'a str> for SmolStr { + fn partial_cmp(&self, other: &&'a str) -> Option { + Some(self.as_str().cmp(*other)) + } +} + +impl PartialOrd for &str { + fn partial_cmp(&self, other: &SmolStr) -> Option { + Some((*self).cmp(other.as_str())) + } +} + +impl PartialOrd for SmolStr { + fn partial_cmp(&self, other: &String) -> Option { + Some(self.as_str().cmp(other.as_str())) + } +} + +impl PartialOrd for String { + fn partial_cmp(&self, other: &SmolStr) -> Option { + Some(self.as_str().cmp(other.as_str())) + } +} + +impl<'a> PartialOrd<&'a String> for SmolStr { + fn partial_cmp(&self, other: &&'a String) -> Option { + Some(self.as_str().cmp(other.as_str())) + } +} + +impl PartialOrd for &String { + fn partial_cmp(&self, other: &SmolStr) -> Option { + Some(self.as_str().cmp(other.as_str())) + } +} + impl hash::Hash for SmolStr { fn hash(&self, hasher: &mut H) { self.as_str().hash(hasher); @@ -359,6 +431,20 @@ fn as_ref(&self) -> &std::path::Path { } } +impl From for SmolStr { + #[inline] + fn from(c: char) -> SmolStr { + let mut buf = [0; INLINE_CAP]; + let len = c.len_utf8(); + c.encode_utf8(&mut buf); + SmolStr(Repr::Inline { + // SAFETY: A char is at most 4 bytes, which is always <= INLINE_CAP (23). + len: unsafe { InlineSize::transmute_from_u8(len as u8) }, + buf, + }) + } +} + impl From<&str> for SmolStr { #[inline] fn from(s: &str) -> SmolStr { @@ -483,11 +569,15 @@ enum InlineSize { } impl InlineSize { - /// SAFETY: `value` must be less than or equal to [`INLINE_CAP`] + /// # Safety + /// + /// `value` must be in the range `0..=23` (i.e. a valid `InlineSize` discriminant). + /// Values outside this range would produce an invalid enum discriminant, which is UB. #[inline(always)] const unsafe fn transmute_from_u8(value: u8) -> Self { debug_assert!(value <= InlineSize::_V23 as u8); - // SAFETY: The caller is responsible to uphold this invariant + // SAFETY: The caller guarantees `value` is a valid discriminant for this + // `#[repr(u8)]` enum (0..=23), so the transmute produces a valid `InlineSize`. unsafe { mem::transmute::(value) } } } @@ -563,24 +653,15 @@ fn as_str(&self) -> &str { Repr::Static(data) => data, Repr::Inline { len, buf } => { let len = *len as usize; - // SAFETY: len is guaranteed to be <= INLINE_CAP + // SAFETY: `len` is an `InlineSize` discriminant (0..=23) which is always + // <= INLINE_CAP (23), so `..len` is always in bounds of `buf: [u8; 23]`. let buf = unsafe { buf.get_unchecked(..len) }; - // SAFETY: buf is guaranteed to be valid utf8 for ..len bytes + // SAFETY: All constructors that produce `Repr::Inline` copy from valid + // UTF-8 sources (`&str` or char encoding), so `buf[..len]` is valid UTF-8. unsafe { ::core::str::from_utf8_unchecked(buf) } } } } - - fn ptr_eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Heap(l0), Self::Heap(r0)) => Arc::ptr_eq(l0, r0), - (Self::Static(l0), Self::Static(r0)) => core::ptr::eq(l0, r0), - (Self::Inline { len: l_len, buf: l_buf }, Self::Inline { len: r_len, buf: r_buf }) => { - l_len == r_len && l_buf == r_buf - } - _ => false, - } - } } /// Convert value to [`SmolStr`] using [`fmt::Display`], potentially without allocating. @@ -666,7 +747,7 @@ fn to_ascii_lowercase_smolstr(&self) -> SmolStr { buf[..len].copy_from_slice(self.as_bytes()); buf[..len].make_ascii_lowercase(); SmolStr(Repr::Inline { - // SAFETY: `len` is in bounds + // SAFETY: `len` is guarded to be <= INLINE_CAP (23), a valid `InlineSize` discriminant. len: unsafe { InlineSize::transmute_from_u8(len as u8) }, buf, }) @@ -683,7 +764,7 @@ fn to_ascii_uppercase_smolstr(&self) -> SmolStr { buf[..len].copy_from_slice(self.as_bytes()); buf[..len].make_ascii_uppercase(); SmolStr(Repr::Inline { - // SAFETY: `len` is in bounds + // SAFETY: `len` is guarded to be <= INLINE_CAP (23), a valid `InlineSize` discriminant. len: unsafe { InlineSize::transmute_from_u8(len as u8) }, buf, }) @@ -703,8 +784,11 @@ fn replacen_smolstr(&self, from: &str, to: &str, mut count: usize) -> SmolStr { if let [from_u8] = from.as_bytes() && let [to_u8] = to.as_bytes() { + // SAFETY: `from` and `to` are single-byte `&str`s. In valid UTF-8, a single-byte + // code unit is always in the range 0x00..=0x7F (i.e. ASCII). The closure only + // replaces the matching ASCII byte with another ASCII byte, and returns all + // other bytes unchanged, so UTF-8 validity is preserved. return if self.len() <= count { - // SAFETY: `from_u8` & `to_u8` are ascii unsafe { replacen_1_ascii(self, |b| if b == from_u8 { *to_u8 } else { *b }) } } else { unsafe { @@ -736,7 +820,11 @@ fn replacen_smolstr(&self, from: &str, to: &str, mut count: usize) -> SmolStr { } } -/// SAFETY: `map` fn must only replace ascii with ascii or return unchanged bytes. +/// # Safety +/// +/// `map` must satisfy: for every byte `b` in `src`, if `b <= 0x7F` (ASCII) then `map(b)` must +/// also be `<= 0x7F` (ASCII). If `b > 0x7F` (part of a multi-byte UTF-8 sequence), `map` must +/// return `b` unchanged. This ensures the output is valid UTF-8 whenever the input is. #[inline] unsafe fn replacen_1_ascii(src: &str, mut map: impl FnMut(&u8) -> u8) -> SmolStr { if src.len() <= INLINE_CAP { @@ -745,13 +833,16 @@ unsafe fn replacen_1_ascii(src: &str, mut map: impl FnMut(&u8) -> u8) -> SmolStr buf[idx] = map(b); } SmolStr(Repr::Inline { - // SAFETY: `len` is in bounds + // SAFETY: `src` is a `&str` so `src.len()` <= INLINE_CAP <= 23, which is a + // valid `InlineSize` discriminant. len: unsafe { InlineSize::transmute_from_u8(src.len() as u8) }, buf, }) } else { let out = src.as_bytes().iter().map(map).collect(); - // SAFETY: We replaced ascii with ascii on valid utf8 strings. + // SAFETY: The caller guarantees `map` only substitutes ASCII bytes with ASCII + // bytes and leaves multi-byte UTF-8 continuation bytes untouched, so the + // output byte sequence is valid UTF-8. unsafe { String::from_utf8_unchecked(out).into() } } } @@ -773,9 +864,11 @@ unsafe fn replacen_1_ascii(src: &str, mut map: impl FnMut(&u8) -> u8) -> SmolStr let mut is_ascii = [false; N]; while slice.len() >= N { - // SAFETY: checked in loop condition + // SAFETY: The loop condition guarantees `slice.len() >= N`, so `..N` is in bounds. let chunk = unsafe { slice.get_unchecked(..N) }; - // SAFETY: out_slice has at least same length as input slice and gets sliced with the same offsets + // SAFETY: `out_slice` starts with the same length as `slice` (both derived from + // `s.len()`) and both are advanced by the same offset `N` each iteration, so + // `out_slice.len() >= N` holds whenever `slice.len() >= N`. let out_chunk = unsafe { out_slice.get_unchecked_mut(..N) }; for j in 0..N { @@ -794,6 +887,7 @@ unsafe fn replacen_1_ascii(src: &str, mut map: impl FnMut(&u8) -> u8) -> SmolStr out_chunk[j] = convert(&chunk[j]); } + // SAFETY: Same reasoning as above — both slices have len >= N at this point. slice = unsafe { slice.get_unchecked(N..) }; out_slice = unsafe { out_slice.get_unchecked_mut(N..) }; } @@ -804,7 +898,9 @@ unsafe fn replacen_1_ascii(src: &str, mut map: impl FnMut(&u8) -> u8) -> SmolStr if byte > 127 { break; } - // SAFETY: out_slice has at least same length as input slice + // SAFETY: `out_slice` is always the same length as `slice` (both start equal and + // are advanced by 1 together), and `slice` is non-empty per the loop condition, + // so index 0 and `1..` are in bounds for both. unsafe { *out_slice.get_unchecked_mut(0) = convert(&byte); } @@ -813,8 +909,10 @@ unsafe fn replacen_1_ascii(src: &str, mut map: impl FnMut(&u8) -> u8) -> SmolStr } unsafe { - // SAFETY: we know this is a valid char boundary - // since we only skipped over leading ascii bytes + // SAFETY: We only advanced past bytes that satisfy `b <= 127`, i.e. ASCII bytes. + // In UTF-8, ASCII bytes (0x00..=0x7F) are always single-byte code points and + // never appear as continuation bytes, so the remaining `slice` starts at a valid + // UTF-8 char boundary. let rest = core::str::from_utf8_unchecked(slice); (out, rest) } @@ -850,10 +948,18 @@ macro_rules! format_smolstr { /// A builder that can be used to efficiently build a [`SmolStr`]. /// /// This won't allocate if the final string fits into the inline buffer. -#[derive(Clone, Default, Debug, PartialEq, Eq)] +#[derive(Clone, Default, Debug)] pub struct SmolStrBuilder(SmolStrBuilderRepr); -#[derive(Clone, Debug, PartialEq, Eq)] +impl PartialEq for SmolStrBuilder { + fn eq(&self, other: &Self) -> bool { + self.as_str() == other.as_str() + } +} + +impl Eq for SmolStrBuilder {} + +#[derive(Clone, Debug)] enum SmolStrBuilderRepr { Inline { len: usize, buf: [u8; INLINE_CAP] }, Heap(String), @@ -873,11 +979,57 @@ pub const fn new() -> Self { Self(SmolStrBuilderRepr::Inline { buf: [0; INLINE_CAP], len: 0 }) } + /// Creates a new empty [`SmolStrBuilder`] with at least the specified capacity. + /// + /// If `capacity` is less than or equal to [`SmolStr::INLINE_CAP`], the builder + /// will use inline storage and not allocate. Otherwise, it will pre-allocate a + /// heap buffer of the requested capacity. + #[must_use] + pub fn with_capacity(capacity: usize) -> Self { + if capacity <= INLINE_CAP { + Self::new() + } else { + Self(SmolStrBuilderRepr::Heap(String::with_capacity(capacity))) + } + } + + /// Returns the number of bytes accumulated in the builder so far. + #[inline] + pub fn len(&self) -> usize { + match &self.0 { + SmolStrBuilderRepr::Inline { len, .. } => *len, + SmolStrBuilderRepr::Heap(heap) => heap.len(), + } + } + + /// Returns `true` if the builder has a length of zero bytes. + #[inline] + pub fn is_empty(&self) -> bool { + match &self.0 { + SmolStrBuilderRepr::Inline { len, .. } => *len == 0, + SmolStrBuilderRepr::Heap(heap) => heap.is_empty(), + } + } + + /// Returns a `&str` slice of the builder's current contents. + #[inline] + pub fn as_str(&self) -> &str { + match &self.0 { + SmolStrBuilderRepr::Inline { len, buf } => { + // SAFETY: `buf[..*len]` was built by prior `push`/`push_str` calls + // that only wrote valid UTF-8, and `*len <= INLINE_CAP` is maintained + // by the inline branch logic. + unsafe { core::str::from_utf8_unchecked(&buf[..*len]) } + } + SmolStrBuilderRepr::Heap(heap) => heap.as_str(), + } + } + /// Builds a [`SmolStr`] from `self`. #[must_use] - pub fn finish(&self) -> SmolStr { - SmolStr(match &self.0 { - &SmolStrBuilderRepr::Inline { len, buf } => { + pub fn finish(self) -> SmolStr { + SmolStr(match self.0 { + SmolStrBuilderRepr::Inline { len, buf } => { debug_assert!(len <= INLINE_CAP); Repr::Inline { // SAFETY: We know that `value.len` is less than or equal to the maximum value of `InlineSize` @@ -885,7 +1037,7 @@ pub fn finish(&self) -> SmolStr { buf, } } - SmolStrBuilderRepr::Heap(heap) => Repr::new(heap), + SmolStrBuilderRepr::Heap(heap) => Repr::new(&heap), }) } @@ -900,8 +1052,10 @@ pub fn push(&mut self, c: char) { *len += char_len; } else { let mut heap = String::with_capacity(new_len); - // copy existing inline bytes over to the heap - // SAFETY: inline data is guaranteed to be valid utf8 for `old_len` bytes + // SAFETY: `buf[..*len]` was built by prior `push`/`push_str` calls + // that only wrote valid UTF-8 (from `char::encode_utf8` or `&str` + // byte copies), so extending the Vec with these bytes preserves the + // String's UTF-8 invariant. unsafe { heap.as_mut_vec().extend_from_slice(&buf[..*len]) }; heap.push(c); self.0 = SmolStrBuilderRepr::Heap(heap); @@ -926,8 +1080,10 @@ pub fn push_str(&mut self, s: &str) { let mut heap = String::with_capacity(*len); - // copy existing inline bytes over to the heap - // SAFETY: inline data is guaranteed to be valid utf8 for `old_len` bytes + // SAFETY: `buf[..old_len]` was built by prior `push`/`push_str` calls + // that only wrote valid UTF-8 (from `char::encode_utf8` or `&str` byte + // copies), so extending the Vec with these bytes preserves the String's + // UTF-8 invariant. unsafe { heap.as_mut_vec().extend_from_slice(&buf[..old_len]) }; heap.push_str(s); self.0 = SmolStrBuilderRepr::Heap(heap); @@ -945,6 +1101,30 @@ fn write_str(&mut self, s: &str) -> fmt::Result { } } +impl iter::Extend for SmolStrBuilder { + fn extend>(&mut self, iter: I) { + for c in iter { + self.push(c); + } + } +} + +impl<'a> iter::Extend<&'a str> for SmolStrBuilder { + fn extend>(&mut self, iter: I) { + for s in iter { + self.push_str(s); + } + } +} + +impl<'a> iter::Extend<&'a String> for SmolStrBuilder { + fn extend>(&mut self, iter: I) { + for s in iter { + self.push_str(s); + } + } +} + impl From for SmolStr { fn from(value: SmolStrBuilder) -> Self { value.finish() diff --git a/src/tools/rust-analyzer/lib/smol_str/src/serde.rs b/src/tools/rust-analyzer/lib/smol_str/src/serde.rs index 66cbcd3badc1..9d82d64805c4 100644 --- a/src/tools/rust-analyzer/lib/smol_str/src/serde.rs +++ b/src/tools/rust-analyzer/lib/smol_str/src/serde.rs @@ -16,7 +16,7 @@ fn smol_str<'de: 'a, 'a, D>(deserializer: D) -> Result impl<'a> Visitor<'a> for SmolStrVisitor { type Value = SmolStr; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a string") } diff --git a/src/tools/rust-analyzer/lib/smol_str/tests/test.rs b/src/tools/rust-analyzer/lib/smol_str/tests/test.rs index 00fab2ee1c7f..83648edeecd0 100644 --- a/src/tools/rust-analyzer/lib/smol_str/tests/test.rs +++ b/src/tools/rust-analyzer/lib/smol_str/tests/test.rs @@ -10,6 +10,7 @@ #[cfg(target_pointer_width = "64")] fn smol_str_is_smol() { assert_eq!(::std::mem::size_of::(), ::std::mem::size_of::(),); + assert_eq!(::std::mem::size_of::>(), ::std::mem::size_of::(),); } #[test] @@ -332,6 +333,29 @@ fn test_builder_push() { assert_eq!("a".repeat(24), s); } +#[test] +fn test_from_char() { + // ASCII char + let s: SmolStr = 'a'.into(); + assert_eq!(s, "a"); + assert!(!s.is_heap_allocated()); + + // Multi-byte char (2 bytes) + let s: SmolStr = SmolStr::from('ñ'); + assert_eq!(s, "ñ"); + assert!(!s.is_heap_allocated()); + + // 3-byte char + let s: SmolStr = '€'.into(); + assert_eq!(s, "€"); + assert!(!s.is_heap_allocated()); + + // 4-byte char (emoji) + let s: SmolStr = '🦀'.into(); + assert_eq!(s, "🦀"); + assert!(!s.is_heap_allocated()); +} + #[cfg(test)] mod test_str_ext { use smol_str::StrExt; diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 7c89bcb9ab04..68f38716dbb0 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -f8704be04fe1150527fc2cf21dd44327f0fe87fb +1174f784096deb8e4ba93f7e4b5ccb7bb4ba2c55 diff --git a/src/tools/rust-installer/Cargo.toml b/src/tools/rust-installer/Cargo.toml index cdd867c5f157..e0c93e3c4477 100644 --- a/src/tools/rust-installer/Cargo.toml +++ b/src/tools/rust-installer/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" anyhow = "1.0.19" flate2 = "1.0.1" rayon = "1.0" -tar = "0.4.38" +tar = "0.4.45" walkdir = "2" xz2 = "0.1.4" diff --git a/src/tools/rust-installer/install-template.sh b/src/tools/rust-installer/install-template.sh index c4f0c618a52d..7079e29eefff 100644 --- a/src/tools/rust-installer/install-template.sh +++ b/src/tools/rust-installer/install-template.sh @@ -433,8 +433,8 @@ uninstall_components() { local _directive while read _directive; do - local _command=`echo $_directive | cut -f1 -d:` - local _file=`echo $_directive | cut -f2 -d:` + local _command="${_directive%%:*}" + local _file="${_directive#*:}" # Sanity checks if [ ! -n "$_command" ]; then critical_err "malformed installation directive"; fi @@ -541,8 +541,8 @@ install_components() { local _directive while read _directive; do - local _command=`echo $_directive | cut -f1 -d:` - local _file=`echo $_directive | cut -f2 -d:` + local _command="${_directive%%:*}" + local _file="${_directive#*:}" # Sanity checks if [ ! -n "$_command" ]; then critical_err "malformed installation directive"; fi diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs index 4741abbe4658..50c0db8ac06e 100644 --- a/src/tools/rustfmt/src/matches.rs +++ b/src/tools/rustfmt/src/matches.rs @@ -571,7 +571,7 @@ fn rewrite_match_body( // The `if ...` guard on a match arm. fn rewrite_guard( context: &RewriteContext<'_>, - guard: &Option>, + guard: &Option>, shape: Shape, // The amount of space used up on this line for the pattern in // the arm (excludes offset). @@ -586,7 +586,7 @@ fn rewrite_guard( .and_then(|s| s.sub_width_opt(5)); if !multiline_pattern { if let Some(cond_shape) = cond_shape { - if let Ok(cond_str) = guard.rewrite_result(context, cond_shape) { + if let Ok(cond_str) = guard.cond.rewrite_result(context, cond_shape) { if !cond_str.contains('\n') || pattern_width <= context.config.tab_spaces() { return Ok(format!(" if {cond_str}")); } @@ -597,9 +597,9 @@ fn rewrite_guard( // Not enough space to put the guard after the pattern, try a newline. // 3 = `if `, 5 = ` => {` let cond_shape = Shape::indented(shape.indent.block_indent(context.config), context.config) - .offset_left(3, guard.span)? - .sub_width(5, guard.span)?; - let cond_str = guard.rewrite_result(context, cond_shape)?; + .offset_left(3, guard.span())? + .sub_width(5, guard.span())?; + let cond_str = guard.cond.rewrite_result(context, cond_shape)?; Ok(format!( "{}if {}", cond_shape.indent.to_string_with_newline(context.config), diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index df2a8dc5c6fd..0a9ff4771b0e 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -361,7 +361,7 @@ pub(crate) fn rewrite_range_pat( shape: Shape, lhs: &Option>, rhs: &Option>, - end_kind: &rustc_span::source_map::Spanned, + end_kind: &rustc_span::Spanned, span: Span, ) -> RewriteResult { let infix = match end_kind.node { diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index 020651e2daac..143fb1dea222 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -1,7 +1,7 @@ use std::cmp::max; use rustc_ast::ast; -use rustc_span::{Span, source_map}; +use rustc_span::Span; use crate::macros::MacroArg; use crate::patterns::RangeOperand; @@ -18,7 +18,7 @@ fn span(&self) -> Span { } } -impl Spanned for source_map::Spanned { +impl Spanned for rustc_span::Spanned { fn span(&self) -> Span { self.span } diff --git a/src/tools/rustfmt/src/vertical.rs b/src/tools/rustfmt/src/vertical.rs index 21e34d29710f..fd9a4a7db6a7 100644 --- a/src/tools/rustfmt/src/vertical.rs +++ b/src/tools/rustfmt/src/vertical.rs @@ -198,7 +198,7 @@ fn struct_field_prefix_max_min_width( .rewrite_prefix(context, shape) .map(|field_str| trimmed_last_line_width(&field_str)) }) - .fold_ok((0, ::std::usize::MAX), |(max_len, min_len), len| { + .fold_ok((0, usize::MAX), |(max_len, min_len), len| { (cmp::max(max_len, len), cmp::min(min_len, len)) }) .unwrap_or((0, 0)) diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 6048084c8da6..560d62e9d57d 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -665,11 +665,11 @@ fn visit_assoc_item(&mut self, ai: &ast::AssocItem, visitor_kind: ItemVisitorKin } // TODO(calebcartwright): consider enabling box_patterns feature gate - match (&ai.kind, visitor_kind) { - (ast::AssocItemKind::Const(c), AssocTraitItem) => { + match (&ai.kind, assoc_ctxt) { + (ast::AssocItemKind::Const(c), visit::AssocCtxt::Trait) => { self.visit_static(&StaticParts::from_trait_item(ai, c.ident)) } - (ast::AssocItemKind::Const(c), AssocImplItem) => { + (ast::AssocItemKind::Const(c), visit::AssocCtxt::Impl { .. }) => { self.visit_static(&StaticParts::from_impl_item(ai, c.ident)) } (ast::AssocItemKind::Fn(ref fn_kind), _) => { @@ -714,7 +714,11 @@ fn visit_assoc_item(&mut self, ai: &ast::AssocItem, visitor_kind: ItemVisitorKin (ast::AssocItemKind::MacCall(ref mac), _) => { self.visit_mac(mac, MacroPosition::Item); } - _ => unreachable!(), + (ast::AssocItemKind::Delegation(_) | ast::AssocItemKind::DelegationMac(_), _) => { + // TODO(ytmimi) #![feature(fn_delegation)] + // add formatting for `AssocItemKind::Delegation` and `AssocItemKind::DelegationMac` + self.push_rewrite(ai.span, None); + } } } diff --git a/src/tools/rustfmt/tests/target/issue_6513.rs b/src/tools/rustfmt/tests/target/issue_6513.rs new file mode 100644 index 000000000000..827d4ccdf27f --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_6513.rs @@ -0,0 +1,10 @@ +#![feature(fn_delegation)] + +struct Ty; +impl Ty { + reuse std::convert::identity; +} + +trait Trait { + reuse std::convert::identity; +} diff --git a/src/tools/tidy/src/codegen.rs b/src/tools/tidy/src/codegen.rs new file mode 100644 index 000000000000..b87e19c40a8f --- /dev/null +++ b/src/tools/tidy/src/codegen.rs @@ -0,0 +1,60 @@ +//! Tidy check for codegen backend TODO policy. + +use std::ffi::OsStr; +use std::path::Path; + +use crate::diagnostics::{CheckId, TidyCtx}; +use crate::walk::walk; + +fn is_codegen_repo_path(path: &Path) -> bool { + const CODEGEN_REPO_PATHS: &[&str] = + &["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"]; + + CODEGEN_REPO_PATHS.iter().any(|repo| path.ancestors().any(|p| p.ends_with(Path::new(repo)))) +} + +fn has_supported_extension(path: &Path) -> bool { + const EXTENSIONS: &[&str] = + &["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "toml", "yml", "yaml"]; + path.extension().is_some_and(|ext| EXTENSIONS.iter().any(|e| ext == OsStr::new(e))) +} + +pub fn check(path: &Path, tidy_ctx: TidyCtx) { + let mut check = tidy_ctx.start_check(CheckId::new("codegen").path(path)); + + fn skip(path: &Path, is_dir: bool) -> bool { + if path.file_name().is_some_and(|name| name.to_string_lossy().starts_with(".#")) { + // Editor temp file. + return true; + } + + if is_dir { + return false; + } + + // Scan only selected text file types. + !has_supported_extension(path) + } + + walk(path, skip, &mut |entry, contents| { + let file = entry.path(); + + if !is_codegen_repo_path(file) { + return; + } + + for (i, line) in contents.split('\n').enumerate() { + let trimmed = line.trim(); + + // TODO policy for codegen-only trees. + if trimmed.contains("TODO") { + check.error(format!( + "{}:{}: TODO is used for tasks that should be done before merging a PR; \ + if you want to leave a message in the codebase use FIXME", + file.display(), + i + 1 + )); + } + } + }); +} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 9e9d463acdb3..c6624b1b3697 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -582,7 +582,7 @@ pub(crate) struct WorkspaceInfo<'a> { "cranelift-srcgen", "crc32fast", "equivalent", - "fallible-iterator", + "fnv", "foldhash", "gimli", "hashbrown", @@ -608,8 +608,8 @@ pub(crate) struct WorkspaceInfo<'a> { "syn", "target-lexicon", "unicode-ident", + "wasmtime-internal-core", "wasmtime-internal-jit-icache-coherence", - "wasmtime-internal-math", "windows-link", "windows-sys", "windows-targets", diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 124de884637e..4ba2da7b5d3f 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -17,7 +17,7 @@ //! 3. Print the output of the given command. If it fails and `TIDY_PRINT_DIFF` //! is set, rerun the tool to print a suggestion diff (for e.g. CI) -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; @@ -58,38 +58,6 @@ pub fn check( pos_args: Vec, tidy_ctx: TidyCtx, ) { - let mut check = tidy_ctx.start_check("extra_checks"); - - if let Err(e) = check_impl( - root_path, - outdir, - librustdoc_path, - tools_path, - npm, - cargo, - extra_checks, - pos_args, - &tidy_ctx, - ) { - check.error(e); - } -} - -fn check_impl( - root_path: &Path, - outdir: &Path, - librustdoc_path: &Path, - tools_path: &Path, - npm: &Path, - cargo: &Path, - extra_checks: Option>, - pos_args: Vec, - tidy_ctx: &TidyCtx, -) -> Result<(), Error> { - let show_diff = - std::env::var("TIDY_PRINT_DIFF").is_ok_and(|v| v.eq_ignore_ascii_case("true") || v == "1"); - let bless = tidy_ctx.is_bless_enabled(); - // Split comma-separated args up let mut lint_args = match extra_checks { Some(s) => s @@ -129,12 +97,6 @@ macro_rules! extra_check { }; } - let rerun_with_bless = |mode: &str, action: &str| { - if !bless { - eprintln!("rerun tidy with `--extra-checks={mode} --bless` to {action}"); - } - }; - let python_lint = extra_check!(Py, Lint); let python_fmt = extra_check!(Py, Fmt); let shell_lint = extra_check!(Shell, Lint); @@ -151,204 +113,351 @@ macro_rules! extra_check { .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with('-'))); if python_lint || python_fmt || cpp_fmt { - let venv_path = outdir.join("venv"); - let mut reqs_path = root_path.to_owned(); - reqs_path.extend(PIP_REQ_PATH); - py_path = Some(get_or_create_venv(&venv_path, &reqs_path)?); + // Since python lint, format and cpp format share python env, we need to ensure python env is installed before running those checks. + let p = py_prepare(root_path, outdir, &tidy_ctx); + if p.is_none() { + return; + } + py_path = p; } if python_lint { - let py_path = py_path.as_ref().unwrap(); - let args: &[&OsStr] = if bless { - eprintln!("linting python files and applying suggestions"); - &["check".as_ref(), "--fix".as_ref()] - } else { - eprintln!("linting python files"); - &["check".as_ref()] - }; + check_python_lint( + root_path, + outdir, + &cfg_args, + &file_args, + py_path.as_ref().unwrap(), + &tidy_ctx, + ); + } - let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, args); + if python_fmt { + check_python_fmt( + root_path, + outdir, + &cfg_args, + &file_args, + py_path.as_ref().unwrap(), + &tidy_ctx, + ); + } - if res.is_err() && show_diff && !bless { - eprintln!("\npython linting failed! Printing diff suggestions:"); + if cpp_fmt { + check_cpp_fmt(root_path, &cfg_args, &file_args, py_path.as_ref().unwrap(), &tidy_ctx); + } - let diff_res = run_ruff( + if shell_lint { + check_shell_lint(root_path, &cfg_args, &file_args, &tidy_ctx); + } + + if spellcheck { + check_spellcheck(root_path, outdir, cargo, &tidy_ctx); + } + + if js_lint || js_typecheck { + // Since js lint and format share node env, we need to ensure node env is installed before running those checks. + if js_prepare(root_path, outdir, npm, &tidy_ctx).is_none() { + return; + } + } + + if js_lint { + check_js_lint(outdir, librustdoc_path, tools_path, &tidy_ctx); + } + + if js_typecheck { + check_js_typecheck(outdir, librustdoc_path, &tidy_ctx); + } +} + +fn py_prepare(root_path: &Path, outdir: &Path, tidy_ctx: &TidyCtx) -> Option { + let mut check = tidy_ctx.start_check("extra_checks:py_prepare"); + + let venv_path = outdir.join("venv"); + let mut reqs_path = root_path.to_owned(); + reqs_path.extend(PIP_REQ_PATH); + + match get_or_create_venv(&venv_path, &reqs_path) { + Ok(p) => Some(p), + Err(e) => { + check.error(e); + None + } + } +} + +fn js_prepare(root_path: &Path, outdir: &Path, npm: &Path, tidy_ctx: &TidyCtx) -> Option<()> { + let mut check = tidy_ctx.start_check("extra_checks:js_prepare"); + + if let Err(e) = rustdoc_js::npm_install(root_path, outdir, npm) { + check.error(e.to_string()); + return None; + } + + Some(()) +} + +fn show_bless_help(mode: &str, action: &str, bless: bool) { + if !bless { + eprintln!("rerun tidy with `--extra-checks={mode} --bless` to {action}"); + } +} + +fn show_diff() -> bool { + std::env::var("TIDY_PRINT_DIFF").is_ok_and(|v| v.eq_ignore_ascii_case("true") || v == "1") +} + +fn check_spellcheck(root_path: &Path, outdir: &Path, cargo: &Path, tidy_ctx: &TidyCtx) { + let mut check = tidy_ctx.start_check("extra_checks:spellcheck"); + + let bless = tidy_ctx.is_bless_enabled(); + + let config_path = root_path.join("typos.toml"); + let mut args = vec!["-c", config_path.as_os_str().to_str().unwrap()]; + args.extend_from_slice(SPELLCHECK_DIRS); + + if bless { + eprintln!("spellchecking files and fixing typos"); + args.push("--write-changes"); + } else { + eprintln!("spellchecking files"); + } + + if let Err(e) = + spellcheck_runner(root_path, &outdir, &cargo, &args, tidy_ctx.is_running_on_ci()) + { + show_bless_help("spellcheck", "fix typos", bless); + check.error(e); + } +} + +fn check_js_lint(outdir: &Path, librustdoc_path: &Path, tools_path: &Path, tidy_ctx: &TidyCtx) { + let mut check = tidy_ctx.start_check("extra_checks:js_lint"); + + let bless = tidy_ctx.is_bless_enabled(); + + if bless { + eprintln!("linting javascript files and applying suggestions"); + } else { + eprintln!("linting javascript files"); + } + + if let Err(e) = rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless) { + show_bless_help("js:lint", "apply esplint suggestion", bless); + check.error(e); + return; + } + + if let Err(e) = rustdoc_js::es_check(outdir, librustdoc_path) { + check.error(e); + } +} + +fn check_js_typecheck(outdir: &Path, librustdoc_path: &Path, tidy_ctx: &TidyCtx) { + let mut check = tidy_ctx.start_check("extra_checks:js_typecheck"); + + eprintln!("typechecking javascript files"); + if let Err(e) = rustdoc_js::typecheck(outdir, librustdoc_path) { + check.error(e); + } +} + +fn check_shell_lint( + root_path: &Path, + cfg_args: &Vec<&OsStr>, + file_args: &Vec<&OsStr>, + tidy_ctx: &TidyCtx, +) { + let mut check = tidy_ctx.start_check("extra_checks:shell_lint"); + + eprintln!("linting shell files"); + + let mut file_args_shc = file_args.clone(); + let files; + if file_args.is_empty() { + match find_with_extension(root_path, None, &[OsStr::new("sh")]) { + Ok(f) => files = f, + Err(e) => { + check.error(e); + return; + } + } + + file_args_shc.extend(files.iter().map(|p| p.as_os_str())); + } + + if let Err(e) = shellcheck_runner(&merge_args(&cfg_args, &file_args_shc)) { + check.error(e); + } +} + +fn check_python_lint( + root_path: &Path, + outdir: &Path, + cfg_args: &Vec<&OsStr>, + file_args: &Vec<&OsStr>, + py_path: &Path, + tidy_ctx: &TidyCtx, +) { + let mut check = tidy_ctx.start_check("extra_checks:python_lint"); + + let bless = tidy_ctx.is_bless_enabled(); + + let args: &[&OsStr] = if bless { + eprintln!("linting python files and applying suggestions"); + &["check".as_ref(), "--fix".as_ref()] + } else { + eprintln!("linting python files"); + &["check".as_ref()] + }; + + let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, args); + + if res.is_err() && !bless && show_diff() { + eprintln!("\npython linting failed! Printing diff suggestions:"); + + let diff_res = run_ruff( + root_path, + outdir, + py_path, + &cfg_args, + &file_args, + &["check".as_ref(), "--diff".as_ref()], + ); + // `ruff check --diff` will return status 0 if there are no suggestions. + if diff_res.is_err() { + show_bless_help("py:lint", "apply ruff suggestions", bless); + } + } + if let Err(e) = res { + check.error(e); + } +} + +fn check_python_fmt( + root_path: &Path, + outdir: &Path, + cfg_args: &Vec<&OsStr>, + file_args: &Vec<&OsStr>, + py_path: &Path, + tidy_ctx: &TidyCtx, +) { + let mut check = tidy_ctx.start_check("extra_checks:python_fmt"); + + let bless = tidy_ctx.is_bless_enabled(); + + let mut args: Vec<&OsStr> = vec!["format".as_ref()]; + if bless { + eprintln!("formatting python files"); + } else { + eprintln!("checking python file formatting"); + args.push("--check".as_ref()); + } + + let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &args); + + if res.is_err() && !bless { + if show_diff() { + eprintln!("\npython formatting does not match! Printing diff:"); + + let _ = run_ruff( root_path, outdir, py_path, &cfg_args, &file_args, - &["check".as_ref(), "--diff".as_ref()], + &["format".as_ref(), "--diff".as_ref()], ); - // `ruff check --diff` will return status 0 if there are no suggestions. - if diff_res.is_err() { - rerun_with_bless("py:lint", "apply ruff suggestions"); - } } - // Rethrow error - res?; + show_bless_help("py:fmt", "reformat Python code", bless); } - if python_fmt { - let mut args: Vec<&OsStr> = vec!["format".as_ref()]; - if bless { - eprintln!("formatting python files"); - } else { - eprintln!("checking python file formatting"); - args.push("--check".as_ref()); - } - - let py_path = py_path.as_ref().unwrap(); - let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &args); - - if res.is_err() && !bless { - if show_diff { - eprintln!("\npython formatting does not match! Printing diff:"); - - let _ = run_ruff( - root_path, - outdir, - py_path, - &cfg_args, - &file_args, - &["format".as_ref(), "--diff".as_ref()], - ); - } - rerun_with_bless("py:fmt", "reformat Python code"); - } - - // Rethrow error - res?; + if let Err(e) = res { + check.error(e); } +} - if cpp_fmt { - let mut cfg_args_clang_format = cfg_args.clone(); - let mut file_args_clang_format = file_args.clone(); - let config_path = root_path.join(".clang-format"); - let config_file_arg = format!("file:{}", config_path.display()); - cfg_args_clang_format.extend(&["--style".as_ref(), config_file_arg.as_ref()]); - if bless { - eprintln!("formatting C++ files"); - cfg_args_clang_format.push("-i".as_ref()); - } else { - eprintln!("checking C++ file formatting"); - cfg_args_clang_format.extend(&["--dry-run".as_ref(), "--Werror".as_ref()]); +fn check_cpp_fmt( + root_path: &Path, + cfg_args: &Vec<&OsStr>, + file_args: &Vec<&OsStr>, + py_path: &Path, + tidy_ctx: &TidyCtx, +) { + let mut check = tidy_ctx.start_check("extra_checks:cpp_fmt"); + + let bless = tidy_ctx.is_bless_enabled(); + + let mut cfg_args_clang_format = cfg_args.clone(); + let mut file_args_clang_format = file_args.clone(); + let config_path = root_path.join(".clang-format"); + let mut config_file_arg = OsString::from("file:"); + config_file_arg.push(&config_path); + cfg_args_clang_format.extend(&["--style".as_ref(), config_file_arg.as_ref()]); + if bless { + eprintln!("formatting C++ files"); + cfg_args_clang_format.push("-i".as_ref()); + } else { + eprintln!("checking C++ file formatting"); + cfg_args_clang_format.extend(&["--dry-run".as_ref(), "--Werror".as_ref()]); + } + let files; + if file_args_clang_format.is_empty() { + let llvm_wrapper = root_path.join("compiler/rustc_llvm/llvm-wrapper"); + match find_with_extension( + root_path, + Some(llvm_wrapper.as_path()), + &[OsStr::new("h"), OsStr::new("cpp")], + ) { + Ok(f) => files = f, + Err(e) => { + check.error(e); + return; + } } - let files; - if file_args_clang_format.is_empty() { - let llvm_wrapper = root_path.join("compiler/rustc_llvm/llvm-wrapper"); - files = find_with_extension( - root_path, - Some(llvm_wrapper.as_path()), - &[OsStr::new("h"), OsStr::new("cpp")], - )?; - file_args_clang_format.extend(files.iter().map(|p| p.as_os_str())); - } - let args = merge_args(&cfg_args_clang_format, &file_args_clang_format); - let res = py_runner(py_path.as_ref().unwrap(), false, None, "clang-format", &args); + file_args_clang_format.extend(files.iter().map(|p| p.as_os_str())); + } + let args = merge_args(&cfg_args_clang_format, &file_args_clang_format); + let res = py_runner(py_path, false, None, "clang-format", &args); - if res.is_err() && show_diff && !bless { - eprintln!("\nclang-format linting failed! Printing diff suggestions:"); + if res.is_err() && !bless && show_diff() { + eprintln!("\nclang-format linting failed! Printing diff suggestions:"); - let mut cfg_args_clang_format_diff = cfg_args.clone(); - cfg_args_clang_format_diff.extend(&["--style".as_ref(), config_file_arg.as_ref()]); - for file in file_args_clang_format { - let mut formatted = String::new(); - let mut diff_args = cfg_args_clang_format_diff.clone(); - diff_args.push(file); - let _ = py_runner( - py_path.as_ref().unwrap(), - false, - Some(&mut formatted), - "clang-format", - &diff_args, + let mut cfg_args_diff = cfg_args.clone(); + cfg_args_diff.extend(&["--style".as_ref(), config_file_arg.as_ref()]); + for file in file_args { + let mut formatted = String::new(); + let mut diff_args = cfg_args_diff.clone(); + diff_args.push(file); + let _ = py_runner(py_path, false, Some(&mut formatted), "clang-format", &diff_args); + if formatted.is_empty() { + eprintln!( + "failed to obtain the formatted content for '{}'", + file.to_string_lossy() ); - if formatted.is_empty() { - eprintln!( - "failed to obtain the formatted content for '{}'", - file.to_string_lossy() - ); - continue; - } - let actual = std::fs::read_to_string(file).unwrap_or_else(|e| { - panic!( - "failed to read the C++ file at '{}' due to '{e}'", - file.to_string_lossy() + continue; + } + let actual = std::fs::read_to_string(file).unwrap_or_else(|e| { + panic!("failed to read the C++ file at '{}' due to '{e}'", file.to_string_lossy()) + }); + if formatted != actual { + let diff = similar::TextDiff::from_lines(&actual, &formatted); + eprintln!( + "{}", + diff.unified_diff().context_radius(4).header( + &format!("{} (actual)", file.to_string_lossy()), + &format!("{} (formatted)", file.to_string_lossy()) ) - }); - if formatted != actual { - let diff = similar::TextDiff::from_lines(&actual, &formatted); - eprintln!( - "{}", - diff.unified_diff().context_radius(4).header( - &format!("{} (actual)", file.to_string_lossy()), - &format!("{} (formatted)", file.to_string_lossy()) - ) - ); - } + ); } - rerun_with_bless("cpp:fmt", "reformat C++ code"); } - // Rethrow error - res?; + show_bless_help("cpp:fmt", "reformat C++ code", bless); } - if shell_lint { - eprintln!("linting shell files"); - - let mut file_args_shc = file_args.clone(); - let files; - if file_args_shc.is_empty() { - files = find_with_extension(root_path, None, &[OsStr::new("sh")])?; - file_args_shc.extend(files.iter().map(|p| p.as_os_str())); - } - - shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?; + if let Err(e) = res { + check.error(e); } - - if spellcheck { - let config_path = root_path.join("typos.toml"); - let mut args = vec!["-c", config_path.as_os_str().to_str().unwrap()]; - - args.extend_from_slice(SPELLCHECK_DIRS); - - if bless { - eprintln!("spellchecking files and fixing typos"); - args.push("--write-changes"); - } else { - eprintln!("spellchecking files"); - } - let res = spellcheck_runner(root_path, &outdir, &cargo, &args, tidy_ctx.is_running_on_ci()); - if res.is_err() { - rerun_with_bless("spellcheck", "fix typos"); - } - res?; - } - - if js_lint || js_typecheck { - rustdoc_js::npm_install(root_path, outdir, npm)?; - } - - if js_lint { - if bless { - eprintln!("linting javascript files and applying suggestions"); - } else { - eprintln!("linting javascript files"); - } - let res = rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless); - if res.is_err() { - rerun_with_bless("js:lint", "apply eslint suggestions"); - } - res?; - rustdoc_js::es_check(outdir, librustdoc_path)?; - } - - if js_typecheck { - eprintln!("typechecking javascript files"); - rustdoc_js::typecheck(outdir, librustdoc_path)?; - } - - Ok(()) } fn run_ruff( diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index d889a1c0c034..f382502c7068 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -927,7 +927,6 @@ ui/dst/issue-90528-unsizing-suggestion-3.rs ui/dst/issue-90528-unsizing-suggestion-4.rs ui/dyn-keyword/issue-5153.rs ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs -ui/empty/issue-37026.rs ui/enum-discriminant/auxiliary/issue-41394.rs ui/enum-discriminant/issue-104519.rs ui/enum-discriminant/issue-41394-rpass.rs @@ -1359,7 +1358,6 @@ ui/infinite/issue-41731-infinite-macro-print.rs ui/infinite/issue-41731-infinite-macro-println.rs ui/intrinsics/issue-28575.rs ui/intrinsics/issue-84297-reifying-copy.rs -ui/invalid/issue-114435-layout-type-err.rs ui/iterators/issue-28098.rs ui/iterators/issue-58952-filter-type-length.rs ui/lang-items/issue-83471.rs @@ -1477,7 +1475,6 @@ ui/lint/issue-97094.rs ui/lint/issue-99387.rs ui/lint/let_underscore/issue-119696-err-on-fn.rs ui/lint/let_underscore/issue-119697-extra-let.rs -ui/lint/must_not_suspend/issue-89562.rs ui/lint/unused/issue-103320-must-use-ops.rs ui/lint/unused/issue-104397.rs ui/lint/unused/issue-105061-array-lint.rs @@ -1706,9 +1703,6 @@ ui/mismatched_types/issue-47706.rs ui/mismatched_types/issue-74918-missing-lifetime.rs ui/mismatched_types/issue-75361-mismatched-impl.rs ui/mismatched_types/issue-84976.rs -ui/missing-trait-bounds/auxiliary/issue-69725.rs -ui/missing-trait-bounds/issue-35677.rs -ui/missing-trait-bounds/issue-69725.rs ui/modules/auxiliary/issue-13872-1.rs ui/modules/auxiliary/issue-13872-2.rs ui/modules/auxiliary/issue-13872-3.rs @@ -2284,8 +2278,6 @@ ui/recursion/issue-38591-non-regular-dropck-recursion.rs ui/recursion/issue-83150.rs ui/recursion/issue-86784.rs ui/recursion/issue-95134.rs -ui/recursion_limit/issue-105700.rs -ui/recursion_limit/issue-40003.rs ui/regions/issue-101280.rs ui/regions/issue-102374.rs ui/regions/issue-102392.rs diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 2cb8df782d28..292808b90cbf 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -104,6 +104,7 @@ pub fn files_modified( pub mod alphabetical; pub mod arg_parser; pub mod bins; +pub mod codegen; pub mod debug_artifacts; pub mod deps; pub mod diagnostics; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 0e9885138d1e..1b5baf2a2197 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -109,6 +109,7 @@ macro_rules! check { check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path]); check!(target_policy, &root_path); check!(gcc_submodule, &root_path, &compiler_path); + check!(codegen, &compiler_path); // Checks that only make sense for the std libs. check!(pal, &library_path); diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 111fe89e7eb0..77c15672e002 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -227,8 +227,6 @@ fn should_ignore(line: &str) -> bool { /// Returns `true` if `line` is allowed to be longer than the normal limit. fn long_line_is_ok(extension: &str, is_error_code: bool, max_columns: usize, line: &str) -> bool { match extension { - // fluent files are allowed to be any length - "ftl" => true, // non-error code markdown is allowed to be any length "md" if !is_error_code => true, // HACK(Ezrashaw): there is no way to split a markdown header over multiple lines @@ -357,7 +355,7 @@ fn skip(path: &Path, is_dir: bool) -> bool { return false; } - let extensions = ["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "goml"]; + let extensions = ["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "goml"]; // NB: don't skip paths without extensions (or else we'll skip all directories and will only check top level files) if path.extension().is_none_or(|ext| !extensions.iter().any(|e| ext == OsStr::new(e))) { @@ -378,6 +376,7 @@ fn skip(path: &Path, is_dir: bool) -> bool { // In some cases, a style check would be triggered by its own implementation // or comments. A simple workaround is to just allowlist this file. let this_file = Path::new(file!()); + let codegen_file = Path::new("src/tools/tidy/src/codegen.rs"); walk(path, skip, &mut |entry, contents| { let file = entry.path(); @@ -449,6 +448,7 @@ fn skip(path: &Path, is_dir: bool) -> bool { let is_this_file = file.ends_with(this_file) || this_file.ends_with(file); let is_test_for_this_file = is_test && file.parent().unwrap().ends_with(this_file.with_extension("")); + let is_codegen_tidy_file = file.ends_with(codegen_file); // scanning the whole file for multiple needles at once is more efficient than // executing lines times needles separate searches. let any_problematic_line = @@ -516,7 +516,7 @@ fn skip(path: &Path, is_dir: bool) -> bool { if line.contains('\r') { suppressible_tidy_err!(err, skip_cr, "CR character"); } - if !is_this_file { + if !is_this_file && !is_codegen_tidy_file { let directive_line_starts = ["// ", "# ", "/* ", " replaced | LL | Type::bar(); - | ^^^ function or associated item not found in `dep_2_reexport::Type` + | ^^^ associated function or constant not found in `dep_2_reexport::Type` | note: there are multiple different versions of crate `dependency` in the dependency graph --> replaced @@ -177,14 +177,14 @@ LL | Err(Error2)?; | this can't be annotated with `?` because it has type `Result<_, Error2>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait -help: the following other types implement trait `From` +help: `dependency::OtherError` implements trait `From` --> replaced | LL | impl From<()> for OtherError { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dependency::OtherError` implements `From<()>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `From<()>` ... LL | impl From for OtherError { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dependency::OtherError` implements `From` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `From` = note: there are multiple different versions of crate `dependency` in the dependency graph = help: you can use `cargo tree` to explore your dependency tree diff --git a/tests/run-make/emit-shared-files/rmake.rs b/tests/run-make/emit-shared-files/rmake.rs index bd868d4fd19e..9841dce27fa2 100644 --- a/tests/run-make/emit-shared-files/rmake.rs +++ b/tests/run-make/emit-shared-files/rmake.rs @@ -34,7 +34,7 @@ fn main() { rustdoc() .arg("-Zunstable-options") - .arg("--emit=toolchain-shared-resources") + .arg("--emit=html-static-files") .out_dir("toolchain-only") .arg("--resource-suffix=-xxx") .args(&["--extend-css", "z.css"]) @@ -68,7 +68,7 @@ fn main() { rustdoc() .arg("-Zunstable-options") - .arg("--emit=toolchain-shared-resources") + .arg("--emit=html-static-files") .out_dir("all-shared") .arg("--resource-suffix=-xxx") .args(&["--extend-css", "z.css"]) diff --git a/tests/run-make/incremental-finalize-fail/foo.rs b/tests/run-make/incremental-finalize-fail/foo.rs new file mode 100644 index 000000000000..1f1e2842b465 --- /dev/null +++ b/tests/run-make/incremental-finalize-fail/foo.rs @@ -0,0 +1,5 @@ +poison::poison_finalize!(); + +pub fn hello() -> i32 { + 42 +} diff --git a/tests/run-make/incremental-finalize-fail/poison/lib.rs b/tests/run-make/incremental-finalize-fail/poison/lib.rs new file mode 100644 index 000000000000..e191cf7ade4c --- /dev/null +++ b/tests/run-make/incremental-finalize-fail/poison/lib.rs @@ -0,0 +1,87 @@ +//! A proc macro that sabotages the incremental compilation finalize step. +//! +//! When invoked, it locates the `-working` session directory inside the +//! incremental compilation directory (passed via POISON_INCR_DIR) and +//! makes it impossible to rename: +//! +//! - On Unix: removes write permission from the parent (crate) directory. +//! - On Windows: creates a file inside the -working directory and leaks +//! the file handle, preventing the directory from being renamed. + +extern crate proc_macro; + +use std::fs; +use std::path::PathBuf; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn poison_finalize(_input: TokenStream) -> TokenStream { + let incr_dir = std::env::var("POISON_INCR_DIR").expect("POISON_INCR_DIR must be set"); + + let crate_dir = find_crate_dir(&incr_dir); + let working_dir = find_working_dir(&crate_dir); + + #[cfg(unix)] + poison_unix(&crate_dir); + + #[cfg(windows)] + poison_windows(&working_dir); + + TokenStream::new() +} + +/// Remove write permission from the crate directory. +/// This causes rename() to fail with EACCES +#[cfg(unix)] +fn poison_unix(crate_dir: &PathBuf) { + use std::os::unix::fs::PermissionsExt; + let mut perms = fs::metadata(crate_dir).unwrap().permissions(); + perms.set_mode(0o555); // r-xr-xr-x + fs::set_permissions(crate_dir, perms).unwrap(); +} + +/// Create a file inside the -working directory and leak the +/// handle. Windows prevents renaming a directory when any file inside it +/// has an open handle. The handle stays open until the rustc process exits. +#[cfg(windows)] +fn poison_windows(working_dir: &PathBuf) { + let poison_file = working_dir.join("_poison_handle"); + let f = fs::File::create(&poison_file).unwrap(); + // Leak the handle so it stays open for the lifetime of the rustc process. + std::mem::forget(f); +} + +/// Find the crate directory for `foo` inside the incremental compilation dir. +/// +/// The incremental directory layout is: +/// {incr_dir}/{crate_name}-{stable_crate_id}/ +fn find_crate_dir(incr_dir: &str) -> PathBuf { + let mut dirs = fs::read_dir(incr_dir).unwrap().filter_map(|e| { + let e = e.ok()?; + let name = e.file_name(); + let name = name.to_str()?; + if e.file_type().ok()?.is_dir() && name.starts_with("foo-") { Some(e.path()) } else { None } + }); + + let first = + dirs.next().unwrap_or_else(|| panic!("no foo-* crate directory found in {incr_dir}")); + assert!( + dirs.next().is_none(), + "expected exactly one foo-* crate directory in {incr_dir}, found multiple" + ); + first +} + +/// Find the session directory ending in "-working" inside the crate directory +fn find_working_dir(crate_dir: &PathBuf) -> PathBuf { + for entry in fs::read_dir(crate_dir).unwrap() { + let entry = entry.unwrap(); + let name = entry.file_name(); + let name = name.to_str().unwrap().to_string(); + if name.starts_with("s-") && name.ends_with("-working") { + return entry.path(); + } + } + panic!("no -working session directory found in {}", crate_dir.display()); +} diff --git a/tests/run-make/incremental-finalize-fail/rmake.rs b/tests/run-make/incremental-finalize-fail/rmake.rs new file mode 100644 index 000000000000..96dae4856ca0 --- /dev/null +++ b/tests/run-make/incremental-finalize-fail/rmake.rs @@ -0,0 +1,106 @@ +//@ ignore-cross-compile +//@ needs-crate-type: proc-macro + +//! Test that a failure to finalize the incremental compilation session directory +//! (i.e., the rename from "-working" to the SVH-based name) results in a +//! note, not an ICE, and that the compilation output is still produced. +//! +//! Strategy: +//! 1. Build the `poison` proc-macro crate +//! 2. Compile foo.rs with incremental compilation +//! The proc macro runs mid-compilation (after prepare_session_directory +//! but before finalize_session_directory) and sabotages the rename: +//! - On Unix: removes write permission from the crate directory, +//! so rename() fails with EACCES. +//! - On Windows: creates and leaks an open file handle inside the +//! -working directory, so rename() fails with ERROR_ACCESS_DENIED. +//! 3. Assert that stderr contains the finalize failure messages + +use std::fs; +use std::path::{Path, PathBuf}; + +use run_make_support::rustc; + +/// Guard that restores permissions on the incremental directory on drop, +/// to ensure cleanup is possible +struct IncrDirCleanup; + +fn main() { + let _cleanup = IncrDirCleanup; + + // Build the poison proc-macro crate + rustc().input("poison/lib.rs").crate_name("poison").crate_type("proc-macro").run(); + + let poison_dylib = find_proc_macro_dylib("poison"); + + // Incremental compile with the poison macro active + let out = rustc() + .input("foo.rs") + .crate_type("rlib") + .incremental("incr") + .extern_("poison", &poison_dylib) + .env("POISON_INCR_DIR", "incr") + .run(); + + out.assert_stderr_contains("note: did not finalize incremental compilation session directory"); + out.assert_stderr_contains( + "help: the next build will not be able to reuse work from this compilation", + ); + out.assert_stderr_not_contains("internal compiler error"); +} + +impl Drop for IncrDirCleanup { + fn drop(&mut self) { + let incr = Path::new("incr"); + if !incr.exists() { + return; + } + + #[cfg(unix)] + restore_permissions(incr); + } +} + +/// Recursively restore write permissions so rm -rf works after the chmod trick +#[cfg(unix)] +fn restore_permissions(path: &Path) { + use std::os::unix::fs::PermissionsExt; + if let Ok(entries) = fs::read_dir(path) { + for entry in entries.filter_map(|e| e.ok()) { + if entry.file_type().map_or(false, |ft| ft.is_dir()) { + let mut perms = match fs::metadata(entry.path()) { + Ok(m) => m.permissions(), + Err(_) => continue, + }; + perms.set_mode(0o755); + let _ = fs::set_permissions(entry.path(), perms); + } + } + } +} + +/// Locate the compiled proc-macro dylib by scanning the current directory. +fn find_proc_macro_dylib(name: &str) -> PathBuf { + let prefix = if cfg!(target_os = "windows") { "" } else { "lib" }; + + let ext: &str = if cfg!(target_os = "macos") { + "dylib" + } else if cfg!(target_os = "windows") { + "dll" + } else { + "so" + }; + + let lib_name = format!("{prefix}{name}.{ext}"); + + for entry in fs::read_dir(".").unwrap() { + let entry = entry.unwrap(); + let name = entry.file_name(); + let name = name.to_str().unwrap(); + if name == lib_name { + return entry.path(); + } + } + + panic!("could not find proc-macro dylib for `{name}`"); +} diff --git a/tests/run-make/instrument-mcount-link-pg/main.rs b/tests/run-make/instrument-mcount-link-pg/main.rs new file mode 100644 index 000000000000..47ad8c634112 --- /dev/null +++ b/tests/run-make/instrument-mcount-link-pg/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello World!"); +} diff --git a/tests/run-make/instrument-mcount-link-pg/rmake.rs b/tests/run-make/instrument-mcount-link-pg/rmake.rs new file mode 100644 index 000000000000..184bd9429bfd --- /dev/null +++ b/tests/run-make/instrument-mcount-link-pg/rmake.rs @@ -0,0 +1,19 @@ +// When building a binary instrumented with mcount, verify the +// binary is linked with the correct crt to enable profiling. +// +//@ only-gnu +//@ ignore-cross-compile + +use run_make_support::{path, run, rustc}; + +fn main() { + // Compile instrumentation enabled binary, and verify -pg is passed + let link_args = + rustc().input("main.rs").arg("-Zinstrument-mcount").print("link-args").run().stdout_utf8(); + assert!(link_args.contains("\"-pg\"")); + + // Run it, and verify gmon.out is created + assert!(!path("gmon.out").exists()); + run("main"); + assert!(path("gmon.out").exists()); +} diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs index 2ac5fdee063c..1d06fe118e06 100644 --- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs @@ -32,6 +32,7 @@ fn main() { .opt_level("2") .linker(&env_var("CLANG")) .link_arg("-fuse-ld=lld") + .arg("-Cunsafe-allow-abi-mismatch=branch-protection") .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf") .input("test.rs") .output("test.bin") diff --git a/tests/run-make/pointer-auth-link-with-c/rmake.rs b/tests/run-make/pointer-auth-link-with-c/rmake.rs index 1ddcb79d64ff..1ac68c95559c 100644 --- a/tests/run-make/pointer-auth-link-with-c/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c/rmake.rs @@ -15,7 +15,11 @@ fn main() { build_native_static_lib("test"); - rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run(); + rustc() + .arg("-Cunsafe-allow-abi-mismatch=branch-protection") + .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf") + .input("test.rs") + .run(); run("test"); cc().arg("-v") .arg("-c") @@ -25,7 +29,11 @@ fn main() { .run(); let obj_file = if is_windows_msvc() { "test.obj" } else { "test" }; llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run(); - rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run(); + rustc() + .arg("-Cunsafe-allow-abi-mismatch=branch-protection") + .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf") + .input("test.rs") + .run(); run("test"); // FIXME: +pc was only recently added to LLVM @@ -37,6 +45,10 @@ fn main() { // .run(); // let obj_file = if is_windows_msvc() { "test.obj" } else { "test" }; // llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run(); - // rustc().arg("-Zbranch-protection=bti,pac-ret,pc,leaf").input("test.rs").run(); + // rustc() + // .arg("-Cunsafe-allow-abi-mismatch=branch-protection") + // .arg("-Zbranch-protection=bti,pac-ret,pc,leaf") + // .input("test.rs") + // .run(); // run("test"); } diff --git a/tests/run-make/raw-dylib-elf/library.c b/tests/run-make/raw-dylib-elf/library.c index 2e3a95b7edec..060cab6ee02f 100644 --- a/tests/run-make/raw-dylib-elf/library.c +++ b/tests/run-make/raw-dylib-elf/library.c @@ -1,3 +1,8 @@ +int global_variable = 3; +__thread int tls_variable = 33; +const long const_array[] = {795, 906}; +const char *const_string = "sums of three cubes"; + int this_is_a_library_function() { return 42; } diff --git a/tests/run-make/raw-dylib-elf/main.rs b/tests/run-make/raw-dylib-elf/main.rs index 3be944d29514..b55cde766a37 100644 --- a/tests/run-make/raw-dylib-elf/main.rs +++ b/tests/run-make/raw-dylib-elf/main.rs @@ -1,11 +1,29 @@ #![feature(raw_dylib_elf)] +#![feature(thread_local)] #![allow(incomplete_features)] +use std::ffi::{CStr, c_char, c_int, c_long}; + #[link(name = "library", kind = "raw-dylib")] unsafe extern "C" { - safe fn this_is_a_library_function() -> core::ffi::c_int; + safe fn this_is_a_library_function() -> c_int; + static mut global_variable: c_int; + #[thread_local] + static mut tls_variable: c_int; + safe static const_array: [c_long; 2]; + safe static const_string: *const c_char; } fn main() { - println!("{}", this_is_a_library_function()) + unsafe { + println!( + "{} {} {} {} {} {}", + this_is_a_library_function(), + global_variable, + tls_variable, + const_array[0], + const_array[1], + CStr::from_ptr(const_string).to_str().unwrap(), + ); + } } diff --git a/tests/run-make/raw-dylib-elf/output.txt b/tests/run-make/raw-dylib-elf/output.txt index d81cc0710eb6..6a9770dcb39b 100644 --- a/tests/run-make/raw-dylib-elf/output.txt +++ b/tests/run-make/raw-dylib-elf/output.txt @@ -1 +1 @@ -42 +42 3 33 795 906 sums of three cubes diff --git a/tests/run-make/raw-dylib-elf/rmake.rs b/tests/run-make/raw-dylib-elf/rmake.rs index 59f901ac1ed7..d8a10fcb7f83 100644 --- a/tests/run-make/raw-dylib-elf/rmake.rs +++ b/tests/run-make/raw-dylib-elf/rmake.rs @@ -11,19 +11,27 @@ use run_make_support::{build_native_dynamic_lib, cwd, diff, run, rustc}; fn main() { - // We compile the binary without having the library present. + // We compile the binaries without having the library present with different relocation + // models. // We also set the rpath to the current directory so we can pick up the library at runtime. - rustc() - .crate_type("bin") - .input("main.rs") - .arg(&format!("-Wl,-rpath={}", cwd().display())) - .run(); + let relocation_models = ["static", "pic", "pie"]; + for relocation_model in relocation_models { + rustc() + .crate_type("bin") + .input("main.rs") + .arg(&format!("-Wl,-rpath={}", cwd().display())) + .arg(&format!("-Crelocation-model={}", relocation_model)) + .output(&format!("main-{}", relocation_model)) + .run(); + } - // Now, *after* building the binary, we build the library... + // Now, *after* building the binaries, we build the library... build_native_dynamic_lib("library"); - // ... and run with this library, ensuring it was linked correctly at runtime. - let output = run("main").stdout_utf8(); - - diff().expected_file("output.txt").actual_text("actual", output).run(); + for relocation_model in relocation_models { + // ... and run with this library, ensuring it was linked correctly at runtime. + // The output here should be the same regardless of the relocation model. + let output = run(&format!("main-{}", relocation_model)).stdout_utf8(); + diff().expected_file("output.txt").actual_text("actual", output).run(); + } } diff --git a/tests/run-make/repr128-dwarf/main.rs b/tests/run-make/repr128-dwarf/main.rs index a8a414fd72e4..a50c950a0c40 100644 --- a/tests/run-make/repr128-dwarf/main.rs +++ b/tests/run-make/repr128-dwarf/main.rs @@ -17,7 +17,6 @@ pub enum I128Enum { I128D = i128::MAX.to_le(), } -#[cfg(not(old_llvm))] #[repr(u128)] pub enum U128VariantEnum { VariantU128A(u8) = 0_u128.to_le(), @@ -26,7 +25,6 @@ pub enum U128VariantEnum { VariantU128D = u128::MAX.to_le(), } -#[cfg(not(old_llvm))] #[repr(i128)] pub enum I128VariantEnum { VariantI128A(u8) = 0_i128.to_le(), @@ -37,13 +35,9 @@ pub enum I128VariantEnum { pub fn f(_: U128Enum, _: I128Enum) {} -#[cfg(not(old_llvm))] pub fn g(_: U128VariantEnum, _: I128VariantEnum) {} fn main() { f(U128Enum::U128A, I128Enum::I128A); - #[cfg(not(old_llvm))] - { - g(U128VariantEnum::VariantU128A(1), I128VariantEnum::VariantI128A(2)); - } + g(U128VariantEnum::VariantU128A(1), I128VariantEnum::VariantI128A(2)); } diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index 96c65d7d8977..38c69d510733 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -13,25 +13,8 @@ use run_make_support::{gimli, object, rfs, rustc}; fn main() { - // Before LLVM 20, 128-bit enums with variants didn't emit debuginfo correctly. - // This check can be removed once Rust no longer supports LLVM 18 and 19. - let llvm_version = rustc() - .verbose() - .arg("--version") - .run() - .stdout_utf8() - .lines() - .filter_map(|line| line.strip_prefix("LLVM version: ")) - .map(|version| version.split(".").next().unwrap().parse::().unwrap()) - .next() - .unwrap(); - let is_old_llvm = llvm_version < 20; - let output = PathBuf::from("repr128"); let mut rustc = rustc(); - if is_old_llvm { - rustc.cfg("old_llvm"); - } rustc.input("main.rs").output(&output).arg("-Cdebuginfo=2").run(); // Mach-O uses packed debug info let dsym_location = output @@ -88,7 +71,7 @@ fn main() { while let Some((_, entry)) = cursor.next_dfs().unwrap() { match entry.tag() { - gimli::constants::DW_TAG_variant if !is_old_llvm => { + gimli::constants::DW_TAG_variant => { let Some(value) = entry.attr(gimli::constants::DW_AT_discr_value).unwrap() else { // `std` enums might have variants without `DW_AT_discr_value`. @@ -143,7 +126,7 @@ fn main() { if !enumerators_to_find.is_empty() { panic!("Didn't find debug enumerator entries for {enumerators_to_find:?}"); } - if !is_old_llvm && !variants_to_find.is_empty() { + if !variants_to_find.is_empty() { panic!("Didn't find debug variant entries for {variants_to_find:?}"); } } diff --git a/tests/run-make/rustdoc-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout index 4e28be347cbb..bc3a67a1ebcd 100644 --- a/tests/run-make/rustdoc-default-output/output-default.stdout +++ b/tests/run-make/rustdoc-default-output/output-default.stdout @@ -150,7 +150,7 @@ Options: --generate-redirect-map Generate JSON file at the top level instead of generating HTML redirection files - --emit [toolchain-shared-resources,invocation-specific,dep-info] + --emit [html-static-files,html-non-static-files,dep-info] Comma separated list of types of output for rustdoc to emit --no-run Compile doctests without running them diff --git a/tests/run-make/target-cpu-native/foo.rs b/tests/run-make/target-cpu-native/foo.rs index f328e4d9d04c..5abcd25abc3f 100644 --- a/tests/run-make/target-cpu-native/foo.rs +++ b/tests/run-make/target-cpu-native/foo.rs @@ -1 +1,9 @@ fn main() {} + +// This forces explicit emission of a +neon target feature on targets +// where it is implied by the target-cpu, like aarch64-apple-darwin. +// This is a regression test for #153397. +#[cfg(target_feature = "neon")] +#[target_feature(enable = "neon")] +#[unsafe(no_mangle)] +pub fn with_neon() {} diff --git a/tests/run-make/target-cpu-native/rmake.rs b/tests/run-make/target-cpu-native/rmake.rs index 7b7974f30978..5791bf01bba2 100644 --- a/tests/run-make/target-cpu-native/rmake.rs +++ b/tests/run-make/target-cpu-native/rmake.rs @@ -8,7 +8,12 @@ use run_make_support::{run, rustc}; fn main() { - let out = rustc().input("foo.rs").arg("-Ctarget-cpu=native").run().stderr_utf8(); + let out = rustc() + .input("foo.rs") + .arg("-Ctarget-cpu=native") + .arg("-Zverify-llvm-ir") + .run() + .stderr_utf8(); run("foo"); // There should be zero warnings emitted - the bug would cause "unknown CPU `native`" // to be printed out. diff --git a/tests/rustdoc-gui/item-info-overflow.goml b/tests/rustdoc-gui/item-info-overflow.goml index 2c4e06e297c7..b53ffb00f1c3 100644 --- a/tests/rustdoc-gui/item-info-overflow.goml +++ b/tests/rustdoc-gui/item-info-overflow.goml @@ -8,7 +8,7 @@ assert-property: (".item-info", {"scrollWidth": "940"}) // Just to be sure we're comparing the correct "item-info": assert-text: ( ".item-info", - "Available on Android or Linux or Emscripten or DragonFly BSD", + "Available on Android or Linux or Emscripten or DragonFly BSD or FreeBSD or NetBSD or OpenBSD", STARTS_WITH, ) @@ -26,6 +26,6 @@ assert-property: ( // Just to be sure we're comparing the correct "item-info": assert-text: ( "#impl-SimpleTrait-for-LongItemInfo2 .item-info", - "Available on Android or Linux or Emscripten or DragonFly BSD", + "Available on Android or Linux or Emscripten or DragonFly BSD or FreeBSD or NetBSD or OpenBSD", STARTS_WITH, ) diff --git a/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs b/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs index c79d07ff5bd7..96cc612b597c 100644 --- a/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs +++ b/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs @@ -3,7 +3,6 @@ // https://github.com/rust-lang/rust/issues/20646 #![crate_name="issue_20646"] -#![feature(associated_types)] extern crate issue_20646; diff --git a/tests/rustdoc-html/deprecated.rs b/tests/rustdoc-html/deprecated.rs index a84657a3df5a..c7db816cffcf 100644 --- a/tests/rustdoc-html/deprecated.rs +++ b/tests/rustdoc-html/deprecated.rs @@ -30,3 +30,8 @@ // 'Deprecated: shorthand reason: code$' #[deprecated = "shorthand reason: `code`"] pub struct X; + +//@ matches deprecated/struct.Y.html '//*[@class="stab deprecated"]//p[1]' 'multiple' +//@ matches deprecated/struct.Y.html '//*[@class="stab deprecated"]//p[2]' 'paragraphs' +#[deprecated = "multiple\n\nparagraphs"] +pub struct Y; diff --git a/tests/rustdoc-html/doc-cfg/all-targets.rs b/tests/rustdoc-html/doc-cfg/all-targets.rs new file mode 100644 index 000000000000..4db41e1f8344 --- /dev/null +++ b/tests/rustdoc-html/doc-cfg/all-targets.rs @@ -0,0 +1,139 @@ +#![feature(doc_cfg)] + +//@ has all_targets/fn.foo.html \ +// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available on GNU or Catalyst or mac ABI or MSVC or musl or Newlib or \ +// Neutrino 7.0 or Neutrino 7.1 or Neutrino 7.1 with io-sock or Neutrino 8.0 or \ +// OpenHarmony or relibc or SGX or Simulator or WASIp1 or WASIp2 or WASIp3 or \ +// uClibc or V5 or target_env=fake_env only.' +#[doc(cfg(any( + target_env = "gnu", + target_env = "macabi", + target_env = "mlibc", + target_env = "msvc", + target_env = "musl", + target_env = "newlib", + target_env = "nto70", + target_env = "nto71", + target_env = "nto71_iosock", + target_env = "nto80", + target_env = "ohos", + target_env = "relibc", + target_env = "sgx", + target_env = "sim", + target_env = "p1", + target_env = "p2", + target_env = "p3", + target_env = "uclibc", + target_env = "v5", + target_env = "fake_env", +)))] +pub fn foo() {} + +//@ has all_targets/fn.bar.html \ +// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available on AArch64 or AMG GPU or ARM or ARM64EC or AVR or BPF or C-SKY or \ +// Hexagon or LoongArch64 or LoongArch32 or Motorola 680x0 or MIPS or MIPS release \ +// 6 or MIPS-64 or MIPS-64 release 6 or MSP430 or NVidia GPU or PowerPC or \ +// PowerPC64 or RISC-V RV32 or RISC-V RV64 or s390x or SPARC or SPARC-64 or SPIR-V \ +// or WebAssembly or WebAssembly or x86 or x86-64 or Xtensa or \ +// target_arch=fake_arch only.' +#[doc(cfg(any( + target_arch = "aarch64", + target_arch = "amdgpu", + target_arch = "arm", + target_arch = "arm64ec", + target_arch = "avr", + target_arch = "bpf", + target_arch = "csky", + target_arch = "hexagon", + target_arch = "loongarch32", + target_arch = "loongarch64", + target_arch = "m68k", + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "msp430", + target_arch = "nvptx64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "s390x", + target_arch = "sparc", + target_arch = "sparc64", + target_arch = "spirv", + target_arch = "wasm32", + target_arch = "wasm64", + target_arch = "x86", + target_arch = "x86_64", + target_arch = "xtensa", + target_arch = "fake_arch", +)))] +pub fn bar() {} + +//@ has all_targets/fn.baz.html \ +// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available on AIX and AMD HSA and Android and CUDA and Cygwin and DragonFly \ +// BSD and Emscripten and ESP-IDF and FreeBSD and Fuchsia and Haiku and HelenOS \ +// and Hermit and Horizon and GNU/Hurd and illumos and iOS and L4Re and Linux \ +// and LynxOS-178 and macOS and Managarm and Motor OS and NetBSD and bare-metal \ +// and QNX Neutrino and NuttX and OpenBSD and Play Station Portable and Play \ +// Station 1 and QuRT and Redox OS and RTEMS OS and Solaris and SOLID ASP3 and \ +// TEEOS and Trusty and tvOS and UEFI and VEXos and visionOS and Play Station \ +// Vita and VxWorks and WASI and watchOS and Windows and Xous and zero knowledge \ +// Virtual Machine and target_os=unknown and target_os=fake_os only.' +#[doc(cfg(all( + target_os = "aix", + target_os = "amdhsa", + target_os = "android", + target_os = "cuda", + target_os = "cygwin", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "espidf", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "helenos", + target_os = "hermit", + target_os = "horizon", + target_os = "hurd", + target_os = "illumos", + target_os = "ios", + target_os = "l4re", + target_os = "linux", + target_os = "lynxos178", + target_os = "macos", + target_os = "managarm", + target_os = "motor", + target_os = "netbsd", + target_os = "none", + target_os = "nto", + target_os = "nuttx", + target_os = "openbsd", + target_os = "psp", + target_os = "psx", + target_os = "qurt", + target_os = "redox", + target_os = "rtems", + target_os = "solaris", + target_os = "solid_asp3", + target_os = "teeos", + target_os = "trusty", + target_os = "tvos", + target_os = "uefi", + target_os = "vexos", + target_os = "visionos", + target_os = "vita", + target_os = "vxworks", + target_os = "wasi", + target_os = "watchos", + target_os = "windows", + target_os = "xous", + target_os = "zkvm", + target_os = "unknown", + target_os = "fake_os", +)))] +pub fn baz() {} diff --git a/tests/rustdoc-html/doc-cfg/doc-cfg.rs b/tests/rustdoc-html/doc-cfg/doc-cfg.rs index 652c8419b4fb..ba2a8de5b29e 100644 --- a/tests/rustdoc-html/doc-cfg/doc-cfg.rs +++ b/tests/rustdoc-html/doc-cfg/doc-cfg.rs @@ -1,5 +1,4 @@ #![feature(doc_cfg)] -#![feature(target_feature, cfg_target_feature)] //@ has doc_cfg/struct.Portable.html //@ !has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' '' diff --git a/tests/rustdoc-html/doc-cfg/trait-impls-manual.rs b/tests/rustdoc-html/doc-cfg/trait-impls-manual.rs new file mode 100644 index 000000000000..fbd96cc46d80 --- /dev/null +++ b/tests/rustdoc-html/doc-cfg/trait-impls-manual.rs @@ -0,0 +1,92 @@ +// This test ensures that `doc_cfg` feature is working as expected on trait impls. +// Regression test for . + +#![feature(doc_cfg)] +#![doc(auto_cfg(hide( + target_pointer_width = "64", +)))] + +#![crate_name = "foo"] + +pub trait Trait { + fn f(&self) {} +} + +pub trait Bob { + fn bob(&self) {} +} + +pub trait Foo { + fn foo(&self) {} +} + +pub struct X; + +//@has 'foo/struct.X.html' +//@count - '//*[@id="impl-Bob-for-X"]' 1 +//@count - '//*[@id="impl-Bob-for-X"]/*[@class="item-info"]' 0 +//@count - '//*[@id="impl-Trait-for-X"]' 1 +//@count - '//*[@id="impl-Trait-for-X"]/*[@class="item-info"]' 0 + +// If you need to update this XPath, in particular `item-info`, update all +// the others in this file. +//@count - '//*[@id="impl-Foo-for-X"]/*[@class="item-info"]' 1 + +//@has 'foo/trait.Trait.html' +//@count - '//*[@id="impl-Trait-for-X"]' 1 +//@count - '//*[@id="impl-Trait-for-X"]/*[@class="item-info"]' 0 +#[doc(cfg(any(target_pointer_width = "64", target_arch = "wasm32")))] +#[doc(auto_cfg(hide(target_arch = "wasm32")))] +mod imp { + impl super::Trait for super::X { fn f(&self) {} } +} + +//@has 'foo/trait.Bob.html' +//@count - '//*[@id="impl-Bob-for-X"]' 1 +//@count - '//*[@id="impl-Bob-for-X"]/*[@class="item-info"]' 0 +#[doc(cfg(any(target_pointer_width = "64", target_arch = "wasm32")))] +#[doc(auto_cfg = false)] +mod imp2 { + impl super::Bob for super::X { fn bob(&self) {} } +} + +//@has 'foo/trait.Foo.html' +//@count - '//*[@id="impl-Foo-for-X"]/*[@class="item-info"]' 1 +// We use this to force xpath tests to be updated if `item-info` class is changed. +#[doc(cfg(any(target_pointer_width = "64", target_arch = "wasm32")))] +mod imp3 { + impl super::Foo for super::X { fn foo(&self) {} } +} + +pub struct Y; + +//@has 'foo/struct.Y.html' +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]' 1 +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]/*[@class="item-info"]' 0 +#[doc(cfg(any(target_pointer_width = "64", target_arch = "wasm32")))] +#[doc(auto_cfg(hide(target_arch = "wasm32")))] +mod imp4 { + impl super::Y { pub fn plain_auto() {} } +} + +pub struct Z; + +//@has 'foo/struct.Z.html' +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]' 1 +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]/*[@class="item-info"]' 0 +#[doc(cfg(any(target_pointer_width = "64", target_arch = "wasm32")))] +#[doc(auto_cfg = false)] +mod imp5 { + impl super::Z { pub fn plain_auto() {} } +} + +// The "witness" which has the item info. +pub struct W; + +//@has 'foo/struct.W.html' +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]' 1 +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]/*[@class="item-info"]' 1 +#[doc(cfg(any(target_pointer_width = "64", target_arch = "wasm32")))] +mod imp6 { + impl super::W { pub fn plain_auto() {} } +} diff --git a/tests/rustdoc-html/doc-cfg/trait-impls.rs b/tests/rustdoc-html/doc-cfg/trait-impls.rs new file mode 100644 index 000000000000..581d171123d0 --- /dev/null +++ b/tests/rustdoc-html/doc-cfg/trait-impls.rs @@ -0,0 +1,92 @@ +// This test ensures that `doc_cfg` feature is working as expected on trait impls. +// Regression test for . + +#![feature(doc_cfg)] +#![doc(auto_cfg(hide( + target_pointer_width = "64", +)))] + +#![crate_name = "foo"] + +pub trait Trait { + fn f(&self) {} +} + +pub trait Bob { + fn bob(&self) {} +} + +pub trait Foo { + fn foo(&self) {} +} + +pub struct X; + +//@has 'foo/struct.X.html' +//@count - '//*[@id="impl-Bob-for-X"]' 1 +//@count - '//*[@id="impl-Bob-for-X"]/*[@class="item-info"]' 0 +//@count - '//*[@id="impl-Trait-for-X"]' 1 +//@count - '//*[@id="impl-Trait-for-X"]/*[@class="item-info"]' 0 + +// If you need to update this XPath, in particular `item-info`, update all +// the others in this file. +//@count - '//*[@id="impl-Foo-for-X"]/*[@class="item-info"]' 1 + +//@has 'foo/trait.Trait.html' +//@count - '//*[@id="impl-Trait-for-X"]' 1 +//@count - '//*[@id="impl-Trait-for-X"]/*[@class="item-info"]' 0 +#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] +#[doc(auto_cfg(hide(target_arch = "wasm32")))] +mod imp { + impl super::Trait for super::X { fn f(&self) {} } +} + +//@has 'foo/trait.Bob.html' +//@count - '//*[@id="impl-Bob-for-X"]' 1 +//@count - '//*[@id="impl-Bob-for-X"]/*[@class="item-info"]' 0 +#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] +#[doc(auto_cfg = false)] +mod imp2 { + impl super::Bob for super::X { fn bob(&self) {} } +} + +//@has 'foo/trait.Foo.html' +//@count - '//*[@id="impl-Foo-for-X"]/*[@class="item-info"]' 1 +// We use this to force xpath tests to be updated if `item-info` class is changed. +#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] +mod imp3 { + impl super::Foo for super::X { fn foo(&self) {} } +} + +pub struct Y; + +//@has 'foo/struct.Y.html' +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]' 1 +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]/*[@class="item-info"]' 0 +#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] +#[doc(auto_cfg(hide(target_arch = "wasm32")))] +mod imp4 { + impl super::Y { pub fn plain_auto() {} } +} + +pub struct Z; + +//@has 'foo/struct.Z.html' +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]' 1 +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]/*[@class="item-info"]' 0 +#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] +#[doc(auto_cfg = false)] +mod imp5 { + impl super::Z { pub fn plain_auto() {} } +} + +// The "witness" which has the item info. +pub struct W; + +//@has 'foo/struct.W.html' +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]' 1 +//@count - '//*[@id="implementations-list"]/*[@class="impl-items"]/*[@class="item-info"]' 1 +#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] +mod imp6 { + impl super::W { pub fn plain_auto() {} } +} diff --git a/tests/rustdoc-ui/doctest/emit-test.rs b/tests/rustdoc-ui/doctest/emit-test.rs new file mode 100644 index 000000000000..4e40bde4648b --- /dev/null +++ b/tests/rustdoc-ui/doctest/emit-test.rs @@ -0,0 +1,5 @@ +//@ compile-flags:--test --emit=dep-info -Z unstable-options +//@ check-fail +//~? ERROR the `--test` flag and the `--emit` flag + +//! This example intentionally left blank. diff --git a/tests/rustdoc-ui/doctest/emit-test.stderr b/tests/rustdoc-ui/doctest/emit-test.stderr new file mode 100644 index 000000000000..2b1ebae5b139 --- /dev/null +++ b/tests/rustdoc-ui/doctest/emit-test.stderr @@ -0,0 +1,2 @@ +error: the `--test` flag and the `--emit` flag are not supported together + diff --git a/tests/rustdoc-ui/intra-doc/doc-link-private-reexport-issue-154383.rs b/tests/rustdoc-ui/intra-doc/doc-link-private-reexport-issue-154383.rs new file mode 100644 index 000000000000..1c736785933e --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/doc-link-private-reexport-issue-154383.rs @@ -0,0 +1,10 @@ +//@ check-pass + +// Regression test for . +// Rustdoc used to ICE on the doc link attached to a `pub use` inside a +// private module. + +mod inner { + /// [std::vec::Vec] + pub use std::vec::Vec as MyVec; +} diff --git a/tests/rustdoc-ui/issues/issue-79494.rs b/tests/rustdoc-ui/issues/issue-79494.rs index 737c00a0269b..c80e0a984213 100644 --- a/tests/rustdoc-ui/issues/issue-79494.rs +++ b/tests/rustdoc-ui/issues/issue-79494.rs @@ -1,6 +1,4 @@ //@ only-64bit -#![feature(const_transmute)] - pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; //~^ ERROR transmuting from 8-byte type to 16-byte type diff --git a/tests/rustdoc-ui/issues/issue-79494.stderr b/tests/rustdoc-ui/issues/issue-79494.stderr index fa797bfd50a6..31ed8f18ab07 100644 --- a/tests/rustdoc-ui/issues/issue-79494.stderr +++ b/tests/rustdoc-ui/issues/issue-79494.stderr @@ -1,5 +1,5 @@ error[E0080]: transmuting from 8-byte type to 16-byte type: `usize` -> `&[u8]` - --> $DIR/issue-79494.rs:5:33 + --> $DIR/issue-79494.rs:3:33 | LL | pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here diff --git a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs index 8e5c31d50edc..731d19bffec5 100644 --- a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs +++ b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs @@ -78,7 +78,11 @@ fn clone(&self) -> Self { } } - +impl Struct { // No doc or code example and it's fine! + pub fn bar() {} + //~^ ERROR missing code example in this documentation + //~| ERROR missing documentation for an associated function +} /// doc /// diff --git a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr index 22533b9816a7..6382c5926e8f 100644 --- a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr +++ b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr @@ -1,3 +1,15 @@ +error: missing documentation for an associated function + --> $DIR/lint-missing-doc-code-example.rs:82:5 + | +LL | pub fn bar() {} + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-missing-doc-code-example.rs:2:9 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + error: missing code example in this documentation --> $DIR/lint-missing-doc-code-example.rs:38:3 | @@ -28,5 +40,11 @@ error: missing code example in this documentation LL | /// Doc | ^^^^^^^ -error: aborting due to 4 previous errors +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:82:5 + | +LL | pub fn bar() {} + | ^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_non_static.stderr b/tests/rustdoc-ui/output-format-json-emit-html.html_non_static.stderr new file mode 100644 index 000000000000..8d8e8c6d1228 --- /dev/null +++ b/tests/rustdoc-ui/output-format-json-emit-html.html_non_static.stderr @@ -0,0 +1,2 @@ +error: the `--emit=html-non-static-files` flag is not supported with `--output-format=json` + diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_static.stderr b/tests/rustdoc-ui/output-format-json-emit-html.html_static.stderr new file mode 100644 index 000000000000..bc1ddc1b155d --- /dev/null +++ b/tests/rustdoc-ui/output-format-json-emit-html.html_static.stderr @@ -0,0 +1,2 @@ +error: the `--emit=html-static-files` flag is not supported with `--output-format=json` + diff --git a/tests/rustdoc-ui/output-format-json-emit-html.rs b/tests/rustdoc-ui/output-format-json-emit-html.rs new file mode 100644 index 000000000000..7a99cbd91ba6 --- /dev/null +++ b/tests/rustdoc-ui/output-format-json-emit-html.rs @@ -0,0 +1,8 @@ +//@ revisions: html_static html_non_static +//@ check-fail +//@[html_static] compile-flags: -Z unstable-options --output-format=json --emit=html-static-files +//@[html_non_static] compile-flags: -Z unstable-options --output-format=json --emit=html-non-static-files +//[html_static]~? ERROR the `--emit=html-static-files` flag is not supported with `--output-format=json` +//[html_non_static]~? ERROR the `--emit=html-non-static-files` flag is not supported with `--output-format=json` + +pub struct Foo; diff --git a/tests/rustdoc-ui/rustc-check-passes.rs b/tests/rustdoc-ui/rustc-check-passes.rs index 56d59164d68f..54028a6d18ee 100644 --- a/tests/rustdoc-ui/rustc-check-passes.rs +++ b/tests/rustdoc-ui/rustc-check-passes.rs @@ -1,4 +1,4 @@ #![feature(rustdoc_internals)] -#![feature(rustdoc_internals)] //~ ERROR +#![feature(rustdoc_internals)] //~ ERROR duplicate pub fn foo() {} diff --git a/tests/rustdoc-ui/rustc-check-passes.stderr b/tests/rustdoc-ui/rustc-check-passes.stderr index 5b20d1128c59..2789d8236d32 100644 --- a/tests/rustdoc-ui/rustc-check-passes.stderr +++ b/tests/rustdoc-ui/rustc-check-passes.stderr @@ -1,9 +1,10 @@ -error[E0636]: the feature `rustdoc_internals` has already been enabled +error: the feature `rustdoc_internals` has already been enabled --> $DIR/rustc-check-passes.rs:2:12 | LL | #![feature(rustdoc_internals)] | ^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(duplicate_features)]` on by default error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0636`. diff --git a/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.rs b/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.rs new file mode 100644 index 000000000000..b0f67a3b4195 --- /dev/null +++ b/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.rs @@ -0,0 +1,5 @@ +//@ compile-flags: -Z unstable-options --show-coverage --output-format=json --emit=html-non-static-files +//@ check-fail +//~? ERROR the `--emit=html-non-static-files` flag is not supported with `--output-format=json` + +pub struct Foo; diff --git a/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.stderr b/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.stderr new file mode 100644 index 000000000000..8d8e8c6d1228 --- /dev/null +++ b/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.stderr @@ -0,0 +1,2 @@ +error: the `--emit=html-non-static-files` flag is not supported with `--output-format=json` + diff --git a/tests/rustdoc-ui/track-diagnostics.rs b/tests/rustdoc-ui/track-diagnostics.rs index f8e710659a5c..f7f0c9849ef0 100644 --- a/tests/rustdoc-ui/track-diagnostics.rs +++ b/tests/rustdoc-ui/track-diagnostics.rs @@ -3,6 +3,7 @@ // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. //@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:CC" +//@ normalize-stderr: "/rustc(?:-dev)?/[a-z0-9.]+/" -> "" struct A; struct B; @@ -11,3 +12,4 @@ //~^ ERROR mismatched types //~| NOTE created at //~| NOTE expected `A`, found `B` +//~| NOTE expected because of the type of the const diff --git a/tests/rustdoc-ui/track-diagnostics.stderr b/tests/rustdoc-ui/track-diagnostics.stderr index a25fd2862aaf..c7dfe07c596f 100644 --- a/tests/rustdoc-ui/track-diagnostics.stderr +++ b/tests/rustdoc-ui/track-diagnostics.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/track-diagnostics.rs:LL:CC | LL | pub const S: A = B; - | ^ expected `A`, found `B` + | - ^ expected `A`, found `B` + | | + | expected because of the type of the constant | = note: -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 8d7425186680..84f9a09990fd 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -38,9 +38,8 @@ use rustc_ast::*; use rustc_ast_pretty::pprust; use rustc_session::parse::ParseSess; -use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::DUMMY_SP; +use rustc_span::{DUMMY_SP, Spanned}; use thin_vec::{thin_vec, ThinVec}; // Helper functions for building exprs diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index bd92cc6218f1..d99d9c42d547 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -66,7 +66,7 @@ fn compile(code: String, output: PathBuf, sysroot: Sysroot, linker: Option<&Path file_loader: None, lint_caps: Default::default(), psess_created: None, - hash_untracked_state: None, + track_state: None, register_lints: None, override_queries: None, extra_symbols: Vec::new(), diff --git a/tests/ui-fulldeps/rustc_public/check_vtable.rs b/tests/ui-fulldeps/rustc_public/check_vtable.rs new file mode 100644 index 000000000000..9b72eff7f6c9 --- /dev/null +++ b/tests/ui-fulldeps/rustc_public/check_vtable.rs @@ -0,0 +1,149 @@ +//@ run-pass +// Test that users are able to use rustc_public to retrieve vtable info. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote + +#![feature(rustc_private)] + +extern crate rustc_middle; +extern crate rustc_driver; +extern crate rustc_interface; +#[macro_use] +extern crate rustc_public; + +use rustc_public::ty::VtblEntry; +use rustc_public::CrateDef; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "vtable_test"; + +/// This function uses the rustc_public APIs to test the `vtable_entries()`. +fn test_vtable_entries() -> ControlFlow<()> { + let local_crate = rustc_public::local_crate(); + let local_impls = local_crate.trait_impls(); + let child_impl = local_impls + .iter() + .find(|i| i.trimmed_name() == "") + .expect("Could not find "); + + let child_trait_ref = child_impl.trait_impl().value; + let entries = child_trait_ref.vtable_entries(); + match &entries[..] { + [ + VtblEntry::MetadataDropInPlace, + VtblEntry::MetadataSize, + VtblEntry::MetadataAlign, + VtblEntry::Method(primary), + VtblEntry::Method(secondary), + VtblEntry::TraitVPtr(secondary_vptr), + VtblEntry::Method(child), + ] => { + assert!( + primary.name().contains("primary"), + "Expected primary method at index 3" + ); + assert!( + secondary.name().contains("secondary"), + "Expected secondary method at index 4" + ); + let vptr_str = secondary_vptr.def_id.name(); + assert!( + vptr_str.contains("Secondary"), + "Expected Secondary VPtr at index 5" + ); + assert!( + child.name().contains("child"), + "Expected child method at index 6" + ); + } + _ => panic!( + "Unexpected vtable layout for . Found: {:#?}", + entries + ), + } + let vacant_impl = local_impls + .iter() + .find(|i| i.trimmed_name() == "") + .expect("Could not find "); + let vacant_trait_ref = vacant_impl.trait_impl().value; + let vacant_entries = vacant_trait_ref.vtable_entries(); + match &vacant_entries[..] { + [ + VtblEntry::MetadataDropInPlace, + VtblEntry::MetadataSize, + VtblEntry::MetadataAlign, + VtblEntry::Method(valid), + ] => { + assert!(valid.name().contains("valid"), "Expected valid method"); + } + _ => panic!( + "Unexpected vtable layout for . Found: {:#?}", + vacant_entries + ), + } + ControlFlow::Continue(()) +} + +fn main() { + let path = "vtable_input.rs"; + generate_input(&path).unwrap(); + let args = &[ + "rustc".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, test_vtable_entries).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + pub struct Concrete; + + pub trait Primary {{ + fn primary(&self); + }} + + pub trait Secondary {{ + fn secondary(&self); + }} + + pub trait Child: Primary + Secondary {{ + fn child(&self); + }} + + impl Primary for Concrete {{ + fn primary(&self) {{}} + }} + + impl Secondary for Concrete {{ + fn secondary(&self) {{}} + }} + + impl Child for Concrete {{ + fn child(&self) {{}} + }} + + pub trait WithVacant {{ + fn valid(&self); + + fn excluded(&self, meow: T) where Self: Sized; + }} + + impl WithVacant for Concrete {{ + fn valid(&self) {{}} + fn excluded(&self, meow: T) {{}} + }} + + fn main() {{}} + "# + )?; + Ok(()) +} 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 9149baaa4087..48a338db297e 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 @@ -13,6 +13,7 @@ help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `Not LL | struct NotIntoDiagArg; | ^^^^^^^^^^^^^^^^^^^^^ = help: normalized in stderr + = note: there's an inherent method on `DiagInner` of the same name, which can be auto-dereferenced from `&mut DiagInner` note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr index 48138fc9fb55..28800016cea9 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr @@ -589,6 +589,7 @@ help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `Hel LL | struct Hello {} | ^^^^^^^^^^^^ = help: normalized in stderr + = note: there's an inherent method on `DiagInner` of the same name, which can be auto-dereferenced from `&mut DiagInner` note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC diff --git a/tests/ui/README.md b/tests/ui/README.md index 689a61b47269..eb14039d8151 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -133,7 +133,7 @@ Runtime panics and error handling generate backtraces to assist in debugging and This directory was originally meant to contain tests related to time complexity and benchmarking. -However, only a single test was ever added to this category: https://github.com/rust-lang/rust/pull/32062 +However, only a single test was ever added to this category: **FIXME**: It is also unclear what would happen were this test to "fail" - would it cause the test suite to remain stuck on this test for a much greater duration than normal? @@ -344,10 +344,6 @@ Tests for `#![feature(coverage_attribute)]`. See [Tracking issue for function at Tests for crate resolution and loading behavior, including `extern crate` declarations, `--extern` flags, or the `use` keyword. -## `tests/ui/cross/`: Various tests related to the concept of "cross" - -**FIXME**: The unifying topic of these tests appears to be that their filenames begin with the word "cross". The similarities end there - one test is about "cross-borrowing" a `Box` into `&T`, while another is about a global trait used "across" files. Some of this terminology is really outdated and does not match the current terminology. Additionally, "cross" is also way too generic, it's easy to confuse with cross-compile. - ## `tests/ui/cross-crate/`: Cross-Crate Interaction Tests for behavior spanning multiple crates, including visibility rules, trait implementations, and type resolution across crate boundaries. @@ -498,10 +494,6 @@ See: Previously known as "object safety". -## `tests/ui/dyn-drop/`: `dyn Drop` - -**FIXME**: Contains a single test, used only to check the `dyn_drop` lint (which is normally `warn` level). - ## `tests/ui/dyn-keyword/`: `dyn` and Dynamic Dispatch The `dyn` keyword is used to highlight that calls to methods on the associated Trait are dynamically dispatched. To use the trait this way, it must be dyn-compatible - tests about dyn-compatibility belong in `tests/ui/dyn-compatibility/`, while more general tests on dynamic dispatch belong here. @@ -518,10 +510,6 @@ These tests run in specific Rust editions, such as Rust 2015 or Rust 2018, and c Exercises `eii` keyword. -## `tests/ui/empty/`: Various tests related to the concept of "empty" - -**FIXME**: These tests need better homes, this is not very informative. - ## `tests/ui/entry-point/`: `main` function Tests exercising the `main` entry-point. @@ -706,9 +694,7 @@ This test category revolves around trait objects with `Sized` having illegal ope Tests on lifetime elision in impl function signatures. See [Lifetime elision | Nomicon](https://doc.rust-lang.org/nomicon/lifetime-elision.html). ## `tests/ui/impl-restriction/` -Tests for `#![feature(impl_restriction)]`. See [Tracking issue for restrictions #105077 -](https://github.com/rust-lang/rust/issues/105077). - +Tests for `#![feature(impl_restriction)]`. See [Tracking issue for restrictions #105077](https://github.com/rust-lang/rust/issues/105077). ## `tests/ui/impl-trait/` @@ -768,12 +754,6 @@ Tests for rustc-internal lints. Tests for the `{std,core}::intrinsics`, internal implementation detail. -## `tests/ui/invalid/` - -Various tests related to rejecting invalid inputs. - -**FIXME**: This is rather uninformative, possibly rehome into more meaningful directories. - ## `tests/ui/io-checks/`: Input Output Tests for I/O related behaviour, covering stdout/stderr handling and error propagation. @@ -796,10 +776,6 @@ These tests revolve around the `--json` compiler flag. See [JSON Output](https:/ Tests exercising keywords, such as attempting to use them as identifiers when not contextual keywords. -## `tests/ui/kindck/` - -**FIXME**: `kindck` is no longer a thing, these tests probably need to be audited and rehomed. - ## `tests/ui/label/` Exercises block and loop `'label`s. @@ -818,8 +794,7 @@ See [Type Layout | Reference](https://doc.rust-lang.org/reference/type-layout.ht ## `tests/ui/lazy-type-alias/` -Tests for `#![feature(lazy_type_alias)]`. See [Tracking issue for lazy type aliases #112792 -](https://github.com/rust-lang/rust/issues/112792). +Tests for `#![feature(lazy_type_alias)]`. See [Tracking issue for lazy type aliases #112792](https://github.com/rust-lang/rust/issues/112792). ## `tests/ui/lazy-type-alias-impl-trait/` @@ -874,7 +849,7 @@ See: Tests exercising analysis for unused variables, unreachable statements, functions which are supposed to return a value but do not, as well as values moved elsewhere before they could be used by a function. -**FIXME**: This seems unrelated to "liveness" as defined in the rustc compiler guide. Is this misleadingly named? https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/lifetime_parameters.html#liveness-and-universal-regions +**FIXME**: This seems unrelated to "liveness" as defined in the rustc compiler guide. Is this misleadingly named? ## `tests/ui/loop-match` @@ -940,12 +915,6 @@ Something is missing which could be added to fix (e.g. suggestions). **FIXME**: this is way too vague, tests should be rehomed. -## `tests/ui/missing-trait-bounds/` - -Tests for checking missing trait bounds, and their diagnostics. - -**FIXME**: Maybe a subdirectory of `ui/trait-bounds` would be more appropriate. - ## `tests/ui/modules/` Tests on the module system. @@ -1014,12 +983,6 @@ Tests on lifetimes on objects, such as a lifetime bound not being able to be ded **FIXME**: Just a more specific subset of `ui/lifetimes`. -## `tests/ui/obsolete-in-place/` - -Contains a single test. Check that we reject the ancient Rust syntax `x <- y` and `in(BINDING) {}` construct. - -**FIXME**: Definitely should be rehomed, maybe to `tests/ui/deprecation/`. - ## `tests/ui/offload` Exercises the offload feature. @@ -1037,10 +1000,6 @@ Exercises the [`std::mem::offset_of` macro](https://doc.rust-lang.org/beta/std/m Exercises the `#[rustc_on_unimplemented]`. -## `tests/ui/operator-recovery/` - -**FIXME**: Probably move under `tests/ui/binop/` or `tests/ui/parser/`. - ## `tests/ui/or-patterns/` Exercises `||` and `|` in patterns. @@ -1173,12 +1132,6 @@ Broad category of tests exercising recursions (compile test and run time), in fu Also exercises the `#![recursion_limit = ""]` attribute. -## `tests/ui/recursion_limit/`: `#![recursion_limit = ""]` - -Sets a recursion limit on recursive code. - -**FIXME**: Should be merged with `tests/ui/recursion/`. - ## `tests/ui/reflection/` Exercises the `#![feature(type_info)]` feature. @@ -1467,7 +1420,7 @@ Tests for the `#[doc(hidden)]` items. ## `tests/ui/try-block/` -`#![feature(try_blocks)]`. See [Tracking issue for `?` operator and `try` blocks (RFC 243, `question_mark` & `try_blocks` features)](https://github.com/rust-lang/rust/issues/31436). +`#![feature(try_blocks)]` & `#![feature(try_blocks_heterogeneous)]`. See [Tracking Issue for homogeneous `try_blocks`](https://github.com/rust-lang/rust/issues/154391) & [Experimental Tracking Issue for Heterogeneous Try Blocks](https://github.com/rust-lang/rust/issues/149488). ## `tests/ui/try-trait/` @@ -1601,10 +1554,6 @@ Tests on `enum` variants. **FIXME**: Should be rehomed with `tests/ui/enum/`. -## `tests/ui/version/` - -**FIXME**: Contains a single test described as "Check that rustc accepts various version info flags.", should be rehomed. - ## `tests/ui/wasm/` These tests target the `wasm32` architecture specifically. They are usually regression tests for WASM-specific bugs which were observed in the past. diff --git a/tests/ui/abi/simd-abi-checks-avx.rs b/tests/ui/abi/simd-abi-checks-avx.rs index 7432381d15b7..c68ba2fb5f89 100644 --- a/tests/ui/abi/simd-abi-checks-avx.rs +++ b/tests/ui/abi/simd-abi-checks-avx.rs @@ -1,7 +1,7 @@ //@ only-x86_64 //@ build-fail //@ compile-flags: -C target-feature=-avx - +//@ ignore-parallel-frontend post-monomorphization errors #![feature(portable_simd)] #![feature(simd_ffi)] #![allow(improper_ctypes_definitions)] diff --git a/tests/ui/array-slice-vec/closure-in-array-len.stderr b/tests/ui/array-slice-vec/closure-in-array-len.stderr index decdde042c6f..04841f1d1f66 100644 --- a/tests/ui/array-slice-vec/closure-in-array-len.stderr +++ b/tests/ui/array-slice-vec/closure-in-array-len.stderr @@ -6,6 +6,7 @@ LL | fn([u8; |x: u8| {}]), | = note: expected type `usize` found closure `{closure@$DIR/closure-in-array-len.rs:3:13: 3:20}` + = note: array length can only be `usize` error: aborting due to 1 previous error diff --git a/tests/ui/array-slice-vec/subslice-only-once-semantic-restriction.stderr b/tests/ui/array-slice-vec/subslice-only-once-semantic-restriction.stderr index 4d6078788b22..d665125608af 100644 --- a/tests/ui/array-slice-vec/subslice-only-once-semantic-restriction.stderr +++ b/tests/ui/array-slice-vec/subslice-only-once-semantic-restriction.stderr @@ -16,7 +16,9 @@ error[E0308]: mismatched types --> $DIR/subslice-only-once-semantic-restriction.rs:11:30 | LL | const RECOVERY_WITNESS: () = 0; - | ^ expected `()`, found integer + | -- ^ expected `()`, found integer + | | + | expected because of the type of the constant error: aborting due to 3 previous errors diff --git a/tests/ui/asm/aarch64/aarch64-sve.rs b/tests/ui/asm/aarch64/aarch64-sve.rs index 81c82d5ad006..a146d7334555 100644 --- a/tests/ui/asm/aarch64/aarch64-sve.rs +++ b/tests/ui/asm/aarch64/aarch64-sve.rs @@ -1,13 +1,17 @@ -//@ only-aarch64 //@ build-pass -//@ needs-asm-support - +//@ add-minicore +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc #![crate_type = "rlib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; // AArch64 test corresponding to arm64ec-sve.rs. -use std::arch::asm; - fn f(x: f64) { unsafe { asm!("", out("p0") _); diff --git a/tests/ui/asm/aarch64/bad-options.rs b/tests/ui/asm/aarch64/bad-options.rs index 9e721d55b2d7..ebba9255d324 100644 --- a/tests/ui/asm/aarch64/bad-options.rs +++ b/tests/ui/asm/aarch64/bad-options.rs @@ -1,6 +1,13 @@ -//@ only-aarch64 +//@ add-minicore +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::{asm, global_asm}; +extern crate minicore; +use minicore::*; fn main() { let mut foo = 0; diff --git a/tests/ui/asm/aarch64/bad-options.stderr b/tests/ui/asm/aarch64/bad-options.stderr index 54ab7cafa49f..8f3e464a7200 100644 --- a/tests/ui/asm/aarch64/bad-options.stderr +++ b/tests/ui/asm/aarch64/bad-options.stderr @@ -1,35 +1,35 @@ error: the `nomem` and `readonly` options are mutually exclusive - --> $DIR/bad-options.rs:8:18 + --> $DIR/bad-options.rs:15:18 | LL | asm!("", options(nomem, readonly)); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: the `pure` and `noreturn` options are mutually exclusive - --> $DIR/bad-options.rs:10:18 + --> $DIR/bad-options.rs:17:18 | LL | asm!("", options(pure, nomem, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm with the `pure` option must have at least one output - --> $DIR/bad-options.rs:10:18 + --> $DIR/bad-options.rs:17:18 | LL | asm!("", options(pure, nomem, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm with the `pure` option must have at least one output - --> $DIR/bad-options.rs:13:33 + --> $DIR/bad-options.rs:20:33 | LL | asm!("{}", in(reg) foo, options(pure, nomem)); | ^^^^^^^^^^^^^^^^^^^^ error: asm outputs are not allowed with the `noreturn` option - --> $DIR/bad-options.rs:15:20 + --> $DIR/bad-options.rs:22:20 | LL | asm!("{}", out(reg) foo, options(noreturn)); | ^^^^^^^^^^^^ error: asm with `clobber_abi` must specify explicit registers for outputs - --> $DIR/bad-options.rs:22:20 + --> $DIR/bad-options.rs:29:20 | LL | asm!("{}", out(reg) foo, clobber_abi("C")); | ^^^^^^^^^^^^ ---------------- clobber_abi @@ -37,48 +37,48 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C")); | generic outputs error: the `nomem` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:28:25 + --> $DIR/bad-options.rs:35:25 | LL | global_asm!("", options(nomem)); | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly error: the `readonly` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:30:25 + --> $DIR/bad-options.rs:37:25 | LL | global_asm!("", options(readonly)); | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly error: the `noreturn` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:32:25 + --> $DIR/bad-options.rs:39:25 | LL | global_asm!("", options(noreturn)); | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly error: the `pure` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:34:25 + --> $DIR/bad-options.rs:41:25 | LL | global_asm!("", options(pure)); | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly error: the `nostack` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:36:25 + --> $DIR/bad-options.rs:43:25 | LL | global_asm!("", options(nostack)); | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly error: the `preserves_flags` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:38:25 + --> $DIR/bad-options.rs:45:25 | LL | global_asm!("", options(preserves_flags)); | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly error: invalid ABI for `clobber_abi` - --> $DIR/bad-options.rs:20:18 + --> $DIR/bad-options.rs:27:18 | LL | asm!("", clobber_abi("foo")); | ^^^^^^^^^^^^^^^^^^ | - = note: the following ABIs are supported on this target: `C`, `system`, `efiapi` + = note: the following ABIs are supported on this target: `C`, `system`, and `efiapi` error: aborting due to 13 previous errors diff --git a/tests/ui/asm/aarch64/bad-reg.rs b/tests/ui/asm/aarch64/bad-reg.rs index b99e5fe4b9e3..39a3e386bb6e 100644 --- a/tests/ui/asm/aarch64/bad-reg.rs +++ b/tests/ui/asm/aarch64/bad-reg.rs @@ -1,7 +1,13 @@ -//@ only-aarch64 -//@ compile-flags: -C target-feature=+neon +//@ add-minicore +//@ compile-flags: --target aarch64-unknown-linux-gnu -C target-feature=+neon +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; fn main() { let mut foo = 0; @@ -14,11 +20,11 @@ fn main() { asm!("", in("foo") foo); //~^ ERROR invalid register `foo`: unknown register asm!("{:z}", in(reg) foo); - //~^ ERROR invalid asm template modifier for this register class + //~^ ERROR invalid asm template modifier `z` for this register class asm!("{:r}", in(vreg) foo); - //~^ ERROR invalid asm template modifier for this register class + //~^ ERROR invalid asm template modifier `r` for this register class asm!("{:r}", in(vreg_low16) foo); - //~^ ERROR invalid asm template modifier for this register class + //~^ ERROR invalid asm template modifier `r` for this register class asm!("{:a}", const 0); //~^ ERROR asm template modifiers are not allowed for `const` arguments asm!("{:a}", sym main); diff --git a/tests/ui/asm/aarch64/bad-reg.stderr b/tests/ui/asm/aarch64/bad-reg.stderr index c76722f32a74..9f3d54eb4666 100644 --- a/tests/ui/asm/aarch64/bad-reg.stderr +++ b/tests/ui/asm/aarch64/bad-reg.stderr @@ -1,49 +1,49 @@ error: invalid register class `foo`: unknown register class - --> $DIR/bad-reg.rs:12:20 + --> $DIR/bad-reg.rs:18:20 | LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ | - = note: the following register classes are supported on this target: `reg`, `vreg`, `vreg_low16`, `preg` + = note: the following register classes are supported on this target: `reg`, `vreg`, `vreg_low16`, and `preg` error: invalid register `foo`: unknown register - --> $DIR/bad-reg.rs:14:18 + --> $DIR/bad-reg.rs:20:18 | LL | asm!("", in("foo") foo); | ^^^^^^^^^^^^^ -error: invalid asm template modifier for this register class - --> $DIR/bad-reg.rs:16:15 +error: invalid asm template modifier `z` for this register class + --> $DIR/bad-reg.rs:22:15 | LL | asm!("{:z}", in(reg) foo); | ^^^^ ----------- argument | | | template modifier | - = note: the `reg` register class supports the following template modifiers: `w`, `x` + = note: the `reg` register class supports the following template modifiers: `w` and `x` -error: invalid asm template modifier for this register class - --> $DIR/bad-reg.rs:18:15 +error: invalid asm template modifier `r` for this register class + --> $DIR/bad-reg.rs:24:15 | LL | asm!("{:r}", in(vreg) foo); | ^^^^ ------------ argument | | | template modifier | - = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` + = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, and `v` -error: invalid asm template modifier for this register class - --> $DIR/bad-reg.rs:20:15 +error: invalid asm template modifier `r` for this register class + --> $DIR/bad-reg.rs:26:15 | LL | asm!("{:r}", in(vreg_low16) foo); | ^^^^ ------------------ argument | | | template modifier | - = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` + = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, and `v` error: asm template modifiers are not allowed for `const` arguments - --> $DIR/bad-reg.rs:22:15 + --> $DIR/bad-reg.rs:28:15 | LL | asm!("{:a}", const 0); | ^^^^ ------- argument @@ -51,7 +51,7 @@ LL | asm!("{:a}", const 0); | template modifier error: asm template modifiers are not allowed for `sym` arguments - --> $DIR/bad-reg.rs:24:15 + --> $DIR/bad-reg.rs:30:15 | LL | asm!("{:a}", sym main); | ^^^^ -------- argument @@ -59,49 +59,49 @@ LL | asm!("{:a}", sym main); | template modifier error: invalid register `x29`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:26:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", in("x29") foo); | ^^^^^^^^^^^^^ error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:28:18 + --> $DIR/bad-reg.rs:34:18 | LL | asm!("", in("sp") foo); | ^^^^^^^^^^^^ error: invalid register `xzr`: the zero register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:30:18 + --> $DIR/bad-reg.rs:36:18 | LL | asm!("", in("xzr") foo); | ^^^^^^^^^^^^^ error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:38:18 | LL | asm!("", in("x19") foo); | ^^^^^^^^^^^^^ error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:35:18 + --> $DIR/bad-reg.rs:41:18 | LL | asm!("", in("p0") foo); | ^^^^^^^^^^^^ error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:39:20 + --> $DIR/bad-reg.rs:45:20 | LL | asm!("{}", in(preg) foo); | ^^^^^^^^^^^^ error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:42:20 + --> $DIR/bad-reg.rs:48:20 | LL | asm!("{}", out(preg) _); | ^^^^^^^^^^^ error: register `w0` conflicts with register `x0` - --> $DIR/bad-reg.rs:48:32 + --> $DIR/bad-reg.rs:54:32 | LL | asm!("", in("x0") foo, in("w0") bar); | ------------ ^^^^^^^^^^^^ register `w0` @@ -109,7 +109,7 @@ LL | asm!("", in("x0") foo, in("w0") bar); | register `x0` error: register `x0` conflicts with register `x0` - --> $DIR/bad-reg.rs:50:32 + --> $DIR/bad-reg.rs:56:32 | LL | asm!("", in("x0") foo, out("x0") bar); | ------------ ^^^^^^^^^^^^^ register `x0` @@ -117,13 +117,13 @@ LL | asm!("", in("x0") foo, out("x0") bar); | register `x0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:50:18 + --> $DIR/bad-reg.rs:56:18 | LL | asm!("", in("x0") foo, out("x0") bar); | ^^^^^^^^^^^^ error: register `q0` conflicts with register `v0` - --> $DIR/bad-reg.rs:53:32 + --> $DIR/bad-reg.rs:59:32 | LL | asm!("", in("v0") foo, in("q0") bar); | ------------ ^^^^^^^^^^^^ register `q0` @@ -131,7 +131,7 @@ LL | asm!("", in("v0") foo, in("q0") bar); | register `v0` error: register `q0` conflicts with register `v0` - --> $DIR/bad-reg.rs:55:32 + --> $DIR/bad-reg.rs:61:32 | LL | asm!("", in("v0") foo, out("q0") bar); | ------------ ^^^^^^^^^^^^^ register `q0` @@ -139,13 +139,13 @@ LL | asm!("", in("v0") foo, out("q0") bar); | register `v0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:55:18 + --> $DIR/bad-reg.rs:61:18 | LL | asm!("", in("v0") foo, out("q0") bar); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:35:27 + --> $DIR/bad-reg.rs:41:27 | LL | asm!("", in("p0") foo); | ^^^ @@ -153,7 +153,7 @@ LL | asm!("", in("p0") foo); = note: register class `preg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:39:29 + --> $DIR/bad-reg.rs:45:29 | LL | asm!("{}", in(preg) foo); | ^^^ diff --git a/tests/ui/asm/aarch64/duplicate-options.fixed b/tests/ui/asm/aarch64/duplicate-options.fixed index b221c7c78bc7..efddf9570e31 100644 --- a/tests/ui/asm/aarch64/duplicate-options.fixed +++ b/tests/ui/asm/aarch64/duplicate-options.fixed @@ -1,8 +1,14 @@ -//@ only-aarch64 -//@ needs-asm-support //@ run-rustfix +//@ add-minicore +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ needs-asm-support +//@ ignore-backends: gcc +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; fn main() { unsafe { diff --git a/tests/ui/asm/aarch64/duplicate-options.rs b/tests/ui/asm/aarch64/duplicate-options.rs index 44a45187d2d5..ee45e7b322d0 100644 --- a/tests/ui/asm/aarch64/duplicate-options.rs +++ b/tests/ui/asm/aarch64/duplicate-options.rs @@ -1,8 +1,14 @@ -//@ only-aarch64 -//@ needs-asm-support //@ run-rustfix +//@ add-minicore +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ needs-asm-support +//@ ignore-backends: gcc +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; fn main() { unsafe { diff --git a/tests/ui/asm/aarch64/duplicate-options.stderr b/tests/ui/asm/aarch64/duplicate-options.stderr index feb3838f4f79..06bd9ea6baf9 100644 --- a/tests/ui/asm/aarch64/duplicate-options.stderr +++ b/tests/ui/asm/aarch64/duplicate-options.stderr @@ -1,53 +1,53 @@ error: the `nomem` option was already provided - --> $DIR/duplicate-options.rs:9:33 + --> $DIR/duplicate-options.rs:15:33 | LL | asm!("", options(nomem, nomem)); | ^^^^^ this option was already provided error: the `preserves_flags` option was already provided - --> $DIR/duplicate-options.rs:11:43 + --> $DIR/duplicate-options.rs:17:43 | LL | asm!("", options(preserves_flags, preserves_flags)); | ^^^^^^^^^^^^^^^ this option was already provided error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:13:61 + --> $DIR/duplicate-options.rs:19:61 | LL | asm!("", options(nostack, preserves_flags), options(nostack)); | ^^^^^^^ this option was already provided error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:15:35 + --> $DIR/duplicate-options.rs:21:35 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); | ^^^^^^^ this option was already provided error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:15:53 + --> $DIR/duplicate-options.rs:21:53 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); | ^^^^^^^ this option was already provided error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:15:71 + --> $DIR/duplicate-options.rs:21:71 | LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); | ^^^^^^^ this option was already provided error: the `noreturn` option was already provided - --> $DIR/duplicate-options.rs:22:38 + --> $DIR/duplicate-options.rs:28:38 | LL | options(preserves_flags, noreturn), | ^^^^^^^^ this option was already provided error: the `nomem` option was already provided - --> $DIR/duplicate-options.rs:23:21 + --> $DIR/duplicate-options.rs:29:21 | LL | options(nomem, nostack), | ^^^^^ this option was already provided error: the `noreturn` option was already provided - --> $DIR/duplicate-options.rs:24:21 + --> $DIR/duplicate-options.rs:30:21 | LL | options(noreturn), | ^^^^^^^^ this option was already provided diff --git a/tests/ui/asm/aarch64/interpolated-idents.rs b/tests/ui/asm/aarch64/interpolated-idents.rs index 3d9cf763e4d7..d51fdbc6add2 100644 --- a/tests/ui/asm/aarch64/interpolated-idents.rs +++ b/tests/ui/asm/aarch64/interpolated-idents.rs @@ -1,6 +1,13 @@ -//@ only-aarch64 -//@ needs-asm-support -use std::arch::asm; +//@ add-minicore +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; macro_rules! m { ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident diff --git a/tests/ui/asm/aarch64/interpolated-idents.stderr b/tests/ui/asm/aarch64/interpolated-idents.stderr index 74cb992f2adb..8537a5ebf46b 100644 --- a/tests/ui/asm/aarch64/interpolated-idents.stderr +++ b/tests/ui/asm/aarch64/interpolated-idents.stderr @@ -1,5 +1,5 @@ error: the `nomem` and `readonly` options are mutually exclusive - --> $DIR/interpolated-idents.rs:13:13 + --> $DIR/interpolated-idents.rs:20:13 | LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | | noreturn nostack options); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: the `pure` and `noreturn` options are mutually exclusive - --> $DIR/interpolated-idents.rs:13:13 + --> $DIR/interpolated-idents.rs:20:13 | LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | | noreturn nostack options); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm outputs are not allowed with the `noreturn` option - --> $DIR/interpolated-idents.rs:10:32 + --> $DIR/interpolated-idents.rs:17:32 | LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/aarch64/parse-error.rs b/tests/ui/asm/aarch64/parse-error.rs index 622f99aa1b1e..f9ee9a1802b1 100644 --- a/tests/ui/asm/aarch64/parse-error.rs +++ b/tests/ui/asm/aarch64/parse-error.rs @@ -1,6 +1,13 @@ -//@ only-aarch64 +//@ add-minicore +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; fn main() { let mut foo = 0; diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr index ca21311f87f9..630f2a4f2241 100644 --- a/tests/ui/asm/aarch64/parse-error.stderr +++ b/tests/ui/asm/aarch64/parse-error.stderr @@ -1,11 +1,11 @@ error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:9:18 + --> $DIR/parse-error.rs:16:18 | LL | asm!("", a = in("x0") foo); | ^^^^^^^^^^^^^^^^ error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:15:35 + --> $DIR/parse-error.rs:22:35 | LL | asm!("{1}", in("x0") foo, const bar); | ------------ ^^^^^^^^^ positional argument @@ -13,7 +13,7 @@ LL | asm!("{1}", in("x0") foo, const bar); | explicit register argument error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:11:45 + --> $DIR/parse-error.rs:18:45 | LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value @@ -25,7 +25,7 @@ LL + const bar: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:13:45 + --> $DIR/parse-error.rs:20:45 | LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value @@ -37,7 +37,7 @@ LL + const bar: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:15:41 + --> $DIR/parse-error.rs:22:41 | LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value diff --git a/tests/ui/asm/aarch64/srcloc.rs b/tests/ui/asm/aarch64/srcloc.rs index c635fa6ba700..91a2ef3514ae 100644 --- a/tests/ui/asm/aarch64/srcloc.rs +++ b/tests/ui/asm/aarch64/srcloc.rs @@ -1,12 +1,19 @@ -//@ only-aarch64 +//@ add-minicore //@ build-fail //@ needs-asm-support -//@ compile-flags: -Ccodegen-units=1 +//@ compile-flags: --target aarch64-unknown-linux-gnu -Ccodegen-units=1 +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; // Checks that inline asm errors are mapped to the correct line in the source code. - +#[unsafe(no_mangle)] +#[rustfmt::skip] fn main() { unsafe { asm!("invalid_instruction"); diff --git a/tests/ui/asm/aarch64/srcloc.stderr b/tests/ui/asm/aarch64/srcloc.stderr index b47f19bea614..44ee44fa4f5e 100644 --- a/tests/ui/asm/aarch64/srcloc.stderr +++ b/tests/ui/asm/aarch64/srcloc.stderr @@ -1,5 +1,5 @@ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:12:15 + --> $DIR/srcloc.rs:19:15 | LL | asm!("invalid_instruction"); | ^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:16:13 + --> $DIR/srcloc.rs:23:13 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:21:13 + --> $DIR/srcloc.rs:28:13 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -34,18 +34,6 @@ note: instantiated into assembly here LL | invalid_instruction | ^ -error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:27:13 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - | -note: instantiated into assembly here - --> :3:13 - | -LL | invalid_instruction - | ^ - error: unrecognized instruction mnemonic --> $DIR/srcloc.rs:34:13 | @@ -59,7 +47,19 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:39:14 + --> $DIR/srcloc.rs:41:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:46:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:43:14 + --> $DIR/srcloc.rs:50:14 | LL | "invalid_instruction", | ^^^^^^^^^^^^^^^^^^^ @@ -82,18 +82,6 @@ note: instantiated into assembly here LL | invalid_instruction | ^ -error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:49:14 - | -LL | "invalid_instruction", - | ^^^^^^^^^^^^^^^^^^^ - | -note: instantiated into assembly here - --> :2:1 - | -LL | invalid_instruction - | ^ - error: unrecognized instruction mnemonic --> $DIR/srcloc.rs:56:14 | @@ -101,19 +89,19 @@ LL | "invalid_instruction", | ^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here - --> :3:1 + --> :2:1 | LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:63:13 + --> $DIR/srcloc.rs:63:14 | -LL | concat!("invalid", "_", "instruction"), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here - --> :2:1 + --> :3:1 | LL | invalid_instruction | ^ @@ -131,7 +119,19 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:77:14 + --> $DIR/srcloc.rs:77:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:84:14 | LL | "invalid_instruction1", | ^^^^^^^^^^^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:78:14 + --> $DIR/srcloc.rs:85:14 | LL | "invalid_instruction2", | ^^^^^^^^^^^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:84:13 + --> $DIR/srcloc.rs:91:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -170,7 +170,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:84:13 + --> $DIR/srcloc.rs:91:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -185,7 +185,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:93:13 + --> $DIR/srcloc.rs:100:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -200,7 +200,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:93:13 + --> $DIR/srcloc.rs:100:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -215,7 +215,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:97:13 + --> $DIR/srcloc.rs:104:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -230,7 +230,7 @@ LL | invalid_instruction3 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:97:13 + --> $DIR/srcloc.rs:104:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -245,7 +245,7 @@ LL | invalid_instruction4 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:108:13 + --> $DIR/srcloc.rs:115:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -260,7 +260,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:108:13 + --> $DIR/srcloc.rs:115:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -275,7 +275,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:112:13 + --> $DIR/srcloc.rs:119:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -290,7 +290,7 @@ LL | invalid_instruction3 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:112:13 + --> $DIR/srcloc.rs:119:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -305,7 +305,7 @@ LL | invalid_instruction4 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:125:14 + --> $DIR/srcloc.rs:132:14 | LL | "invalid_instruction" | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/aarch64/ttbr0_el2.rs b/tests/ui/asm/aarch64/ttbr0_el2.rs index a283d75c8fff..4032c70ed03c 100644 --- a/tests/ui/asm/aarch64/ttbr0_el2.rs +++ b/tests/ui/asm/aarch64/ttbr0_el2.rs @@ -1,7 +1,15 @@ //! Regression test for #97724, recognising ttbr0_el2 as a valid armv8 system register -//@ only-aarch64 +//@ add-minicore //@ build-pass -use std::arch::asm; +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; static PT: [u64; 512] = [0; 512]; fn main() { diff --git a/tests/ui/asm/x86_64/bad-clobber-abi.rs b/tests/ui/asm/x86_64/bad-clobber-abi.rs index 5205a084162b..1b27c427b4df 100644 --- a/tests/ui/asm/x86_64/bad-clobber-abi.rs +++ b/tests/ui/asm/x86_64/bad-clobber-abi.rs @@ -1,7 +1,12 @@ -//@ needs-asm-support -//@ only-x86_64 +//@ add-minicore +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; // checks various modes of failure for the `clobber_abi` argument (after parsing) diff --git a/tests/ui/asm/x86_64/bad-clobber-abi.stderr b/tests/ui/asm/x86_64/bad-clobber-abi.stderr index 46e91a3951fb..a79506a2101d 100644 --- a/tests/ui/asm/x86_64/bad-clobber-abi.stderr +++ b/tests/ui/asm/x86_64/bad-clobber-abi.stderr @@ -1,21 +1,21 @@ error: invalid ABI for `clobber_abi` - --> $DIR/bad-clobber-abi.rs:11:18 + --> $DIR/bad-clobber-abi.rs:16:18 | LL | asm!("", clobber_abi("foo")); | ^^^^^^^^^^^^^^^^^^ | - = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, and `sysv64` error: invalid ABI for `clobber_abi` - --> $DIR/bad-clobber-abi.rs:13:35 + --> $DIR/bad-clobber-abi.rs:18:35 | LL | asm!("", clobber_abi("C", "foo")); | ^^^^^ | - = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, and `sysv64` error: `C` ABI specified multiple times - --> $DIR/bad-clobber-abi.rs:15:35 + --> $DIR/bad-clobber-abi.rs:20:35 | LL | asm!("", clobber_abi("C", "C")); | --- ^^^ @@ -23,7 +23,7 @@ LL | asm!("", clobber_abi("C", "C")); | previously specified here error: `win64` ABI specified multiple times - --> $DIR/bad-clobber-abi.rs:18:39 + --> $DIR/bad-clobber-abi.rs:23:39 | LL | asm!("", clobber_abi("win64", "efiapi")); | ------- ^^^^^^^^ @@ -33,15 +33,15 @@ LL | asm!("", clobber_abi("win64", "efiapi")); = note: these ABIs are equivalent on the current target error: invalid ABI for `clobber_abi` - --> $DIR/bad-clobber-abi.rs:20:35 + --> $DIR/bad-clobber-abi.rs:25:35 | LL | asm!("", clobber_abi("C", "foo", "C")); | ^^^^^ | - = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, and `sysv64` error: `C` ABI specified multiple times - --> $DIR/bad-clobber-abi.rs:20:42 + --> $DIR/bad-clobber-abi.rs:25:42 | LL | asm!("", clobber_abi("C", "foo", "C")); | --- ^^^ @@ -49,15 +49,15 @@ LL | asm!("", clobber_abi("C", "foo", "C")); | previously specified here error: invalid ABI for `clobber_abi` - --> $DIR/bad-clobber-abi.rs:23:39 + --> $DIR/bad-clobber-abi.rs:28:39 | LL | asm!("", clobber_abi("win64", "foo", "efiapi")); | ^^^^^ | - = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, and `sysv64` error: `win64` ABI specified multiple times - --> $DIR/bad-clobber-abi.rs:23:46 + --> $DIR/bad-clobber-abi.rs:28:46 | LL | asm!("", clobber_abi("win64", "foo", "efiapi")); | ------- ^^^^^^^^ @@ -67,7 +67,7 @@ LL | asm!("", clobber_abi("win64", "foo", "efiapi")); = note: these ABIs are equivalent on the current target error: `C` ABI specified multiple times - --> $DIR/bad-clobber-abi.rs:26:36 + --> $DIR/bad-clobber-abi.rs:31:36 | LL | asm!("", clobber_abi("C"), clobber_abi("C")); | ---------------- ^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | asm!("", clobber_abi("C"), clobber_abi("C")); | previously specified here error: `win64` ABI specified multiple times - --> $DIR/bad-clobber-abi.rs:29:40 + --> $DIR/bad-clobber-abi.rs:34:40 | LL | asm!("", clobber_abi("win64"), clobber_abi("efiapi")); | -------------------- ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/x86_64/bad-options.rs b/tests/ui/asm/x86_64/bad-options.rs index 123febc06fc9..594ee6016541 100644 --- a/tests/ui/asm/x86_64/bad-options.rs +++ b/tests/ui/asm/x86_64/bad-options.rs @@ -1,8 +1,13 @@ -//@ only-x86_64 - +//@ add-minicore +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] #![feature(asm_unwind)] -use std::arch::{asm, global_asm}; +extern crate minicore; +use minicore::*; fn main() { let mut foo = 0; diff --git a/tests/ui/asm/x86_64/bad-options.stderr b/tests/ui/asm/x86_64/bad-options.stderr index 366eb7cb90f3..576d5a1b7fd1 100644 --- a/tests/ui/asm/x86_64/bad-options.stderr +++ b/tests/ui/asm/x86_64/bad-options.stderr @@ -1,41 +1,41 @@ error: the `nomem` and `readonly` options are mutually exclusive - --> $DIR/bad-options.rs:10:18 + --> $DIR/bad-options.rs:15:18 | LL | asm!("", options(nomem, readonly)); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: the `pure` and `noreturn` options are mutually exclusive - --> $DIR/bad-options.rs:12:18 + --> $DIR/bad-options.rs:17:18 | LL | asm!("", options(pure, nomem, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm with the `pure` option must have at least one output - --> $DIR/bad-options.rs:12:18 + --> $DIR/bad-options.rs:17:18 | LL | asm!("", options(pure, nomem, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm with the `pure` option must have at least one output - --> $DIR/bad-options.rs:15:33 + --> $DIR/bad-options.rs:20:33 | LL | asm!("{}", in(reg) foo, options(pure, nomem)); | ^^^^^^^^^^^^^^^^^^^^ error: asm outputs are not allowed with the `noreturn` option - --> $DIR/bad-options.rs:17:20 + --> $DIR/bad-options.rs:22:20 | LL | asm!("{}", out(reg) foo, options(noreturn)); | ^^^^^^^^^^^^ error: asm labels are not allowed with the `may_unwind` option - --> $DIR/bad-options.rs:19:20 + --> $DIR/bad-options.rs:24:20 | LL | asm!("{}", label {}, options(may_unwind)); | ^^^^^^^^ error: asm with `clobber_abi` must specify explicit registers for outputs - --> $DIR/bad-options.rs:26:20 + --> $DIR/bad-options.rs:31:20 | LL | asm!("{}", out(reg) foo, clobber_abi("C")); | ^^^^^^^^^^^^ ---------------- clobber_abi @@ -43,7 +43,7 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C")); | generic outputs error: asm with `clobber_abi` must specify explicit registers for outputs - --> $DIR/bad-options.rs:28:20 + --> $DIR/bad-options.rs:33:20 | LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); | ^^^^^^^^^^^^ ---------------- ---------------- clobber_abi @@ -52,51 +52,51 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); | generic outputs error: the `nomem` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:35:25 + --> $DIR/bad-options.rs:40:25 | LL | global_asm!("", options(nomem)); | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly error: the `readonly` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:37:25 + --> $DIR/bad-options.rs:42:25 | LL | global_asm!("", options(readonly)); | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly error: the `noreturn` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:39:25 + --> $DIR/bad-options.rs:44:25 | LL | global_asm!("", options(noreturn)); | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly error: the `pure` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:41:25 + --> $DIR/bad-options.rs:46:25 | LL | global_asm!("", options(pure)); | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly error: the `nostack` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:43:25 + --> $DIR/bad-options.rs:48:25 | LL | global_asm!("", options(nostack)); | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly error: the `preserves_flags` option cannot be used with `global_asm!` - --> $DIR/bad-options.rs:45:25 + --> $DIR/bad-options.rs:50:25 | LL | global_asm!("", options(preserves_flags)); | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly error: invalid ABI for `clobber_abi` - --> $DIR/bad-options.rs:24:18 + --> $DIR/bad-options.rs:29:18 | LL | asm!("", clobber_abi("foo")); | ^^^^^^^^^^^^^^^^^^ | - = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, and `sysv64` error: `C` ABI specified multiple times - --> $DIR/bad-options.rs:28:52 + --> $DIR/bad-options.rs:33:52 | LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); | ---------------- ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr b/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr index 133921b894dd..fe2a53aec5d4 100644 --- a/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr +++ b/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr @@ -4,7 +4,7 @@ error: invalid register class `foo`: unknown register class LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ | - = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, `tmm_reg` + = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, and `tmm_reg` error: invalid register `foo`: unknown register --> $DIR/bad-reg.rs:22:18 @@ -12,7 +12,7 @@ error: invalid register `foo`: unknown register LL | asm!("", in("foo") foo); | ^^^^^^^^^^^^^ -error: invalid asm template modifier for this register class +error: invalid asm template modifier `z` for this register class --> $DIR/bad-reg.rs:24:15 | LL | asm!("{:z}", in(reg) foo); @@ -20,9 +20,9 @@ LL | asm!("{:z}", in(reg) foo); | | | template modifier | - = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r` + = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, and `r` -error: invalid asm template modifier for this register class +error: invalid asm template modifier `r` for this register class --> $DIR/bad-reg.rs:26:15 | LL | asm!("{:r}", in(xmm_reg) foo); @@ -30,7 +30,7 @@ LL | asm!("{:r}", in(xmm_reg) foo); | | | template modifier | - = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z` + = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, and `z` error: asm template modifiers are not allowed for `const` arguments --> $DIR/bad-reg.rs:28:15 diff --git a/tests/ui/asm/x86_64/bad-reg.rs b/tests/ui/asm/x86_64/bad-reg.rs index 4b3005d5675b..cc3def95508f 100644 --- a/tests/ui/asm/x86_64/bad-reg.rs +++ b/tests/ui/asm/x86_64/bad-reg.rs @@ -1,7 +1,7 @@ //@ add-minicore -//@ only-x86_64 //@ revisions: stable experimental_reg -//@ compile-flags: -C target-feature=+avx2,+avx512f +//@ compile-flags: --target x86_64-unknown-linux-gnu -C target-feature=+avx2,+avx512f +//@ needs-llvm-components: x86 #![cfg_attr(experimental_reg, feature(asm_experimental_reg))] #![crate_type = "lib"] @@ -22,9 +22,9 @@ fn main() { asm!("", in("foo") foo); //~^ ERROR invalid register `foo`: unknown register asm!("{:z}", in(reg) foo); - //~^ ERROR invalid asm template modifier for this register class + //~^ ERROR invalid asm template modifier `z` for this register class asm!("{:r}", in(xmm_reg) foo); - //~^ ERROR invalid asm template modifier for this register class + //~^ ERROR invalid asm template modifier `r` for this register class asm!("{:a}", const 0); //~^ ERROR asm template modifiers are not allowed for `const` arguments asm!("{:a}", sym main); diff --git a/tests/ui/asm/x86_64/bad-reg.stable.stderr b/tests/ui/asm/x86_64/bad-reg.stable.stderr index a1c2792a5b1f..d8a37933065e 100644 --- a/tests/ui/asm/x86_64/bad-reg.stable.stderr +++ b/tests/ui/asm/x86_64/bad-reg.stable.stderr @@ -4,7 +4,7 @@ error: invalid register class `foo`: unknown register class LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ | - = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, `tmm_reg` + = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, and `tmm_reg` error: invalid register `foo`: unknown register --> $DIR/bad-reg.rs:22:18 @@ -12,7 +12,7 @@ error: invalid register `foo`: unknown register LL | asm!("", in("foo") foo); | ^^^^^^^^^^^^^ -error: invalid asm template modifier for this register class +error: invalid asm template modifier `z` for this register class --> $DIR/bad-reg.rs:24:15 | LL | asm!("{:z}", in(reg) foo); @@ -20,9 +20,9 @@ LL | asm!("{:z}", in(reg) foo); | | | template modifier | - = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r` + = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, and `r` -error: invalid asm template modifier for this register class +error: invalid asm template modifier `r` for this register class --> $DIR/bad-reg.rs:26:15 | LL | asm!("{:r}", in(xmm_reg) foo); @@ -30,7 +30,7 @@ LL | asm!("{:r}", in(xmm_reg) foo); | | | template modifier | - = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z` + = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, and `z` error: asm template modifiers are not allowed for `const` arguments --> $DIR/bad-reg.rs:28:15 diff --git a/tests/ui/asm/x86_64/goto-block-safe.rs b/tests/ui/asm/x86_64/goto-block-safe.rs index b739e9f9ced8..1364425b07ac 100644 --- a/tests/ui/asm/x86_64/goto-block-safe.rs +++ b/tests/ui/asm/x86_64/goto-block-safe.rs @@ -1,16 +1,22 @@ -//@ only-x86_64 +//@ add-minicore +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 //@ needs-asm-support - +#![feature(no_core)] +#![no_core] #![deny(unreachable_code)] -use std::arch::asm; +extern crate minicore; +use minicore::*; + +unsafe fn such_unsafe() {} fn goto_fallthough() { unsafe { asm!( "/* {} */", label { - core::hint::unreachable_unchecked(); + such_unsafe() //~^ ERROR [E0133] } ) diff --git a/tests/ui/asm/x86_64/goto-block-safe.stderr b/tests/ui/asm/x86_64/goto-block-safe.stderr index ee7313bc8be3..3f9afdd6fc70 100644 --- a/tests/ui/asm/x86_64/goto-block-safe.stderr +++ b/tests/ui/asm/x86_64/goto-block-safe.stderr @@ -1,11 +1,11 @@ -error[E0133]: call to unsafe function `unreachable_unchecked` is unsafe and requires unsafe function or block - --> $DIR/goto-block-safe.rs:13:17 +error[E0133]: call to unsafe function `such_unsafe` is unsafe and requires unsafe function or block + --> $DIR/goto-block-safe.rs:19:17 | LL | unsafe { | ------ items do not inherit unsafety from separate enclosing items ... -LL | core::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function +LL | such_unsafe() + | ^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/tests/ui/asm/x86_64/interpolated-idents.rs b/tests/ui/asm/x86_64/interpolated-idents.rs index 4f349c5b2134..9790802679a1 100644 --- a/tests/ui/asm/x86_64/interpolated-idents.rs +++ b/tests/ui/asm/x86_64/interpolated-idents.rs @@ -1,6 +1,12 @@ -//@ only-x86_64 +//@ add-minicore +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; macro_rules! m { ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident diff --git a/tests/ui/asm/x86_64/interpolated-idents.stderr b/tests/ui/asm/x86_64/interpolated-idents.stderr index a91bc768fc4d..1fb817ec8de0 100644 --- a/tests/ui/asm/x86_64/interpolated-idents.stderr +++ b/tests/ui/asm/x86_64/interpolated-idents.stderr @@ -1,5 +1,5 @@ error: the `nomem` and `readonly` options are mutually exclusive - --> $DIR/interpolated-idents.rs:13:13 + --> $DIR/interpolated-idents.rs:19:13 | LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | | noreturn nostack att_syntax options); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: the `pure` and `noreturn` options are mutually exclusive - --> $DIR/interpolated-idents.rs:13:13 + --> $DIR/interpolated-idents.rs:19:13 | LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | | noreturn nostack att_syntax options); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm outputs are not allowed with the `noreturn` option - --> $DIR/interpolated-idents.rs:10:32 + --> $DIR/interpolated-idents.rs:16:32 | LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/x86_64/issue-82869.rs b/tests/ui/asm/x86_64/issue-82869.rs index 448ebd9c99f4..4af09cb0d63a 100644 --- a/tests/ui/asm/x86_64/issue-82869.rs +++ b/tests/ui/asm/x86_64/issue-82869.rs @@ -1,10 +1,14 @@ -//@ needs-asm-support -//@ only-x86_64 -// Make sure rustc doesn't ICE on asm! for a foreign architecture. - +//@ add-minicore +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 #![crate_type = "rlib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; + +// Make sure rustc doesn't ICE on asm! for a foreign architecture. pub unsafe fn aarch64(a: f64, b: f64) -> f64 { let c; diff --git a/tests/ui/asm/x86_64/issue-82869.stderr b/tests/ui/asm/x86_64/issue-82869.stderr index 56e490995691..56699ac9850b 100644 --- a/tests/ui/asm/x86_64/issue-82869.stderr +++ b/tests/ui/asm/x86_64/issue-82869.stderr @@ -1,21 +1,21 @@ error: invalid register class `vreg`: unknown register class - --> $DIR/issue-82869.rs:11:32 + --> $DIR/issue-82869.rs:15:32 | LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { | ^^^^^^^^^^^ | - = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, `tmm_reg` + = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, and `tmm_reg` error: invalid register class `vreg`: unknown register class - --> $DIR/issue-82869.rs:11:45 + --> $DIR/issue-82869.rs:15:45 | LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { | ^^^^^^^^^^ | - = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, `tmm_reg` + = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, and `tmm_reg` error: invalid register `d0`: unknown register - --> $DIR/issue-82869.rs:11:57 + --> $DIR/issue-82869.rs:15:57 | LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { | _________________________________________________________^ diff --git a/tests/ui/asm/x86_64/issue-89875.rs b/tests/ui/asm/x86_64/issue-89875.rs index 0252859cff0a..a45ef1b2d17e 100644 --- a/tests/ui/asm/x86_64/issue-89875.rs +++ b/tests/ui/asm/x86_64/issue-89875.rs @@ -1,9 +1,16 @@ //@ build-pass +//@ add-minicore +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 //@ needs-asm-support -//@ only-x86_64 +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; +#[unsafe(no_mangle)] #[target_feature(enable = "avx")] fn foo() { unsafe { @@ -13,5 +20,3 @@ fn foo() { ); } } - -fn main() {} diff --git a/tests/ui/asm/x86_64/issue-96797.rs b/tests/ui/asm/x86_64/issue-96797.rs index 531e16795dd8..9978a4856a81 100644 --- a/tests/ui/asm/x86_64/issue-96797.rs +++ b/tests/ui/asm/x86_64/issue-96797.rs @@ -1,13 +1,17 @@ +//@ add-minicore //@ build-pass -//@ compile-flags: -O -//@ needs-asm-support -//@ only-x86_64 -//@ only-linux +//@ compile-flags: --target x86_64-unknown-linux-gnu -O +//@ needs-llvm-components: x86 +//@ ignore-backends: gcc +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; // regression test for #96797 -use std::arch::global_asm; - #[no_mangle] fn my_func() {} diff --git a/tests/ui/asm/x86_64/srcloc.rs b/tests/ui/asm/x86_64/srcloc.rs index f4ffa8c5c3b2..e73854acf152 100644 --- a/tests/ui/asm/x86_64/srcloc.rs +++ b/tests/ui/asm/x86_64/srcloc.rs @@ -1,12 +1,19 @@ -//@ only-x86_64 +//@ add-minicore //@ build-fail -//@ compile-flags: -Ccodegen-units=1 +//@ compile-flags: --target x86_64-unknown-linux-gnu -Ccodegen-units=1 +//@ needs-llvm-components: x86 //@ ignore-backends: gcc +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; // Checks that inline asm errors are mapped to the correct line in the source code. +#[unsafe(no_mangle)] +#[rustfmt::skip] fn main() { unsafe { asm!("invalid_instruction"); diff --git a/tests/ui/asm/x86_64/srcloc.stderr b/tests/ui/asm/x86_64/srcloc.stderr index b2079120ec06..d2ab93f56b49 100644 --- a/tests/ui/asm/x86_64/srcloc.stderr +++ b/tests/ui/asm/x86_64/srcloc.stderr @@ -1,5 +1,5 @@ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:12:15 + --> $DIR/srcloc.rs:19:15 | LL | asm!("invalid_instruction"); | ^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:16:13 + --> $DIR/srcloc.rs:23:13 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:21:13 + --> $DIR/srcloc.rs:28:13 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -34,18 +34,6 @@ note: instantiated into assembly here LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:27:13 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - | -note: instantiated into assembly here - --> :4:13 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - error: invalid instruction mnemonic 'invalid_instruction' --> $DIR/srcloc.rs:34:13 | @@ -59,7 +47,19 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:39:14 + --> $DIR/srcloc.rs:41:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:46:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ warning: scale factor without index register is ignored - --> $DIR/srcloc.rs:42:15 + --> $DIR/srcloc.rs:49:15 | LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +83,7 @@ LL | movaps %xmm3, (%esi, 2) | ^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:46:14 + --> $DIR/srcloc.rs:53:14 | LL | "invalid_instruction", | ^^^^^^^^^^^^^^^^^^^ @@ -94,18 +94,6 @@ note: instantiated into assembly here LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:52:14 - | -LL | "invalid_instruction", - | ^^^^^^^^^^^^^^^^^^^ - | -note: instantiated into assembly here - --> :3:1 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - error: invalid instruction mnemonic 'invalid_instruction' --> $DIR/srcloc.rs:59:14 | @@ -113,19 +101,19 @@ LL | "invalid_instruction", | ^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here - --> :4:1 + --> :3:1 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:66:13 + --> $DIR/srcloc.rs:66:14 | -LL | concat!("invalid", "_", "instruction"), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here - --> :3:1 + --> :4:1 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -142,8 +130,20 @@ note: instantiated into assembly here LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:80:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:80:14 + --> $DIR/srcloc.rs:87:14 | LL | "invalid_instruction1", | ^^^^^^^^^^^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:81:14 + --> $DIR/srcloc.rs:88:14 | LL | "invalid_instruction2", | ^^^^^^^^^^^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:87:13 + --> $DIR/srcloc.rs:94:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -182,7 +182,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:87:13 + --> $DIR/srcloc.rs:94:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -197,7 +197,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:96:13 + --> $DIR/srcloc.rs:103:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -212,7 +212,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:96:13 + --> $DIR/srcloc.rs:103:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -227,7 +227,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:100:13 + --> $DIR/srcloc.rs:107:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -242,7 +242,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:100:13 + --> $DIR/srcloc.rs:107:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -257,7 +257,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:111:13 + --> $DIR/srcloc.rs:118:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -272,7 +272,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:111:13 + --> $DIR/srcloc.rs:118:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -287,7 +287,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:115:13 + --> $DIR/srcloc.rs:122:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -302,7 +302,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:115:13 + --> $DIR/srcloc.rs:122:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -317,7 +317,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:128:14 + --> $DIR/srcloc.rs:135:14 | LL | "invalid_instruction" | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/x86_64/target-feature-attr.rs b/tests/ui/asm/x86_64/target-feature-attr.rs index 2193117caeb6..ada5fecd797e 100644 --- a/tests/ui/asm/x86_64/target-feature-attr.rs +++ b/tests/ui/asm/x86_64/target-feature-attr.rs @@ -1,15 +1,20 @@ -//@ only-x86_64 +//@ add-minicore // Set the base cpu explicitly, in case the default has been changed. -//@ compile-flags: -C target-cpu=x86-64 +//@ compile-flags: --target x86_64-unknown-linux-gnu -C target-cpu=x86-64 +//@ needs-llvm-components: x86 +#![crate_type = "rlib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; #[target_feature(enable = "avx")] unsafe fn foo() { let mut x = 1; let y = 2; asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); - assert_eq!(x, 3); + let _ = x; } unsafe fn bar() { @@ -19,7 +24,7 @@ unsafe fn bar() { //~^ ERROR: register class `ymm_reg` requires the `avx` target feature //~| ERROR: register class `ymm_reg` requires the `avx` target feature //~| ERROR: register class `ymm_reg` requires the `avx` target feature - assert_eq!(x, 3); + let _ = x; } #[target_feature(enable = "avx512bw")] diff --git a/tests/ui/asm/x86_64/target-feature-attr.stderr b/tests/ui/asm/x86_64/target-feature-attr.stderr index c852726ee7ff..625f10416735 100644 --- a/tests/ui/asm/x86_64/target-feature-attr.stderr +++ b/tests/ui/asm/x86_64/target-feature-attr.stderr @@ -1,23 +1,23 @@ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:18:40 + --> $DIR/target-feature-attr.rs:23:40 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:18:55 + --> $DIR/target-feature-attr.rs:23:55 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:18:70 + --> $DIR/target-feature-attr.rs:23:70 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^^^^^^ error: register class `kreg` requires at least one of the following target features: avx512bw, avx512f - --> $DIR/target-feature-attr.rs:33:23 + --> $DIR/target-feature-attr.rs:38:23 | LL | asm!("/* {0} */", in(kreg) x); | ^^^^^^^^^^ diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.rs b/tests/ui/asm/x86_64/x86_64_parse_error.rs index 3df0febf6b07..3d011416c6f5 100644 --- a/tests/ui/asm/x86_64/x86_64_parse_error.rs +++ b/tests/ui/asm/x86_64/x86_64_parse_error.rs @@ -1,6 +1,12 @@ -//@ only-x86_64 +//@ add-minicore +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -use std::arch::asm; +extern crate minicore; +use minicore::*; fn main() { let mut foo = 0; @@ -14,6 +20,6 @@ fn main() { //~^ ERROR attempt to use a non-constant value in a constant asm!("{1}", in("eax") foo, const bar); //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments - //~^^ ERROR attempt to use a non-constant value in a constant + //~| ERROR attempt to use a non-constant value in a constant } } diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr index dfa3e1d0ef20..30d2c57c70a4 100644 --- a/tests/ui/asm/x86_64/x86_64_parse_error.stderr +++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr @@ -1,11 +1,11 @@ error: explicit register arguments cannot have names - --> $DIR/x86_64_parse_error.rs:9:18 + --> $DIR/x86_64_parse_error.rs:15:18 | LL | asm!("", a = in("eax") foo); | ^^^^^^^^^^^^^^^^^ error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/x86_64_parse_error.rs:15:36 + --> $DIR/x86_64_parse_error.rs:21:36 | LL | asm!("{1}", in("eax") foo, const bar); | ------------- ^^^^^^^^^ positional argument @@ -13,7 +13,7 @@ LL | asm!("{1}", in("eax") foo, const bar); | explicit register argument error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/x86_64_parse_error.rs:11:46 + --> $DIR/x86_64_parse_error.rs:17:46 | LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value @@ -25,7 +25,7 @@ LL + const bar: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/x86_64_parse_error.rs:13:46 + --> $DIR/x86_64_parse_error.rs:19:46 | LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value @@ -37,7 +37,7 @@ LL + const bar: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/x86_64_parse_error.rs:15:42 + --> $DIR/x86_64_parse_error.rs:21:42 | LL | asm!("{1}", in("eax") foo, const bar); | ^^^ non-constant value diff --git a/tests/ui/associated-consts/associated-const-in-trait.rs b/tests/ui/associated-consts/associated-const-in-trait.rs index 6b0b43feb109..da68a0fa97c8 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.rs +++ b/tests/ui/associated-consts/associated-const-in-trait.rs @@ -7,6 +7,8 @@ trait Trait { impl dyn Trait { //~^ ERROR the trait `Trait` is not dyn compatible [E0038] const fn n() -> usize { Self::N } + //~^ ERROR the trait `Trait` is not dyn compatible [E0038] + //~| ERROR the trait `Trait` is not dyn compatible [E0038] } fn main() {} diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr index fb4a55110b4e..4085f8c99078 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.stderr +++ b/tests/ui/associated-consts/associated-const-in-trait.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/associated-const-in-trait.rs:7:10 + --> $DIR/associated-const-in-trait.rs:7:6 | LL | impl dyn Trait { - | ^^^^^ `Trait` is not dyn compatible + | ^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -14,6 +14,38 @@ LL | const N: usize; | ^ ...because it contains associated const `N` = help: consider moving `N` to another trait -error: aborting due to 1 previous error +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/associated-const-in-trait.rs:9:29 + | +LL | const fn n() -> usize { Self::N } + | ^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/associated-const-in-trait.rs:4:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const N: usize; + | ^ ...because it contains associated const `N` + = help: consider moving `N` to another trait + +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/associated-const-in-trait.rs:9:29 + | +LL | const fn n() -> usize { Self::N } + | ^^^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/associated-const-in-trait.rs:4:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const N: usize; + | ^ ...because it contains associated const `N` + = help: consider moving `N` to another trait + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/associated-consts/associated-const-no-item.rs b/tests/ui/associated-consts/associated-const-no-item.rs index 024d14e21b5f..116f1aab3f48 100644 --- a/tests/ui/associated-consts/associated-const-no-item.rs +++ b/tests/ui/associated-consts/associated-const-no-item.rs @@ -3,7 +3,7 @@ trait Foo { } const X: i32 = ::ID; -//~^ ERROR no associated item named `ID` found +//~^ ERROR no associated function or constant named `ID` found fn main() { assert_eq!(1, X); diff --git a/tests/ui/associated-consts/associated-const-no-item.stderr b/tests/ui/associated-consts/associated-const-no-item.stderr index 7ded05b7b48e..40cd7791399b 100644 --- a/tests/ui/associated-consts/associated-const-no-item.stderr +++ b/tests/ui/associated-consts/associated-const-no-item.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `ID` found for type `i32` in the current scope +error[E0599]: no associated function or constant named `ID` found for type `i32` in the current scope --> $DIR/associated-const-no-item.rs:5:23 | LL | const X: i32 = ::ID; - | ^^ associated item not found in `i32` + | ^^ associated function or constant not found in `i32` | = help: items from traits can only be used if the trait is implemented and in scope note: `Foo` defines an item `ID`, perhaps you need to implement it diff --git a/tests/ui/associated-consts/type-const-in-array-len-wrong-type.rs b/tests/ui/associated-consts/type-const-in-array-len-wrong-type.rs index cb0b8a102eb4..c260ab1ee584 100644 --- a/tests/ui/associated-consts/type-const-in-array-len-wrong-type.rs +++ b/tests/ui/associated-consts/type-const-in-array-len-wrong-type.rs @@ -1,9 +1,6 @@ #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete #![feature(min_generic_const_args)] -//~^ WARN the feature `min_generic_const_args` is incomplete #![feature(inherent_associated_types)] -//~^ WARN the feature `inherent_associated_types` is incomplete struct OnDiskDirEntry<'a>(&'a ()); diff --git a/tests/ui/associated-consts/type-const-in-array-len-wrong-type.stderr b/tests/ui/associated-consts/type-const-in-array-len-wrong-type.stderr index b69a1b7fd7de..a90b1f666067 100644 --- a/tests/ui/associated-consts/type-const-in-array-len-wrong-type.stderr +++ b/tests/ui/associated-consts/type-const-in-array-len-wrong-type.stderr @@ -1,35 +1,10 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-const-in-array-len-wrong-type.rs:1:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-const-in-array-len-wrong-type.rs:3:12 - | -LL | #![feature(min_generic_const_args)] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #132980 for more information - -warning: the feature `inherent_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-const-in-array-len-wrong-type.rs:5:12 - | -LL | #![feature(inherent_associated_types)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #8995 for more information - error: the constant `2` is not of type `usize` - --> $DIR/type-const-in-array-len-wrong-type.rs:13:26 + --> $DIR/type-const-in-array-len-wrong-type.rs:10:26 | LL | fn lfn_contents() -> [char; Self::LFN_FRAGMENT_LEN] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `i64` | = note: the length of array `[char; 2]` must be type `usize` -error: aborting due to 1 previous error; 3 warnings emitted +error: aborting due to 1 previous error diff --git a/tests/ui/associated-consts/type-const-in-array-len.rs b/tests/ui/associated-consts/type-const-in-array-len.rs index d33eacaade2d..7a809cefe9f7 100644 --- a/tests/ui/associated-consts/type-const-in-array-len.rs +++ b/tests/ui/associated-consts/type-const-in-array-len.rs @@ -1,9 +1,7 @@ //@ check-pass #![feature(min_generic_const_args)] -//~^ WARN the feature `min_generic_const_args` is incomplete #![feature(inherent_associated_types)] -//~^ WARN the feature `inherent_associated_types` is incomplete // Test case from #138226: generic impl with multiple type parameters struct Foo(A, B); diff --git a/tests/ui/associated-consts/type-const-in-array-len.stderr b/tests/ui/associated-consts/type-const-in-array-len.stderr deleted file mode 100644 index 546995d13a0a..000000000000 --- a/tests/ui/associated-consts/type-const-in-array-len.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-const-in-array-len.rs:3:12 - | -LL | #![feature(min_generic_const_args)] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #132980 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `inherent_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-const-in-array-len.rs:5:12 - | -LL | #![feature(inherent_associated_types)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #8995 for more information - -warning: 2 warnings emitted - diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs index a33d4928f014..0de982142df4 100644 --- a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs @@ -7,5 +7,5 @@ impl Fail { fn main() { Fail::<()>::C - //~^ ERROR no associated item named `C` found for struct `Fail<()>` in the current scope + //~^ ERROR no associated function or constant named `C` found for struct `Fail<()>` in the current scope } diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr index c58163931071..0ddde320f95e 100644 --- a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr @@ -7,17 +7,16 @@ LL | struct Fail; = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error[E0599]: no associated item named `C` found for struct `Fail<()>` in the current scope +error[E0599]: no associated function or constant named `C` found for struct `Fail<()>` in the current scope --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg.rs:9:17 | LL | struct Fail; - | -------------- associated item `C` not found for this struct + | -------------- associated function or constant `C` not found for this struct ... LL | Fail::<()>::C - | ^ associated item not found in `Fail<()>` + | ^ associated function or constant not found in `Fail<()>` | - = note: the associated item was found for - - `Fail` + = note: the associated function or constant was found for `Fail` error: aborting due to 2 previous errors diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs index d891b7bd62b4..e4f2bbf24e6b 100644 --- a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs @@ -14,5 +14,5 @@ impl Fail { fn main() { Fail::::C //~^ ERROR: type mismatch - //~| ERROR no associated item named `C` found for struct `Fail` in the current scope + //~| ERROR no associated function or constant named `C` found for struct `Fail` in the current scope } diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr index 165e89010b68..04568b874b5e 100644 --- a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr @@ -15,17 +15,16 @@ note: required by a bound in `Fail` LL | struct Fail, U>(T); | ^^^^^^^^^ required by this bound in `Fail` -error[E0599]: no associated item named `C` found for struct `Fail` in the current scope +error[E0599]: no associated function or constant named `C` found for struct `Fail` in the current scope --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:23 | LL | struct Fail, U>(T); - | ---------------------------------- associated item `C` not found for this struct + | ---------------------------------- associated function or constant `C` not found for this struct ... LL | Fail::::C - | ^ associated item not found in `Fail` + | ^ associated function or constant not found in `Fail` | - = note: the associated item was found for - - `Fail` + = note: the associated function or constant was found for `Fail` error: aborting due to 2 previous errors diff --git a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs index e5c1f47b9e02..27b3b93f071d 100644 --- a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs +++ b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs @@ -2,7 +2,6 @@ // Regression test for #146467. #![feature(inherent_associated_types)] -//~^ WARN the feature `inherent_associated_types` is incomplete struct Foo(T); diff --git a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr index 4c0726d4ddca..b06add2f5db5 100644 --- a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr +++ b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr @@ -1,20 +1,11 @@ -warning: the feature `inherent_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/hr-do-not-blame-outlives-static-ice.rs:4:12 - | -LL | #![feature(inherent_associated_types)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #8995 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/hr-do-not-blame-outlives-static-ice.rs:9:6 + --> $DIR/hr-do-not-blame-outlives-static-ice.rs:8:6 | LL | impl<'a> Foo { | ^^ unconstrained lifetime parameter error[E0308]: mismatched types - --> $DIR/hr-do-not-blame-outlives-static-ice.rs:14:11 + --> $DIR/hr-do-not-blame-outlives-static-ice.rs:13:11 | LL | fn foo(_: for<'a> fn(Foo::Assoc)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other @@ -23,12 +14,12 @@ LL | fn foo(_: for<'a> fn(Foo::Assoc)) {} found struct `Foo fn(&'a ())>` error: higher-ranked subtype error - --> $DIR/hr-do-not-blame-outlives-static-ice.rs:14:1 + --> $DIR/hr-do-not-blame-outlives-static-ice.rs:13:1 | LL | fn foo(_: for<'a> fn(Foo::Assoc)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors Some errors have detailed explanations: E0207, E0308. For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.rs b/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.rs new file mode 100644 index 000000000000..960e19c21a2c --- /dev/null +++ b/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Znext-solver=globally +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Regression test for https://github.com/rust-lang/rust/issues/153539: + +struct S<'a>(&'a ()); + +impl S<'_> { + //~^ ERROR the type parameter `X` is not constrained by the impl trait, self type, or predicates + type P = (); +} + +fn ret_ref_local<'e>() -> &'e i32 { + let f: for<'a> fn(&'a i32) -> S<'a>::P = |x| _ = x; + + f(&1) + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr b/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr new file mode 100644 index 000000000000..74d88889223f --- /dev/null +++ b/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr @@ -0,0 +1,22 @@ +error[E0207]: the type parameter `X` is not constrained by the impl trait, self type, or predicates + --> $DIR/inherent-assoc-ty-mismatch-issue-153539.rs:9:6 + | +LL | impl S<'_> { + | ^ unconstrained type parameter + +error[E0308]: mismatched types + --> $DIR/inherent-assoc-ty-mismatch-issue-153539.rs:17:5 + | +LL | fn ret_ref_local<'e>() -> &'e i32 { + | ------- expected `&'e i32` because of return type +... +LL | f(&1) + | ^^^^^ expected `&i32`, found associated type + | + = help: consider constraining the associated type `S<'_>::P` to `&'e i32` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0207, E0308. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/associated-inherent-types/variance-computation-requires-equality.rs b/tests/ui/associated-inherent-types/variance-computation-requires-equality.rs index 3f726792b4a1..b7f8586e31e8 100644 --- a/tests/ui/associated-inherent-types/variance-computation-requires-equality.rs +++ b/tests/ui/associated-inherent-types/variance-computation-requires-equality.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(inherent_associated_types)] -//~^ WARN the feature `inherent_associated_types` is incomplete struct D { a: T diff --git a/tests/ui/associated-inherent-types/variance-computation-requires-equality.stderr b/tests/ui/associated-inherent-types/variance-computation-requires-equality.stderr deleted file mode 100644 index 93064f551abd..000000000000 --- a/tests/ui/associated-inherent-types/variance-computation-requires-equality.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `inherent_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/variance-computation-requires-equality.rs:3:12 - | -LL | #![feature(inherent_associated_types)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #8995 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/associated-item/associated-item-enum.rs b/tests/ui/associated-item/associated-item-enum.rs index 30ba258155bb..3a5c058f5ec2 100644 --- a/tests/ui/associated-item/associated-item-enum.rs +++ b/tests/ui/associated-item/associated-item-enum.rs @@ -14,7 +14,7 @@ fn misspellable_trait() {} } fn main() { - Enum::mispellable(); //~ ERROR no variant or associated item - Enum::mispellable_trait(); //~ ERROR no variant or associated item - Enum::MISPELLABLE; //~ ERROR no variant or associated item + Enum::mispellable(); //~ ERROR no variant, associated function, or constant + Enum::mispellable_trait(); //~ ERROR no variant, associated function, or constant + Enum::MISPELLABLE; //~ ERROR no variant, associated function, or constant } diff --git a/tests/ui/associated-item/associated-item-enum.stderr b/tests/ui/associated-item/associated-item-enum.stderr index c3ce7c34d056..6cb53e5cd0cc 100644 --- a/tests/ui/associated-item/associated-item-enum.stderr +++ b/tests/ui/associated-item/associated-item-enum.stderr @@ -1,39 +1,39 @@ -error[E0599]: no variant or associated item named `mispellable` found for enum `Enum` in the current scope +error[E0599]: no variant, associated function, or constant named `mispellable` found for enum `Enum` in the current scope --> $DIR/associated-item-enum.rs:17:11 | LL | enum Enum { Variant } - | --------- variant or associated item `mispellable` not found for this enum + | --------- variant, associated function, or constant `mispellable` not found for this enum ... LL | Enum::mispellable(); - | ^^^^^^^^^^^ variant or associated item not found in `Enum` + | ^^^^^^^^^^^ variant, associated function, or constant not found in `Enum` | help: there is an associated function `misspellable` with a similar name | LL | Enum::misspellable(); | + -error[E0599]: no variant or associated item named `mispellable_trait` found for enum `Enum` in the current scope +error[E0599]: no variant, associated function, or constant named `mispellable_trait` found for enum `Enum` in the current scope --> $DIR/associated-item-enum.rs:18:11 | LL | enum Enum { Variant } - | --------- variant or associated item `mispellable_trait` not found for this enum + | --------- variant, associated function, or constant `mispellable_trait` not found for this enum ... LL | Enum::mispellable_trait(); - | ^^^^^^^^^^^^^^^^^ variant or associated item not found in `Enum` + | ^^^^^^^^^^^^^^^^^ variant, associated function, or constant not found in `Enum` | help: there is an associated function `misspellable_trait` with a similar name | LL | Enum::misspellable_trait(); | + -error[E0599]: no variant or associated item named `MISPELLABLE` found for enum `Enum` in the current scope +error[E0599]: no variant, associated function, or constant named `MISPELLABLE` found for enum `Enum` in the current scope --> $DIR/associated-item-enum.rs:19:11 | LL | enum Enum { Variant } - | --------- variant or associated item `MISPELLABLE` not found for this enum + | --------- variant, associated function, or constant `MISPELLABLE` not found for this enum ... LL | Enum::MISPELLABLE; - | ^^^^^^^^^^^ variant or associated item not found in `Enum` + | ^^^^^^^^^^^ variant, associated function, or constant not found in `Enum` | help: there is an associated constant `MISSPELLABLE` with a similar name | diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr index 7abcabc1c79d..978c377d438a 100644 --- a/tests/ui/associated-item/issue-48027.stderr +++ b/tests/ui/associated-item/issue-48027.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-48027.rs:6:10 + --> $DIR/issue-48027.rs:6:6 | LL | impl dyn Bar {} - | ^^^ `Bar` is not dyn compatible + | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr index 3b89ed66b355..50bafc96acaa 100644 --- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:13:21 | LL | const N: C::M = 4u8; - | ^^^ expected associated type, found `u8` + | ---- ^^^ expected associated type, found `u8` + | | + | expected because of the type of the associated constant | = note: expected associated type `::M` found type `u8` diff --git a/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.next.stderr b/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.next.stderr new file mode 100644 index 000000000000..30eccc3a72d5 --- /dev/null +++ b/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.next.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `Self: Eq<::Assoc>` is not satisfied + --> $DIR/always-applicable-impls-shadowed-in-trait-def.rs:13:17 + | +LL | fn foo() -> IsEqual { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<::Assoc>` is not implemented for `Self` + | +note: required by a bound in `IsEqual` + --> $DIR/always-applicable-impls-shadowed-in-trait-def.rs:9:19 + | +LL | struct IsEqual, U>(T, U); + | ^^^^^ required by this bound in `IsEqual` +help: consider further restricting `Self` + | +LL | fn foo() -> IsEqual where Self: Eq<::Assoc> { + | ++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.old.stderr b/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.old.stderr new file mode 100644 index 000000000000..30eccc3a72d5 --- /dev/null +++ b/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.old.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `Self: Eq<::Assoc>` is not satisfied + --> $DIR/always-applicable-impls-shadowed-in-trait-def.rs:13:17 + | +LL | fn foo() -> IsEqual { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<::Assoc>` is not implemented for `Self` + | +note: required by a bound in `IsEqual` + --> $DIR/always-applicable-impls-shadowed-in-trait-def.rs:9:19 + | +LL | struct IsEqual, U>(T, U); + | ^^^^^ required by this bound in `IsEqual` +help: consider further restricting `Self` + | +LL | fn foo() -> IsEqual where Self: Eq<::Assoc> { + | ++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.rs b/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.rs new file mode 100644 index 000000000000..2f8abb6a70d8 --- /dev/null +++ b/tests/ui/associated-types/always-applicable-impls-shadowed-in-trait-def.rs @@ -0,0 +1,23 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +// Testing that even if there's an always applicable blanket impl, the trait +// definition cannot use that impl to normalize its own associated types. + +trait Eq {} +impl Eq for T {} +struct IsEqual, U>(T, U); + +trait Trait: Sized { + type Assoc; + fn foo() -> IsEqual { + //~^ ERROR the trait bound `Self: Eq<::Assoc>` is not satisfied + todo!() + } +} + +impl Trait for T { + type Assoc = T; +} + +fn main() {} diff --git a/tests/ui/associated-types/associated-type-as-value-in-impl-issue-142797.rs b/tests/ui/associated-types/associated-type-as-value-in-impl-issue-142797.rs new file mode 100644 index 000000000000..f588d6d0a43f --- /dev/null +++ b/tests/ui/associated-types/associated-type-as-value-in-impl-issue-142797.rs @@ -0,0 +1,21 @@ +// issue: + +struct SomeStruct { + some_field: u64, +} + +trait SomeTrait { + type SomeType; + fn foo(); +} + +impl SomeTrait for bool { + type SomeType = SomeStruct; + + fn foo() { + let ss = Self::SomeType; + //~^ ERROR no associated function or constant named `SomeType` found for type `bool` in the current scope + } +} + +fn main() {} diff --git a/tests/ui/associated-types/associated-type-as-value-in-impl-issue-142797.stderr b/tests/ui/associated-types/associated-type-as-value-in-impl-issue-142797.stderr new file mode 100644 index 000000000000..83b915c2684e --- /dev/null +++ b/tests/ui/associated-types/associated-type-as-value-in-impl-issue-142797.stderr @@ -0,0 +1,9 @@ +error[E0599]: no associated function or constant named `SomeType` found for type `bool` in the current scope + --> $DIR/associated-type-as-value-in-impl-issue-142797.rs:16:24 + | +LL | let ss = Self::SomeType; + | ^^^^^^^^ associated function or constant not found in `bool` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/associated-types/associated-type-as-value.rs b/tests/ui/associated-types/associated-type-as-value.rs index ddc808236658..7fefc48eb337 100644 --- a/tests/ui/associated-types/associated-type-as-value.rs +++ b/tests/ui/associated-types/associated-type-as-value.rs @@ -1,7 +1,7 @@ //! regression test for fn foo() { - T::Item; //~ ERROR no associated item named `Item` found + T::Item; //~ ERROR no associated function or constant named `Item` found } fn main() { } diff --git a/tests/ui/associated-types/associated-type-as-value.stderr b/tests/ui/associated-types/associated-type-as-value.stderr index c553582b3907..0015ebe767dd 100644 --- a/tests/ui/associated-types/associated-type-as-value.stderr +++ b/tests/ui/associated-types/associated-type-as-value.stderr @@ -1,10 +1,10 @@ -error[E0599]: no associated item named `Item` found for type parameter `T` in the current scope +error[E0599]: no associated function or constant named `Item` found for type parameter `T` in the current scope --> $DIR/associated-type-as-value.rs:4:8 | LL | fn foo() { - | - associated item `Item` not found for this type parameter + | - associated function or constant `Item` not found for this type parameter LL | T::Item; - | ^^^^ associated item not found in `T` + | ^^^^ associated function or constant not found in `T` error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/associated-type-call.fixed b/tests/ui/associated-types/associated-type-call.fixed index d450b3b82c96..f2df7807b31e 100644 --- a/tests/ui/associated-types/associated-type-call.fixed +++ b/tests/ui/associated-types/associated-type-call.fixed @@ -15,7 +15,7 @@ impl Trait for () { fn f() { T(); - //~^ ERROR no associated item named `Assoc` found for unit type `()` in the current scope + //~^ ERROR no associated function or constant named `Assoc` found for unit type `()` in the current scope } } diff --git a/tests/ui/associated-types/associated-type-call.rs b/tests/ui/associated-types/associated-type-call.rs index ffe540c329eb..88d017219b78 100644 --- a/tests/ui/associated-types/associated-type-call.rs +++ b/tests/ui/associated-types/associated-type-call.rs @@ -15,7 +15,7 @@ impl Trait for () { fn f() { ::Assoc(); - //~^ ERROR no associated item named `Assoc` found for unit type `()` in the current scope + //~^ ERROR no associated function or constant named `Assoc` found for unit type `()` in the current scope } } diff --git a/tests/ui/associated-types/associated-type-call.stderr b/tests/ui/associated-types/associated-type-call.stderr index eaef775e3040..94cfc2446562 100644 --- a/tests/ui/associated-types/associated-type-call.stderr +++ b/tests/ui/associated-types/associated-type-call.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `Assoc` found for unit type `()` in the current scope +error[E0599]: no associated function or constant named `Assoc` found for unit type `()` in the current scope --> $DIR/associated-type-call.rs:17:17 | LL | ::Assoc(); - | ^^^^^ associated item not found in `()` + | ^^^^^ associated function or constant not found in `()` | help: to construct a value of type `T`, use the explicit path | diff --git a/tests/ui/associated-types/defaults-in-other-trait-items.rs b/tests/ui/associated-types/defaults-in-other-trait-items.rs index 3de64e0d0db6..7b3e7f96acb5 100644 --- a/tests/ui/associated-types/defaults-in-other-trait-items.rs +++ b/tests/ui/associated-types/defaults-in-other-trait-items.rs @@ -37,6 +37,7 @@ trait AssocConst { //~^ ERROR mismatched types //~| NOTE expected associated type, found `u8` //~| NOTE expected associated type `::Ty` + //~| NOTE expected because } // An impl can, however diff --git a/tests/ui/associated-types/defaults-in-other-trait-items.stderr b/tests/ui/associated-types/defaults-in-other-trait-items.stderr index 56abd6ebf73b..fe9023e52324 100644 --- a/tests/ui/associated-types/defaults-in-other-trait-items.stderr +++ b/tests/ui/associated-types/defaults-in-other-trait-items.stderr @@ -19,13 +19,15 @@ LL | type Ty = u8; | ------- associated type defaults can't be assumed inside the trait defining them ... LL | const C: Self::Ty = 0u8; - | ^^^ expected associated type, found `u8` + | -------- ^^^ expected associated type, found `u8` + | | + | expected because of the type of the associated constant | = note: expected associated type `::Ty` found type `u8` error[E0308]: mismatched types - --> $DIR/defaults-in-other-trait-items.rs:54:9 + --> $DIR/defaults-in-other-trait-items.rs:55:9 | LL | type Res = isize; | -------- associated type defaults can't be assumed inside the trait defining them diff --git a/tests/ui/associated-types/defaults-specialization.rs b/tests/ui/associated-types/defaults-specialization.rs index 553705b2a4fa..d0ed718b8392 100644 --- a/tests/ui/associated-types/defaults-specialization.rs +++ b/tests/ui/associated-types/defaults-specialization.rs @@ -1,7 +1,6 @@ //! Tests the interaction of associated type defaults and specialization. #![feature(associated_type_defaults, specialization)] -//~^ WARN the feature `specialization` is incomplete trait Tr { type Ty = u8; diff --git a/tests/ui/associated-types/defaults-specialization.stderr b/tests/ui/associated-types/defaults-specialization.stderr index d22d9ce659a7..2e880a7d50ad 100644 --- a/tests/ui/associated-types/defaults-specialization.stderr +++ b/tests/ui/associated-types/defaults-specialization.stderr @@ -1,21 +1,11 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/defaults-specialization.rs:3:38 - | -LL | #![feature(associated_type_defaults, specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0053]: method `make` has an incompatible type for trait - --> $DIR/defaults-specialization.rs:19:18 + --> $DIR/defaults-specialization.rs:18:18 | LL | fn make() -> u8 { 0 } | ^^ expected associated type, found `u8` | note: type in trait - --> $DIR/defaults-specialization.rs:9:18 + --> $DIR/defaults-specialization.rs:8:18 | LL | fn make() -> Self::Ty { | ^^^^^^^^ @@ -28,7 +18,7 @@ LL + fn make() -> as Tr>::Ty { 0 } | error[E0053]: method `make` has an incompatible type for trait - --> $DIR/defaults-specialization.rs:35:18 + --> $DIR/defaults-specialization.rs:34:18 | LL | default type Ty = bool; | --------------- associated type is `default` and may be overridden @@ -37,7 +27,7 @@ LL | fn make() -> bool { true } | ^^^^ expected associated type, found `bool` | note: type in trait - --> $DIR/defaults-specialization.rs:9:18 + --> $DIR/defaults-specialization.rs:8:18 | LL | fn make() -> Self::Ty { | ^^^^^^^^ @@ -50,7 +40,7 @@ LL + fn make() -> as Tr>::Ty { true } | error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:10:9 + --> $DIR/defaults-specialization.rs:9:9 | LL | type Ty = u8; | ------- associated type defaults can't be assumed inside the trait defining them @@ -64,7 +54,7 @@ LL | 0u8 found type `u8` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:26:29 + --> $DIR/defaults-specialization.rs:25:29 | LL | fn make() -> Self::Ty { 0u8 } | -------- ^^^ expected associated type, found `u8` @@ -79,7 +69,7 @@ LL | fn make() -> Self::Ty { 0u8 } see issue #152409 for more information error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:44:29 + --> $DIR/defaults-specialization.rs:43:29 | LL | default type Ty = bool; | --------------- associated type is `default` and may be overridden @@ -95,7 +85,7 @@ LL | fn make() -> Self::Ty { true } see issue #152409 for more information error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:87:32 + --> $DIR/defaults-specialization.rs:86:32 | LL | let _: as Tr>::Ty = 0u8; | ----------------- ^^^ expected associated type, found `u8` @@ -105,13 +95,13 @@ LL | let _: as Tr>::Ty = 0u8; = note: expected associated type ` as Tr>::Ty` found type `u8` help: a method is available that returns ` as Tr>::Ty` - --> $DIR/defaults-specialization.rs:9:5 + --> $DIR/defaults-specialization.rs:8:5 | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:88:32 + --> $DIR/defaults-specialization.rs:87:32 | LL | let _: as Tr>::Ty = true; | ----------------- ^^^^ expected associated type, found `bool` @@ -121,7 +111,7 @@ LL | let _: as Tr>::Ty = true; = note: expected associated type ` as Tr>::Ty` found type `bool` help: a method is available that returns ` as Tr>::Ty` - --> $DIR/defaults-specialization.rs:9:5 + --> $DIR/defaults-specialization.rs:8:5 | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` @@ -129,7 +119,7 @@ LL | fn make() -> Self::Ty { see issue #152409 for more information error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:89:33 + --> $DIR/defaults-specialization.rs:88:33 | LL | let _: as Tr>::Ty = 0u8; | ------------------ ^^^ expected associated type, found `u8` @@ -139,13 +129,13 @@ LL | let _: as Tr>::Ty = 0u8; = note: expected associated type ` as Tr>::Ty` found type `u8` help: a method is available that returns ` as Tr>::Ty` - --> $DIR/defaults-specialization.rs:9:5 + --> $DIR/defaults-specialization.rs:8:5 | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:90:33 + --> $DIR/defaults-specialization.rs:89:33 | LL | let _: as Tr>::Ty = true; | ------------------ ^^^^ expected associated type, found `bool` @@ -155,14 +145,14 @@ LL | let _: as Tr>::Ty = true; = note: expected associated type ` as Tr>::Ty` found type `bool` help: a method is available that returns ` as Tr>::Ty` - --> $DIR/defaults-specialization.rs:9:5 + --> $DIR/defaults-specialization.rs:8:5 | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` = note: the associated type ` as Tr>::Ty` is defined as `bool` in the implementation, but the where-bound `B2<()>` shadows this definition see issue #152409 for more information -error: aborting due to 9 previous errors; 1 warning emitted +error: aborting due to 9 previous errors Some errors have detailed explanations: E0053, E0308. For more information about an error, try `rustc --explain E0053`. diff --git a/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs b/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs new file mode 100644 index 000000000000..ad999a1c7735 --- /dev/null +++ b/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs @@ -0,0 +1,20 @@ +// Regression test for #112104. +// +// Don't suggest `Item = &::Item` when +// the expected type wraps the found projection. + +fn option_of_ref_assoc(iter: &mut I) { + let _: Option<&I::Item> = iter.next(); + //~^ ERROR mismatched types +} + +// Valid constraint suggestions should still fire. +trait Foo { + type Assoc; +} + +fn assoc_to_concrete(x: T::Assoc) -> u32 { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr b/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr new file mode 100644 index 000000000000..e6e37cdf7e51 --- /dev/null +++ b/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr @@ -0,0 +1,33 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-self-referential-constraint.rs:7:31 + | +LL | let _: Option<&I::Item> = iter.next(); + | ---------------- ^^^^^^^^^^^ expected `Option<&::Item>`, found `Option<::Item>` + | | + | expected due to this + | + = note: expected enum `Option<&_>` + found enum `Option<_>` +help: try using `.as_ref()` to convert `Option<::Item>` to `Option<&::Item>` + | +LL | let _: Option<&I::Item> = iter.next().as_ref(); + | +++++++++ + +error[E0308]: mismatched types + --> $DIR/dont-suggest-self-referential-constraint.rs:17:5 + | +LL | fn assoc_to_concrete(x: T::Assoc) -> u32 { + | --- expected `u32` because of return type +LL | x + | ^ expected `u32`, found associated type + | + = note: expected type `u32` + found associated type `::Assoc` +help: consider constraining the associated type `::Assoc` to `u32` + | +LL | fn assoc_to_concrete>(x: T::Assoc) -> u32 { + | +++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-types/invalid-ctor.fixed b/tests/ui/associated-types/invalid-ctor.fixed index eba3820de0c1..75980101f045 100644 --- a/tests/ui/associated-types/invalid-ctor.fixed +++ b/tests/ui/associated-types/invalid-ctor.fixed @@ -15,7 +15,7 @@ impl Trait for () { fn mk() -> Self::Out { Constructor(1) - //~^ ERROR no associated item named `Out` found for unit type `()` + //~^ ERROR no associated function or constant named `Out` found for unit type `()` } } diff --git a/tests/ui/associated-types/invalid-ctor.rs b/tests/ui/associated-types/invalid-ctor.rs index 73335c065c2a..82ec17df430f 100644 --- a/tests/ui/associated-types/invalid-ctor.rs +++ b/tests/ui/associated-types/invalid-ctor.rs @@ -15,7 +15,7 @@ impl Trait for () { fn mk() -> Self::Out { Self::Out(1) - //~^ ERROR no associated item named `Out` found for unit type `()` + //~^ ERROR no associated function or constant named `Out` found for unit type `()` } } diff --git a/tests/ui/associated-types/invalid-ctor.stderr b/tests/ui/associated-types/invalid-ctor.stderr index 0b3bf316f60f..50dc7188b681 100644 --- a/tests/ui/associated-types/invalid-ctor.stderr +++ b/tests/ui/associated-types/invalid-ctor.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `Out` found for unit type `()` in the current scope +error[E0599]: no associated function or constant named `Out` found for unit type `()` in the current scope --> $DIR/invalid-ctor.rs:17:15 | LL | Self::Out(1) - | ^^^ associated item not found in `()` + | ^^^ associated function or constant not found in `()` | help: to construct a value of type `Constructor`, use the explicit path | diff --git a/tests/ui/associated-types/issue-26681.stderr b/tests/ui/associated-types/issue-26681.stderr index 5fb1a4ef3f5f..798f0eb392c4 100644 --- a/tests/ui/associated-types/issue-26681.stderr +++ b/tests/ui/associated-types/issue-26681.stderr @@ -4,7 +4,9 @@ error[E0308]: mismatched types LL | type Fv: Foo = u8; | ------------ associated type defaults can't be assumed inside the trait defining them LL | const C: ::Bar = 6665; - | ^^^^ expected associated type, found integer + | ---------------------- ^^^^ expected associated type, found integer + | | + | expected because of the type of the associated constant | = note: expected associated type `<::Fv as Foo>::Bar` found type `{integer}` diff --git a/tests/ui/associated-types/issue-43924.rs b/tests/ui/associated-types/issue-43924.rs index 63ebbddea76f..dfc84611e8f6 100644 --- a/tests/ui/associated-types/issue-43924.rs +++ b/tests/ui/associated-types/issue-43924.rs @@ -13,5 +13,5 @@ impl Foo for () {} fn main() { assert_eq!(<() as Foo>::Out::default().to_string(), "false"); - //~^ ERROR no function or associated item named `default` found for trait object + //~^ ERROR no associated function or constant named `default` found for trait object } diff --git a/tests/ui/associated-types/issue-43924.stderr b/tests/ui/associated-types/issue-43924.stderr index 196ad85f084e..5bf8ee730e61 100644 --- a/tests/ui/associated-types/issue-43924.stderr +++ b/tests/ui/associated-types/issue-43924.stderr @@ -10,11 +10,11 @@ note: required by a bound in `Foo::Out` LL | type Out: Default + ToString + ?Sized = dyn ToString; | ^^^^^^^ required by this bound in `Foo::Out` -error[E0599]: no function or associated item named `default` found for trait object `(dyn ToString + 'static)` in the current scope +error[E0599]: no associated function or constant named `default` found for trait object `(dyn ToString + 'static)` in the current scope --> $DIR/issue-43924.rs:15:39 | LL | assert_eq!(<() as Foo>::Out::default().to_string(), "false"); - | ^^^^^^^ function or associated item not found in `(dyn ToString + 'static)` + | ^^^^^^^ associated function or constant not found in `(dyn ToString + 'static)` error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/issue-64855-2.rs b/tests/ui/associated-types/issue-64855-2.rs index 20b8ff17e9e5..5509ebb2e4e9 100644 --- a/tests/ui/associated-types/issue-64855-2.rs +++ b/tests/ui/associated-types/issue-64855-2.rs @@ -3,6 +3,6 @@ // also inadvertently a test for the (non-)co-inductiveness of WF predicates. pub struct Bar<'a>(&'a Self) where Self: ; -//~^ ERROR overflow evaluating the requirement `Bar<'a> well-formed` +//~^ ERROR overflow evaluating whether `Bar<'a>` is well-formed fn main() {} diff --git a/tests/ui/associated-types/issue-64855-2.stderr b/tests/ui/associated-types/issue-64855-2.stderr index 22292a8721a1..75da64505916 100644 --- a/tests/ui/associated-types/issue-64855-2.stderr +++ b/tests/ui/associated-types/issue-64855-2.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `Bar<'a> well-formed` +error[E0275]: overflow evaluating whether `Bar<'a>` is well-formed --> $DIR/issue-64855-2.rs:5:36 | LL | pub struct Bar<'a>(&'a Self) where Self: ; diff --git a/tests/ui/associated-types/issue-64855.rs b/tests/ui/associated-types/issue-64855.rs index 5d325b981a2c..003f11f4a509 100644 --- a/tests/ui/associated-types/issue-64855.rs +++ b/tests/ui/associated-types/issue-64855.rs @@ -8,6 +8,6 @@ pub trait Foo { pub struct Bar(::Type) where Self: ; //~^ ERROR the trait bound `Bar: Foo` is not satisfied -//~| ERROR overflow evaluating the requirement `Bar well-formed` +//~| ERROR overflow evaluating whether `Bar` is well-formed fn main() {} diff --git a/tests/ui/associated-types/issue-64855.stderr b/tests/ui/associated-types/issue-64855.stderr index 4358ab473651..9472dbf6adb6 100644 --- a/tests/ui/associated-types/issue-64855.stderr +++ b/tests/ui/associated-types/issue-64855.stderr @@ -15,7 +15,7 @@ help: this trait has no implementations, consider adding one LL | pub trait Foo { | ^^^^^^^^^^^^^ -error[E0275]: overflow evaluating the requirement `Bar well-formed` +error[E0275]: overflow evaluating whether `Bar` is well-formed --> $DIR/issue-64855.rs:9:46 | LL | pub struct Bar(::Type) where Self: ; diff --git a/tests/ui/async-await/async-closures/is-fn.rs b/tests/ui/async-await/async-closures/is-fn.rs index 45c2b6ae342b..1d546cd44b49 100644 --- a/tests/ui/async-await/async-closures/is-fn.rs +++ b/tests/ui/async-await/async-closures/is-fn.rs @@ -9,11 +9,11 @@ extern crate block_on; -// Check that closures that don't capture any state may implement `Fn`. +// Check that async closures that don't capture any state may implement `Fn`. fn main() { block_on::block_on(async { - async fn call_once(x: impl FnOnce(&'static str) -> F) -> F::Output { + async fn call_once(x: impl Fn(&'static str) -> F) -> F::Output { x("hello, world").await } call_once(async |x: &'static str| { diff --git a/tests/ui/async-await/async-closures/unifying-function-types-involving-hrtb.rs b/tests/ui/async-await/async-closures/unifying-function-types-involving-hrtb.rs new file mode 100644 index 000000000000..05505206b713 --- /dev/null +++ b/tests/ui/async-await/async-closures/unifying-function-types-involving-hrtb.rs @@ -0,0 +1,33 @@ +//! Regresssion test for . + +//@ edition:2018 +//@ check-pass + +use std::future::Future; + +trait Foo<'a> { + type Future: Future + 'a; + + fn start(self, f: &'a u8) -> Self::Future; +} + +impl<'a, Fn, Fut> Foo<'a> for Fn +where + Fn: FnOnce(&'a u8) -> Fut, + Fut: Future + 'a, +{ + type Future = Fut; + + fn start(self, f: &'a u8) -> Self::Future { (self)(f) } +} + +fn foo(f: F) where F: for<'a> Foo<'a> { + let bar = 5; + f.start(&bar); +} + +fn main() { + foo(async move | f: &u8 | { *f }); + + foo({ async fn baz(f: &u8) -> u8 { *f } baz }); +} diff --git a/tests/ui/async-await/async-drop/foreign-fundamental.rs b/tests/ui/async-await/async-drop/foreign-fundamental.rs index 1c192fccd9f0..44be20449469 100644 --- a/tests/ui/async-await/async-drop/foreign-fundamental.rs +++ b/tests/ui/async-await/async-drop/foreign-fundamental.rs @@ -1,7 +1,6 @@ //@ edition: 2018 #![feature(async_drop)] -//~^ WARN the feature `async_drop` is incomplete use std::future::AsyncDrop; use std::pin::Pin; diff --git a/tests/ui/async-await/async-drop/foreign-fundamental.stderr b/tests/ui/async-await/async-drop/foreign-fundamental.stderr index 7b52329ac99d..78bfdf66901a 100644 --- a/tests/ui/async-await/async-drop/foreign-fundamental.stderr +++ b/tests/ui/async-await/async-drop/foreign-fundamental.stderr @@ -1,24 +1,15 @@ -warning: the feature `async_drop` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/foreign-fundamental.rs:3:12 - | -LL | #![feature(async_drop)] - | ^^^^^^^^^^ - | - = note: see issue #126482 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0120]: the `AsyncDrop` trait may only be implemented for local structs, enums, and unions - --> $DIR/foreign-fundamental.rs:11:20 + --> $DIR/foreign-fundamental.rs:10:20 | LL | impl AsyncDrop for &Foo { | ^^^^ must be a struct, enum, or union in the current crate error[E0120]: the `AsyncDrop` trait may only be implemented for local structs, enums, and unions - --> $DIR/foreign-fundamental.rs:16:20 + --> $DIR/foreign-fundamental.rs:15:20 | LL | impl AsyncDrop for Pin { | ^^^^^^^^ must be a struct, enum, or union in the current crate -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0120`. diff --git a/tests/ui/async-await/drop-option-future.rs b/tests/ui/async-await/drop-option-future.rs new file mode 100644 index 000000000000..155b1d76e44a --- /dev/null +++ b/tests/ui/async-await/drop-option-future.rs @@ -0,0 +1,16 @@ +//! Regression test for . + +//@ edition:2018 +//@ check-pass + +#![allow(dead_code)] +#![allow(unused_assignments)] + +async fn foo() { + let mut f = None; + let value = 0; + f = Some(async { value }); + core::mem::drop(f); +} + +fn main() { } diff --git a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr index 6689539ff453..0f390522620e 100644 --- a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr +++ b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr @@ -1,12 +1,3 @@ -warning: the feature `async_fn_in_dyn_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/mut-is-pointer-like.rs:6:12 - | -LL | #![feature(async_fn_in_dyn_trait)] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #133119 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0038]: the trait `AsyncTrait` is not dyn compatible --> $DIR/mut-is-pointer-like.rs:35:29 | @@ -24,6 +15,6 @@ LL | async fn async_dispatch(self: Pin<&mut Self>) -> Self::Output; | ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async` = help: consider moving `async_dispatch` to another trait -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/dyn/works.stderr b/tests/ui/async-await/dyn/works.stderr index 338479d8b70a..c7d0d14d70e7 100644 --- a/tests/ui/async-await/dyn/works.stderr +++ b/tests/ui/async-await/dyn/works.stderr @@ -1,12 +1,3 @@ -warning: the feature `async_fn_in_dyn_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/works.rs:6:12 - | -LL | #![feature(async_fn_in_dyn_trait)] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #133119 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0038]: the trait `AsyncTrait` is not dyn compatible --> $DIR/works.rs:27:21 | @@ -24,6 +15,6 @@ LL | async fn async_dispatch(&self); = help: consider moving `async_dispatch` to another trait = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/dyn/wrong-size.stderr b/tests/ui/async-await/dyn/wrong-size.stderr index a465f91f62af..4835c173f0d7 100644 --- a/tests/ui/async-await/dyn/wrong-size.stderr +++ b/tests/ui/async-await/dyn/wrong-size.stderr @@ -1,12 +1,3 @@ -warning: the feature `async_fn_in_dyn_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/wrong-size.rs:4:12 - | -LL | #![feature(async_fn_in_dyn_trait)] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #133119 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0038]: the trait `AsyncTrait` is not dyn compatible --> $DIR/wrong-size.rs:21:17 | @@ -24,6 +15,6 @@ LL | async fn async_dispatch(&self); = help: consider moving `async_dispatch` to another trait = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/gat-is-send-across-await.rs b/tests/ui/async-await/gat-is-send-across-await.rs new file mode 100644 index 000000000000..43b777449edd --- /dev/null +++ b/tests/ui/async-await/gat-is-send-across-await.rs @@ -0,0 +1,23 @@ +//! Regression test for . + +//@ edition:2018 +//@ check-pass + +#![allow(unused)] + +trait G: Send { + type Gat<'l>: Send + where + Self: 'l; + + fn as_gat(&self) -> Self::Gat<'_>; +} + +fn a(g: impl G) { + let _: &dyn Send = &async move { + let _gat = g.as_gat(); + async{}.await + }; +} + +fn main() { } diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs index 645a136eeb4e..69c4777ecb44 100644 --- a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs @@ -1,7 +1,7 @@ //@ edition:2018 // Test that impl trait does not allow creating recursive types that are // otherwise forbidden when using `async` and `await`. - +//@ ignore-parallel-frontend query cycle async fn rec_1() { //~ ERROR recursion in an async fn rec_2().await; } diff --git a/tests/ui/attributes/crate-type-macro-empty.rs b/tests/ui/attributes/crate-type-macro-empty.rs index d55074ed686c..217ff598f7a4 100644 --- a/tests/ui/attributes/crate-type-macro-empty.rs +++ b/tests/ui/attributes/crate-type-macro-empty.rs @@ -1,7 +1,6 @@ // Tests for the issue in #137589 #[crate_type = foo!()] //~^ ERROR cannot find macro `foo` in this scope -//~| ERROR attribute value must be a literal macro_rules! foo {} //~ ERROR macros must contain at least one rule diff --git a/tests/ui/attributes/crate-type-macro-empty.stderr b/tests/ui/attributes/crate-type-macro-empty.stderr index 2e24a9972287..130fa454ca19 100644 --- a/tests/ui/attributes/crate-type-macro-empty.stderr +++ b/tests/ui/attributes/crate-type-macro-empty.stderr @@ -1,5 +1,5 @@ error: macros must contain at least one rule - --> $DIR/crate-type-macro-empty.rs:6:1 + --> $DIR/crate-type-macro-empty.rs:5:1 | LL | macro_rules! foo {} | ^^^^^^^^^^^^^^^^^^^ @@ -11,16 +11,10 @@ LL | #[crate_type = foo!()] | ^^^ consider moving the definition of `foo` before this call | note: a macro with the same name exists, but it appears later - --> $DIR/crate-type-macro-empty.rs:6:14 + --> $DIR/crate-type-macro-empty.rs:5:14 | LL | macro_rules! foo {} | ^^^ -error: attribute value must be a literal - --> $DIR/crate-type-macro-empty.rs:2:16 - | -LL | #[crate_type = foo!()] - | ^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/crate-type-macro-not-found.rs b/tests/ui/attributes/crate-type-macro-not-found.rs index eac780944572..901ece48de0a 100644 --- a/tests/ui/attributes/crate-type-macro-not-found.rs +++ b/tests/ui/attributes/crate-type-macro-not-found.rs @@ -1,7 +1,6 @@ // Tests for the issue in #137589 #[crate_type = foo!()] //~^ ERROR cannot find macro `foo` in this scope -//~| ERROR attribute value must be a literal macro_rules! foo { ($x:expr) => {"rlib"} diff --git a/tests/ui/attributes/crate-type-macro-not-found.stderr b/tests/ui/attributes/crate-type-macro-not-found.stderr index 9db7f7f6ec0b..4d4d843a5396 100644 --- a/tests/ui/attributes/crate-type-macro-not-found.stderr +++ b/tests/ui/attributes/crate-type-macro-not-found.stderr @@ -5,16 +5,10 @@ LL | #[crate_type = foo!()] | ^^^ consider moving the definition of `foo` before this call | note: a macro with the same name exists, but it appears later - --> $DIR/crate-type-macro-not-found.rs:6:14 + --> $DIR/crate-type-macro-not-found.rs:5:14 | LL | macro_rules! foo { | ^^^ -error: attribute value must be a literal - --> $DIR/crate-type-macro-not-found.rs:2:16 - | -LL | #[crate_type = foo!()] - | ^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/attributes/doc-attr-compile-error.rs b/tests/ui/attributes/doc-attr-compile-error.rs new file mode 100644 index 000000000000..f5dedf5b103a --- /dev/null +++ b/tests/ui/attributes/doc-attr-compile-error.rs @@ -0,0 +1,3 @@ +#[doc = compile_error!("my error message")] +//~^ ERROR my error message +fn main() {} diff --git a/tests/ui/attributes/doc-attr-compile-error.stderr b/tests/ui/attributes/doc-attr-compile-error.stderr new file mode 100644 index 000000000000..fed7151ff4b7 --- /dev/null +++ b/tests/ui/attributes/doc-attr-compile-error.stderr @@ -0,0 +1,8 @@ +error: my error message + --> $DIR/doc-attr-compile-error.rs:1:9 + | +LL | #[doc = compile_error!("my error message")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/attributes/extented-attribute-macro-error.rs b/tests/ui/attributes/extented-attribute-macro-error.rs index f85a28ad706e..83060024dac9 100644 --- a/tests/ui/attributes/extented-attribute-macro-error.rs +++ b/tests/ui/attributes/extented-attribute-macro-error.rs @@ -3,6 +3,5 @@ #![doc = include_str!("../not_existing_file.md")] struct Documented {} //~^^ ERROR couldn't read -//~| ERROR attribute value must be a literal fn main() {} diff --git a/tests/ui/attributes/extented-attribute-macro-error.stderr b/tests/ui/attributes/extented-attribute-macro-error.stderr index ed46cba3d040..7b93b98f64cd 100644 --- a/tests/ui/attributes/extented-attribute-macro-error.stderr +++ b/tests/ui/attributes/extented-attribute-macro-error.stderr @@ -4,11 +4,5 @@ error: couldn't read the file LL | #![doc = include_str!("../not_existing_file.md")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: attribute value must be a literal - --> $DIR/extented-attribute-macro-error.rs:3:10 - | -LL | #![doc = include_str!("../not_existing_file.md")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/invalid/invalid-inline.rs b/tests/ui/attributes/inline/invalid-inline.rs similarity index 100% rename from tests/ui/invalid/invalid-inline.rs rename to tests/ui/attributes/inline/invalid-inline.rs diff --git a/tests/ui/invalid/invalid-inline.stderr b/tests/ui/attributes/inline/invalid-inline.stderr similarity index 100% rename from tests/ui/invalid/invalid-inline.stderr rename to tests/ui/attributes/inline/invalid-inline.stderr diff --git a/tests/ui/invalid/invalid-crate-type.rs b/tests/ui/attributes/invalid-crate-type.rs similarity index 100% rename from tests/ui/invalid/invalid-crate-type.rs rename to tests/ui/attributes/invalid-crate-type.rs diff --git a/tests/ui/invalid/invalid-crate-type.stderr b/tests/ui/attributes/invalid-crate-type.stderr similarity index 100% rename from tests/ui/invalid/invalid-crate-type.stderr rename to tests/ui/attributes/invalid-crate-type.stderr diff --git a/tests/ui/invalid/invalid-debugger-visualizer-option.rs b/tests/ui/attributes/invalid-debugger-visualizer-option.rs similarity index 100% rename from tests/ui/invalid/invalid-debugger-visualizer-option.rs rename to tests/ui/attributes/invalid-debugger-visualizer-option.rs diff --git a/tests/ui/invalid/invalid-debugger-visualizer-option.stderr b/tests/ui/attributes/invalid-debugger-visualizer-option.stderr similarity index 100% rename from tests/ui/invalid/invalid-debugger-visualizer-option.stderr rename to tests/ui/attributes/invalid-debugger-visualizer-option.stderr diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.rs b/tests/ui/attributes/invalid-debugger-visualizer-target.rs similarity index 100% rename from tests/ui/invalid/invalid-debugger-visualizer-target.rs rename to tests/ui/attributes/invalid-debugger-visualizer-target.rs diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr b/tests/ui/attributes/invalid-debugger-visualizer-target.stderr similarity index 100% rename from tests/ui/invalid/invalid-debugger-visualizer-target.stderr rename to tests/ui/attributes/invalid-debugger-visualizer-target.stderr diff --git a/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.rs b/tests/ui/attributes/invalid_rustc_layout_scalar_valid_range.rs similarity index 100% rename from tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.rs rename to tests/ui/attributes/invalid_rustc_layout_scalar_valid_range.rs diff --git a/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr b/tests/ui/attributes/invalid_rustc_layout_scalar_valid_range.stderr similarity index 100% rename from tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr rename to tests/ui/attributes/invalid_rustc_layout_scalar_valid_range.stderr diff --git a/tests/ui/attributes/key-value-expansion-scope.rs b/tests/ui/attributes/key-value-expansion-scope.rs index b30da2eda24a..6688d698f9ea 100644 --- a/tests/ui/attributes/key-value-expansion-scope.rs +++ b/tests/ui/attributes/key-value-expansion-scope.rs @@ -1,29 +1,19 @@ #![doc = in_root!()] //~ ERROR cannot find macro `in_root` //~| WARN this was previously accepted by the compiler #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope - //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` //~| WARN this was previously accepted by the compiler #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope - //~| ERROR attribute value must be a literal #[doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope - //~| ERROR attribute value must be a literal #[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope - //~| ERROR attribute value must be a literal #[doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope - //~| ERROR attribute value must be a literal #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope - //~| ERROR attribute value must be a literal fn before() { #![doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope - //~| ERROR attribute value must be a literal #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope - //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope - //~| ERROR attribute value must be a literal #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope - //~| ERROR attribute value must be a literal } macro_rules! in_root { () => { "" } } @@ -58,10 +48,8 @@ fn f() { } #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope - //~| ERROR attribute value must be a literal fn block() { #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope - //~| ERROR attribute value must be a literal macro_rules! in_block { () => { "" } } @@ -73,17 +61,13 @@ fn f() { #[doc = in_root!()] // OK #[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope - //~| ERROR attribute value must be a literal #[doc = in_mod_escape!()] // OK #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope - //~| ERROR attribute value must be a literal fn after() { #![doc = in_root!()] // OK #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope - //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] // OK #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope - //~| ERROR attribute value must be a literal } fn main() {} diff --git a/tests/ui/attributes/key-value-expansion-scope.stderr b/tests/ui/attributes/key-value-expansion-scope.stderr index 70e831729cd4..1387ffe21a37 100644 --- a/tests/ui/attributes/key-value-expansion-scope.stderr +++ b/tests/ui/attributes/key-value-expansion-scope.stderr @@ -7,7 +7,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:7:10 + --> $DIR/key-value-expansion-scope.rs:6:10 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -15,7 +15,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_root` in this scope - --> $DIR/key-value-expansion-scope.rs:10:9 + --> $DIR/key-value-expansion-scope.rs:8:9 | LL | #[doc = in_root!()] | ^^^^^^^ @@ -23,7 +23,7 @@ LL | #[doc = in_root!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:12:9 + --> $DIR/key-value-expansion-scope.rs:9:9 | LL | #[doc = in_mod!()] | ^^^^^^ @@ -31,7 +31,7 @@ LL | #[doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod_escape` in this scope - --> $DIR/key-value-expansion-scope.rs:14:9 + --> $DIR/key-value-expansion-scope.rs:10:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | #[doc = in_mod_escape!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:16:9 + --> $DIR/key-value-expansion-scope.rs:11:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -47,7 +47,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_root` in this scope - --> $DIR/key-value-expansion-scope.rs:19:14 + --> $DIR/key-value-expansion-scope.rs:13:14 | LL | #![doc = in_root!()] | ^^^^^^^ @@ -55,7 +55,7 @@ LL | #![doc = in_root!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:21:14 + --> $DIR/key-value-expansion-scope.rs:14:14 | LL | #![doc = in_mod!()] | ^^^^^^ @@ -63,7 +63,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod_escape` in this scope - --> $DIR/key-value-expansion-scope.rs:23:14 + --> $DIR/key-value-expansion-scope.rs:15:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | #![doc = in_mod_escape!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:25:14 + --> $DIR/key-value-expansion-scope.rs:16:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -79,7 +79,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:60:9 + --> $DIR/key-value-expansion-scope.rs:50:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -87,7 +87,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:63:14 + --> $DIR/key-value-expansion-scope.rs:52:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -95,7 +95,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:75:9 + --> $DIR/key-value-expansion-scope.rs:63:9 | LL | #[doc = in_mod!()] | ^^^^^^ @@ -103,7 +103,7 @@ LL | #[doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:78:9 + --> $DIR/key-value-expansion-scope.rs:65:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -111,7 +111,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:82:14 + --> $DIR/key-value-expansion-scope.rs:68:14 | LL | #![doc = in_mod!()] | ^^^^^^ @@ -119,7 +119,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:85:14 + --> $DIR/key-value-expansion-scope.rs:70:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -138,7 +138,7 @@ LL | #![doc = in_root!()] = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root - --> $DIR/key-value-expansion-scope.rs:5:10 + --> $DIR/key-value-expansion-scope.rs:4:10 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from the crate root @@ -148,7 +148,7 @@ LL | #![doc = in_mod_escape!()] = note: for more information, see issue #124535 error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:31:9 + --> $DIR/key-value-expansion-scope.rs:21:9 | LL | #[doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -158,7 +158,7 @@ LL | #[doc = in_mod!()] = note: for more information, see issue #124535 error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:34:14 + --> $DIR/key-value-expansion-scope.rs:24:14 | LL | #![doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -168,7 +168,7 @@ LL | #![doc = in_mod!()] = note: for more information, see issue #124535 error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:46:9 + --> $DIR/key-value-expansion-scope.rs:36:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -178,7 +178,7 @@ LL | #[doc = in_mod_escape!()] = note: for more information, see issue #124535 error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:49:14 + --> $DIR/key-value-expansion-scope.rs:39:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -187,103 +187,7 @@ LL | #![doc = in_mod_escape!()] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #124535 -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:3:10 - | -LL | #![doc = in_mod!()] - | ^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:7:10 - | -LL | #![doc = in_block!()] - | ^^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:10:9 - | -LL | #[doc = in_root!()] - | ^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:12:9 - | -LL | #[doc = in_mod!()] - | ^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:14:9 - | -LL | #[doc = in_mod_escape!()] - | ^^^^^^^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:16:9 - | -LL | #[doc = in_block!()] - | ^^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:19:14 - | -LL | #![doc = in_root!()] - | ^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:21:14 - | -LL | #![doc = in_mod!()] - | ^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:23:14 - | -LL | #![doc = in_mod_escape!()] - | ^^^^^^^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:25:14 - | -LL | #![doc = in_block!()] - | ^^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:60:9 - | -LL | #[doc = in_block!()] - | ^^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:63:14 - | -LL | #![doc = in_block!()] - | ^^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:75:9 - | -LL | #[doc = in_mod!()] - | ^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:78:9 - | -LL | #[doc = in_block!()] - | ^^^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:82:14 - | -LL | #![doc = in_mod!()] - | ^^^^^^^^^ - -error: attribute value must be a literal - --> $DIR/key-value-expansion-scope.rs:85:14 - | -LL | #![doc = in_block!()] - | ^^^^^^^^^^^ - -error: aborting due to 38 previous errors +error: aborting due to 22 previous errors Future incompatibility report: Future breakage diagnostic: error: cannot find macro `in_root` in the current scope when looking from the crate root @@ -299,7 +203,7 @@ LL | #![doc = in_root!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root - --> $DIR/key-value-expansion-scope.rs:5:10 + --> $DIR/key-value-expansion-scope.rs:4:10 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from the crate root @@ -311,7 +215,7 @@ LL | #![doc = in_mod_escape!()] Future breakage diagnostic: error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:31:9 + --> $DIR/key-value-expansion-scope.rs:21:9 | LL | #[doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -323,7 +227,7 @@ LL | #[doc = in_mod!()] Future breakage diagnostic: error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:34:14 + --> $DIR/key-value-expansion-scope.rs:24:14 | LL | #![doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -335,7 +239,7 @@ LL | #![doc = in_mod!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:46:9 + --> $DIR/key-value-expansion-scope.rs:36:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -347,7 +251,7 @@ LL | #[doc = in_mod_escape!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:49:14 + --> $DIR/key-value-expansion-scope.rs:39:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` diff --git a/tests/ui/attributes/malformed-reprs.stderr b/tests/ui/attributes/malformed-reprs.stderr index 504ba91aac5f..6e77c6e4b9a9 100644 --- a/tests/ui/attributes/malformed-reprs.stderr +++ b/tests/ui/attributes/malformed-reprs.stderr @@ -6,12 +6,6 @@ LL | #![repr] | = note: for more information, visit -error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/malformed-reprs.rs:9:14 - | -LL | #[repr(align(0))] - | ^ - error: `repr` attribute cannot be used at crate level --> $DIR/malformed-reprs.rs:4:1 | @@ -19,7 +13,7 @@ LL | #![repr] | ^^^^^^^^ ... LL | enum Foo {} - | --- the inner attribute doesn't annotate this enum + | ----------- the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | @@ -27,6 +21,12 @@ LL - #![repr] LL + #[repr] | +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/malformed-reprs.rs:9:14 + | +LL | #[repr(align(0))] + | ^ + error[E0084]: unsupported representation for zero-variant enum --> $DIR/malformed-reprs.rs:9:1 | diff --git a/tests/ui/attributes/no_link/auxiliary/empty-struct.rs b/tests/ui/attributes/no_link/auxiliary/empty-struct.rs new file mode 100644 index 000000000000..091db1e76c39 --- /dev/null +++ b/tests/ui/attributes/no_link/auxiliary/empty-struct.rs @@ -0,0 +1 @@ +pub struct XEmpty {} diff --git a/tests/ui/empty/no-link.rs b/tests/ui/attributes/no_link/no-link-struct.rs similarity index 76% rename from tests/ui/empty/no-link.rs rename to tests/ui/attributes/no_link/no-link-struct.rs index 9f78714b7694..40b0c53185f9 100644 --- a/tests/ui/empty/no-link.rs +++ b/tests/ui/attributes/no_link/no-link-struct.rs @@ -5,5 +5,5 @@ extern crate empty_struct; fn main() { - empty_struct::XEmpty1 {}; + empty_struct::XEmpty {}; } diff --git a/tests/ui/attributes/rustc_confusables_assoc_fn.rs b/tests/ui/attributes/rustc_confusables_assoc_fn.rs new file mode 100644 index 000000000000..6a93f7bb4385 --- /dev/null +++ b/tests/ui/attributes/rustc_confusables_assoc_fn.rs @@ -0,0 +1,22 @@ +#![feature(rustc_attrs)] + +struct S; + +impl S { + #[rustc_confusables("bar")] + fn foo() {} + + #[rustc_confusables("baz")] + fn qux(&self, x: i32) {} +} + +fn main() { + S::bar(); + //~^ ERROR no associated function or constant named `bar` + //~| HELP you might have meant to use `foo` + + let s = S; + s.baz(10); + //~^ ERROR no method named `baz` + //~| HELP you might have meant to use `qux` +} diff --git a/tests/ui/attributes/rustc_confusables_assoc_fn.stderr b/tests/ui/attributes/rustc_confusables_assoc_fn.stderr new file mode 100644 index 000000000000..da5cf27632ac --- /dev/null +++ b/tests/ui/attributes/rustc_confusables_assoc_fn.stderr @@ -0,0 +1,33 @@ +error[E0599]: no associated function or constant named `bar` found for struct `S` in the current scope + --> $DIR/rustc_confusables_assoc_fn.rs:14:8 + | +LL | struct S; + | -------- associated function or constant `bar` not found for this struct +... +LL | S::bar(); + | ^^^ associated function or constant not found in `S` + | +help: you might have meant to use `foo` + | +LL - S::bar(); +LL + S::foo(); + | + +error[E0599]: no method named `baz` found for struct `S` in the current scope + --> $DIR/rustc_confusables_assoc_fn.rs:19:7 + | +LL | struct S; + | -------- method `baz` not found for this struct +... +LL | s.baz(10); + | ^^^ method not found in `S` + | +help: you might have meant to use `qux` + | +LL - s.baz(10); +LL + s.qux(10); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/auto-traits/pre-cfg.rs b/tests/ui/auto-traits/pre-cfg.rs deleted file mode 100644 index 4820a5353580..000000000000 --- a/tests/ui/auto-traits/pre-cfg.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ check-pass - -#[cfg(false)] -auto trait Foo {} -//~^ WARN `auto` traits are unstable -//~| WARN unstable syntax can change at any point in the future, causing a hard error! - -fn main() {} diff --git a/tests/ui/binding/match-naked-record.rs b/tests/ui/binding/match-naked-record.rs deleted file mode 100644 index ce9489a00f2c..000000000000 --- a/tests/ui/binding/match-naked-record.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -struct X { x: isize } - -pub fn main() { - let _x = match 0 { - _ => X { - x: 0 - } - }; -} diff --git a/tests/ui/binop/augmented-assignment.rs b/tests/ui/binop/augmented-assignment.rs index 755ecb466ceb..a8de7ae1d3fc 100644 --- a/tests/ui/binop/augmented-assignment.rs +++ b/tests/ui/binop/augmented-assignment.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ reference: expr.arith-logic.behavior #![allow(unused_imports)] #![deny(unused_assignments)] diff --git a/tests/ui/binop/binary-minus-without-space.rs b/tests/ui/binop/binary-minus-without-space.rs index c80c0c88fcbc..64243ebbb94e 100644 --- a/tests/ui/binop/binary-minus-without-space.rs +++ b/tests/ui/binop/binary-minus-without-space.rs @@ -1,4 +1,7 @@ //@ run-pass +//@ reference: expr.arith-logic.syntax +//@ reference: patterns.literal.syntax +//@ reference: patterns.literal.intro // Check that issue #954 stays fixed diff --git a/tests/ui/binop/binop-consume-args.rs b/tests/ui/binop/binop-consume-args.rs index 8d6c725d7560..1bd803ce4c8f 100644 --- a/tests/ui/binop/binop-consume-args.rs +++ b/tests/ui/binop/binop-consume-args.rs @@ -1,3 +1,4 @@ +//@ reference: expr.arith-logic.behavior // Test that binary operators consume their arguments use std::ops::{Add, Sub, Mul, Div, Rem, BitAnd, BitXor, BitOr, Shl, Shr}; diff --git a/tests/ui/binop/binop-consume-args.stderr b/tests/ui/binop/binop-consume-args.stderr index d9d92a44766d..2b2bb1062049 100644 --- a/tests/ui/binop/binop-consume-args.stderr +++ b/tests/ui/binop/binop-consume-args.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:7:10 + --> $DIR/binop-consume-args.rs:8:10 | LL | fn add, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -9,7 +9,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:5:8 + --> $DIR/binop-consume-args.rs:6:8 | LL | fn add, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -23,7 +23,7 @@ LL | fn add + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:8:10 + --> $DIR/binop-consume-args.rs:9:10 | LL | fn add, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -34,7 +34,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:5:30 + --> $DIR/binop-consume-args.rs:6:30 | LL | fn add, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -46,7 +46,7 @@ LL | fn add, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:13:10 + --> $DIR/binop-consume-args.rs:14:10 | LL | fn sub, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -56,7 +56,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:11:8 + --> $DIR/binop-consume-args.rs:12:8 | LL | fn sub, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -70,7 +70,7 @@ LL | fn sub + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:14:10 + --> $DIR/binop-consume-args.rs:15:10 | LL | fn sub, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -81,7 +81,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:11:30 + --> $DIR/binop-consume-args.rs:12:30 | LL | fn sub, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -93,7 +93,7 @@ LL | fn sub, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:19:10 + --> $DIR/binop-consume-args.rs:20:10 | LL | fn mul, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -103,7 +103,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:17:8 + --> $DIR/binop-consume-args.rs:18:8 | LL | fn mul, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -117,7 +117,7 @@ LL | fn mul + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:20:10 + --> $DIR/binop-consume-args.rs:21:10 | LL | fn mul, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -128,7 +128,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:17:30 + --> $DIR/binop-consume-args.rs:18:30 | LL | fn mul, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -140,7 +140,7 @@ LL | fn mul, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:25:10 + --> $DIR/binop-consume-args.rs:26:10 | LL | fn div, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -150,7 +150,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:23:8 + --> $DIR/binop-consume-args.rs:24:8 | LL | fn div, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -164,7 +164,7 @@ LL | fn div + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:26:10 + --> $DIR/binop-consume-args.rs:27:10 | LL | fn div, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -175,7 +175,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:23:30 + --> $DIR/binop-consume-args.rs:24:30 | LL | fn div, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -187,7 +187,7 @@ LL | fn div, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:31:10 + --> $DIR/binop-consume-args.rs:32:10 | LL | fn rem, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -197,7 +197,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:29:8 + --> $DIR/binop-consume-args.rs:30:8 | LL | fn rem, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -211,7 +211,7 @@ LL | fn rem + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:32:10 + --> $DIR/binop-consume-args.rs:33:10 | LL | fn rem, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -222,7 +222,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:29:30 + --> $DIR/binop-consume-args.rs:30:30 | LL | fn rem, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -234,7 +234,7 @@ LL | fn rem, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:37:10 + --> $DIR/binop-consume-args.rs:38:10 | LL | fn bitand, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -244,7 +244,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:35:11 + --> $DIR/binop-consume-args.rs:36:11 | LL | fn bitand, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -258,7 +258,7 @@ LL | fn bitand + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:38:10 + --> $DIR/binop-consume-args.rs:39:10 | LL | fn bitand, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -269,7 +269,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:35:36 + --> $DIR/binop-consume-args.rs:36:36 | LL | fn bitand, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -281,7 +281,7 @@ LL | fn bitand, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:43:10 + --> $DIR/binop-consume-args.rs:44:10 | LL | fn bitor, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -291,7 +291,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:41:10 + --> $DIR/binop-consume-args.rs:42:10 | LL | fn bitor, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -305,7 +305,7 @@ LL | fn bitor + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:44:10 + --> $DIR/binop-consume-args.rs:45:10 | LL | fn bitor, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -316,7 +316,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:41:34 + --> $DIR/binop-consume-args.rs:42:34 | LL | fn bitor, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -328,7 +328,7 @@ LL | fn bitor, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:49:10 + --> $DIR/binop-consume-args.rs:50:10 | LL | fn bitxor, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -338,7 +338,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:47:11 + --> $DIR/binop-consume-args.rs:48:11 | LL | fn bitxor, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -352,7 +352,7 @@ LL | fn bitxor + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:50:10 + --> $DIR/binop-consume-args.rs:51:10 | LL | fn bitxor, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -363,7 +363,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:47:36 + --> $DIR/binop-consume-args.rs:48:36 | LL | fn bitxor, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -375,7 +375,7 @@ LL | fn bitxor, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:55:10 + --> $DIR/binop-consume-args.rs:56:10 | LL | fn shl, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -385,7 +385,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:53:8 + --> $DIR/binop-consume-args.rs:54:8 | LL | fn shl, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -399,7 +399,7 @@ LL | fn shl + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:56:10 + --> $DIR/binop-consume-args.rs:57:10 | LL | fn shl, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -410,7 +410,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:53:30 + --> $DIR/binop-consume-args.rs:54:30 | LL | fn shl, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -422,7 +422,7 @@ LL | fn shl, B: Copy>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:61:10 + --> $DIR/binop-consume-args.rs:62:10 | LL | fn shr, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait @@ -432,7 +432,7 @@ LL | drop(lhs); | ^^^ value used here after move | help: if `A` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:59:8 + --> $DIR/binop-consume-args.rs:60:8 | LL | fn shr, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` @@ -446,7 +446,7 @@ LL | fn shr + Copy, B>(lhs: A, rhs: B) { | ++++++ error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:62:10 + --> $DIR/binop-consume-args.rs:63:10 | LL | fn shr, B>(lhs: A, rhs: B) { | --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait @@ -457,7 +457,7 @@ LL | drop(rhs); | ^^^ value used here after move | help: if `B` implemented `Clone`, you could clone the value - --> $DIR/binop-consume-args.rs:59:30 + --> $DIR/binop-consume-args.rs:60:30 | LL | fn shr, B>(lhs: A, rhs: B) { | ^ consider constraining this type parameter with `Clone` diff --git a/tests/ui/binop/binop-move-semantics.rs b/tests/ui/binop/binop-move-semantics.rs index b5133ea7c92a..c49613c02d50 100644 --- a/tests/ui/binop/binop-move-semantics.rs +++ b/tests/ui/binop/binop-move-semantics.rs @@ -1,3 +1,4 @@ +//@ reference: expr.arith-logic.behavior // Test that move restrictions are enforced on overloaded binary operations use std::ops::Add; diff --git a/tests/ui/binop/binop-move-semantics.stderr b/tests/ui/binop/binop-move-semantics.stderr index 2e661c44abd1..029a94a49452 100644 --- a/tests/ui/binop/binop-move-semantics.stderr +++ b/tests/ui/binop/binop-move-semantics.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/binop-move-semantics.rs:8:5 + --> $DIR/binop-move-semantics.rs:9:5 | LL | fn double_move>(x: T) { | - move occurs because `x` has type `T`, which does not implement the `Copy` trait @@ -12,7 +12,7 @@ LL | | x; | `x` moved due to usage in operator | help: if `T` implemented `Clone`, you could clone the value - --> $DIR/binop-move-semantics.rs:5:16 + --> $DIR/binop-move-semantics.rs:6:16 | LL | fn double_move>(x: T) { | ^ consider constraining this type parameter with `Clone` @@ -26,7 +26,7 @@ LL | fn double_move + Copy>(x: T) { | ++++++ error[E0382]: borrow of moved value: `x` - --> $DIR/binop-move-semantics.rs:14:5 + --> $DIR/binop-move-semantics.rs:15:5 | LL | fn move_then_borrow + Clone>(x: T) { | - move occurs because `x` has type `T`, which does not implement the `Copy` trait @@ -46,7 +46,7 @@ LL | fn move_then_borrow + Clone + Copy>(x: T) { | ++++++ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/binop-move-semantics.rs:21:5 + --> $DIR/binop-move-semantics.rs:22:5 | LL | fn move_borrowed>(x: T, mut y: T) { | - binding `x` declared here @@ -60,7 +60,7 @@ LL | use_mut(n); use_imm(m); | - borrow later used here | help: if `T` implemented `Clone`, you could clone the value - --> $DIR/binop-move-semantics.rs:17:18 + --> $DIR/binop-move-semantics.rs:18:18 | LL | fn move_borrowed>(x: T, mut y: T) { | ^ consider constraining this type parameter with `Clone` @@ -68,7 +68,7 @@ LL | let m = &x; | - you could clone this value error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/binop-move-semantics.rs:23:5 + --> $DIR/binop-move-semantics.rs:24:5 | LL | fn move_borrowed>(x: T, mut y: T) { | ----- binding `y` declared here @@ -82,7 +82,7 @@ LL | use_mut(n); use_imm(m); | - borrow later used here | help: if `T` implemented `Clone`, you could clone the value - --> $DIR/binop-move-semantics.rs:17:18 + --> $DIR/binop-move-semantics.rs:18:18 | LL | fn move_borrowed>(x: T, mut y: T) { | ^ consider constraining this type parameter with `Clone` @@ -91,7 +91,7 @@ LL | let n = &mut y; | - you could clone this value error[E0507]: cannot move out of `*m` which is behind a mutable reference - --> $DIR/binop-move-semantics.rs:30:5 + --> $DIR/binop-move-semantics.rs:31:5 | LL | *m | -^ @@ -105,7 +105,7 @@ LL | | *n; note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: if `T` implemented `Clone`, you could clone the value - --> $DIR/binop-move-semantics.rs:26:24 + --> $DIR/binop-move-semantics.rs:27:24 | LL | fn illegal_dereference>(mut x: T, y: T) { | ^ consider constraining this type parameter with `Clone` @@ -114,13 +114,13 @@ LL | *m | -- you could clone this value error[E0507]: cannot move out of `*n` which is behind a shared reference - --> $DIR/binop-move-semantics.rs:32:5 + --> $DIR/binop-move-semantics.rs:33:5 | LL | *n; | ^^ move occurs because `*n` has type `T`, which does not implement the `Copy` trait | help: if `T` implemented `Clone`, you could clone the value - --> $DIR/binop-move-semantics.rs:26:24 + --> $DIR/binop-move-semantics.rs:27:24 | LL | fn illegal_dereference>(mut x: T, y: T) { | ^ consider constraining this type parameter with `Clone` @@ -129,7 +129,7 @@ LL | *n; | -- you could clone this value error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable - --> $DIR/binop-move-semantics.rs:54:5 + --> $DIR/binop-move-semantics.rs:55:5 | LL | &mut f | ------ @@ -144,7 +144,7 @@ LL | | &f; | immutable borrow occurs here error[E0502]: cannot borrow `f` as mutable because it is also borrowed as immutable - --> $DIR/binop-move-semantics.rs:62:5 + --> $DIR/binop-move-semantics.rs:63:5 | LL | &f | -- diff --git a/tests/ui/operator-recovery/box-arithmetic-14915.rs b/tests/ui/binop/box-arithmetic-14915.rs similarity index 100% rename from tests/ui/operator-recovery/box-arithmetic-14915.rs rename to tests/ui/binop/box-arithmetic-14915.rs diff --git a/tests/ui/operator-recovery/box-arithmetic-14915.stderr b/tests/ui/binop/box-arithmetic-14915.stderr similarity index 100% rename from tests/ui/operator-recovery/box-arithmetic-14915.stderr rename to tests/ui/binop/box-arithmetic-14915.stderr diff --git a/tests/ui/operator-recovery/less-than-greater-than.rs b/tests/ui/binop/less-than-greater-than.rs similarity index 100% rename from tests/ui/operator-recovery/less-than-greater-than.rs rename to tests/ui/binop/less-than-greater-than.rs diff --git a/tests/ui/operator-recovery/less-than-greater-than.stderr b/tests/ui/binop/less-than-greater-than.stderr similarity index 100% rename from tests/ui/operator-recovery/less-than-greater-than.stderr rename to tests/ui/binop/less-than-greater-than.stderr diff --git a/tests/ui/binop/operator-overloading.rs b/tests/ui/binop/operator-overloading.rs index 7f29856194e0..76a9ed079a09 100644 --- a/tests/ui/binop/operator-overloading.rs +++ b/tests/ui/binop/operator-overloading.rs @@ -1,4 +1,7 @@ //@ run-pass +//@ reference: expr.arith-logic.behavior +//@ reference: expr.array.index.trait +//@ reference: expr.negate.results #![allow(unused_variables)] use std::cmp; diff --git a/tests/ui/operator-recovery/spaceship.rs b/tests/ui/binop/spaceship.rs similarity index 100% rename from tests/ui/operator-recovery/spaceship.rs rename to tests/ui/binop/spaceship.rs diff --git a/tests/ui/operator-recovery/spaceship.stderr b/tests/ui/binop/spaceship.stderr similarity index 100% rename from tests/ui/operator-recovery/spaceship.stderr rename to tests/ui/binop/spaceship.stderr diff --git a/tests/ui/blind/blind-item-block-middle.stderr b/tests/ui/blind/blind-item-block-middle.stderr index b2ae169013a6..5c05f31ab895 100644 --- a/tests/ui/blind/blind-item-block-middle.stderr +++ b/tests/ui/blind/blind-item-block-middle.stderr @@ -9,7 +9,11 @@ LL | let bar = 5; | | | expected integer, found `bar` | `bar` is interpreted as a unit struct, not a new binding - | help: introduce a new binding instead: `other_bar` + | +help: introduce a new binding instead + | +LL | let other_bar = 5; + | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/access-mode-in-closures.stderr b/tests/ui/borrowck/access-mode-in-closures.stderr index b9a45edb330c..94593d51fdf5 100644 --- a/tests/ui/borrowck/access-mode-in-closures.stderr +++ b/tests/ui/borrowck/access-mode-in-closures.stderr @@ -2,10 +2,7 @@ error[E0507]: cannot move out of `s` which is behind a shared reference --> $DIR/access-mode-in-closures.rs:8:15 | LL | match *s { S(v) => v } - | ^^ - - | | - | data moved here - | move occurs because `v` has type `Vec`, which does not implement the `Copy` trait + | ^^ - data moved here because `v` has type `Vec`, which does not implement the `Copy` trait | help: consider removing the dereference here | diff --git a/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr index f9ced03e0f03..1ff5c78df780 100644 --- a/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr +++ b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | for &a in x.iter() { | - ^^^^^^^^ | | - | data moved here - | move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait + | data moved here because `a` has type `&mut i32`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -19,8 +18,7 @@ error[E0507]: cannot move out of a shared reference LL | for &a in &f.a { | - ^^^^ | | - | data moved here - | move occurs because `a` has type `Box`, which does not implement the `Copy` trait + | data moved here because `a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -34,8 +32,7 @@ error[E0507]: cannot move out of a shared reference LL | for &a in x.iter() { | - ^^^^^^^^ | | - | data moved here - | move occurs because `a` has type `Box`, which does not implement the `Copy` trait + | data moved here because `a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/borrowck/borrowck-move-error-with-note.stderr b/tests/ui/borrowck/borrowck-move-error-with-note.stderr index 722c2c1443a7..e9f0395fa0d4 100644 --- a/tests/ui/borrowck/borrowck-move-error-with-note.stderr +++ b/tests/ui/borrowck/borrowck-move-error-with-note.stderr @@ -44,10 +44,7 @@ error[E0507]: cannot move out of `a.a` which is behind a shared reference LL | match a.a { | ^^^ LL | n => { - | - - | | - | data moved here - | move occurs because `n` has type `Box`, which does not implement the `Copy` trait + | - data moved here because `n` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here | diff --git a/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr index 21bd073321b8..c67499c7d6d7 100644 --- a/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr +++ b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | fn arg_item(&_x: &String) {} | ^-- | | - | data moved here - | move occurs because `_x` has type `String`, which does not implement the `Copy` trait + | data moved here because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -19,8 +18,7 @@ error[E0507]: cannot move out of a shared reference LL | with(|&_x| ()) | ^-- | | - | data moved here - | move occurs because `_x` has type `String`, which does not implement the `Copy` trait + | data moved here because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -34,8 +32,7 @@ error[E0507]: cannot move out of a shared reference LL | let &_x = &"hi".to_string(); | -- ^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `_x` has type `String`, which does not implement the `Copy` trait + | data moved here because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr index 58f706c65ff2..fa77eddb4965 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr @@ -5,10 +5,7 @@ LL | match (S {f:"foo".to_string()}) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here LL | LL | S {f:_s} => {} - | -- - | | - | data moved here - | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | -- data moved here because `_s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -21,8 +18,7 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait LL | let S {f:_s} = S {f:"foo".to_string()}; | -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here | | - | data moved here - | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | data moved here because `_s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -35,8 +31,7 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait LL | fn move_in_fn_arg(S {f:_s}: S) { | ^^^^^--^ | | | - | | data moved here - | | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | | data moved here because `_s` has type `String`, which does not implement the `Copy` trait | cannot move out of here | help: consider borrowing the pattern binding diff --git a/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr index 160a1f99f63f..17e9792b628d 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr @@ -5,10 +5,7 @@ LL | match S("foo".to_string()) { | ^^^^^^^^^^^^^^^^^^^^ cannot move out of here LL | LL | S(_s) => {} - | -- - | | - | data moved here - | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | -- data moved here because `_s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -21,8 +18,7 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait LL | let S(_s) = S("foo".to_string()); | -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here | | - | data moved here - | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | data moved here because `_s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -35,8 +31,7 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait LL | fn move_in_fn_arg(S(_s): S) { | ^^--^ | | | - | | data moved here - | | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | | data moved here because `_s` has type `String`, which does not implement the `Copy` trait | cannot move out of here | help: consider borrowing the pattern binding diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs index 400e5f010ecb..657c4789aa30 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -35,8 +35,7 @@ fn c() { //~^ ERROR cannot move out //~| NOTE cannot move out &mut [_a, - //~^ NOTE data moved here - //~| NOTE move occurs because `_a` has type + //~^ NOTE data moved here because `_a` has type //~| HELP consider removing the mutable borrow .. ] => { @@ -59,8 +58,7 @@ fn d() { &mut [ //~^ HELP consider removing the mutable borrow _b] => {} - //~^ NOTE data moved here - //~| NOTE move occurs because `_b` has type + //~^ NOTE data moved here because `_b` has type _ => {} } let a = vec[0]; //~ ERROR cannot move out diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr index fff997fd5559..a002b7e3d7f6 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -29,10 +29,7 @@ LL | match vec { | ^^^ cannot move out of here ... LL | &mut [_a, - | -- - | | - | data moved here - | move occurs because `_a` has type `Box`, which does not implement the `Copy` trait + | -- data moved here because `_a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -41,7 +38,7 @@ LL + [_a, | error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:46:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:45:13 | LL | let a = vec[0]; | ^^^^^^ @@ -59,16 +56,13 @@ LL | let a = vec[0].clone(); | ++++++++ error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:56:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:55:11 | LL | match vec { | ^^^ cannot move out of here ... LL | _b] => {} - | -- - | | - | data moved here - | move occurs because `_b` has type `Box`, which does not implement the `Copy` trait + | -- data moved here because `_b` has type `Box`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -77,7 +71,7 @@ LL + [ | error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:66:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:64:13 | LL | let a = vec[0]; | ^^^^^^ @@ -95,7 +89,7 @@ LL | let a = vec[0].clone(); | ++++++++ error[E0508]: cannot move out of type `[Box]`, 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 @@ -114,7 +108,7 @@ LL + [_a, _b, _c] => {} | error[E0508]: cannot move out of type `[Box]`, 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/closure-upvar-named-lifetime.rs b/tests/ui/borrowck/closure-upvar-named-lifetime.rs new file mode 100644 index 000000000000..a0ce192201b1 --- /dev/null +++ b/tests/ui/borrowck/closure-upvar-named-lifetime.rs @@ -0,0 +1,41 @@ +// Regression test for #153545. +// +// When a closure captures a variable whose type involves a named +// lifetime from the parent function, diagnostics should use the +// actual lifetime name (e.g., `'a`) instead of a synthetic name +// like `'1`. + +use std::cell::RefCell; +use std::sync::Arc; +use std::collections::HashMap; +use std::collections::hash_map::Entry; + +fn apply<'a>( + f: Arc) + 'a>, +) -> impl Fn(RefCell>) +{ + move |map| { + //~^ ERROR hidden type for `impl Fn(RefCell>)` captures lifetime that does not appear in bounds + let value = map.borrow_mut().entry("foo".to_string()); + //~^ ERROR `map` does not live long enough + //~| ERROR temporary value dropped while borrowed + let wrapped_value = value; + f(wrapped_value); + } +} + +// Also test with Box instead of Arc, a simpler captured type. +fn apply_box<'a>( + f: Box) + 'a>, +) -> impl Fn(RefCell>) +{ + move |map| { + //~^ ERROR hidden type for `impl Fn(RefCell>)` captures lifetime that does not appear in bounds + let value = map.borrow_mut().entry("foo".to_string()); + //~^ ERROR `map` does not live long enough + //~| ERROR temporary value dropped while borrowed + f(value); + } +} + +fn main() {} diff --git a/tests/ui/borrowck/closure-upvar-named-lifetime.stderr b/tests/ui/borrowck/closure-upvar-named-lifetime.stderr new file mode 100644 index 000000000000..fc7c59fa97c8 --- /dev/null +++ b/tests/ui/borrowck/closure-upvar-named-lifetime.stderr @@ -0,0 +1,116 @@ +error[E0597]: `map` does not live long enough + --> $DIR/closure-upvar-named-lifetime.rs:19:21 + | +LL | fn apply<'a>( + | -- lifetime `'a` defined here +... +LL | move |map| { + | --- binding `map` declared here +LL | +LL | let value = map.borrow_mut().entry("foo".to_string()); + | ^^^ borrowed value does not live long enough +... +LL | f(wrapped_value); + | ---------------- argument requires that `map` is borrowed for `'a` +LL | } + | - `map` dropped here while still borrowed + | +note: requirement that the value outlives `'a` introduced here + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error[E0716]: temporary value dropped while borrowed + --> $DIR/closure-upvar-named-lifetime.rs:19:21 + | +LL | fn apply<'a>( + | -- lifetime `'a` defined here +... +LL | let value = map.borrow_mut().entry("foo".to_string()); + | ^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | f(wrapped_value); + | ---------------- argument requires that borrow lasts for `'a` + | +note: requirement that the value outlives `'a` introduced here + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error[E0700]: hidden type for `impl Fn(RefCell>)` captures lifetime that does not appear in bounds + --> $DIR/closure-upvar-named-lifetime.rs:17:5 + | +LL | fn apply<'a>( + | -- hidden type `{closure@$DIR/closure-upvar-named-lifetime.rs:17:5: 17:15}` captures the lifetime `'a` as defined here +LL | f: Arc) + 'a>, +LL | ) -> impl Fn(RefCell>) + | ----------------------------------------- opaque type defined here +LL | { +LL | / move |map| { +LL | | +LL | | let value = map.borrow_mut().entry("foo".to_string()); +... | +LL | | f(wrapped_value); +LL | | } + | |_____^ + | +help: add a `use<...>` bound to explicitly capture `'a` + | +LL | ) -> impl Fn(RefCell>) + use<'a> + | +++++++++ + +error[E0597]: `map` does not live long enough + --> $DIR/closure-upvar-named-lifetime.rs:34:21 + | +LL | fn apply_box<'a>( + | -- lifetime `'a` defined here +... +LL | move |map| { + | --- binding `map` declared here +LL | +LL | let value = map.borrow_mut().entry("foo".to_string()); + | ^^^ borrowed value does not live long enough +... +LL | f(value); + | -------- argument requires that `map` is borrowed for `'a` +LL | } + | - `map` dropped here while still borrowed + +error[E0716]: temporary value dropped while borrowed + --> $DIR/closure-upvar-named-lifetime.rs:34:21 + | +LL | fn apply_box<'a>( + | -- lifetime `'a` defined here +... +LL | let value = map.borrow_mut().entry("foo".to_string()); + | ^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | f(value); + | -------- argument requires that borrow lasts for `'a` + +error[E0700]: hidden type for `impl Fn(RefCell>)` captures lifetime that does not appear in bounds + --> $DIR/closure-upvar-named-lifetime.rs:32:5 + | +LL | fn apply_box<'a>( + | -- hidden type `{closure@$DIR/closure-upvar-named-lifetime.rs:32:5: 32:15}` captures the lifetime `'a` as defined here +LL | f: Box) + 'a>, +LL | ) -> impl Fn(RefCell>) + | ----------------------------------------- opaque type defined here +LL | { +LL | / move |map| { +LL | | +LL | | let value = map.borrow_mut().entry("foo".to_string()); +... | +LL | | f(value); +LL | | } + | |_____^ + | +help: add a `use<...>` bound to explicitly capture `'a` + | +LL | ) -> impl Fn(RefCell>) + use<'a> + | +++++++++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0597, E0700, E0716. +For more information about an error, try `rustc --explain E0597`. diff --git a/tests/ui/borrowck/dbg-issue-120327.rs b/tests/ui/borrowck/dbg-issue-120327.rs index 2de43f634877..45605acc3433 100644 --- a/tests/ui/borrowck/dbg-issue-120327.rs +++ b/tests/ui/borrowck/dbg-issue-120327.rs @@ -1,67 +1,44 @@ +//! Diagnostic test for : suggest borrowing +//! variables passed to `dbg!` that are later used. +//@ dont-require-annotations: HELP + fn s() -> String { let a = String::new(); - dbg!(a); + dbg!(a); //~ HELP consider borrowing instead of transferring ownership return a; //~ ERROR use of moved value: } fn m() -> String { let a = String::new(); - dbg!(1, 2, a, 1, 2); + dbg!(1, 2, a, 1, 2); //~ HELP consider borrowing instead of transferring ownership return a; //~ ERROR use of moved value: } fn t(a: String) -> String { let b: String = "".to_string(); - dbg!(a, b); + dbg!(a, b); //~ HELP consider borrowing instead of transferring ownership return b; //~ ERROR use of moved value: } fn x(a: String) -> String { let b: String = "".to_string(); - dbg!(a, b); + dbg!(a, b); //~ HELP consider borrowing instead of transferring ownership return a; //~ ERROR use of moved value: } -macro_rules! my_dbg { - () => { - eprintln!("[{}:{}:{}]", file!(), line!(), column!()) - }; - ($val:expr $(,)?) => { - match $val { - tmp => { - eprintln!("[{}:{}:{}] {} = {:#?}", - file!(), line!(), column!(), stringify!($val), &tmp); - tmp - } - } - }; - ($($val:expr),+ $(,)?) => { - ($(my_dbg!($val)),+,) - }; -} - -fn test_my_dbg() -> String { - let b: String = "".to_string(); - my_dbg!(b, 1); - return b; //~ ERROR use of moved value: -} - -fn test_not_macro() -> String { - let a = String::new(); - let _b = match a { - tmp => { - eprintln!("dbg: {}", tmp); - tmp - } - }; - return a; //~ ERROR use of moved value: +fn two_of_them(a: String) -> String { + dbg!(a, a); //~ ERROR use of moved value + //~| HELP consider borrowing instead of transferring ownership + //~| HELP consider borrowing instead of transferring ownership + return a; //~ ERROR use of moved value } fn get_expr(_s: String) {} +// The suggestion is purely syntactic; applying it here will result in a type error. fn test() { let a: String = "".to_string(); - let _res = get_expr(dbg!(a)); + let _res = get_expr(dbg!(a)); //~ HELP consider borrowing instead of transferring ownership let _l = a.len(); //~ ERROR borrow of moved value } diff --git a/tests/ui/borrowck/dbg-issue-120327.stderr b/tests/ui/borrowck/dbg-issue-120327.stderr index efacc0c3f134..e7a7151e541d 100644 --- a/tests/ui/borrowck/dbg-issue-120327.stderr +++ b/tests/ui/borrowck/dbg-issue-120327.stderr @@ -1,112 +1,133 @@ error[E0382]: use of moved value: `a` - --> $DIR/dbg-issue-120327.rs:4:12 + --> $DIR/dbg-issue-120327.rs:8:12 | LL | let a = String::new(); | - move occurs because `a` has type `String`, which does not implement the `Copy` trait LL | dbg!(a); - | ------- value moved here + | - value moved here LL | return a; | ^ value used here after move | +help: consider cloning the value if the performance cost is acceptable + | +LL | dbg!(a.clone()); + | ++++++++ help: consider borrowing instead of transferring ownership | LL | dbg!(&a); | + error[E0382]: use of moved value: `a` - --> $DIR/dbg-issue-120327.rs:10:12 + --> $DIR/dbg-issue-120327.rs:14:12 | LL | let a = String::new(); | - move occurs because `a` has type `String`, which does not implement the `Copy` trait LL | dbg!(1, 2, a, 1, 2); - | ------------------- value moved here + | - value moved here LL | return a; | ^ value used here after move | +help: consider cloning the value if the performance cost is acceptable + | +LL | dbg!(1, 2, a.clone(), 1, 2); + | ++++++++ help: consider borrowing instead of transferring ownership | LL | dbg!(1, 2, &a, 1, 2); | + error[E0382]: use of moved value: `b` - --> $DIR/dbg-issue-120327.rs:16:12 + --> $DIR/dbg-issue-120327.rs:20:12 | LL | let b: String = "".to_string(); | - move occurs because `b` has type `String`, which does not implement the `Copy` trait LL | dbg!(a, b); - | ---------- value moved here + | - value moved here LL | return b; | ^ value used here after move | +help: consider cloning the value if the performance cost is acceptable + | +LL | dbg!(a, b.clone()); + | ++++++++ help: consider borrowing instead of transferring ownership | LL | dbg!(a, &b); | + error[E0382]: use of moved value: `a` - --> $DIR/dbg-issue-120327.rs:22:12 + --> $DIR/dbg-issue-120327.rs:26:12 | LL | fn x(a: String) -> String { | - move occurs because `a` has type `String`, which does not implement the `Copy` trait LL | let b: String = "".to_string(); LL | dbg!(a, b); - | ---------- value moved here + | - value moved here LL | return a; | ^ value used here after move | +help: consider cloning the value if the performance cost is acceptable + | +LL | dbg!(a.clone(), b); + | ++++++++ help: consider borrowing instead of transferring ownership | LL | dbg!(&a, b); | + -error[E0382]: use of moved value: `b` - --> $DIR/dbg-issue-120327.rs:46:12 +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:30:13 | -LL | tmp => { - | --- value moved here -... -LL | let b: String = "".to_string(); - | - move occurs because `b` has type `String`, which does not implement the `Copy` trait -LL | my_dbg!(b, 1); -LL | return b; - | ^ value used here after move +LL | fn two_of_them(a: String) -> String { + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a, a); + | - ^ value used here after move + | | + | value moved here | +help: consider cloning the value if the performance cost is acceptable + | +LL | dbg!(a.clone(), a); + | ++++++++ help: consider borrowing instead of transferring ownership | -LL | my_dbg!(&b, 1); - | + -help: borrow this binding in the pattern to avoid moving the value - | -LL | ref tmp => { - | +++ +LL | dbg!(&a, a); + | + error[E0382]: use of moved value: `a` - --> $DIR/dbg-issue-120327.rs:57:12 + --> $DIR/dbg-issue-120327.rs:33:12 | -LL | let a = String::new(); - | - move occurs because `a` has type `String`, which does not implement the `Copy` trait -LL | let _b = match a { -LL | tmp => { - | --- value moved here +LL | fn two_of_them(a: String) -> String { + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a, a); + | - value moved here ... LL | return a; | ^ value used here after move | -help: borrow this binding in the pattern to avoid moving the value +help: consider cloning the value if the performance cost is acceptable | -LL | ref tmp => { - | +++ +LL | dbg!(a, a.clone()); + | ++++++++ +help: consider borrowing instead of transferring ownership + | +LL | dbg!(a, &a); + | + error[E0382]: borrow of moved value: `a` - --> $DIR/dbg-issue-120327.rs:65:14 + --> $DIR/dbg-issue-120327.rs:42:14 | LL | let a: String = "".to_string(); | - move occurs because `a` has type `String`, which does not implement the `Copy` trait LL | let _res = get_expr(dbg!(a)); - | ------- value moved here + | - value moved here LL | let _l = a.len(); | ^ value borrowed here after move | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _res = get_expr(dbg!(a.clone())); + | ++++++++ help: consider borrowing instead of transferring ownership | LL | let _res = get_expr(dbg!(&a)); diff --git a/tests/ui/borrowck/generic_const_early_param.rs b/tests/ui/borrowck/generic_const_early_param.rs index 0d07b6869f12..e5fab5919793 100644 --- a/tests/ui/borrowck/generic_const_early_param.rs +++ b/tests/ui/borrowck/generic_const_early_param.rs @@ -1,5 +1,4 @@ #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete struct DataWrapper<'static> { //~^ ERROR invalid lifetime parameter name: `'static` diff --git a/tests/ui/borrowck/generic_const_early_param.stderr b/tests/ui/borrowck/generic_const_early_param.stderr index 6447f92aba85..a9ee43838814 100644 --- a/tests/ui/borrowck/generic_const_early_param.stderr +++ b/tests/ui/borrowck/generic_const_early_param.stderr @@ -1,11 +1,11 @@ error[E0262]: invalid lifetime parameter name: `'static` - --> $DIR/generic_const_early_param.rs:4:20 + --> $DIR/generic_const_early_param.rs:3:20 | LL | struct DataWrapper<'static> { | ^^^^^^^ 'static is a reserved lifetime name error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/generic_const_early_param.rs:6:12 + --> $DIR/generic_const_early_param.rs:5:12 | LL | data: &'a [u8; Self::SIZE], | ^^ undeclared lifetime @@ -16,7 +16,7 @@ LL | struct DataWrapper<'a, 'static> { | +++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/generic_const_early_param.rs:10:18 + --> $DIR/generic_const_early_param.rs:9:18 | LL | impl DataWrapper<'a> { | ^^ undeclared lifetime @@ -26,16 +26,7 @@ help: consider introducing lifetime `'a` here LL | impl<'a> DataWrapper<'a> { | ++++ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/generic_const_early_param.rs:1:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors Some errors have detailed explanations: E0261, E0262. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/borrowck/issue-51301.stderr b/tests/ui/borrowck/issue-51301.stderr index c0b06437093a..b5c06649e864 100644 --- a/tests/ui/borrowck/issue-51301.stderr +++ b/tests/ui/borrowck/issue-51301.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | .find(|(&event_type, _)| event == event_type) | ^^----------^^^^ | | - | data moved here - | move occurs because `event_type` has type `EventType`, which does not implement the `Copy` trait + | data moved here because `event_type` has type `EventType`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/borrowck/issue-51415.stderr b/tests/ui/borrowck/issue-51415.stderr index e51e0b33ebd3..dd44c5e5f037 100644 --- a/tests/ui/borrowck/issue-51415.stderr +++ b/tests/ui/borrowck/issue-51415.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | let opt = a.iter().enumerate().find(|(_, &s)| { | ^^^^^-^ | | - | data moved here - | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | data moved here because `s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs b/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs deleted file mode 100644 index 22ed8bd3beef..000000000000 --- a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ run-pass - -#![allow(unused_must_use)] -#![allow(dead_code)] -use std::thread; - -fn user(_i: isize) {} - -fn foo() { - // Here, i is *copied* into the proc (heap closure). - // Requires allocation. The proc's copy is not mutable. - let mut i = 0; - let t = thread::spawn(move|| { - user(i); - println!("spawned {}", i) - }); - i += 1; - println!("original {}", i); - t.join(); -} - -fn bar() { - // Here, the original i has not been moved, only copied, so is still - // mutable outside of the proc. - let mut i = 0; - while i < 10 { - let t = thread::spawn(move|| { - user(i); - }); - i += 1; - t.join(); - } -} - -fn car() { - // Here, i must be shadowed in the proc to be mutable. - let mut i = 0; - while i < 10 { - let t = thread::spawn(move|| { - let mut i = i; - i += 1; - user(i); - }); - i += 1; - t.join(); - } -} - -pub fn main() {} diff --git a/tests/ui/issues/issue-52049.rs b/tests/ui/borrowck/non-promotable-static-ref.rs similarity index 53% rename from tests/ui/issues/issue-52049.rs rename to tests/ui/borrowck/non-promotable-static-ref.rs index efdcc4493056..44733493ec06 100644 --- a/tests/ui/issues/issue-52049.rs +++ b/tests/ui/borrowck/non-promotable-static-ref.rs @@ -1,3 +1,5 @@ +//Test for https://github.com/rust-lang/rust/issues/52049 +//Tests that a non-promotable temp variable cannot be used as a static reference. fn foo(_: &'static u32) {} fn unpromotable(t: T) -> T { t } diff --git a/tests/ui/issues/issue-52049.stderr b/tests/ui/borrowck/non-promotable-static-ref.stderr similarity index 90% rename from tests/ui/issues/issue-52049.stderr rename to tests/ui/borrowck/non-promotable-static-ref.stderr index 1d8e136f217b..979b349b7c00 100644 --- a/tests/ui/issues/issue-52049.stderr +++ b/tests/ui/borrowck/non-promotable-static-ref.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-52049.rs:6:10 + --> $DIR/non-promotable-static-ref.rs:8:10 | LL | foo(&unpromotable(5u32)); | -----^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement diff --git a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr index 9b4061af967e..e2199fa90f26 100644 --- a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr +++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -4,11 +4,18 @@ error[E0507]: cannot move out of `*cb` which is behind a mutable reference LL | cb.map(|cb| cb()); | ^^ -------------- `*cb` moved due to this method call | | - | help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents | move occurs because `*cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait | note: `Option::::map` takes ownership of the receiver `self`, which moves `*cb` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider calling `.as_ref()` to borrow the value's contents + | +LL | cb.as_ref().map(|cb| cb()); + | +++++++++ +help: consider calling `.as_mut()` to mutably borrow the value's contents + | +LL | cb.as_mut().map(|cb| cb()); + | +++++++++ help: you could `clone` the value and consume it, if the `&mut dyn FnMut(): Clone` trait bound could be satisfied | LL | as Clone>::clone(&cb).map(|cb| cb()); diff --git a/tests/ui/cfg/both-true-false.rs b/tests/ui/cfg/both-true-false.rs index 5fca8f654ad8..62a4ef6a2dbe 100644 --- a/tests/ui/cfg/both-true-false.rs +++ b/tests/ui/cfg/both-true-false.rs @@ -1,5 +1,6 @@ /// Test that placing a `cfg(true)` and `cfg(false)` on the same item result in //. it being disabled.` +//@ reference: cfg.attr.duplicates #[cfg(false)] #[cfg(true)] diff --git a/tests/ui/cfg/both-true-false.stderr b/tests/ui/cfg/both-true-false.stderr index 1a7c509aec0c..76a5661f0873 100644 --- a/tests/ui/cfg/both-true-false.stderr +++ b/tests/ui/cfg/both-true-false.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find function `foo` in this scope - --> $DIR/both-true-false.rs:13:5 + --> $DIR/both-true-false.rs:14:5 | LL | foo(); | ^^^ not found in this scope | note: found an item that was configured out - --> $DIR/both-true-false.rs:6:4 + --> $DIR/both-true-false.rs:7:4 | LL | #[cfg(false)] | ----- the item is gated here @@ -13,7 +13,7 @@ LL | #[cfg(true)] LL | fn foo() {} | ^^^ note: found an item that was configured out - --> $DIR/both-true-false.rs:10:4 + --> $DIR/both-true-false.rs:11:4 | LL | #[cfg(false)] | ----- the item is gated here diff --git a/tests/ui/cfg/cfg-false-use-item.rs b/tests/ui/cfg/cfg-false-use-item.rs index d37b48cdedb7..d907e17a0c11 100644 --- a/tests/ui/cfg/cfg-false-use-item.rs +++ b/tests/ui/cfg/cfg-false-use-item.rs @@ -1,6 +1,8 @@ //! Test that use items with cfg(false) are properly filtered out //@ run-pass +//@ reference: cfg.predicate.literal +//@ reference: cfg.attr.effect pub fn main() { // Make sure that this view item is filtered out because otherwise it would diff --git a/tests/ui/cfg/cfg-family.rs b/tests/ui/cfg/cfg-family.rs index a13ae7f9616b..60594c7105f7 100644 --- a/tests/ui/cfg/cfg-family.rs +++ b/tests/ui/cfg/cfg-family.rs @@ -1,6 +1,8 @@ //@ build-pass //@ ignore-wasm32 no bare family //@ ignore-sgx +//@ reference: cfg.target_family.unix +//@ reference: cfg.target_family.windows #[cfg(windows)] pub fn main() { diff --git a/tests/ui/cfg/cfg-panic-abort.rs b/tests/ui/cfg/cfg-panic-abort.rs index b39888573b3a..af4e119ef9fe 100644 --- a/tests/ui/cfg/cfg-panic-abort.rs +++ b/tests/ui/cfg/cfg-panic-abort.rs @@ -2,6 +2,8 @@ //@ compile-flags: -C panic=abort //@ no-prefer-dynamic //@ ignore-backends: gcc +//@ reference: cfg.panic.def +//@ reference: cfg.panic.values #[cfg(panic = "unwind")] pub fn bad() -> i32 { } diff --git a/tests/ui/cfg/cfg-panic.rs b/tests/ui/cfg/cfg-panic.rs index 4e3ed0cd9c2f..7c911c5754e7 100644 --- a/tests/ui/cfg/cfg-panic.rs +++ b/tests/ui/cfg/cfg-panic.rs @@ -1,6 +1,8 @@ //@ build-pass //@ compile-flags: -C panic=unwind //@ needs-unwind +//@ reference: cfg.panic.def +//@ reference: cfg.panic.values #[cfg(panic = "abort")] pub fn bad() -> i32 { } diff --git a/tests/ui/cfg/cfg-path-error.rs b/tests/ui/cfg/cfg-path-error.rs index f22e6be32f3e..9bb10d3a6f6a 100644 --- a/tests/ui/cfg/cfg-path-error.rs +++ b/tests/ui/cfg/cfg-path-error.rs @@ -1,4 +1,5 @@ //@ check-fail +//@ reference: cfg.option-spec #![allow(unexpected_cfgs)] // invalid cfgs diff --git a/tests/ui/cfg/cfg-path-error.stderr b/tests/ui/cfg/cfg-path-error.stderr index bb9b7039c8a3..f3b0a2d3c28e 100644 --- a/tests/ui/cfg/cfg-path-error.stderr +++ b/tests/ui/cfg/cfg-path-error.stderr @@ -1,5 +1,5 @@ error[E0539]: malformed `cfg` attribute input - --> $DIR/cfg-path-error.rs:5:1 + --> $DIR/cfg-path-error.rs:6:1 | LL | #[cfg(any(foo, foo::bar))] | ^^^^^^^^^^^^^^^--------^^^ @@ -10,7 +10,7 @@ LL | #[cfg(any(foo, foo::bar))] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/cfg-path-error.rs:11:1 + --> $DIR/cfg-path-error.rs:12:1 | LL | #[cfg(any(foo::bar, foo))] | ^^^^^^^^^^--------^^^^^^^^ @@ -21,7 +21,7 @@ LL | #[cfg(any(foo::bar, foo))] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/cfg-path-error.rs:17:1 + --> $DIR/cfg-path-error.rs:18:1 | LL | #[cfg(all(foo, foo::bar))] | ^^^^^^^^^^^^^^^--------^^^ @@ -32,7 +32,7 @@ LL | #[cfg(all(foo, foo::bar))] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/cfg-path-error.rs:23:1 + --> $DIR/cfg-path-error.rs:24:1 | LL | #[cfg(all(foo::bar, foo))] | ^^^^^^^^^^--------^^^^^^^^ diff --git a/tests/ui/cfg/cfg-target-abi.rs b/tests/ui/cfg/cfg-target-abi.rs index 306ae077325b..b00107118517 100644 --- a/tests/ui/cfg/cfg-target-abi.rs +++ b/tests/ui/cfg/cfg-target-abi.rs @@ -1,4 +1,6 @@ //@ run-pass +//@ reference: cfg.target_abi.def +//@ reference: cfg.target_abi.values #[cfg(target_abi = "eabihf")] pub fn main() { diff --git a/tests/ui/cfg/cfg-target-family.rs b/tests/ui/cfg/cfg-target-family.rs index 0b1c323307a9..33dc5b1e8242 100644 --- a/tests/ui/cfg/cfg-target-family.rs +++ b/tests/ui/cfg/cfg-target-family.rs @@ -1,5 +1,7 @@ //@ build-pass //@ ignore-sgx +//@ reference: cfg.target_family.def +//@ reference: cfg.target_family.values #[cfg(target_family = "windows")] diff --git a/tests/ui/cfg/cfg-target-vendor.rs b/tests/ui/cfg/cfg-target-vendor.rs index e5de95d04e54..04dfbdb064d0 100644 --- a/tests/ui/cfg/cfg-target-vendor.rs +++ b/tests/ui/cfg/cfg-target-vendor.rs @@ -1,4 +1,6 @@ //@ run-pass +//@ reference: cfg.target_vendor.def +//@ reference: cfg.target_vendor.values #[cfg(target_vendor = "unknown")] pub fn main() { } diff --git a/tests/ui/cfg/cfg_attr.rs b/tests/ui/cfg/cfg_attr.rs index ba4adafd3a56..1fab79c5e1f2 100644 --- a/tests/ui/cfg/cfg_attr.rs +++ b/tests/ui/cfg/cfg_attr.rs @@ -1,5 +1,7 @@ //@ run-pass //@ compile-flags:--cfg set1 --cfg set2 +//@ reference: cfg.cfg_attr.intro +//@ reference: cfg.cfg_attr.syntax #![allow(dead_code, unexpected_cfgs)] diff --git a/tests/ui/cfg/cfg_false_no_std-1.rs b/tests/ui/cfg/cfg_false_no_std-1.rs index 17286e219b86..7f8a43ecdfed 100644 --- a/tests/ui/cfg/cfg_false_no_std-1.rs +++ b/tests/ui/cfg/cfg_false_no_std-1.rs @@ -2,6 +2,7 @@ //@ check-pass //@ aux-build: cfg_false_lib_no_std_after.rs +//@ reference: cfg.attr.crate-level-attrs #![no_std] diff --git a/tests/ui/cfg/cfg_false_no_std-2.rs b/tests/ui/cfg/cfg_false_no_std-2.rs index 666c90deaf0f..a3816f0e1551 100644 --- a/tests/ui/cfg/cfg_false_no_std-2.rs +++ b/tests/ui/cfg/cfg_false_no_std-2.rs @@ -7,6 +7,7 @@ //@ compile-flags: -Cpanic=abort //@ aux-build: cfg_false_lib_no_std_before.rs +//@ reference: cfg.attr.crate-level-attrs #![no_std] diff --git a/tests/ui/cfg/cfg_false_no_std.rs b/tests/ui/cfg/cfg_false_no_std.rs index 910f3f8b9ae1..08032c5a91e6 100644 --- a/tests/ui/cfg/cfg_false_no_std.rs +++ b/tests/ui/cfg/cfg_false_no_std.rs @@ -2,6 +2,7 @@ //@ check-pass //@ aux-build: cfg_false_lib.rs +//@ reference: cfg.attr.crate-level-attrs #![no_std] diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs index 128321a23320..ef74a0b75df1 100644 --- a/tests/ui/cfg/cfg_stmt_expr.rs +++ b/tests/ui/cfg/cfg_stmt_expr.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ reference: cfg.attr.allowed-positions #![allow(dead_code)] #![allow(unused_mut)] #![allow(unused_variables)] diff --git a/tests/ui/cfg/cfgs-on-items.rs b/tests/ui/cfg/cfgs-on-items.rs index 8992a8fca9c3..56f87350fea2 100644 --- a/tests/ui/cfg/cfgs-on-items.rs +++ b/tests/ui/cfg/cfgs-on-items.rs @@ -1,5 +1,8 @@ //@ run-pass //@ compile-flags: --cfg fooA --cfg fooB --check-cfg=cfg(fooA,fooB,fooC,bar) +//@ reference: cfg.predicate.all +//@ reference: cfg.predicate.any +//@ reference: cfg.predicate.not // fooA AND !bar #[cfg(all(fooA, not(bar)))] diff --git a/tests/ui/cfg/conditional-compile-arch.rs b/tests/ui/cfg/conditional-compile-arch.rs index f16805474074..0d57a50be530 100644 --- a/tests/ui/cfg/conditional-compile-arch.rs +++ b/tests/ui/cfg/conditional-compile-arch.rs @@ -1,4 +1,6 @@ //@ run-pass +//@ reference: cfg.target_arch.def +//@ reference: cfg.target_arch.values #[cfg(target_arch = "x86")] pub fn main() { } diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs index 8761197891f5..637bd0e12e8b 100644 --- a/tests/ui/cfg/conditional-compile.rs +++ b/tests/ui/cfg/conditional-compile.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ reference: cfg.attr.allowed-positions #![allow(dead_code)] #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] diff --git a/tests/ui/cfg/crate-attributes-using-cfg_attr.rs b/tests/ui/cfg/crate-attributes-using-cfg_attr.rs index f99fad881f28..6dbc59ccc4ed 100644 --- a/tests/ui/cfg/crate-attributes-using-cfg_attr.rs +++ b/tests/ui/cfg/crate-attributes-using-cfg_attr.rs @@ -1,5 +1,6 @@ //@ check-fail //@ compile-flags:--cfg foo --check-cfg=cfg(foo) +//@ reference: cfg.cfg_attr.attr-restriction #![cfg_attr(foo, crate_type="bin")] //~^ERROR `crate_type` within diff --git a/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr index 1dfca2b88d0e..3d6f00760502 100644 --- a/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr +++ b/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr @@ -1,17 +1,17 @@ error: `crate_type` within an `#![cfg_attr]` attribute is forbidden - --> $DIR/crate-attributes-using-cfg_attr.rs:4:18 + --> $DIR/crate-attributes-using-cfg_attr.rs:5:18 | LL | #![cfg_attr(foo, crate_type="bin")] | ^^^^^^^^^^^^^^^^ error: `crate_name` within an `#![cfg_attr]` attribute is forbidden - --> $DIR/crate-attributes-using-cfg_attr.rs:7:18 + --> $DIR/crate-attributes-using-cfg_attr.rs:8:18 | LL | #![cfg_attr(foo, crate_name="bar")] | ^^^^^^^^^^^^^^^^ error: `crate_type` within an `#![cfg_attr]` attribute is forbidden - --> $DIR/crate-attributes-using-cfg_attr.rs:4:18 + --> $DIR/crate-attributes-using-cfg_attr.rs:5:18 | LL | #![cfg_attr(foo, crate_type="bin")] | ^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | #![cfg_attr(foo, crate_type="bin")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `crate_name` within an `#![cfg_attr]` attribute is forbidden - --> $DIR/crate-attributes-using-cfg_attr.rs:7:18 + --> $DIR/crate-attributes-using-cfg_attr.rs:8:18 | LL | #![cfg_attr(foo, crate_name="bar")] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cfg/invalid-cli-cfg-pred.rs b/tests/ui/cfg/invalid-cli-cfg-pred.rs index fdfb6b18d96b..817362a40f3d 100644 --- a/tests/ui/cfg/invalid-cli-cfg-pred.rs +++ b/tests/ui/cfg/invalid-cli-cfg-pred.rs @@ -1,4 +1,7 @@ //@ compile-flags: --cfg foo=1x +//@ reference: cfg.option-spec +//@ reference: cfg.option-name +//@ reference: cfg.option-key-value fn main() {} diff --git a/tests/ui/cfg/invalid-cli-check-cfg-pred.rs b/tests/ui/cfg/invalid-cli-check-cfg-pred.rs index 30417a912bfc..d5a40f439836 100644 --- a/tests/ui/cfg/invalid-cli-check-cfg-pred.rs +++ b/tests/ui/cfg/invalid-cli-check-cfg-pred.rs @@ -1,4 +1,7 @@ //@ compile-flags: --check-cfg 'foo=1x' +//@ reference: cfg.option-spec +//@ reference: cfg.option-name +//@ reference: cfg.option-key-value fn main() {} diff --git a/tests/ui/cfg/path-kw-as-cfg-pred.rs b/tests/ui/cfg/path-kw-as-cfg-pred.rs index d3b419175163..f161e60385b4 100644 --- a/tests/ui/cfg/path-kw-as-cfg-pred.rs +++ b/tests/ui/cfg/path-kw-as-cfg-pred.rs @@ -1,4 +1,6 @@ //@ edition: 2024 +//@ reference: cfg.attr.syntax +//@ reference: cfg.cfg_attr.syntax #![allow(unexpected_cfgs)] diff --git a/tests/ui/cfg/path-kw-as-cfg-pred.stderr b/tests/ui/cfg/path-kw-as-cfg-pred.stderr index f0bc0b67b933..b10149dd0964 100644 --- a/tests/ui/cfg/path-kw-as-cfg-pred.stderr +++ b/tests/ui/cfg/path-kw-as-cfg-pred.stderr @@ -1,125 +1,125 @@ error: `crate` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:70:10 + --> $DIR/path-kw-as-cfg-pred.rs:72:10 | LL | cfg!(r#crate); | ^^^^^^^ error: `super` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:72:10 + --> $DIR/path-kw-as-cfg-pred.rs:74:10 | LL | cfg!(r#super); | ^^^^^^^ error: `self` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:74:10 + --> $DIR/path-kw-as-cfg-pred.rs:76:10 | LL | cfg!(r#self); | ^^^^^^ error: `Self` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:76:10 + --> $DIR/path-kw-as-cfg-pred.rs:78:10 | LL | cfg!(r#Self); | ^^^^^^ error: `_` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:85:10 + --> $DIR/path-kw-as-cfg-pred.rs:87:10 | LL | cfg!(r#_); | ^^^ error: `crate` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:88:7 + --> $DIR/path-kw-as-cfg-pred.rs:90:7 | LL | #[cfg(r#crate)] | ^^^^^^^ error: `super` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:91:7 + --> $DIR/path-kw-as-cfg-pred.rs:93:7 | LL | #[cfg(r#super)] | ^^^^^^^ error: `self` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:94:7 + --> $DIR/path-kw-as-cfg-pred.rs:96:7 | LL | #[cfg(r#self)] | ^^^^^^ error: `Self` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:97:7 + --> $DIR/path-kw-as-cfg-pred.rs:99:7 | LL | #[cfg(r#Self)] | ^^^^^^ error: `crate` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:100:12 + --> $DIR/path-kw-as-cfg-pred.rs:102:12 | LL | #[cfg_attr(r#crate, cfg(r#crate))] | ^^^^^^^ error: `crate` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:100:25 + --> $DIR/path-kw-as-cfg-pred.rs:102:25 | LL | #[cfg_attr(r#crate, cfg(r#crate))] | ^^^^^^^ error: `super` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:104:12 + --> $DIR/path-kw-as-cfg-pred.rs:106:12 | LL | #[cfg_attr(r#super, cfg(r#super))] | ^^^^^^^ error: `super` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:104:25 + --> $DIR/path-kw-as-cfg-pred.rs:106:25 | LL | #[cfg_attr(r#super, cfg(r#super))] | ^^^^^^^ error: `self` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:108:12 + --> $DIR/path-kw-as-cfg-pred.rs:110:12 | LL | #[cfg_attr(r#self, cfg(r#self))] | ^^^^^^ error: `self` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:108:24 + --> $DIR/path-kw-as-cfg-pred.rs:110:24 | LL | #[cfg_attr(r#self, cfg(r#self))] | ^^^^^^ error: `Self` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:112:12 + --> $DIR/path-kw-as-cfg-pred.rs:114:12 | LL | #[cfg_attr(r#Self, cfg(r#Self))] | ^^^^^^ error: `Self` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:112:24 + --> $DIR/path-kw-as-cfg-pred.rs:114:24 | LL | #[cfg_attr(r#Self, cfg(r#Self))] | ^^^^^^ error: `_` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:121:7 + --> $DIR/path-kw-as-cfg-pred.rs:123:7 | LL | #[cfg(r#_)] | ^^^ error: `_` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:127:12 + --> $DIR/path-kw-as-cfg-pred.rs:129:12 | LL | #[cfg_attr(r#_, cfg(r#_))] | ^^^ error: `_` cannot be a raw identifier - --> $DIR/path-kw-as-cfg-pred.rs:127:21 + --> $DIR/path-kw-as-cfg-pred.rs:129:21 | LL | #[cfg_attr(r#_, cfg(r#_))] | ^^^ error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:18:1 + --> $DIR/path-kw-as-cfg-pred.rs:20:1 | LL | #[cfg(crate)] | ^^^^^^-----^^ @@ -130,7 +130,7 @@ LL | #[cfg(crate)] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:20:1 + --> $DIR/path-kw-as-cfg-pred.rs:22:1 | LL | #[cfg(super)] | ^^^^^^-----^^ @@ -141,7 +141,7 @@ LL | #[cfg(super)] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:22:1 + --> $DIR/path-kw-as-cfg-pred.rs:24:1 | LL | #[cfg(self)] | ^^^^^^----^^ @@ -152,7 +152,7 @@ LL | #[cfg(self)] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:24:1 + --> $DIR/path-kw-as-cfg-pred.rs:26:1 | LL | #[cfg(Self)] | ^^^^^^----^^ @@ -163,7 +163,7 @@ LL | #[cfg(Self)] = note: for more information, visit error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:26:1 + --> $DIR/path-kw-as-cfg-pred.rs:28:1 | LL | #[cfg_attr(crate, path = "foo")] | ^^^^^^^^^^^-----^^^^^^^^^^^^^^^^ @@ -174,7 +174,7 @@ LL | #[cfg_attr(crate, path = "foo")] = note: for more information, visit error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:28:1 + --> $DIR/path-kw-as-cfg-pred.rs:30:1 | LL | #[cfg_attr(super, path = "foo")] | ^^^^^^^^^^^-----^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ LL | #[cfg_attr(super, path = "foo")] = note: for more information, visit error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:30:1 + --> $DIR/path-kw-as-cfg-pred.rs:32:1 | LL | #[cfg_attr(self, path = "foo")] | ^^^^^^^^^^^----^^^^^^^^^^^^^^^^ @@ -196,7 +196,7 @@ LL | #[cfg_attr(self, path = "foo")] = note: for more information, visit error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:32:1 + --> $DIR/path-kw-as-cfg-pred.rs:34:1 | LL | #[cfg_attr(Self, path = "foo")] | ^^^^^^^^^^^----^^^^^^^^^^^^^^^^ @@ -207,7 +207,7 @@ LL | #[cfg_attr(Self, path = "foo")] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:34:18 + --> $DIR/path-kw-as-cfg-pred.rs:36:18 | LL | #[cfg_attr(true, cfg(crate))] | ^^^^-----^ @@ -218,7 +218,7 @@ LL | #[cfg_attr(true, cfg(crate))] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:36:18 + --> $DIR/path-kw-as-cfg-pred.rs:38:18 | LL | #[cfg_attr(true, cfg(super))] | ^^^^-----^ @@ -229,7 +229,7 @@ LL | #[cfg_attr(true, cfg(super))] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:38:18 + --> $DIR/path-kw-as-cfg-pred.rs:40:18 | LL | #[cfg_attr(true, cfg(self))] | ^^^^----^ @@ -240,7 +240,7 @@ LL | #[cfg_attr(true, cfg(self))] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:40:18 + --> $DIR/path-kw-as-cfg-pred.rs:42:18 | LL | #[cfg_attr(true, cfg(Self))] | ^^^^----^ @@ -251,25 +251,25 @@ LL | #[cfg_attr(true, cfg(Self))] = note: for more information, visit error: expected identifier, found keyword `struct` - --> $DIR/path-kw-as-cfg-pred.rs:43:7 + --> $DIR/path-kw-as-cfg-pred.rs:45:7 | LL | #[cfg(struct)] | ^^^^^^ expected identifier, found keyword error: expected identifier, found reserved keyword `priv` - --> $DIR/path-kw-as-cfg-pred.rs:45:7 + --> $DIR/path-kw-as-cfg-pred.rs:47:7 | LL | #[cfg(priv)] | ^^^^ expected identifier, found reserved keyword error: expected identifier, found reserved identifier `_` - --> $DIR/path-kw-as-cfg-pred.rs:47:7 + --> $DIR/path-kw-as-cfg-pred.rs:49:7 | LL | #[cfg(_)] | ^ expected identifier, found reserved identifier error: expected identifier, found keyword `struct` - --> $DIR/path-kw-as-cfg-pred.rs:49:12 + --> $DIR/path-kw-as-cfg-pred.rs:51:12 | LL | #[cfg_attr(struct, path = "foo")] | ^^^^^^ expected identifier, found keyword @@ -280,7 +280,7 @@ LL | #[cfg_attr(r#struct, path = "foo")] | ++ error: expected identifier, found reserved keyword `priv` - --> $DIR/path-kw-as-cfg-pred.rs:51:12 + --> $DIR/path-kw-as-cfg-pred.rs:53:12 | LL | #[cfg_attr(priv, path = "foo")] | ^^^^ expected identifier, found reserved keyword @@ -291,31 +291,31 @@ LL | #[cfg_attr(r#priv, path = "foo")] | ++ error: expected identifier, found reserved identifier `_` - --> $DIR/path-kw-as-cfg-pred.rs:53:12 + --> $DIR/path-kw-as-cfg-pred.rs:55:12 | LL | #[cfg_attr(_, path = "foo")] | ^ expected identifier, found reserved identifier error: expected identifier, found keyword `struct` - --> $DIR/path-kw-as-cfg-pred.rs:55:22 + --> $DIR/path-kw-as-cfg-pred.rs:57:22 | LL | #[cfg_attr(true, cfg(struct))] | ^^^^^^ expected identifier, found keyword error: expected identifier, found reserved keyword `priv` - --> $DIR/path-kw-as-cfg-pred.rs:57:22 + --> $DIR/path-kw-as-cfg-pred.rs:59:22 | LL | #[cfg_attr(true, cfg(priv))] | ^^^^ expected identifier, found reserved keyword error: expected identifier, found reserved identifier `_` - --> $DIR/path-kw-as-cfg-pred.rs:59:22 + --> $DIR/path-kw-as-cfg-pred.rs:61:22 | LL | #[cfg_attr(true, cfg(_))] | ^ expected identifier, found reserved identifier error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:88:1 + --> $DIR/path-kw-as-cfg-pred.rs:90:1 | LL | #[cfg(r#crate)] | ^^^^^^-------^^ @@ -326,7 +326,7 @@ LL | #[cfg(r#crate)] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:91:1 + --> $DIR/path-kw-as-cfg-pred.rs:93:1 | LL | #[cfg(r#super)] | ^^^^^^-------^^ @@ -337,7 +337,7 @@ LL | #[cfg(r#super)] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:94:1 + --> $DIR/path-kw-as-cfg-pred.rs:96:1 | LL | #[cfg(r#self)] | ^^^^^^------^^ @@ -348,7 +348,7 @@ LL | #[cfg(r#self)] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:97:1 + --> $DIR/path-kw-as-cfg-pred.rs:99:1 | LL | #[cfg(r#Self)] | ^^^^^^------^^ @@ -359,7 +359,7 @@ LL | #[cfg(r#Self)] = note: for more information, visit error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:100:1 + --> $DIR/path-kw-as-cfg-pred.rs:102:1 | LL | #[cfg_attr(r#crate, cfg(r#crate))] | ^^^^^^^^^^^-------^^^^^^^^^^^^^^^^ @@ -370,7 +370,7 @@ LL | #[cfg_attr(r#crate, cfg(r#crate))] = note: for more information, visit error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:104:1 + --> $DIR/path-kw-as-cfg-pred.rs:106:1 | LL | #[cfg_attr(r#super, cfg(r#super))] | ^^^^^^^^^^^-------^^^^^^^^^^^^^^^^ @@ -381,7 +381,7 @@ LL | #[cfg_attr(r#super, cfg(r#super))] = note: for more information, visit error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:108:1 + --> $DIR/path-kw-as-cfg-pred.rs:110:1 | LL | #[cfg_attr(r#self, cfg(r#self))] | ^^^^^^^^^^^------^^^^^^^^^^^^^^^ @@ -392,7 +392,7 @@ LL | #[cfg_attr(r#self, cfg(r#self))] = note: for more information, visit error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:112:1 + --> $DIR/path-kw-as-cfg-pred.rs:114:1 | LL | #[cfg_attr(r#Self, cfg(r#Self))] | ^^^^^^^^^^^------^^^^^^^^^^^^^^^ @@ -403,7 +403,7 @@ LL | #[cfg_attr(r#Self, cfg(r#Self))] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:7:9 + --> $DIR/path-kw-as-cfg-pred.rs:9:9 | LL | #[cfg($crate)] | ^^^^^^------^^ @@ -418,7 +418,7 @@ LL | foo!(); = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:9:9 + --> $DIR/path-kw-as-cfg-pred.rs:11:9 | LL | #[cfg_attr($crate, path = "foo")] | ^^^^^^^^^^^------^^^^^^^^^^^^^^^^ @@ -433,7 +433,7 @@ LL | foo!(); = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0539]: malformed `cfg` attribute input - --> $DIR/path-kw-as-cfg-pred.rs:11:26 + --> $DIR/path-kw-as-cfg-pred.rs:13:26 | LL | #[cfg_attr(true, cfg($crate))] | ^^^^------^ @@ -448,7 +448,7 @@ LL | foo!(); = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:14:9 + --> $DIR/path-kw-as-cfg-pred.rs:16:9 | LL | cfg!($crate); | ^^^^^------^ @@ -463,7 +463,7 @@ LL | foo!(); = note: this error originates in the macro `cfg` which comes from the expansion of the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:65:5 + --> $DIR/path-kw-as-cfg-pred.rs:67:5 | LL | cfg!(crate); | ^^^^^-----^ @@ -474,7 +474,7 @@ LL | cfg!(crate); = note: for more information, visit error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:66:5 + --> $DIR/path-kw-as-cfg-pred.rs:68:5 | LL | cfg!(super); | ^^^^^-----^ @@ -485,7 +485,7 @@ LL | cfg!(super); = note: for more information, visit error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:67:5 + --> $DIR/path-kw-as-cfg-pred.rs:69:5 | LL | cfg!(self); | ^^^^^----^ @@ -496,7 +496,7 @@ LL | cfg!(self); = note: for more information, visit error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:68:5 + --> $DIR/path-kw-as-cfg-pred.rs:70:5 | LL | cfg!(Self); | ^^^^^----^ @@ -507,7 +507,7 @@ LL | cfg!(Self); = note: for more information, visit error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:70:5 + --> $DIR/path-kw-as-cfg-pred.rs:72:5 | LL | cfg!(r#crate); | ^^^^^-------^ @@ -518,7 +518,7 @@ LL | cfg!(r#crate); = note: for more information, visit error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:72:5 + --> $DIR/path-kw-as-cfg-pred.rs:74:5 | LL | cfg!(r#super); | ^^^^^-------^ @@ -529,7 +529,7 @@ LL | cfg!(r#super); = note: for more information, visit error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:74:5 + --> $DIR/path-kw-as-cfg-pred.rs:76:5 | LL | cfg!(r#self); | ^^^^^------^ @@ -540,7 +540,7 @@ LL | cfg!(r#self); = note: for more information, visit error[E0539]: malformed `cfg` macro input - --> $DIR/path-kw-as-cfg-pred.rs:76:5 + --> $DIR/path-kw-as-cfg-pred.rs:78:5 | LL | cfg!(r#Self); | ^^^^^------^ @@ -551,19 +551,19 @@ LL | cfg!(r#Self); = note: for more information, visit error: expected identifier, found keyword `struct` - --> $DIR/path-kw-as-cfg-pred.rs:79:10 + --> $DIR/path-kw-as-cfg-pred.rs:81:10 | LL | cfg!(struct); | ^^^^^^ expected identifier, found keyword error: expected identifier, found reserved keyword `priv` - --> $DIR/path-kw-as-cfg-pred.rs:80:10 + --> $DIR/path-kw-as-cfg-pred.rs:82:10 | LL | cfg!(priv); | ^^^^ expected identifier, found reserved keyword error: expected identifier, found reserved identifier `_` - --> $DIR/path-kw-as-cfg-pred.rs:81:10 + --> $DIR/path-kw-as-cfg-pred.rs:83:10 | LL | cfg!(_); | ^ expected identifier, found reserved identifier diff --git a/tests/ui/cfg/true-false.rs b/tests/ui/cfg/true-false.rs index 0bd1cf427faf..b8e0e8968c83 100644 --- a/tests/ui/cfg/true-false.rs +++ b/tests/ui/cfg/true-false.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ reference: cfg.predicate.literal #![feature(link_cfg)] diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 06a7f477a7fd..06384c2202f1 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -17,6 +17,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `addsubiw` `adx` `aes` +`allows-misaligned-mem-access` `altivec` `alu32` `amx-avx512` diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index efa0a7f4af9a..0ba2f0b0f209 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -120,7 +120,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | sanitize = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `realtime`, `safestack`, `shadow-call-stack`, and `thread` + = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `kernel-hwaddress`, `leak`, `memory`, `memtag`, `realtime`, `safestack`, `shadow-call-stack`, and `thread` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/closures/2229_closure_analysis/issue-118144.stderr b/tests/ui/closures/2229_closure_analysis/issue-118144.stderr index bfe4afc4b58c..dd17a305881e 100644 --- a/tests/ui/closures/2229_closure_analysis/issue-118144.stderr +++ b/tests/ui/closures/2229_closure_analysis/issue-118144.stderr @@ -6,7 +6,7 @@ LL | V(x) = func_arg; | | | expected `&mut V`, found `V` | -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | V(x) = &*func_arg; | ++ diff --git a/tests/ui/closures/binder/bounds-on-closure-type-binders.rs b/tests/ui/closures/binder/bounds-on-closure-type-binders.rs index cf53241407fe..80f48a1e2b40 100644 --- a/tests/ui/closures/binder/bounds-on-closure-type-binders.rs +++ b/tests/ui/closures/binder/bounds-on-closure-type-binders.rs @@ -10,5 +10,4 @@ fn main() { // Regression test for issue #119067 let _ = for || -> () {}; //~^ ERROR bounds cannot be used in this context - //~| ERROR late-bound type parameter not allowed on closures } diff --git a/tests/ui/closures/binder/bounds-on-closure-type-binders.stderr b/tests/ui/closures/binder/bounds-on-closure-type-binders.stderr index 9cb921f66314..50fa11ed0ed1 100644 --- a/tests/ui/closures/binder/bounds-on-closure-type-binders.stderr +++ b/tests/ui/closures/binder/bounds-on-closure-type-binders.stderr @@ -4,11 +4,5 @@ error: bounds cannot be used in this context LL | let _ = for || -> () {}; | ^^^^^ -error: late-bound type parameter not allowed on closures - --> $DIR/bounds-on-closure-type-binders.rs:11:17 - | -LL | let _ = for || -> () {}; - | ^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/closures/binder/const-bound.rs b/tests/ui/closures/binder/const-bound.rs index 10d869fcc851..e6984ed6d559 100644 --- a/tests/ui/closures/binder/const-bound.rs +++ b/tests/ui/closures/binder/const-bound.rs @@ -1,5 +1,4 @@ #![feature(closure_lifetime_binder, non_lifetime_binders)] -//~^ WARN is incomplete and may not be safe to use fn main() { for || -> () {}; diff --git a/tests/ui/closures/binder/const-bound.stderr b/tests/ui/closures/binder/const-bound.stderr index b805879f7fab..a57788072b0b 100644 --- a/tests/ui/closures/binder/const-bound.stderr +++ b/tests/ui/closures/binder/const-bound.stderr @@ -1,23 +1,14 @@ error: late-bound const parameters cannot be used currently - --> $DIR/const-bound.rs:5:15 + --> $DIR/const-bound.rs:4:15 | LL | for || -> () {}; | ^ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-bound.rs:1:37 - | -LL | #![feature(closure_lifetime_binder, non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error: late-bound const parameter not allowed on closures - --> $DIR/const-bound.rs:5:9 + --> $DIR/const-bound.rs:4:9 | LL | for || -> () {}; | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/closures/binder/type-bound-2.rs b/tests/ui/closures/binder/type-bound-2.rs index f4edcdaa9ca9..064fbf975d45 100644 --- a/tests/ui/closures/binder/type-bound-2.rs +++ b/tests/ui/closures/binder/type-bound-2.rs @@ -1,5 +1,4 @@ #![feature(closure_lifetime_binder, non_lifetime_binders)] -//~^ WARN is incomplete and may not be safe to use fn main() { for || -> () {}; diff --git a/tests/ui/closures/binder/type-bound-2.stderr b/tests/ui/closures/binder/type-bound-2.stderr index 6609b326f19a..6fd7d576dd70 100644 --- a/tests/ui/closures/binder/type-bound-2.stderr +++ b/tests/ui/closures/binder/type-bound-2.stderr @@ -1,17 +1,8 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-bound-2.rs:1:37 - | -LL | #![feature(closure_lifetime_binder, non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error: late-bound type parameter not allowed on closures - --> $DIR/type-bound-2.rs:5:9 + --> $DIR/type-bound-2.rs:4:9 | LL | for || -> () {}; | ^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/closures/binder/type-bound.rs b/tests/ui/closures/binder/type-bound.rs index 59a3353f4965..9fc60b30167b 100644 --- a/tests/ui/closures/binder/type-bound.rs +++ b/tests/ui/closures/binder/type-bound.rs @@ -1,5 +1,4 @@ #![feature(closure_lifetime_binder, non_lifetime_binders)] -//~^ WARN is incomplete and may not be safe to use fn main() { for || -> T {}; diff --git a/tests/ui/closures/binder/type-bound.stderr b/tests/ui/closures/binder/type-bound.stderr index 22431130a5d4..11dc3288fe87 100644 --- a/tests/ui/closures/binder/type-bound.stderr +++ b/tests/ui/closures/binder/type-bound.stderr @@ -1,17 +1,8 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-bound.rs:1:37 - | -LL | #![feature(closure_lifetime_binder, non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error: late-bound type parameter not allowed on closures - --> $DIR/type-bound.rs:5:9 + --> $DIR/type-bound.rs:4:9 | LL | for || -> T {}; | ^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/closures/issue-90871.stderr b/tests/ui/closures/issue-90871.stderr index 140f24982140..a70c761201b6 100644 --- a/tests/ui/closures/issue-90871.stderr +++ b/tests/ui/closures/issue-90871.stderr @@ -20,6 +20,7 @@ LL | type_ascribe!(2, n([u8; || 1])) | = note: expected type `usize` found closure `{closure@$DIR/issue-90871.rs:4:29: 4:31}` + = note: array length can only be `usize` help: use parentheses to call this closure | LL | type_ascribe!(2, n([u8; (|| 1)()])) diff --git a/tests/ui/issues/issue-17734.rs b/tests/ui/codegen/box-str-drop-glue.rs similarity index 85% rename from tests/ui/issues/issue-17734.rs rename to tests/ui/codegen/box-str-drop-glue.rs index 984adeece6de..6a25db722af7 100644 --- a/tests/ui/issues/issue-17734.rs +++ b/tests/ui/codegen/box-str-drop-glue.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass // Test that generating drop glue for Box doesn't ICE diff --git a/tests/ui/codegen/freeze-on-polymorphic-projection.rs b/tests/ui/codegen/freeze-on-polymorphic-projection.rs index f382a3780fcf..4744fa580b37 100644 --- a/tests/ui/codegen/freeze-on-polymorphic-projection.rs +++ b/tests/ui/codegen/freeze-on-polymorphic-projection.rs @@ -2,7 +2,6 @@ //@ compile-flags: -Copt-level=1 --crate-type=lib #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete pub unsafe trait Storage { type Handle; diff --git a/tests/ui/codegen/freeze-on-polymorphic-projection.stderr b/tests/ui/codegen/freeze-on-polymorphic-projection.stderr deleted file mode 100644 index 903cb2ff6aa9..000000000000 --- a/tests/ui/codegen/freeze-on-polymorphic-projection.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/freeze-on-polymorphic-projection.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/coercion/fudge-inference/input-ty-closure-param-fn-trait-bounds.rs b/tests/ui/coercion/fudge-inference/input-ty-closure-param-fn-trait-bounds.rs new file mode 100644 index 000000000000..91dc8e394563 --- /dev/null +++ b/tests/ui/coercion/fudge-inference/input-ty-closure-param-fn-trait-bounds.rs @@ -0,0 +1,17 @@ +//@ check-pass + +// Regression test for + +struct Inv(*mut (T, U)); + +fn pass_through(_: F) -> Inv { + todo!() +} + +fn map(_: Inv) {} + +fn traverse() { + map(pass_through(|| ())) +} + +fn main() {} diff --git a/tests/ui/coercion/fudge-inference/input-ty-higher-ranked-fn-trait.rs b/tests/ui/coercion/fudge-inference/input-ty-higher-ranked-fn-trait.rs new file mode 100644 index 000000000000..241a177e4c15 --- /dev/null +++ b/tests/ui/coercion/fudge-inference/input-ty-higher-ranked-fn-trait.rs @@ -0,0 +1,21 @@ +//@ check-pass + +// Regression test for + +#[expect(dead_code)] +// Must be invariant +pub struct Server(*mut T); +impl Server { + fn new(_: T) -> Self + where + // Must be higher-ranked + T: Fn(&mut i32), + { + todo!() + } +} + +fn main() { + // Must have a type annotation + let _: Server<_> = Server::new(|_| ()); +} diff --git a/tests/ui/coercion/no-implicit-box-to-ref-coercion.rs b/tests/ui/coercion/no-implicit-box-to-ref-coercion.rs new file mode 100644 index 000000000000..f061117d67ed --- /dev/null +++ b/tests/ui/coercion/no-implicit-box-to-ref-coercion.rs @@ -0,0 +1,11 @@ +// Test that implicitly converting from `Box` to `&T` is +// forbidden when `T` is a trait. + +struct Foo; +trait Trait { fn foo(&self) {} } +impl Trait for Foo {} + +pub fn main() { + let x: Box = Box::new(Foo); + let _y: &dyn Trait = x; //~ ERROR E0308 +} diff --git a/tests/ui/cross/cross-borrow-trait.stderr b/tests/ui/coercion/no-implicit-box-to-ref-coercion.stderr similarity index 88% rename from tests/ui/cross/cross-borrow-trait.stderr rename to tests/ui/coercion/no-implicit-box-to-ref-coercion.stderr index 5fe80b5a3eef..da0b28b0149d 100644 --- a/tests/ui/cross/cross-borrow-trait.stderr +++ b/tests/ui/coercion/no-implicit-box-to-ref-coercion.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/cross-borrow-trait.rs:12:26 + --> $DIR/no-implicit-box-to-ref-coercion.rs:10:26 | LL | let _y: &dyn Trait = x; | ---------- ^ expected `&dyn Trait`, found `Box` diff --git a/tests/ui/coherence/coherence-doesnt-use-infcx-evaluate.rs b/tests/ui/coherence/coherence-doesnt-use-infcx-evaluate.rs index 7e53695f987e..a3dc9b5628fc 100644 --- a/tests/ui/coherence/coherence-doesnt-use-infcx-evaluate.rs +++ b/tests/ui/coherence/coherence-doesnt-use-infcx-evaluate.rs @@ -5,7 +5,6 @@ // since they are using a different infcx which doesn't preserve the intercrate flag. #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait Assoc { type Output; diff --git a/tests/ui/coherence/coherence-doesnt-use-infcx-evaluate.stderr b/tests/ui/coherence/coherence-doesnt-use-infcx-evaluate.stderr deleted file mode 100644 index 56eb21cd20f2..000000000000 --- a/tests/ui/coherence/coherence-doesnt-use-infcx-evaluate.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/coherence-doesnt-use-infcx-evaluate.rs:7:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr index 41164e99e6d0..0558def70cff 100644 --- a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr +++ b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr @@ -6,9 +6,9 @@ LL | impl Trait for for<'r> fn(fn(&'r ())) {} LL | impl<'a> Trait for fn(fn(&'a ())) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/coherence-fn-implied-bounds.stderr b/tests/ui/coherence/coherence-fn-implied-bounds.stderr index ece3288989d7..aaad1acb2235 100644 --- a/tests/ui/coherence/coherence-fn-implied-bounds.stderr +++ b/tests/ui/coherence/coherence-fn-implied-bounds.stderr @@ -7,9 +7,9 @@ LL | LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details note: the lint level is defined here --> $DIR/coherence-fn-implied-bounds.rs:15:9 | diff --git a/tests/ui/coherence/coherence-fn-inputs.stderr b/tests/ui/coherence/coherence-fn-inputs.stderr index 75df33913a97..6a0f2ee2b1c2 100644 --- a/tests/ui/coherence/coherence-fn-inputs.stderr +++ b/tests/ui/coherence/coherence-fn-inputs.stderr @@ -6,9 +6,9 @@ LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {} LL | impl Trait for for<'c> fn(&'c u32, &'c u32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/coherence-free-vs-bound-region.stderr b/tests/ui/coherence/coherence-free-vs-bound-region.stderr index e45cf5ad3a4c..9884e1b041ad 100644 --- a/tests/ui/coherence/coherence-free-vs-bound-region.stderr +++ b/tests/ui/coherence/coherence-free-vs-bound-region.stderr @@ -7,9 +7,9 @@ LL | LL | impl TheTrait for fn(&u8) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details note: the lint level is defined here --> $DIR/coherence-free-vs-bound-region.rs:10:9 | diff --git a/tests/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs b/tests/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs index d74d3a2a5235..7f0e5472c3c2 100644 --- a/tests/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs +++ b/tests/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs @@ -4,7 +4,6 @@ // // No we expect to run into a more user-friendly cycle error instead. #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait Trait { type Assoc; } //~^ ERROR E0391 diff --git a/tests/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr b/tests/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr index 9f813d6d5716..3d4d19197baf 100644 --- a/tests/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr +++ b/tests/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr @@ -1,27 +1,17 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:6:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0391]: cycle detected when building specialization graph of trait `Trait` - --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1 + --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1 | LL | trait Trait { type Assoc; } | ^^^^^^^^^^^^^^ | = note: ...which immediately requires building specialization graph of trait `Trait` again note: cycle used when coherence checking all impls of trait `Trait` - --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1 + --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1 | LL | trait Trait { type Assoc; } | ^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/coherence/coherence-subtyping.stderr b/tests/ui/coherence/coherence-subtyping.stderr index f380ea878291..7817d929da97 100644 --- a/tests/ui/coherence/coherence-subtyping.stderr +++ b/tests/ui/coherence/coherence-subtyping.stderr @@ -7,9 +7,9 @@ LL | LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/coherence-wasm-bindgen.stderr b/tests/ui/coherence/coherence-wasm-bindgen.stderr index 939f1fce9a40..65c64b9beece 100644 --- a/tests/ui/coherence/coherence-wasm-bindgen.stderr +++ b/tests/ui/coherence/coherence-wasm-bindgen.stderr @@ -13,10 +13,10 @@ LL | | A: RefFromWasmAbi, LL | | R: ReturnWasmAbi, | |_____________________^ conflicting implementation for `&dyn Fn(&_) -> _` | - = warning: the behavior may change in a future release - = note: for more information, see issue #56105 = note: downstream crates may implement trait `FromWasmAbi` for type `&_` = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + = warning: the behavior may change in a future release + = note: for more information, see issue #56105 note: the lint level is defined here --> $DIR/coherence-wasm-bindgen.rs:10:9 | diff --git a/tests/ui/coherence/generalize-associated-type-alias.rs b/tests/ui/coherence/generalize-associated-type-alias.rs new file mode 100644 index 000000000000..f333a0d8ae85 --- /dev/null +++ b/tests/ui/coherence/generalize-associated-type-alias.rs @@ -0,0 +1,22 @@ +// Regression test for https://github.com/rust-lang/rust/issues/154189. +#![feature(unboxed_closures)] + +trait ToUnit<'a> { + type Unit; +} + +impl ToUnit<'_> for *const u32 { + type Unit = (); +} + +trait Overlap {} + +type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit; + +impl Overlap for T {} + +impl<'a, T> Overlap<(&'a (), Assoc<'a, T>)> for T {} +//~^ ERROR the trait bound `*const T: ToUnit<'a>` is not satisfied +//~| ERROR the trait bound `T: Overlap<(&'a (), _)>` is not satisfied + +fn main() {} diff --git a/tests/ui/coherence/generalize-associated-type-alias.stderr b/tests/ui/coherence/generalize-associated-type-alias.stderr new file mode 100644 index 000000000000..e65205dbccbd --- /dev/null +++ b/tests/ui/coherence/generalize-associated-type-alias.stderr @@ -0,0 +1,28 @@ +error[E0277]: the trait bound `*const T: ToUnit<'a>` is not satisfied + --> $DIR/generalize-associated-type-alias.rs:18:13 + | +LL | impl<'a, T> Overlap<(&'a (), Assoc<'a, T>)> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToUnit<'a>` is not implemented for `*const T` + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | impl<'a, T> Overlap<(&'a (), Assoc<'a, T>)> for T where *const T: ToUnit<'a> {} + | ++++++++++++++++++++++++++ + +error[E0277]: the trait bound `T: Overlap<(&'a (), _)>` is not satisfied + --> $DIR/generalize-associated-type-alias.rs:18:49 + | +LL | impl<'a, T> Overlap<(&'a (), Assoc<'a, T>)> for T {} + | ^ the trait `Overlap<(&'a (), _)>` is not implemented for `T` + | +help: the trait `Overlap<(&'a (), _)>` is not implemented for `T` + but trait `Overlap<(&(), ())>` is implemented for `u32` + --> $DIR/generalize-associated-type-alias.rs:18:1 + | +LL | impl<'a, T> Overlap<(&'a (), Assoc<'a, T>)> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: for that trait implementation, expected `u32`, found `T` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr index 8d59cbc3466b..697a1bc81dbf 100644 --- a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr +++ b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr @@ -6,10 +6,10 @@ LL | impl FnMarker for fn(T) {} LL | impl FnMarker for fn(&T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&_)` | - = warning: the behavior may change in a future release - = note: for more information, see issue #56105 = note: downstream crates may implement trait `Marker` for type `&_` = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + = warning: the behavior may change in a future release + = note: for more information, see issue #56105 note: the lint level is defined here --> $DIR/negative-coherence-placeholder-region-constraints-on-unification.rs:4:11 | diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs index f0424e724344..ff3999f83f6d 100644 --- a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(adt_const_params, unsized_const_params)] -//~^ WARN the feature `unsized_const_params` is incomplete #![feature(with_negative_coherence, negative_impls)] pub trait A {} diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr deleted file mode 100644 index 720449152945..000000000000 --- a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/regions-in-canonical.rs:3:30 - | -LL | #![feature(adt_const_params, unsized_const_params)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 52794b19945b..381f5c60f983 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:32:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index 9fa443eefb3d..40811a67dd18 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:32:1 | diff --git a/tests/ui/version/version-info-flags.rs b/tests/ui/compile-flags/version-info-flags.rs similarity index 100% rename from tests/ui/version/version-info-flags.rs rename to tests/ui/compile-flags/version-info-flags.rs diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs index e90426ec0c76..8825d5384ab9 100644 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs +++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs @@ -1,6 +1,5 @@ //@ check-pass #![feature(adt_const_params, lazy_type_alias)] -//~^ WARN: the feature `lazy_type_alias` is incomplete pub type Matrix = [usize; 1]; const EMPTY_MATRIX: Matrix = [0; 1]; diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr deleted file mode 100644 index 4f5133474c60..000000000000 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/alias_const_param_ty-1.rs:2:30 - | -LL | #![feature(adt_const_params, lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs index d49fb49d253c..5d6e34804c5c 100644 --- a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs @@ -9,6 +9,7 @@ //~^ ERROR rustc_dump_predicates //~| NOTE Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } //~| NOTE Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } +//~| NOTE expected because of the type of the const parameter where ConstBytes: Sized; diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr index 1273a74102a2..34c65af7cd97 100644 --- a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr @@ -1,11 +1,16 @@ error[E0308]: mismatched types - --> $DIR/byte-string-u8-validation.rs:14:16 + --> $DIR/byte-string-u8-validation.rs:15:16 | LL | ConstBytes: Sized; | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` | = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` +note: expected because of the type of the const parameter + --> $DIR/byte-string-u8-validation.rs:8:19 + | +LL | struct ConstBytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: rustc_dump_predicates --> $DIR/byte-string-u8-validation.rs:8:1 diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs index 2008a96310a8..a7c051cd4c39 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params, unsized_const_params)] +#![feature(adt_const_params, const_param_ty_trait)] #[derive(PartialEq, Eq)] struct NotParam; diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs index 2fcf872c99aa..535447cf2b94 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs @@ -1,4 +1,4 @@ -#![feature(adt_const_params, unsized_const_params)] +#![feature(adt_const_params, const_param_ty_trait)] #![allow(incomplete_features)] use std::marker::ConstParamTy_; diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs index a86d74275de8..0d67854ecfc8 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params, unsized_const_params)] +#![feature(adt_const_params, const_param_ty_trait)] #[derive(PartialEq, Eq)] struct NotParam; diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs index 1900931b3f35..dd425a28e972 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params, unsized_const_params)] +#![feature(adt_const_params, const_param_ty_trait)] #[derive(PartialEq, Eq)] struct NotParam; diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs index a8f190609c04..7f4dee418fe9 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params, unsized_const_params)] +#![feature(adt_const_params, const_param_ty_trait)] #[derive(PartialEq, Eq)] struct ImplementsConstParamTy; diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs index 0c9b12805f75..a7e0fa2ef212 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params, unsized_const_params)] +#![feature(adt_const_params, const_param_ty_trait)] union Union { a: u8, diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_trait_gate.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_trait_gate.rs new file mode 100644 index 000000000000..591e550d7b99 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_trait_gate.rs @@ -0,0 +1,8 @@ +//@check-pass +#![feature(const_param_ty_trait)] + +use std::marker::ConstParamTy_; + +fn meow() {} + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_trait_implied.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_trait_implied.rs new file mode 100644 index 000000000000..9b66daaf9aea --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_trait_implied.rs @@ -0,0 +1,9 @@ +//@check-pass +#![feature(unsized_const_params, adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy_; + +fn miow() {} + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_trait_no_gate.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_trait_no_gate.rs new file mode 100644 index 000000000000..85283a0cbac4 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_trait_no_gate.rs @@ -0,0 +1,7 @@ +use std::marker::ConstParamTy_; + //~^ ERROR use of unstable library feature `const_param_ty_trait` [E0658] + +fn miaw() {} + //~^ ERROR use of unstable library feature `const_param_ty_trait` [E0658] + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_trait_no_gate.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_trait_no_gate.stderr new file mode 100644 index 000000000000..87dedcdab908 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_trait_no_gate.stderr @@ -0,0 +1,23 @@ +error[E0658]: use of unstable library feature `const_param_ty_trait` + --> $DIR/const_param_ty_trait_no_gate.rs:1:5 + | +LL | use std::marker::ConstParamTy_; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #95174 for more information + = help: add `#![feature(const_param_ty_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `const_param_ty_trait` + --> $DIR/const_param_ty_trait_no_gate.rs:4:12 + | +LL | fn miaw() {} + | ^^^^^^^^^^^^^ + | + = note: see issue #95174 for more information + = help: add `#![feature(const_param_ty_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr index d7eec45bae0f..14afd18f82a7 100644 --- a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr @@ -15,6 +15,11 @@ LL | let _: ConstBytes = ConstBytes::; | = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` +note: expected because of the type of the const parameter + --> $DIR/mismatch-raw-ptr-in-adt.rs:5:19 + | +LL | struct ConstBytes; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/mismatch-raw-ptr-in-adt.rs:9:46 @@ -24,6 +29,11 @@ LL | let _: ConstBytes = ConstBytes::; | = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` +note: expected because of the type of the const parameter + --> $DIR/mismatch-raw-ptr-in-adt.rs:5:19 + | +LL | struct ConstBytes; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs index e364368b8a4c..3f092d08274c 100644 --- a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.rs @@ -15,5 +15,5 @@ fn call() {} fn main() { Wrapper::::call; - //~^ ERROR: the function or associated item `call` exists for struct `Wrapper`, + //~^ ERROR: the associated function or constant `call` exists for struct `Wrapper`, } diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr index b13f76eabadb..4d469deb00c0 100644 --- a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr @@ -15,14 +15,14 @@ error[E0741]: using function pointers as const generic parameters is forbidden LL | struct Wrapper; | ^^^^ -error[E0599]: the function or associated item `call` exists for struct `Wrapper`, but its trait bounds were not satisfied +error[E0599]: the associated function or constant `call` exists for struct `Wrapper`, but its trait bounds were not satisfied --> $DIR/non_valtreeable_const_arg-2.rs:17:26 | LL | struct Wrapper; - | ----------------------------- function or associated item `call` not found for this struct because it doesn't satisfy `Wrapper: Fn<_>` + | ----------------------------- associated function or constant `call` not found for this struct because it doesn't satisfy `Wrapper: Fn<_>` ... LL | Wrapper::::call; - | ^^^^ function or associated item cannot be called on `Wrapper` due to unsatisfied trait bounds + | ^^^^ associated function or constant cannot be called on `Wrapper` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `Wrapper: Fn<_>` diff --git a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr index 967166856147..bc8feaf5214a 100644 --- a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr +++ b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr @@ -16,7 +16,9 @@ error[E0308]: mismatched types --> $DIR/transmutable-ice-110969.rs:25:29 | LL | const FALSE: bool = assert::is_transmutable::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | | + | expected because of the type of the associated constant error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-1.stderr b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-1.stderr index daea55efbbc7..4125461f92b2 100644 --- a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-1.stderr +++ b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-1.stderr @@ -36,7 +36,9 @@ error[E0308]: mismatched types --> $DIR/unsized-anon-const-err-1.rs:8:34 | LL | const EMPTY_MATRIX: Matrix = [[0; 4]; 4]; - | ^^^^^^^^^^^ expected `[&u32]`, found `[&u32; 4]` + | ------ ^^^^^^^^^^^ expected `[&u32]`, found `[&u32; 4]` + | | + | expected because of the type of the constant error: aborting due to 5 previous errors diff --git a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.rs b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.rs index 81b1ec6a7719..9e2212bc8097 100644 --- a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.rs +++ b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.rs @@ -2,7 +2,6 @@ #![feature(adt_const_params)] #![feature(unsized_const_params)] -//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes #[derive(Clone)] struct S; diff --git a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr index d538bb0af09a..8112613f3bf8 100644 --- a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr +++ b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr @@ -1,22 +1,13 @@ error: free constant item without body - --> $DIR/unsized-anon-const-err-2.rs:10:1 + --> $DIR/unsized-anon-const-err-2.rs:9:1 | LL | const A: [u8]; | ^^^^^^^^^^^^^- | | | help: provide a definition for the constant: `= ;` -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unsized-anon-const-err-2.rs:4:12 - | -LL | #![feature(unsized_const_params)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-anon-const-err-2.rs:10:10 + --> $DIR/unsized-anon-const-err-2.rs:9:10 | LL | const A: [u8]; | ^^^^ doesn't have a size known at compile-time @@ -25,7 +16,7 @@ LL | const A: [u8]; = note: statics and constants must have a statically known size error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-anon-const-err-2.rs:14:31 + --> $DIR/unsized-anon-const-err-2.rs:13:31 | LL | impl Copy for S {} | ^ doesn't have a size known at compile-time @@ -34,7 +25,7 @@ LL | impl Copy for S {} = note: statics and constants must have a statically known size error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-anon-const-err-2.rs:17:33 + --> $DIR/unsized-anon-const-err-2.rs:16:33 | LL | impl Copy for S {} | ^ doesn't have a size known at compile-time @@ -43,7 +34,7 @@ LL | impl Copy for S {} = note: statics and constants must have a statically known size error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates - --> $DIR/unsized-anon-const-err-2.rs:14:6 + --> $DIR/unsized-anon-const-err-2.rs:13:6 | LL | impl Copy for S {} | ^^^^^^^^^^^^ unconstrained const parameter @@ -52,7 +43,7 @@ LL | impl Copy for S {} = note: proving the result of expressions other than the parameter are unique is not supported error[E0207]: the const parameter `M` is not constrained by the impl trait, self type, or predicates - --> $DIR/unsized-anon-const-err-2.rs:17:6 + --> $DIR/unsized-anon-const-err-2.rs:16:6 | LL | impl Copy for S {} | ^^^^^^^^^^^^^^ unconstrained const parameter @@ -60,7 +51,7 @@ LL | impl Copy for S {} = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors Some errors have detailed explanations: E0207, E0277. For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/const-generics/adt_const_params/unsized-anon-const-func-err.stderr b/tests/ui/const-generics/adt_const_params/unsized-anon-const-func-err.stderr index 14a41e87e4aa..9e22119cf87f 100644 --- a/tests/ui/const-generics/adt_const_params/unsized-anon-const-func-err.stderr +++ b/tests/ui/const-generics/adt_const_params/unsized-anon-const-func-err.stderr @@ -21,7 +21,9 @@ error[E0308]: mismatched types --> $DIR/unsized-anon-const-func-err.rs:9:22 | LL | const VALUE: [u32] = [0; 4]; - | ^^^^^^ expected `[u32]`, found `[u32; 4]` + | ----- ^^^^^^ expected `[u32]`, found `[u32; 4]` + | | + | expected because of the type of the constant error[E0277]: the size for values of type `[u32]` cannot be known at compilation time --> $DIR/unsized-anon-const-func-err.rs:14:12 diff --git a/tests/ui/const-generics/adt_const_params/unsized-anon-const-struct-err.stderr b/tests/ui/const-generics/adt_const_params/unsized-anon-const-struct-err.stderr index d9a13976d68a..d81eeb465d6f 100644 --- a/tests/ui/const-generics/adt_const_params/unsized-anon-const-struct-err.stderr +++ b/tests/ui/const-generics/adt_const_params/unsized-anon-const-struct-err.stderr @@ -30,7 +30,9 @@ error[E0308]: mismatched types --> $DIR/unsized-anon-const-struct-err.rs:6:22 | LL | const VALUE: [u32] = [0; 4]; - | ^^^^^^ expected `[u32]`, found `[u32; 4]` + | ----- ^^^^^^ expected `[u32]`, found `[u32; 4]` + | | + | expected because of the type of the constant error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.rs b/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.rs index 53f65319db9d..b66dff43a3d1 100644 --- a/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.rs +++ b/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.rs @@ -3,7 +3,7 @@ #![feature( min_generic_const_args, adt_const_params, - unsized_const_params, + const_param_ty_trait, generic_const_parameter_types, )] #![allow(incomplete_features)] diff --git a/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty.rs b/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty.rs index a509fe0d52e3..e5757c8ef447 100644 --- a/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty.rs +++ b/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty.rs @@ -6,7 +6,7 @@ #![feature( min_generic_const_args, adt_const_params, - unsized_const_params, + const_param_ty_trait, generic_const_parameter_types, )] #![allow(incomplete_features)] diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs index 771f48cba068..454ce7b3875f 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs @@ -7,7 +7,7 @@ #![feature(generic_const_items)] #![feature(generic_const_parameter_types)] #![feature(min_generic_const_args)] -#![feature(unsized_const_params)] +#![feature(const_param_ty_trait)] #![expect(incomplete_features)] trait Trait { diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs index 623769f5d12f..fb2bc308ae18 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs @@ -7,7 +7,7 @@ #![feature( adt_const_params, min_generic_const_args, - unsized_const_params, + const_param_ty_trait, generic_const_parameter_types )] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/associated-const-bindings/supertraits.rs b/tests/ui/const-generics/associated-const-bindings/supertraits.rs index cdceb682a854..6c8ae165a50d 100644 --- a/tests/ui/const-generics/associated-const-bindings/supertraits.rs +++ b/tests/ui/const-generics/associated-const-bindings/supertraits.rs @@ -6,7 +6,7 @@ #![feature( min_generic_const_args, adt_const_params, - unsized_const_params, + const_param_ty_trait, generic_const_parameter_types, )] #![allow(incomplete_features)] diff --git a/tests/ui/const-generics/bad-generic-in-copy-impl.stderr b/tests/ui/const-generics/bad-generic-in-copy-impl.stderr index fbd546d42fb5..c2cf80f38eca 100644 --- a/tests/ui/const-generics/bad-generic-in-copy-impl.stderr +++ b/tests/ui/const-generics/bad-generic-in-copy-impl.stderr @@ -3,6 +3,8 @@ error[E0308]: mismatched types | LL | x: [u8; SIZE], | ^^^^ expected `usize`, found `u32` + | + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/bad-generic-in-copy-impl.rs:3:13 @@ -10,6 +12,7 @@ error[E0308]: mismatched types LL | x: [u8; SIZE], | ^^^^ expected `usize`, found `u32` | + = note: array length can only be `usize` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/check_const_arg_type_in_free_alias.eager.stderr b/tests/ui/const-generics/check_const_arg_type_in_free_alias.eager.stderr new file mode 100644 index 000000000000..f62023bd146b --- /dev/null +++ b/tests/ui/const-generics/check_const_arg_type_in_free_alias.eager.stderr @@ -0,0 +1,133 @@ +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:15:1 + | +LL | type ArrLen = [(); B]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | + = note: the length of array `[(); B]` must be type `usize` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:19:1 + | +LL | type ConstArg = Foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required by a const generic parameter in `Foo` + --> $DIR/check_const_arg_type_in_free_alias.rs:13:12 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:32:1 + | +LL | type Alias = <() as IdentityWithUnused>::This; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required by a const generic parameter in `IdentityWithUnused` + --> $DIR/check_const_arg_type_in_free_alias.rs:24:26 + | +LL | trait IdentityWithUnused { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `IdentityWithUnused` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:38:1 + | +LL | type UseFree = Free; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | + = note: the length of array `[(); B]` must be type `usize` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:58:1 + | +LL | type IndirectArr = Wrap>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | + = note: the length of array `[(); B]` must be type `usize` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:62:1 + | +LL | type IndirectConstArg = Wrap>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required by a const generic parameter in `Foo` + --> $DIR/check_const_arg_type_in_free_alias.rs:13:12 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:17:24 + | +LL | type AnonArrLen = [(); true]; + | ^^^^ expected `usize`, found `bool` + | + = note: array length can only be `usize` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:21:25 + | +LL | type AnonConstArg = Foo; + | ^^^^ expected `usize`, found `bool` + | +note: expected because of the type of the const parameter + --> $DIR/check_const_arg_type_in_free_alias.rs:13:12 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:34:44 + | +LL | type AnonAlias = <() as IdentityWithUnused>::This; + | ^^^^ expected `usize`, found `bool` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:40:25 + | +LL | type AnonUseFree = Free; + | ^^^^ expected `usize`, found `bool` + | +note: expected because of the type of the const parameter + --> $DIR/check_const_arg_type_in_free_alias.rs:37:11 + | +LL | type Free = [(); N]; + | ^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:53:45 + | +LL | type AnonUseFreeIndirectlyCorrect = UseFree<1_usize>; + | ^^^^^^^ expected `bool`, found `usize` + | +note: expected because of the type of the const parameter + --> $DIR/check_const_arg_type_in_free_alias.rs:38:14 + | +LL | type UseFree = Free; + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:60:39 + | +LL | type AnonIndirectArr = Wrap>; + | ^^^^ expected `usize`, found `bool` + | + = note: array length can only be `usize` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:64:43 + | +LL | type AnonIndirectConstArg = Wrap>>; + | ^^^^ expected `usize`, found `bool` + | +note: expected because of the type of the const parameter + --> $DIR/check_const_arg_type_in_free_alias.rs:13:12 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/check_const_arg_type_in_free_alias.lazy.stderr b/tests/ui/const-generics/check_const_arg_type_in_free_alias.lazy.stderr new file mode 100644 index 000000000000..b9adb4e51e1a --- /dev/null +++ b/tests/ui/const-generics/check_const_arg_type_in_free_alias.lazy.stderr @@ -0,0 +1,151 @@ +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:15:1 + | +LL | type ArrLen = [(); B]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | + = note: the length of array `[(); B]` must be type `usize` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:17:24 + | +LL | type AnonArrLen = [(); true]; + | ^^^^ expected `usize`, found `bool` + | + = note: array length can only be `usize` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:19:1 + | +LL | type ConstArg = Foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required by a const generic parameter in `Foo` + --> $DIR/check_const_arg_type_in_free_alias.rs:13:12 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:21:25 + | +LL | type AnonConstArg = Foo; + | ^^^^ expected `usize`, found `bool` + | +note: expected because of the type of the const parameter + --> $DIR/check_const_arg_type_in_free_alias.rs:13:12 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^ + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:32:1 + | +LL | type Alias = <() as IdentityWithUnused>::This; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required for `()` to implement `IdentityWithUnused` + --> $DIR/check_const_arg_type_in_free_alias.rs:28:25 + | +LL | impl IdentityWithUnused for T { + | -------------- ^^^^^^^^^^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:34:44 + | +LL | type AnonAlias = <() as IdentityWithUnused>::This; + | ^^^^ expected `usize`, found `bool` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:38:1 + | +LL | type UseFree = Free; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required by a bound on the type alias `Free` + --> $DIR/check_const_arg_type_in_free_alias.rs:37:11 + | +LL | type Free = [(); N]; + | ^^^^^^^^^^^^^^ required by this bound + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:40:25 + | +LL | type AnonUseFree = Free; + | ^^^^ expected `usize`, found `bool` + | +note: expected because of the type of the const parameter + --> $DIR/check_const_arg_type_in_free_alias.rs:37:11 + | +LL | type Free = [(); N]; + | ^^^^^^^^^^^^^^ + +error: the constant `N` is not of type `bool` + --> $DIR/check_const_arg_type_in_free_alias.rs:51:1 + | +LL | type UseFreeIndirectlyCorrect = UseFree; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `usize` + | +note: required by a bound on the type alias `UseFree` + --> $DIR/check_const_arg_type_in_free_alias.rs:38:14 + | +LL | type UseFree = Free; + | ^^^^^^^^^^^^^ required by this bound + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:53:45 + | +LL | type AnonUseFreeIndirectlyCorrect = UseFree<1_usize>; + | ^^^^^^^ expected `bool`, found `usize` + | +note: expected because of the type of the const parameter + --> $DIR/check_const_arg_type_in_free_alias.rs:38:14 + | +LL | type UseFree = Free; + | ^^^^^^^^^^^^^ + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:58:1 + | +LL | type IndirectArr = Wrap>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | + = note: the length of array `[(); B]` must be type `usize` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:60:39 + | +LL | type AnonIndirectArr = Wrap>; + | ^^^^ expected `usize`, found `bool` + | + = note: array length can only be `usize` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_free_alias.rs:62:1 + | +LL | type IndirectConstArg = Wrap>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required by a const generic parameter in `Foo` + --> $DIR/check_const_arg_type_in_free_alias.rs:13:12 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_free_alias.rs:64:43 + | +LL | type AnonIndirectConstArg = Wrap>>; + | ^^^^ expected `usize`, found `bool` + | +note: expected because of the type of the const parameter + --> $DIR/check_const_arg_type_in_free_alias.rs:13:12 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^ + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/check_const_arg_type_in_free_alias.rs b/tests/ui/const-generics/check_const_arg_type_in_free_alias.rs new file mode 100644 index 000000000000..12e277f0c545 --- /dev/null +++ b/tests/ui/const-generics/check_const_arg_type_in_free_alias.rs @@ -0,0 +1,67 @@ +//@ revisions: eager lazy +#![cfg_attr(lazy, feature(lazy_type_alias))] +#![cfg_attr(lazy, expect(incomplete_features))] + +// We currently do not check free type aliases for well formedness. +// However, previously we desugared all const arguments to anon +// consts which resulted in us happening to check that they were +// of the correct type. Nowadays we don't necessarily lower to a +// const argument, but to continue erroring on such code we special +// case `ConstArgHasType` clauses to be checked for free type aliases +// even though we ignore the rest of the wf requirements. + +struct Foo; + +type ArrLen = [(); B]; +//~^ ERROR: the constant `B` is not of type +type AnonArrLen = [(); true]; +//~^ ERROR: mismatched types +type ConstArg = Foo; +//~^ ERROR: the constant `B` is not of type +type AnonConstArg = Foo; +//~^ ERROR: mismatched types + +trait IdentityWithUnused { + type This; +} + +impl IdentityWithUnused for T { + type This = T; +} + +type Alias = <() as IdentityWithUnused>::This; +//~^ ERROR: the constant `B` is not of type +type AnonAlias = <() as IdentityWithUnused>::This; +//~^ ERROR: mismatched types + +type Free = [(); N]; +type UseFree = Free; +//~^ ERROR: the constant `B` is not of type +type AnonUseFree = Free; +//~^ ERROR: mismatched types + +// This previously emitted an error before we stopped using +// anon consts. Now, as free aliases don't exist after ty +// lowering, we don't emit an error because we only see `N` +// being used as an argument to an array length. +// +// Free type aliases are not allowed to have unused generic +// parameters so this shouldn't be able to cause code to +// pass that should error. +type UseFreeIndirectlyCorrect = UseFree; +//[lazy]~^ ERROR: the constant `N` is not of type +type AnonUseFreeIndirectlyCorrect = UseFree<1_usize>; +//~^ ERROR: mismatched types + +struct Wrap(T); + +type IndirectArr = Wrap>; +//~^ ERROR: the constant `B` is not of type +type AnonIndirectArr = Wrap>; +//~^ ERROR: mismatched types +type IndirectConstArg = Wrap>>; +//~^ ERROR: the constant `B` is not of type +type AnonIndirectConstArg = Wrap>>; +//~^ ERROR: mismatched types + +fn main() {} diff --git a/tests/ui/const-generics/check_const_arg_type_in_trait_object.rs b/tests/ui/const-generics/check_const_arg_type_in_trait_object.rs new file mode 100644 index 000000000000..f5c5350194b7 --- /dev/null +++ b/tests/ui/const-generics/check_const_arg_type_in_trait_object.rs @@ -0,0 +1,36 @@ +// We currently do not check trait objects for well formedness. +// However, previously we desugared all const arguments to anon +// consts which resulted in us happening to check that they were +// of the correct type. Nowadays we don't necessarily lower to a +// const argument, but to continue erroring on such code we special +// case `ConstArgHasType` clauses to be checked for trait objects +// even though we ignore the rest of the wf requirements. + +trait Object {} +trait Object2 {} +trait Object3<'a: 'static, const N: usize> {} + +struct Wrap(T); + +fn arg( + param: &dyn Object, + //~^ ERROR: the constant `B` is not of type + anon: &dyn Object, + //~^ ERROR: mismatched types +) { +} + +fn indirect( + param: &dyn Object2>, + //~^ ERROR: the constant `B` is not of type + anon: &dyn Object2>, + //~^ ERROR: mismatched types +) { +} + +// the 'a: 'static bound should *not* have its error reported (at least, until we implement checking +// all wf things for dyn objects) +fn binder(param: &dyn for<'a> Object3<'a, B>) {} +//~^ ERROR: the constant `B` is not of type + +fn main() {} diff --git a/tests/ui/const-generics/check_const_arg_type_in_trait_object.stderr b/tests/ui/const-generics/check_const_arg_type_in_trait_object.stderr new file mode 100644 index 000000000000..4e228f65ab6d --- /dev/null +++ b/tests/ui/const-generics/check_const_arg_type_in_trait_object.stderr @@ -0,0 +1,49 @@ +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_trait_object.rs:18:23 + | +LL | anon: &dyn Object, + | ^^^^ expected `usize`, found `bool` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_trait_object.rs:16:12 + | +LL | param: &dyn Object, + | ^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required by a const generic parameter in `Object` + --> $DIR/check_const_arg_type_in_trait_object.rs:9:14 + | +LL | trait Object {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Object` + +error[E0308]: mismatched types + --> $DIR/check_const_arg_type_in_trait_object.rs:26:34 + | +LL | anon: &dyn Object2>, + | ^^^^ expected `usize`, found `bool` + | + = note: array length can only be `usize` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_trait_object.rs:24:12 + | +LL | param: &dyn Object2>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | + = note: the length of array `[(); B]` must be type `usize` + +error: the constant `B` is not of type `usize` + --> $DIR/check_const_arg_type_in_trait_object.rs:33:33 + | +LL | fn binder(param: &dyn for<'a> Object3<'a, B>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | +note: required by a const generic parameter in `Object3` + --> $DIR/check_const_arg_type_in_trait_object.rs:11:28 + | +LL | trait Object3<'a: 'static, const N: usize> {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Object3` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/const-generic-function.rs b/tests/ui/const-generics/const-generic-function.rs index c8d2683e53f4..03c94d90d105 100644 --- a/tests/ui/const-generics/const-generic-function.rs +++ b/tests/ui/const-generics/const-generic-function.rs @@ -14,7 +14,7 @@ const fn baz() -> i32 { fn main() { foo::(); //~ ERROR expected type, found function `baz` - //~| ERROR unresolved item provided when a constant was expected + //~^ ERROR unresolved item provided when a constant was expected foo::(); //~ ERROR expected type, found `1` foo::(); //~ ERROR expected type, found `1` foo::(); //~ ERROR expected type, found `2` diff --git a/tests/ui/const-generics/const-param-with-additional-obligations.rs b/tests/ui/const-generics/const-param-with-additional-obligations.rs index 5110f95d5bf9..8c03cf0a6d37 100644 --- a/tests/ui/const-generics/const-param-with-additional-obligations.rs +++ b/tests/ui/const-generics/const-param-with-additional-obligations.rs @@ -1,4 +1,4 @@ -#![feature(adt_const_params, unsized_const_params)] +#![feature(adt_const_params, const_param_ty_trait)] #![allow(incomplete_features)] use std::marker::ConstParamTy_; diff --git a/tests/ui/const-generics/defaults/concrete-const-param-type.rs b/tests/ui/const-generics/defaults/concrete-const-param-type.rs index c411f81192bd..a2eb37b535eb 100644 --- a/tests/ui/const-generics/defaults/concrete-const-param-type.rs +++ b/tests/ui/const-generics/defaults/concrete-const-param-type.rs @@ -1,6 +1,4 @@ #![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)] -//~^ WARN the feature `generic_const_parameter_types` is incomplete -//~| WARN the feature `unsized_const_params` is incomplete // Make sure that we test the const param type of default const parameters // if both the type of the default and the type of the parameter are concrete. diff --git a/tests/ui/const-generics/defaults/concrete-const-param-type.stderr b/tests/ui/const-generics/defaults/concrete-const-param-type.stderr index ad077f87e5df..805d5a1e91fb 100644 --- a/tests/ui/const-generics/defaults/concrete-const-param-type.stderr +++ b/tests/ui/const-generics/defaults/concrete-const-param-type.stderr @@ -1,25 +1,8 @@ -warning: the feature `generic_const_parameter_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/concrete-const-param-type.rs:1:12 - | -LL | #![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #137626 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/concrete-const-param-type.rs:1:43 - | -LL | #![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - error: the constant `N` is not of type `u64` - --> $DIR/concrete-const-param-type.rs:9:26 + --> $DIR/concrete-const-param-type.rs:7:26 | LL | struct Foo; | ^^^^^^^^^^^^^^^^ expected `u64`, found `u32` -error: aborting due to 1 previous error; 2 warnings emitted +error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/early/invalid-const-arguments.rs b/tests/ui/const-generics/early/invalid-const-arguments.rs index 68e6b2ac458e..82cc948129a6 100644 --- a/tests/ui/const-generics/early/invalid-const-arguments.rs +++ b/tests/ui/const-generics/early/invalid-const-arguments.rs @@ -1,10 +1,10 @@ -#![crate_type="lib"] +#![crate_type = "lib"] struct A; trait Foo {} impl Foo for A {} -//~^ ERROR cannot find type -//~| ERROR unresolved item provided when a constant +//~^ ERROR cannot find const `N` in this scope +//~| ERROR unresolved item provided when a constant was expected struct B; impl Foo for B {} @@ -12,5 +12,16 @@ impl Foo for B {} struct C; impl Foo for C {} -//~^ ERROR cannot find type -//~| ERROR unresolved item provided when a constant +//~^ ERROR cannot find const `T` in this scope +//~| ERROR unresolved item provided when a constant was expected + +struct D; +impl Foo for D {} +//~^ ERROR cannot find const `E` in this scope +//~| ERROR unresolved item provided when a constant was expected +//~| ERROR cannot find const `X` in this scope +//~| ERROR cannot find const `P` in this scope +struct R; +impl Foo for D {} +//~^ ERROR cannot find const `Q` in this scope +//~| ERROR unresolved item provided when a constant was expected diff --git a/tests/ui/const-generics/early/invalid-const-arguments.stderr b/tests/ui/const-generics/early/invalid-const-arguments.stderr index a0a6d8cc8679..4d8ab68fd71d 100644 --- a/tests/ui/const-generics/early/invalid-const-arguments.stderr +++ b/tests/ui/const-generics/early/invalid-const-arguments.stderr @@ -1,40 +1,82 @@ -error[E0425]: cannot find type `N` in this scope +error[E0425]: cannot find const `N` in this scope --> $DIR/invalid-const-arguments.rs:5:16 | LL | struct A; - | ---------------------- similarly named struct `A` defined here + | ----------- corresponding const parameter on the type defined here LL | trait Foo {} LL | impl Foo for A {} - | ^ + | ^ not found in this scope | -help: a struct with a similar name exists +help: you might have meant to introduce a const parameter `N` on the impl | -LL - impl Foo for A {} -LL + impl Foo for A {} - | -help: you might be missing a type parameter - | -LL | impl Foo for A {} - | +++ +LL | impl Foo for A {} + | +++++++++++++ -error[E0425]: cannot find type `T` in this scope +error[E0425]: cannot find const `T` in this scope --> $DIR/invalid-const-arguments.rs:14:32 | -LL | struct A; - | ---------------------- similarly named struct `A` defined here -... +LL | struct C; + | ----------- corresponding const parameter on the type defined here LL | impl Foo for C {} - | ^ + | ^ not found in this scope | -help: a struct with a similar name exists +help: you might have meant to introduce a const parameter `T` on the impl | -LL - impl Foo for C {} -LL + impl Foo for C {} +LL | impl Foo for C {} + | +++++++++++++ + +error[E0425]: cannot find const `E` in this scope + --> $DIR/invalid-const-arguments.rs:19:16 | -help: you might be missing a type parameter +LL | struct D; + | ----------- corresponding const parameter on the type defined here +LL | impl Foo for D {} + | ^ not found in this scope | -LL | impl Foo for C {} - | +++ +help: you might have meant to introduce a const parameter `E` on the impl + | +LL | impl Foo for D {} + | +++++++++++++ + +error[E0425]: cannot find const `X` in this scope + --> $DIR/invalid-const-arguments.rs:19:19 + | +LL | struct D; + | ----------- corresponding const parameter on the type defined here +LL | impl Foo for D {} + | ^ not found in this scope + | +help: you might have meant to introduce a const parameter `X` on the impl + | +LL | impl Foo for D {} + | +++++++++++++ + +error[E0425]: cannot find const `P` in this scope + --> $DIR/invalid-const-arguments.rs:19:22 + | +LL | struct D; + | ------------ corresponding const parameter on the type defined here +LL | impl Foo for D {} + | ^ not found in this scope + | +help: you might have meant to introduce a const parameter `P` on the impl + | +LL | impl Foo for D {} + | ++++++++++++++ + +error[E0425]: cannot find const `Q` in this scope + --> $DIR/invalid-const-arguments.rs:25:46 + | +LL | struct D; + | ----------- corresponding const parameter on the type defined here +... +LL | impl Foo for D {} + | ^ not found in this scope + | +help: you might have meant to introduce a const parameter `Q` on the impl + | +LL | impl Foo for D {} + | +++++++++++++ error[E0747]: unresolved item provided when a constant was expected --> $DIR/invalid-const-arguments.rs:5:16 @@ -70,7 +112,29 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | impl Foo for C {} | + + -error: aborting due to 5 previous errors +error[E0747]: unresolved item provided when a constant was expected + --> $DIR/invalid-const-arguments.rs:19:16 + | +LL | impl Foo for D {} + | ^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | impl Foo for D<{ E }, X, P> {} + | + + + +error[E0747]: unresolved item provided when a constant was expected + --> $DIR/invalid-const-arguments.rs:25:46 + | +LL | impl Foo for D {} + | ^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | impl Foo for D {} + | + + + +error: aborting due to 11 previous errors Some errors have detailed explanations: E0425, E0747. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/exhaustive-value.stderr b/tests/ui/const-generics/exhaustive-value.stderr index 791bb19ffe86..3377f4cc4e11 100644 --- a/tests/ui/const-generics/exhaustive-value.stderr +++ b/tests/ui/const-generics/exhaustive-value.stderr @@ -4,15 +4,15 @@ error[E0277]: the trait bound `(): Foo` is not satisfied LL | <() as Foo>::test() | ^^ the trait `Foo` is not implemented for `()` | - = help: the following other types implement trait `Foo`: - `()` implements `Foo<0>` - `()` implements `Foo<100>` - `()` implements `Foo<101>` - `()` implements `Foo<102>` - `()` implements `Foo<103>` - `()` implements `Foo<104>` - `()` implements `Foo<105>` - `()` implements `Foo<106>` + = help: `()` implements trait `Foo`: + Foo<0> + Foo<100> + Foo<101> + Foo<102> + Foo<103> + Foo<104> + Foo<105> + Foo<106> and 248 others error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs index 5d538d2679dd..1516b0571490 100644 --- a/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs +++ b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs @@ -9,6 +9,6 @@ struct S() where S<{ U }>:; -//~^ ERROR: overflow evaluating the requirement `S<{ U }> well-formed` +//~^ ERROR: overflow evaluating whether `S<{ U }>` is well-formed fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr index b244acb37dde..1eb2890d4cbc 100644 --- a/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr +++ b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `S<{ U }> well-formed` +error[E0275]: overflow evaluating whether `S<{ U }>` is well-formed --> $DIR/adt_wf_hang.rs:11:5 | LL | S<{ U }>:; diff --git a/tests/ui/const-generics/generic_const_exprs/cannot-convert-refree-ice-114463.rs b/tests/ui/const-generics/generic_const_exprs/cannot-convert-refree-ice-114463.rs index 2ce998e9fd9c..500817996978 100644 --- a/tests/ui/const-generics/generic_const_exprs/cannot-convert-refree-ice-114463.rs +++ b/tests/ui/const-generics/generic_const_exprs/cannot-convert-refree-ice-114463.rs @@ -1,7 +1,7 @@ // issue: rust-lang/rust#114463 // ICE cannot convert `ReFree ..` to a region vid #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + fn bug<'a>() { [(); (|_: &'a u8| (), 0).1]; //~^ ERROR cannot capture late-bound lifetime in constant diff --git a/tests/ui/const-generics/generic_const_exprs/cannot-convert-refree-ice-114463.stderr b/tests/ui/const-generics/generic_const_exprs/cannot-convert-refree-ice-114463.stderr index e4845405ec81..a468ba6183ea 100644 --- a/tests/ui/const-generics/generic_const_exprs/cannot-convert-refree-ice-114463.stderr +++ b/tests/ui/const-generics/generic_const_exprs/cannot-convert-refree-ice-114463.stderr @@ -1,12 +1,3 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/cannot-convert-refree-ice-114463.rs:3:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error: cannot capture late-bound lifetime in constant --> $DIR/cannot-convert-refree-ice-114463.rs:6:16 | @@ -15,5 +6,5 @@ LL | fn bug<'a>() { LL | [(); (|_: &'a u8| (), 0).1]; | ^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs index a6988a492f61..679f6b74bd1d 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs @@ -1,5 +1,4 @@ #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete fn foo() { let _ = [0u8; { const { std::mem::size_of::() } }]; diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr index db547e6a2481..78d1540f25ce 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr @@ -1,14 +1,5 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-block-is-poly.rs:1:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error: overly complex generic constant - --> $DIR/const-block-is-poly.rs:5:19 + --> $DIR/const-block-is-poly.rs:4:19 | LL | let _ = [0u8; { const { std::mem::size_of::() } }]; | ^^----------------------------------^^ @@ -18,5 +9,5 @@ LL | let _ = [0u8; { const { std::mem::size_of::() } }]; = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/double-opaque-parent-predicates.rs b/tests/ui/const-generics/generic_const_exprs/double-opaque-parent-predicates.rs index e48d559aa327..c5f4bbbf4513 100644 --- a/tests/ui/const-generics/generic_const_exprs/double-opaque-parent-predicates.rs +++ b/tests/ui/const-generics/generic_const_exprs/double-opaque-parent-predicates.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use pub fn y<'a, U: 'a>() -> impl IntoIterator + 'a> { [[[1, 2, 3]]] diff --git a/tests/ui/const-generics/generic_const_exprs/double-opaque-parent-predicates.stderr b/tests/ui/const-generics/generic_const_exprs/double-opaque-parent-predicates.stderr deleted file mode 100644 index faaede13e6b6..000000000000 --- a/tests/ui/const-generics/generic_const_exprs/double-opaque-parent-predicates.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/double-opaque-parent-predicates.rs:3:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr index 58f0d31b0960..e10ea5a44b26 100644 --- a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr +++ b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr @@ -29,12 +29,24 @@ error[E0308]: mismatched types | LL | impl A<2> { | ^ expected `[usize; x]`, found integer + | +note: expected because of the type of the const parameter + --> $DIR/error_in_ty.rs:6:14 + | +LL | pub struct A {} + | ^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/error_in_ty.rs:16:8 | LL | impl A<2> { | ^ expected `[usize; x]`, found integer + | +note: expected because of the type of the const parameter + --> $DIR/error_in_ty.rs:6:14 + | +LL | pub struct A {} + | ^^^^^^^^^^^^^^^^^^^ error[E0592]: duplicate definitions with name `B` --> $DIR/error_in_ty.rs:12:5 diff --git a/tests/ui/const-generics/generic_const_exprs/eval-try-unify.rs b/tests/ui/const-generics/generic_const_exprs/eval-try-unify.rs index b61d2dc1945a..d2b8d94c0544 100644 --- a/tests/ui/const-generics/generic_const_exprs/eval-try-unify.rs +++ b/tests/ui/const-generics/generic_const_exprs/eval-try-unify.rs @@ -1,7 +1,6 @@ //@ build-pass #![feature(generic_const_exprs)] -//~^ WARNING the feature `generic_const_exprs` is incomplete trait Generic { const ASSOC: usize; diff --git a/tests/ui/const-generics/generic_const_exprs/eval-try-unify.stderr b/tests/ui/const-generics/generic_const_exprs/eval-try-unify.stderr deleted file mode 100644 index 8eb1fccc5f88..000000000000 --- a/tests/ui/const-generics/generic_const_exprs/eval-try-unify.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/eval-try-unify.rs:3:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/const-generics/generic_const_exprs/issue-105257.stderr b/tests/ui/const-generics/generic_const_exprs/issue-105257.stderr index 1d0ab56519cf..c90feb404181 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-105257.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-105257.stderr @@ -14,7 +14,9 @@ error[E0308]: mismatched types --> $DIR/issue-105257.rs:5:29 | LL | fn fnc(&self) {} - | ^^ expected `usize`, found `&str` + | ----- ^^ expected `usize`, found `&str` + | | + | expected because of the type of the const parameter error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr b/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr index cc35035edf95..dede51416bfa 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/issue-105608.rs:13:22 + --> $DIR/issue-105608.rs:13:28 | LL | Combination::<0>.and::<_>().and::<_>(); - | ^^^ cannot infer type of the type parameter `M` declared on the method `and` + | ^ cannot infer type of the type parameter `M` declared on the method `and` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-69654.rs b/tests/ui/const-generics/generic_const_exprs/issue-69654.rs index 9b36699bbf11..058f404df578 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-69654.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-69654.rs @@ -15,5 +15,5 @@ fn foo() {} fn main() { Foo::foo(); - //~^ ERROR the function or associated item + //~^ ERROR the associated function or constant } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-69654.stderr b/tests/ui/const-generics/generic_const_exprs/issue-69654.stderr index 7fa0d8c7dbaa..9b5e556b94ee 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-69654.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-69654.stderr @@ -11,14 +11,14 @@ help: you might have meant to write a const parameter here LL | impl Bar for [u8; T] {} | +++++ ++++++++++++ -error[E0599]: the function or associated item `foo` exists for struct `Foo<_>`, but its trait bounds were not satisfied +error[E0599]: the associated function or constant `foo` exists for struct `Foo<_>`, but its trait bounds were not satisfied --> $DIR/issue-69654.rs:17:10 | LL | struct Foo {} - | -------------------------- function or associated item `foo` not found for this struct + | -------------------------- associated function or constant `foo` not found for this struct ... LL | Foo::foo(); - | ^^^ function or associated item cannot be called on `Foo<_>` due to unsatisfied trait bounds + | ^^^ associated function or constant cannot be called on `Foo<_>` due to unsatisfied trait bounds | note: trait bound `[u8; _]: Bar<[(); _]>` was not satisfied --> $DIR/issue-69654.rs:11:14 diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.rs b/tests/ui/const-generics/generic_const_exprs/issue-80742.rs index 0d392902be87..99decb368e1d 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-80742.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.rs @@ -27,5 +27,5 @@ pub fn new(val: T) -> Inline { fn main() { let dst = Inline::::new(0); //~^ ERROR the size for values of type `dyn Debug` cannot be known at compilation time - //~| ERROR the function or associated item `new` exists for struct `Inline` + //~| ERROR the associated function or constant `new` exists for struct `Inline` } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr index ac1bfc8d7a1b..bad736b45685 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr @@ -15,14 +15,14 @@ help: consider relaxing the implicit `Sized` restriction LL | struct Inline | ++++++++ -error[E0599]: the function or associated item `new` exists for struct `Inline`, but its trait bounds were not satisfied +error[E0599]: the associated function or constant `new` exists for struct `Inline`, but its trait bounds were not satisfied --> $DIR/issue-80742.rs:28:36 | LL | struct Inline - | ---------------- function or associated item `new` not found for this struct + | ---------------- associated function or constant `new` not found for this struct ... LL | let dst = Inline::::new(0); - | ^^^ function or associated item cannot be called on `Inline` due to unsatisfied trait bounds + | ^^^ associated function or constant cannot be called on `Inline` due to unsatisfied trait bounds | note: trait bound `dyn Debug: Sized` was not satisfied --> $DIR/issue-80742.rs:18:6 diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs index 443d0a2fe87a..965e07499e18 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs @@ -1,8 +1,6 @@ //@ check-pass #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] -//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] -//~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub struct Changes where diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr deleted file mode 100644 index b6b297593a25..000000000000 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-1.rs:3:30 - | -LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-1.rs:3:52 - | -LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - -warning: 2 warnings emitted - diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs index 6a91b5225672..728d132d4bb1 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs @@ -1,8 +1,6 @@ //@ check-pass #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] -//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] -//~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub struct Changes where diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr deleted file mode 100644 index c0c7dcc79dc4..000000000000 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-2.rs:3:30 - | -LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-2.rs:3:52 - | -LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - -warning: 2 warnings emitted - diff --git a/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs index 734a37862940..85af36ebe9a6 100644 --- a/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs +++ b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.rs @@ -1,5 +1,4 @@ #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete trait B { type U; diff --git a/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr index 1036b7261f26..b11eb1059952 100644 --- a/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr +++ b/tests/ui/const-generics/generic_const_exprs/mismatched-gat-subst-kind.stderr @@ -1,18 +1,9 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/mismatched-gat-subst-kind.rs:1:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0747]: constant provided when a type was expected - --> $DIR/mismatched-gat-subst-kind.rs:8:13 + --> $DIR/mismatched-gat-subst-kind.rs:7:13 | LL | fn f = ()>>() {} | ^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr index 9f48a8563c8a..fd597cbde193 100644 --- a/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr +++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr @@ -9,6 +9,7 @@ LL | let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize]; | = note: expected type `usize` found opaque type `Foo` + = note: array length can only be `usize` error[E0605]: non-primitive cast: `usize` as `Foo` --> $DIR/opaque_type.rs:11:17 diff --git a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs index 9af351ec59f0..6e382de436f4 100644 --- a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs +++ b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs @@ -1,6 +1,5 @@ // Regression test for #133271. #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete struct Foo; impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo diff --git a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr index 37eb895f9a8d..d58bc6723275 100644 --- a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr +++ b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr @@ -1,5 +1,5 @@ error[E0407]: method `unimplemented` is not a member of trait `std::ops::Add` - --> $DIR/post-analysis-user-facing-param-env.rs:12:5 + --> $DIR/post-analysis-user-facing-param-env.rs:11:5 | LL | / fn unimplemented(self, _: &Foo) -> Self::Output { LL | | @@ -7,17 +7,8 @@ LL | | loop {} LL | | } | |_____^ not a member of trait `std::ops::Add` -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/post-analysis-user-facing-param-env.rs:2:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0046]: not all trait items implemented, missing: `Output`, `add` - --> $DIR/post-analysis-user-facing-param-env.rs:6:1 + --> $DIR/post-analysis-user-facing-param-env.rs:5:1 | LL | / impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo LL | | @@ -30,7 +21,7 @@ LL | | [(); 1 + 0]: Sized, = help: implement the missing item: `fn add(self, _: &'a Foo) -> >::Output { todo!() }` error[E0207]: the const parameter `NUM` is not constrained by the impl trait, self type, or predicates - --> $DIR/post-analysis-user-facing-param-env.rs:6:10 + --> $DIR/post-analysis-user-facing-param-env.rs:5:10 | LL | impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo | ^^^^^^^^^^^^^^^^ unconstrained const parameter @@ -38,7 +29,7 @@ LL | impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors Some errors have detailed explanations: E0046, E0207, E0407. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/const-generics/generic_const_exprs/size_of-dyn-trait-3.rs b/tests/ui/const-generics/generic_const_exprs/size_of-dyn-trait-3.rs index afb086a41305..1e1ef0d73b45 100644 --- a/tests/ui/const-generics/generic_const_exprs/size_of-dyn-trait-3.rs +++ b/tests/ui/const-generics/generic_const_exprs/size_of-dyn-trait-3.rs @@ -17,5 +17,5 @@ struct Inline fn main() { let dst = Inline::::new(0); //~^ ERROR the size for values of type `dyn Debug` cannot be known at compilation time - //~| ERROR no function or associated item named `new` found for struct `Inline` + //~| ERROR no associated function or constant named `new` found for struct `Inline` } diff --git a/tests/ui/const-generics/generic_const_exprs/size_of-dyn-trait-3.stderr b/tests/ui/const-generics/generic_const_exprs/size_of-dyn-trait-3.stderr index bcc253ed9670..c73c2167dd75 100644 --- a/tests/ui/const-generics/generic_const_exprs/size_of-dyn-trait-3.stderr +++ b/tests/ui/const-generics/generic_const_exprs/size_of-dyn-trait-3.stderr @@ -15,14 +15,14 @@ help: consider relaxing the implicit `Sized` restriction LL | struct Inline | ++++++++ -error[E0599]: no function or associated item named `new` found for struct `Inline` in the current scope +error[E0599]: no associated function or constant named `new` found for struct `Inline` in the current scope --> $DIR/size_of-dyn-trait-3.rs:18:36 | LL | struct Inline - | ---------------- function or associated item `new` not found for this struct + | ---------------- associated function or constant `new` not found for this struct ... LL | let dst = Inline::::new(0); - | ^^^ function or associated item not found in `Inline` + | ^^^ associated function or constant not found in `Inline` error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs b/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs index d3ae863bee96..d605c83239b2 100644 --- a/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs +++ b/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs @@ -5,7 +5,6 @@ #![feature(with_negative_coherence)] #![feature(min_specialization)] #![feature(generic_const_exprs)] -//~^ WARNING the feature `generic_const_exprs` is incomplete #![crate_type = "lib"] trait Trait {} diff --git a/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.stderr b/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.stderr deleted file mode 100644 index f17b248d856d..000000000000 --- a/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-fuzzing-ice-133639.rs:7:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/const-generics/generic_const_parameter_types/bad_inference.rs b/tests/ui/const-generics/generic_const_parameter_types/bad_inference.rs index 9748c14d655d..994863f0fa43 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/bad_inference.rs +++ b/tests/ui/const-generics/generic_const_parameter_types/bad_inference.rs @@ -1,4 +1,4 @@ -#![feature(adt_const_params, unsized_const_params, generic_const_parameter_types)] +#![feature(adt_const_params, const_param_ty_trait, generic_const_parameter_types)] #![allow(incomplete_features)] use std::marker::ConstParamTy_; diff --git a/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs index d3bc544ed6c5..4de1616cdee5 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs +++ b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs @@ -1,8 +1,6 @@ // Ensure that we actually treat `N`'s type as `&'a u32` in MIR typeck. #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)] -//~^ WARN the feature `unsized_const_params` is incomplete -//~| WARN the feature `generic_const_parameter_types` is incomplete fn foo<'a, const N: &'a u32>() { let b: &'static u32 = N; diff --git a/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr index 3dc7ce438fa9..0b7a43a391f0 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr +++ b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr @@ -1,27 +1,10 @@ -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/check-type-in-mir.rs:3:12 - | -LL | #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `generic_const_parameter_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/check-type-in-mir.rs:3:52 - | -LL | #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #137626 for more information - error: lifetime may not live long enough - --> $DIR/check-type-in-mir.rs:8:12 + --> $DIR/check-type-in-mir.rs:6:12 | LL | fn foo<'a, const N: &'a u32>() { | -- lifetime `'a` defined here LL | let b: &'static u32 = N; | ^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` -error: aborting due to 1 previous error; 2 warnings emitted +error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_parameter_types/evaluate_const_parameter_in_mir.rs b/tests/ui/const-generics/generic_const_parameter_types/evaluate_const_parameter_in_mir.rs index 9f3ab1be2502..6226aaaab6fb 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/evaluate_const_parameter_in_mir.rs +++ b/tests/ui/const-generics/generic_const_parameter_types/evaluate_const_parameter_in_mir.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(adt_const_params, unsized_const_params, generic_const_parameter_types)] +#![feature(adt_const_params, const_param_ty_trait, generic_const_parameter_types)] #![allow(incomplete_features)] use std::marker::ConstParamTy_; diff --git a/tests/ui/const-generics/generic_const_parameter_types/mismatched_args_with_value.rs b/tests/ui/const-generics/generic_const_parameter_types/mismatched_args_with_value.rs index df8a057b335a..08d85f183c1e 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/mismatched_args_with_value.rs +++ b/tests/ui/const-generics/generic_const_parameter_types/mismatched_args_with_value.rs @@ -1,4 +1,4 @@ -#![feature(adt_const_params, unsized_const_params, generic_const_parameter_types)] +#![feature(adt_const_params, const_param_ty_trait, generic_const_parameter_types)] #![allow(incomplete_features)] use std::marker::ConstParamTy_; diff --git a/tests/ui/const-generics/generic_const_parameter_types/no_const_param_ty_bound.rs b/tests/ui/const-generics/generic_const_parameter_types/no_const_param_ty_bound.rs index 1a5ab46cda19..20306c7f219d 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/no_const_param_ty_bound.rs +++ b/tests/ui/const-generics/generic_const_parameter_types/no_const_param_ty_bound.rs @@ -1,4 +1,4 @@ -#![feature(adt_const_params, unsized_const_params, generic_const_parameter_types)] +#![feature(adt_const_params, const_param_ty_trait, generic_const_parameter_types)] #![expect(incomplete_features)] use std::marker::{ConstParamTy_, PhantomData}; diff --git a/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.feat.stderr b/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.feat.stderr index 2d47797aef28..7e61566aabdd 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.feat.stderr +++ b/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.feat.stderr @@ -1,14 +1,5 @@ -warning: the feature `generic_const_parameter_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/references-parent-generics.rs:3:27 - | -LL | #![cfg_attr(feat, feature(generic_const_parameter_types))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #137626 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `Self` is forbidden as the type of a const generic parameter - --> $DIR/references-parent-generics.rs:7:25 + --> $DIR/references-parent-generics.rs:6:25 | LL | type Assoc; | ^^^^ @@ -16,10 +7,10 @@ LL | type Assoc; = note: the only supported types are integers, `bool`, and `char` error: anonymous constants referencing generics are not yet supported - --> $DIR/references-parent-generics.rs:15:21 + --> $DIR/references-parent-generics.rs:14:21 | LL | let x: T::Assoc<3>; | ^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.nofeat.stderr b/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.nofeat.stderr index 68ce17317f69..ac25a4eae625 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.nofeat.stderr +++ b/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.nofeat.stderr @@ -1,5 +1,5 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/references-parent-generics.rs:7:25 + --> $DIR/references-parent-generics.rs:6:25 | LL | type Assoc; | ^^^^ the type must not depend on the parameter `Self` diff --git a/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.rs b/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.rs index b91050d540c9..6eadb605f97f 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.rs +++ b/tests/ui/const-generics/generic_const_parameter_types/references-parent-generics.rs @@ -1,7 +1,6 @@ //@ revisions: feat nofeat #![cfg_attr(feat, feature(generic_const_parameter_types))] -//[feat]~^ WARN the feature `generic_const_parameter_types` is incomplete trait Foo { type Assoc; diff --git a/tests/ui/const-generics/generic_const_parameter_types/unrelated_inferred_arg.rs b/tests/ui/const-generics/generic_const_parameter_types/unrelated_inferred_arg.rs index 80117a27a23d..1661d769c4ea 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/unrelated_inferred_arg.rs +++ b/tests/ui/const-generics/generic_const_parameter_types/unrelated_inferred_arg.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(adt_const_params, unsized_const_params, generic_const_parameter_types)] +#![feature(adt_const_params, const_param_ty_trait, generic_const_parameter_types)] #![allow(incomplete_features)] use std::marker::ConstParamTy_; diff --git a/tests/ui/const-generics/invalid-enum.rs b/tests/ui/const-generics/invalid-enum.rs index 56fac3e2eb6c..09d06e0df78d 100644 --- a/tests/ui/const-generics/invalid-enum.rs +++ b/tests/ui/const-generics/invalid-enum.rs @@ -12,27 +12,27 @@ enum CompileFlag { pub fn test_1() {} pub fn test_2(x: T) {} -pub struct Example{ +pub struct Example { x: T, } impl Example { - const ASSOC_FLAG: CompileFlag = CompileFlag::A; + const ASSOC_FLAG: CompileFlag = CompileFlag::A; } pub fn main() { - test_1::(); - //~^ ERROR: expected type, found variant - //~| ERROR: unresolved item provided when a constant was expected + test_1::(); + //~^ ERROR: expected type, found variant + //~| ERROR: unresolved item provided when a constant was expected - test_2::<_, CompileFlag::A>(0); - //~^ ERROR: expected type, found variant - //~| ERROR: unresolved item provided when a constant was expected + test_2::<_, CompileFlag::A>(0); + //~^ ERROR: expected type, found variant + //~| ERROR: unresolved item provided when a constant was expected - let _: Example = Example { x: 0 }; - //~^ ERROR: expected type, found variant - //~| ERROR: unresolved item provided when a constant was expected + let _: Example = Example { x: 0 }; + //~^ ERROR: expected type, found variant + //~| ERROR: unresolved item provided when a constant was expected - let _: Example = Example { x: 0 }; - //~^ ERROR: type provided when a constant was expected + let _: Example = Example { x: 0 }; + //~^ ERROR: type provided when a constant was expected } diff --git a/tests/ui/const-generics/invalid-enum.stderr b/tests/ui/const-generics/invalid-enum.stderr index 911052370f43..a557927cb490 100644 --- a/tests/ui/const-generics/invalid-enum.stderr +++ b/tests/ui/const-generics/invalid-enum.stderr @@ -1,73 +1,73 @@ error[E0573]: expected type, found variant `CompileFlag::A` - --> $DIR/invalid-enum.rs:24:12 + --> $DIR/invalid-enum.rs:24:14 | -LL | test_1::(); - | ^^^^^^^^^^^^^^ - | | - | not a type - | help: try using the variant's enum: `CompileFlag` +LL | test_1::(); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` error[E0573]: expected type, found variant `CompileFlag::A` - --> $DIR/invalid-enum.rs:28:15 + --> $DIR/invalid-enum.rs:28:17 | -LL | test_2::<_, CompileFlag::A>(0); - | ^^^^^^^^^^^^^^ - | | - | not a type - | help: try using the variant's enum: `CompileFlag` +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` error[E0573]: expected type, found variant `CompileFlag::A` - --> $DIR/invalid-enum.rs:32:18 + --> $DIR/invalid-enum.rs:32:20 | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^ - | | - | not a type - | help: try using the variant's enum: `CompileFlag` +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` error[E0747]: unresolved item provided when a constant was expected - --> $DIR/invalid-enum.rs:24:12 + --> $DIR/invalid-enum.rs:24:14 | -LL | test_1::(); - | ^^^^^^^^^^^^^^ +LL | test_1::(); + | ^^^^^^^^^^^^^^ | help: if this generic argument was intended as a const parameter, surround it with braces | -LL | test_1::<{ CompileFlag::A }>(); - | + + +LL | test_1::<{ CompileFlag::A }>(); + | + + error[E0747]: unresolved item provided when a constant was expected - --> $DIR/invalid-enum.rs:28:15 + --> $DIR/invalid-enum.rs:28:17 | -LL | test_2::<_, CompileFlag::A>(0); - | ^^^^^^^^^^^^^^ +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ | help: if this generic argument was intended as a const parameter, surround it with braces | -LL | test_2::<_, { CompileFlag::A }>(0); - | + + +LL | test_2::<_, { CompileFlag::A }>(0); + | + + error[E0747]: unresolved item provided when a constant was expected - --> $DIR/invalid-enum.rs:32:18 + --> $DIR/invalid-enum.rs:32:20 | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^ +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^ | help: if this generic argument was intended as a const parameter, surround it with braces | -LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; - | + + +LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; + | + + error[E0747]: type provided when a constant was expected - --> $DIR/invalid-enum.rs:36:18 + --> $DIR/invalid-enum.rs:36:20 | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^^^^^^ +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^ | help: if this generic argument was intended as a const parameter, surround it with braces | -LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; - | + + +LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; + | + + error: aborting due to 7 previous errors diff --git a/tests/ui/const-generics/invalid-path-in-const.rs b/tests/ui/const-generics/invalid-path-in-const.rs new file mode 100644 index 000000000000..a3c622aa5a96 --- /dev/null +++ b/tests/ui/const-generics/invalid-path-in-const.rs @@ -0,0 +1,4 @@ +fn main() { + fn f(a: [u8; u32::DOESNOTEXIST]) {} + //~^ ERROR no associated function or constant named `DOESNOTEXIST` found for type `u32` +} diff --git a/tests/ui/const-generics/invalid-path-in-const.stderr b/tests/ui/const-generics/invalid-path-in-const.stderr new file mode 100644 index 000000000000..83c90a24d70b --- /dev/null +++ b/tests/ui/const-generics/invalid-path-in-const.stderr @@ -0,0 +1,9 @@ +error[E0599]: no associated function or constant named `DOESNOTEXIST` found for type `u32` in the current scope + --> $DIR/invalid-path-in-const.rs:2:23 + | +LL | fn f(a: [u8; u32::DOESNOTEXIST]) {} + | ^^^^^^^^^^^^ associated function or constant not found in `u32` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs b/tests/ui/const-generics/invalid-rustc_legacy_const_generics-arguments.rs similarity index 100% rename from tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs rename to tests/ui/const-generics/invalid-rustc_legacy_const_generics-arguments.rs diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr b/tests/ui/const-generics/invalid-rustc_legacy_const_generics-arguments.stderr similarity index 100% rename from tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr rename to tests/ui/const-generics/invalid-rustc_legacy_const_generics-arguments.stderr diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs b/tests/ui/const-generics/invalid-rustc_legacy_const_generics-issue-123077.rs similarity index 100% rename from tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs rename to tests/ui/const-generics/invalid-rustc_legacy_const_generics-issue-123077.rs diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr b/tests/ui/const-generics/invalid-rustc_legacy_const_generics-issue-123077.stderr similarity index 100% rename from tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr rename to tests/ui/const-generics/invalid-rustc_legacy_const_generics-issue-123077.stderr diff --git a/tests/ui/const-generics/invariant.stderr b/tests/ui/const-generics/invariant.stderr index 095219f6e5fa..465f708d8f13 100644 --- a/tests/ui/const-generics/invariant.stderr +++ b/tests/ui/const-generics/invariant.stderr @@ -7,9 +7,9 @@ LL | impl SadBee for for<'a> fn(&'a ()) { LL | impl SadBee for fn(&'static ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a ())` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default error[E0308]: mismatched types diff --git a/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs index 1f61356162ca..3eed2e71ae85 100644 --- a/tests/ui/const-generics/issues/issue-100313.rs +++ b/tests/ui/const-generics/issues/issue-100313.rs @@ -1,5 +1,5 @@ //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend different alloc ids #![allow(incomplete_features)] #![feature(adt_const_params, unsized_const_params)] diff --git a/tests/ui/const-generics/issues/issue-83249.stderr b/tests/ui/const-generics/issues/issue-83249.stderr index 2d561dbd6b1c..0f00f70700f5 100644 --- a/tests/ui/const-generics/issues/issue-83249.stderr +++ b/tests/ui/const-generics/issues/issue-83249.stderr @@ -6,7 +6,7 @@ LL | let _ = foo([0; 1]); | | | required by a bound introduced by this call | - = note: cannot satisfy `_: Foo` + = note: the type must implement `Foo` help: the trait `Foo` is implemented for `u8` --> $DIR/issue-83249.rs:8:1 | @@ -17,10 +17,10 @@ note: required by a bound in `foo` | LL | fn foo(_: [u8; T::N]) -> T { | ^^^ required by this bound in `foo` -help: consider giving this pattern a type +help: consider giving this pattern a type, where the type for type parameter `T` is specified | -LL | let _: /* Type */ = foo([0; 1]); - | ++++++++++++ +LL | let _: u8 = foo([0; 1]); + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/lookup-method.stderr b/tests/ui/const-generics/lookup-method.stderr index 4cbd1e17c7be..f55812c1d0d0 100644 --- a/tests/ui/const-generics/lookup-method.stderr +++ b/tests/ui/const-generics/lookup-method.stderr @@ -7,8 +7,7 @@ LL | struct Builder; LL | b.cast().build(); | ^^^^^ method not found in `Builder` | - = note: the method was found for - - `Builder` + = note: the method was found for `Builder` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs b/tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs index 5def3cbb829b..f27cbddaae28 100644 --- a/tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs +++ b/tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs @@ -5,7 +5,7 @@ min_generic_const_args, adt_const_params, generic_const_parameter_types, - unsized_const_params, + const_param_ty_trait, )] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr b/tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr index 759a40cc0675..1a5f77ba33e1 100644 --- a/tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr +++ b/tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr @@ -1,20 +1,24 @@ error: use of `const` in the type system not defined as `type const` --> $DIR/assoc-const-without-type_const.rs:8:35 | -LL | const SIZE: usize; - | - help: add `type` before `const` for `Tr::SIZE`: `type` -... LL | fn mk_array(_x: T) -> [(); T::SIZE] { | ^^^^^^^ + | +help: add `type` before `const` for `Tr::SIZE` + | +LL | type const SIZE: usize; + | ++++ error: use of `const` in the type system not defined as `type const` --> $DIR/assoc-const-without-type_const.rs:10:10 | -LL | const SIZE: usize; - | - help: add `type` before `const` for `Tr::SIZE`: `type` -... LL | [(); T::SIZE] | ^^^^^^^ + | +help: add `type` before `const` for `Tr::SIZE` + | +LL | type const SIZE: usize; + | ++++ error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/braced-const-infer.rs b/tests/ui/const-generics/mgca/braced-const-infer.rs new file mode 100644 index 000000000000..9b007d338d1d --- /dev/null +++ b/tests/ui/const-generics/mgca/braced-const-infer.rs @@ -0,0 +1,9 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/153198 +#![feature(min_generic_const_args)] +#![allow(incomplete_features, rust_2021_compatibility)] + +trait Trait {} + +impl dyn Trait<{_}> {} //~ ERROR: the placeholder `_` is not allowed within types on item signatures + +fn main() {} diff --git a/tests/ui/const-generics/mgca/braced-const-infer.stderr b/tests/ui/const-generics/mgca/braced-const-infer.stderr new file mode 100644 index 000000000000..d8ffee4cd0e8 --- /dev/null +++ b/tests/ui/const-generics/mgca/braced-const-infer.stderr @@ -0,0 +1,9 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations + --> $DIR/braced-const-infer.rs:7:17 + | +LL | impl dyn Trait<{_}> {} + | ^ not allowed in type signatures + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs index 6a4ee3ed1772..ec74a6e53012 100644 --- a/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs +++ b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs @@ -6,14 +6,14 @@ struct U; #[derive(ConstParamTy, PartialEq, Eq)] -//~^ ERROR overflow evaluating the requirement `S well-formed` -//~| ERROR overflow evaluating the requirement `S well-formed` +//~^ ERROR overflow evaluating whether `S` is well-formed +//~| ERROR overflow evaluating whether `S` is well-formed struct S() where S<{ U }>:; -//~^ ERROR overflow evaluating the requirement `S well-formed` -//~| ERROR overflow evaluating the requirement `S well-formed` -//~| ERROR overflow evaluating the requirement `S well-formed` +//~^ ERROR overflow evaluating whether `S` is well-formed +//~| ERROR overflow evaluating whether `S` is well-formed +//~| ERROR overflow evaluating whether `S` is well-formed fn main() {} diff --git a/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr index 4c5ad645bc45..bb393cad567e 100644 --- a/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr +++ b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `S well-formed` +error[E0275]: overflow evaluating whether `S` is well-formed --> $DIR/const-ctor-overflow-eval.rs:14:5 | LL | S<{ U }>:; @@ -13,7 +13,7 @@ LL | where LL | S<{ U }>:; | ^^^^^^^^ required by this bound in `S` -error[E0275]: overflow evaluating the requirement `S well-formed` +error[E0275]: overflow evaluating whether `S` is well-formed --> $DIR/const-ctor-overflow-eval.rs:14:5 | LL | S<{ U }>:; @@ -29,7 +29,7 @@ LL | S<{ U }>:; | ^^^^^^^^ required by this bound in `S` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0275]: overflow evaluating the requirement `S well-formed` +error[E0275]: overflow evaluating whether `S` is well-formed --> $DIR/const-ctor-overflow-eval.rs:14:5 | LL | S<{ U }>:; @@ -45,7 +45,7 @@ LL | S<{ U }>:; | ^^^^^^^^ required by this bound in `S` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0275]: overflow evaluating the requirement `S well-formed` +error[E0275]: overflow evaluating whether `S` is well-formed --> $DIR/const-ctor-overflow-eval.rs:8:24 | LL | #[derive(ConstParamTy, PartialEq, Eq)] @@ -60,7 +60,7 @@ LL | where LL | S<{ U }>:; | ^^^^^^^^ required by this bound in `S` -error[E0275]: overflow evaluating the requirement `S well-formed` +error[E0275]: overflow evaluating whether `S` is well-formed --> $DIR/const-ctor-overflow-eval.rs:8:35 | LL | #[derive(ConstParamTy, PartialEq, Eq)] diff --git a/tests/ui/const-generics/mgca/const-ctor.rs b/tests/ui/const-generics/mgca/const-ctor.rs index 19900b56a816..d84b05f90909 100644 --- a/tests/ui/const-generics/mgca/const-ctor.rs +++ b/tests/ui/const-generics/mgca/const-ctor.rs @@ -8,7 +8,7 @@ min_generic_const_args, adt_const_params, generic_const_parameter_types, - unsized_const_params + const_param_ty_trait )] #![expect(incomplete_features)] use std::marker::{ConstParamTy, ConstParamTy_}; diff --git a/tests/ui/const-generics/mgca/free-const-recursive.rs b/tests/ui/const-generics/mgca/free-const-recursive.rs new file mode 100644 index 000000000000..8d75c1a941a7 --- /dev/null +++ b/tests/ui/const-generics/mgca/free-const-recursive.rs @@ -0,0 +1,13 @@ +//! Regression test for +//@ check-fail +//@compile-flags: -Znext-solver=globally --emit=obj +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +type const A: () = A; +//~^ ERROR type mismatch resolving `A normalizes-to _` +//~| ERROR the constant `A` is not of type `()` + +fn main() { + A; +} diff --git a/tests/ui/const-generics/mgca/free-const-recursive.stderr b/tests/ui/const-generics/mgca/free-const-recursive.stderr new file mode 100644 index 000000000000..d0f10275b40d --- /dev/null +++ b/tests/ui/const-generics/mgca/free-const-recursive.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `A normalizes-to _` + --> $DIR/free-const-recursive.rs:7:1 + | +LL | type const A: () = A; + | ^^^^^^^^^^^^^^^^ types differ + +error: the constant `A` is not of type `()` + --> $DIR/free-const-recursive.rs:7:1 + | +LL | type const A: () = A; + | ^^^^^^^^^^^^^^^^ expected `()`, found a different `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs b/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs index 948b8ce72148..0c975184dfbd 100644 --- a/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs +++ b/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs @@ -5,7 +5,7 @@ generic_const_items, generic_const_parameter_types, min_generic_const_args, - unsized_const_params + const_param_ty_trait )] use std::marker::ConstParamTy_; diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs new file mode 100644 index 000000000000..eeb76683eedf --- /dev/null +++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs @@ -0,0 +1,21 @@ +//! This test ensures compilation failure when trying to pass literals +//! without explicitly stated type as inference variables in generic arguments. +//! +//! See https://github.com/rust-lang/rust/pull/153557 + +#![allow(incomplete_features)] +#![feature(adt_const_params, min_generic_const_args, generic_const_parameter_types)] + +fn main() { + foo::<_, { 2 }>(); + //~^ ERROR: type annotations needed for the literal + let _: PC<_, { 42 }> = PC { a: 1, b: 1 }; + //~^ ERROR: type annotations needed for the literal +} + +struct PC { +//~^ ERROR: `T` can't be used as a const parameter type [E0741] + a: T, +} + +fn foo() {} diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr new file mode 100644 index 000000000000..a4b13f41aef0 --- /dev/null +++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr @@ -0,0 +1,21 @@ +error[E0741]: `T` can't be used as a const parameter type + --> $DIR/infer-vars-in-const-args-conflicting.rs:16:23 + | +LL | struct PC { + | ^ + +error: type annotations needed for the literal + --> $DIR/infer-vars-in-const-args-conflicting.rs:10:16 + | +LL | foo::<_, { 2 }>(); + | ^ + +error: type annotations needed for the literal + --> $DIR/infer-vars-in-const-args-conflicting.rs:12:20 + | +LL | let _: PC<_, { 42 }> = PC { a: 1, b: 1 }; + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs new file mode 100644 index 000000000000..f1c0e0b2b4c3 --- /dev/null +++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs @@ -0,0 +1,22 @@ +//! This test ensures no errors are emitted when lowering literals with +//! explicitly stated types and inference variables in the type of the const +//! generic parameter. +//! +//! See https://github.com/rust-lang/rust/pull/153557 + +//@check-pass + +#![allow(incomplete_features)] +#![feature(adt_const_params, + min_generic_const_args, + generic_const_parameter_types, + unsized_const_params +)] + +use std::marker::ConstParamTy_; + +fn main() { + foo::<_, 2_i32>(); +} + +fn foo() {} diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.rs b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs new file mode 100644 index 000000000000..017c63d8b0db --- /dev/null +++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs @@ -0,0 +1,20 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/153198 +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] +macro_rules! y { + ( $($matcher:tt)*) => { + _ //~ ERROR: the placeholder `_` is not allowed within types on item signatures + }; +} + +struct A; //~ ERROR: type parameter `T` is never used + +const y: A< + { + y! { + x + } + }, +> = 1; //~ ERROR: mismatched types + +fn main() {} diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr new file mode 100644 index 000000000000..406206c59e18 --- /dev/null +++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr @@ -0,0 +1,44 @@ +error[E0392]: type parameter `T` is never used + --> $DIR/macro-const-arg-infer.rs:10:10 + | +LL | struct A; + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error[E0308]: mismatched types + --> $DIR/macro-const-arg-infer.rs:18:5 + | +LL | const y: A< + | __________- +LL | | { +LL | | y! { +LL | | x +LL | | } +LL | | }, +LL | | > = 1; + | | - ^ expected `A<_>`, found integer + | |_| + | expected because of the type of the constant + | + = note: expected struct `A<_>` + found type `{integer}` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/macro-const-arg-infer.rs:6:9 + | +LL | _ + | ^ not allowed in type signatures +... +LL | / y! { +LL | | x +LL | | } + | |_________- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0121, E0308, E0392. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/const-generics/mgca/projection-const-recursive.rs b/tests/ui/const-generics/mgca/projection-const-recursive.rs new file mode 100644 index 000000000000..c9b5039b5fd0 --- /dev/null +++ b/tests/ui/const-generics/mgca/projection-const-recursive.rs @@ -0,0 +1,19 @@ +//! See also +//@ check-fail +//@compile-flags: -Znext-solver=globally --emit=obj +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + type const A: (); +} + +impl Trait for () { + type const A: () = <() as Trait>::A; + //~^ ERROR type mismatch resolving `<() as Trait>::A normalizes-to _` + //~| ERROR the constant `<() as Trait>::A` is not of type `()` +} + +fn main() { + <() as Trait>::A; +} diff --git a/tests/ui/const-generics/mgca/projection-const-recursive.stderr b/tests/ui/const-generics/mgca/projection-const-recursive.stderr new file mode 100644 index 000000000000..d9c60102c318 --- /dev/null +++ b/tests/ui/const-generics/mgca/projection-const-recursive.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `<() as Trait>::A normalizes-to _` + --> $DIR/projection-const-recursive.rs:12:5 + | +LL | type const A: () = <() as Trait>::A; + | ^^^^^^^^^^^^^^^^ types differ + +error: the constant `<() as Trait>::A` is not of type `()` + --> $DIR/projection-const-recursive.rs:12:5 + | +LL | type const A: () = <() as Trait>::A; + | ^^^^^^^^^^^^^^^^ expected `()`, found a different `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/const-generics/mgca/struct-ctor-in-array-len.rs b/tests/ui/const-generics/mgca/struct-ctor-in-array-len.rs index 715caef38a9a..c8288431c7ed 100644 --- a/tests/ui/const-generics/mgca/struct-ctor-in-array-len.rs +++ b/tests/ui/const-generics/mgca/struct-ctor-in-array-len.rs @@ -6,7 +6,6 @@ // It should now produce a proper type error. #![feature(min_generic_const_args)] -//~^ WARN the feature `min_generic_const_args` is incomplete struct S; diff --git a/tests/ui/const-generics/mgca/struct-ctor-in-array-len.stderr b/tests/ui/const-generics/mgca/struct-ctor-in-array-len.stderr index baf587a856bc..fcf02621ca9d 100644 --- a/tests/ui/const-generics/mgca/struct-ctor-in-array-len.stderr +++ b/tests/ui/const-generics/mgca/struct-ctor-in-array-len.stderr @@ -1,19 +1,10 @@ -warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/struct-ctor-in-array-len.rs:8:12 - | -LL | #![feature(min_generic_const_args)] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #132980 for more information - = note: `#[warn(incomplete_features)]` on by default - error: the constant `S` is not of type `usize` - --> $DIR/struct-ctor-in-array-len.rs:14:14 + --> $DIR/struct-ctor-in-array-len.rs:13:14 | LL | let _b = [0; S]; | ^^^^^^ expected `usize`, found `S` | = note: the length of array `[{integer}; S]` must be type `usize` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.rs b/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.rs index 1c3274f6a376..4d96d236cf7f 100644 --- a/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.rs +++ b/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.rs @@ -1,7 +1,6 @@ // Make sure we don't ICE when encountering an fn item during lowering in mGCA. #![feature(min_generic_const_args)] -//~^ WARN the feature `min_generic_const_args` is incomplete trait A {} diff --git a/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.stderr b/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.stderr index 89fc8270e3e7..de64bf7b74c0 100644 --- a/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.stderr +++ b/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.stderr @@ -1,19 +1,10 @@ -warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unexpected-fn-item-in-array.rs:3:12 - | -LL | #![feature(min_generic_const_args)] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #132980 for more information - = note: `#[warn(incomplete_features)]` on by default - error: the constant `fn_item` is not of type `usize` - --> $DIR/unexpected-fn-item-in-array.rs:8:6 + --> $DIR/unexpected-fn-item-in-array.rs:7:6 | LL | impl A<[usize; fn_item]> for () {} | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found fn item | = note: the length of array `[usize; fn_item]` must be type `usize` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/unmarked-free-const.stderr b/tests/ui/const-generics/mgca/unmarked-free-const.stderr index 76875d8db0ef..dd33de4ce022 100644 --- a/tests/ui/const-generics/mgca/unmarked-free-const.stderr +++ b/tests/ui/const-generics/mgca/unmarked-free-const.stderr @@ -1,11 +1,13 @@ error: use of `const` in the type system not defined as `type const` --> $DIR/unmarked-free-const.rs:9:18 | -LL | const N: usize = 4; - | - help: add `type` before `const` for `N`: `type` -... LL | let x = [(); N]; | ^ + | +help: add `type` before `const` for `N` + | +LL | type const N: usize = 4; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index df7c2a0a8629..ec39cc27efb4 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -3,24 +3,48 @@ error[E0308]: mismatched types | LL | get_flag::(); | ^^^^ expected `char`, found `u8` + | +note: expected because of the type of the const parameter + --> $DIR/invalid-patterns.rs:6:34 + | +LL | fn get_flag() -> Option { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:33:14 | LL | get_flag::<7, 'c'>(); | ^ expected `bool`, found integer + | +note: expected because of the type of the const parameter + --> $DIR/invalid-patterns.rs:6:13 + | +LL | fn get_flag() -> Option { + | ^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:35:14 | LL | get_flag::<42, 0x5ad>(); | ^^ expected `bool`, found integer + | +note: expected because of the type of the const parameter + --> $DIR/invalid-patterns.rs:6:13 + | +LL | fn get_flag() -> Option { + | ^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:35:18 | LL | get_flag::<42, 0x5ad>(); | ^^^^^ expected `char`, found `u8` + | +note: expected because of the type of the const parameter + --> $DIR/invalid-patterns.rs:6:34 + | +LL | fn get_flag() -> Option { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 @@ -32,7 +56,7 @@ LL | get_flag::(); ff __ __ __ │ .░░░ } -error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean +error[E0080]: constructing invalid value of type bool: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:42:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); @@ -43,7 +67,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); 42 │ B } -error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean +error[E0080]: constructing invalid value of type bool: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:44:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index df7c2a0a8629..ec39cc27efb4 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -3,24 +3,48 @@ error[E0308]: mismatched types | LL | get_flag::(); | ^^^^ expected `char`, found `u8` + | +note: expected because of the type of the const parameter + --> $DIR/invalid-patterns.rs:6:34 + | +LL | fn get_flag() -> Option { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:33:14 | LL | get_flag::<7, 'c'>(); | ^ expected `bool`, found integer + | +note: expected because of the type of the const parameter + --> $DIR/invalid-patterns.rs:6:13 + | +LL | fn get_flag() -> Option { + | ^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:35:14 | LL | get_flag::<42, 0x5ad>(); | ^^ expected `bool`, found integer + | +note: expected because of the type of the const parameter + --> $DIR/invalid-patterns.rs:6:13 + | +LL | fn get_flag() -> Option { + | ^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:35:18 | LL | get_flag::<42, 0x5ad>(); | ^^^^^ expected `char`, found `u8` + | +note: expected because of the type of the const parameter + --> $DIR/invalid-patterns.rs:6:34 + | +LL | fn get_flag() -> Option { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 @@ -32,7 +56,7 @@ LL | get_flag::(); ff __ __ __ │ .░░░ } -error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean +error[E0080]: constructing invalid value of type bool: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:42:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); @@ -43,7 +67,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); 42 │ B } -error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean +error[E0080]: constructing invalid value of type bool: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:44:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.rs b/tests/ui/const-generics/min_const_generics/invalid-patterns.rs index 85f019adf664..847b51abb6af 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.rs +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.rs @@ -1,6 +1,6 @@ //@ stderr-per-bitwidth //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend different alloc ids use std::mem::transmute; fn get_flag() -> Option { diff --git a/tests/ui/const-generics/occurs-check/unify-fixpoint.rs b/tests/ui/const-generics/occurs-check/unify-fixpoint.rs index 02bc90988e2c..950757efbd42 100644 --- a/tests/ui/const-generics/occurs-check/unify-fixpoint.rs +++ b/tests/ui/const-generics/occurs-check/unify-fixpoint.rs @@ -4,8 +4,7 @@ //@ compile-flags: -Zunstable-options //@ check-pass -#![feature(generic_const_exprs)] //~ WARN the feature `generic_const_exprs` is incomplete - +#![feature(generic_const_exprs)] fn bind(value: [u8; N + 2]) -> [u8; N * 2] { todo!() diff --git a/tests/ui/const-generics/occurs-check/unify-fixpoint.stderr b/tests/ui/const-generics/occurs-check/unify-fixpoint.stderr deleted file mode 100644 index 8b63e8c55d5c..000000000000 --- a/tests/ui/const-generics/occurs-check/unify-fixpoint.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unify-fixpoint.rs:7:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/const-generics/ogca/basic-fail.stderr b/tests/ui/const-generics/ogca/basic-fail.stderr index ce4e8eb1471c..b1808deacd27 100644 --- a/tests/ui/const-generics/ogca/basic-fail.stderr +++ b/tests/ui/const-generics/ogca/basic-fail.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/basic-fail.rs:15:30 | LL | const ARR: [(); ADD1::<0>] = [(); INC::<0>]; - | ^^^^^^^^^^^^^^ expected an array with a size of const { N + 1 }, found one with a size of const { N + 1 } + | --------------- ^^^^^^^^^^^^^^ expected an array with a size of const { N + 1 }, found one with a size of const { N + 1 } + | | + | expected because of the type of the constant error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/ogca/coherence-ambiguous.rs b/tests/ui/const-generics/ogca/coherence-ambiguous.rs index 21efe4cfe981..bb20c0457c03 100644 --- a/tests/ui/const-generics/ogca/coherence-ambiguous.rs +++ b/tests/ui/const-generics/ogca/coherence-ambiguous.rs @@ -1,5 +1,4 @@ -// FIXME(ogca): this should ERROR not pass!! -//@ check-pass +//@ check-fail #![feature(generic_const_items, min_generic_const_args, opaque_generic_const_args)] #![expect(incomplete_features)] @@ -12,8 +11,8 @@ trait Trait {} impl Trait for [(); FOO::<1>] {} impl Trait for [(); BAR::<1>] {} -// FIXME(ogca): this should ERROR! +//~^ ERROR conflicting implementations of trait `Trait` for type `[(); FOO::<1>]` impl Trait for [(); BAR::<2>] {} -// FIXME(ogca): this should ERROR! +//~^ ERROR conflicting implementations of trait `Trait` for type `[(); FOO::<1>]` fn main() {} diff --git a/tests/ui/const-generics/ogca/coherence-ambiguous.stderr b/tests/ui/const-generics/ogca/coherence-ambiguous.stderr new file mode 100644 index 000000000000..919a0c8d70e9 --- /dev/null +++ b/tests/ui/const-generics/ogca/coherence-ambiguous.stderr @@ -0,0 +1,20 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `[(); FOO::<1>]` + --> $DIR/coherence-ambiguous.rs:13:1 + | +LL | impl Trait for [(); FOO::<1>] {} + | ----------------------------- first implementation here +LL | impl Trait for [(); BAR::<1>] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); FOO::<1>]` + +error[E0119]: conflicting implementations of trait `Trait` for type `[(); FOO::<1>]` + --> $DIR/coherence-ambiguous.rs:15:1 + | +LL | impl Trait for [(); FOO::<1>] {} + | ----------------------------- first implementation here +... +LL | impl Trait for [(); BAR::<2>] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); FOO::<1>]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr index f67e1c8ce699..d49a643e0d87 100644 --- a/tests/ui/const-generics/opaque_types.stderr +++ b/tests/ui/const-generics/opaque_types.stderr @@ -30,6 +30,11 @@ LL | foo::<42>(); | = note: expected opaque type `Foo` found type `{integer}` +note: expected because of the type of the const parameter + --> $DIR/opaque_types.rs:6:8 + | +LL | fn foo() {} + | ^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/vec-macro-in-static-array.stderr b/tests/ui/const-generics/vec-macro-in-static-array.stderr index 63d7b0c89fa1..ae08cad556fc 100644 --- a/tests/ui/const-generics/vec-macro-in-static-array.stderr +++ b/tests/ui/const-generics/vec-macro-in-static-array.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/vec-macro-in-static-array.rs:5:26 | LL | static VEC: [u32; 256] = vec![]; - | ^^^^^^ expected `[u32; 256]`, found `Vec<_>` + | ---------- ^^^^^^ expected `[u32; 256]`, found `Vec<_>` + | | + | expected because of the type of the static | = note: expected array `[u32; 256]` found struct `Vec<_>` diff --git a/tests/ui/const-ptr/forbidden_slices.rs b/tests/ui/const-ptr/forbidden_slices.rs index fcb0dccf750e..b7c02e6735b4 100644 --- a/tests/ui/const-ptr/forbidden_slices.rs +++ b/tests/ui/const-ptr/forbidden_slices.rs @@ -1,7 +1,7 @@ // Strip out raw byte dumps to make comparison platform-independent: //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" - +//@ ignore-parallel-frontend different alloc ids #![feature( slice_from_ptr_range, const_slice_from_ptr_range, diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 70ae00af23f5..fb74be3bb52f 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered a null reference +error[E0080]: constructing invalid value of type &[u32]: encountered a null reference --> $DIR/forbidden_slices.rs:16:1 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; @@ -9,7 +9,7 @@ LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered a null reference +error[E0080]: constructing invalid value of type &[()]: encountered a null reference --> $DIR/forbidden_slices.rs:18:1 | LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; @@ -20,7 +20,7 @@ LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type &[u32]: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/forbidden_slices.rs:22:1 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; @@ -31,7 +31,7 @@ LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; HEX_DUMP } -error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:26:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; @@ -42,7 +42,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } HEX_DUMP } -error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered a pointer, but expected an integer --> $DIR/forbidden_slices.rs:28:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; @@ -55,7 +55,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size HEX_DUMP } -error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean +error[E0080]: constructing invalid value of type &[bool]: at .[0], encountered 0x11, but expected a boolean --> $DIR/forbidden_slices.rs:30:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; @@ -66,7 +66,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) HEX_DUMP } -error[E0080]: constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u16]: at .[1], encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:33:1 | LL | pub static S7: &[u16] = unsafe { @@ -77,7 +77,7 @@ LL | pub static S7: &[u16] = unsafe { HEX_DUMP } -error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type &[u64]: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/forbidden_slices.rs:41:1 | LL | pub static S8: &[u64] = unsafe { @@ -88,7 +88,7 @@ LL | pub static S8: &[u64] = unsafe { HEX_DUMP } -error[E0080]: constructing invalid value: encountered a null reference +error[E0080]: constructing invalid value of type &[u32]: encountered a null reference --> $DIR/forbidden_slices.rs:48:1 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; @@ -111,7 +111,7 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer LL | from_ptr_range(ptr..ptr.add(2)) // errors inside libcore | ^^^^^^^^^^ evaluation of `R2` failed here -error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:57:1 | LL | pub static R4: &[u8] = unsafe { @@ -122,7 +122,7 @@ LL | pub static R4: &[u8] = unsafe { HEX_DUMP } -error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered a pointer, but expected an integer --> $DIR/forbidden_slices.rs:62:1 | LL | pub static R5: &[u8] = unsafe { @@ -135,7 +135,7 @@ LL | pub static R5: &[u8] = unsafe { HEX_DUMP } -error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean +error[E0080]: constructing invalid value of type &[bool]: at .[0], encountered 0x11, but expected a boolean --> $DIR/forbidden_slices.rs:67:1 | LL | pub static R6: &[bool] = unsafe { @@ -146,7 +146,7 @@ LL | pub static R6: &[bool] = unsafe { HEX_DUMP } -error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) +error[E0080]: constructing invalid value of type &[u16]: encountered an unaligned reference (required 2 byte alignment but found 1) --> $DIR/forbidden_slices.rs:72:1 | LL | pub static R7: &[u16] = unsafe { diff --git a/tests/ui/const-ptr/out_of_bounds_read.rs b/tests/ui/const-ptr/out_of_bounds_read.rs index b09978badde5..51accc657b81 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.rs +++ b/tests/ui/const-ptr/out_of_bounds_read.rs @@ -1,6 +1,6 @@ fn main() { use std::ptr; - +//@ ignore-parallel-frontend different alloc ids const DATA: [u32; 1] = [42]; const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) }; diff --git a/tests/ui/consts/array-literal-len-mismatch.stderr b/tests/ui/consts/array-literal-len-mismatch.stderr index 39b8a647324b..bf828ff5acf5 100644 --- a/tests/ui/consts/array-literal-len-mismatch.stderr +++ b/tests/ui/consts/array-literal-len-mismatch.stderr @@ -2,9 +2,15 @@ error[E0308]: mismatched types --> $DIR/array-literal-len-mismatch.rs:1:26 | LL | const NUMBERS: [u8; 3] = [10, 20]; - | - ^^^^^^^^ expected an array with a size of 3, found one with a size of 2 - | | - | help: consider specifying the actual array length: `2` + | ------- ^^^^^^^^ expected an array with a size of 3, found one with a size of 2 + | | + | expected because of the type of the constant + | +help: consider specifying the actual array length + | +LL - const NUMBERS: [u8; 3] = [10, 20]; +LL + const NUMBERS: [u8; 2] = [10, 20]; + | error: aborting due to 1 previous error diff --git a/tests/ui/consts/chained-constants-stackoverflow.rs b/tests/ui/consts/chained-constants-stackoverflow.rs index 0f0ce40a1edc..0775ea56bbe0 100644 --- a/tests/ui/consts/chained-constants-stackoverflow.rs +++ b/tests/ui/consts/chained-constants-stackoverflow.rs @@ -1,5 +1,5 @@ //@ run-pass - +//@ ignore-parallel-frontend queries overflow the depth limit // https://github.com/rust-lang/rust/issues/34997 pub const CST_1: u32 = 0; diff --git a/tests/ui/consts/const-array-oob-arith.rs b/tests/ui/consts/const-array-oob-arith.rs index 8e5c56e0ea82..97f8406a10f0 100644 --- a/tests/ui/consts/const-array-oob-arith.rs +++ b/tests/ui/consts/const-array-oob-arith.rs @@ -4,10 +4,12 @@ const BONG: [i32; (ARR[0] - 41) as usize] = [5]; const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; //~^ ERROR: mismatched types -//~| NOTE expected an array +//~| NOTE: expected an array +//~| NOTE: expected because const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; //~^ ERROR: mismatched types -//~| NOTE expected an array +//~| NOTE: expected an array +//~| NOTE: expected because fn main() { let _ = VAL; diff --git a/tests/ui/consts/const-array-oob-arith.stderr b/tests/ui/consts/const-array-oob-arith.stderr index d3299082aa14..0cb654237ab5 100644 --- a/tests/ui/consts/const-array-oob-arith.stderr +++ b/tests/ui/consts/const-array-oob-arith.stderr @@ -2,17 +2,29 @@ error[E0308]: mismatched types --> $DIR/const-array-oob-arith.rs:5:45 | LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; - | ---------------------- ^^^ expected an array with a size of 2, found one with a size of 1 - | | - | help: consider specifying the actual array length: `1` + | ----------------------------- ^^^ expected an array with a size of 2, found one with a size of 1 + | | + | expected because of the type of the constant + | +help: consider specifying the actual array length + | +LL - const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; +LL + const BLUB: [i32; 1] = [5]; + | error[E0308]: mismatched types - --> $DIR/const-array-oob-arith.rs:8:44 + --> $DIR/const-array-oob-arith.rs:9:44 | LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; - | ---------------------- ^^^^^^^ expected an array with a size of 1, found one with a size of 2 - | | - | help: consider specifying the actual array length: `2` + | ----------------------------- ^^^^^^^ expected an array with a size of 1, found one with a size of 2 + | | + | expected because of the type of the constant + | +help: consider specifying the actual array length + | +LL - const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; +LL + const BOO: [i32; 2] = [5, 99]; + | error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-bound.rs b/tests/ui/consts/const-bound.rs deleted file mode 100644 index 00a833ba3f79..000000000000 --- a/tests/ui/consts/const-bound.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -// Make sure const bounds work on things, and test that a few types -// are const. - - -fn foo(x: T) -> T { x } - -struct F { field: isize } - -pub fn main() { - /*foo(1); - foo("hi".to_string()); - foo(vec![1, 2, 3]); - foo(F{field: 42}); - foo((1, 2)); - foo(@1);*/ - foo(Box::new(1)); -} diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs index 7e3df92a2bf5..f30507858f20 100644 --- a/tests/ui/consts/const-compare-bytes-ub.rs +++ b/tests/ui/consts/const-compare-bytes-ub.rs @@ -1,5 +1,5 @@ //@ check-fail - +//@ ignore-parallel-frontend different alloc ids #![feature(core_intrinsics, const_cmp)] use std::intrinsics::compare_bytes; use std::mem::MaybeUninit; diff --git a/tests/ui/consts/const-enum-tuple.rs b/tests/ui/consts/const-enum-tuple.rs deleted file mode 100644 index fe6b54aa7935..000000000000 --- a/tests/ui/consts/const-enum-tuple.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -enum E { V16(u16), V32(u32) } -static C: (E, u16, u16) = (E::V16(0xDEAD), 0x600D, 0xBAD); - -pub fn main() { - let (_, n, _) = C; - assert!(n != 0xBAD); - assert_eq!(n, 0x600D); -} diff --git a/tests/ui/consts/const-enum-tuple2.rs b/tests/ui/consts/const-enum-tuple2.rs deleted file mode 100644 index 713209943d3e..000000000000 --- a/tests/ui/consts/const-enum-tuple2.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -enum E { V0, V16(u16) } -static C: (E, u16, u16) = (E::V0, 0x600D, 0xBAD); - -pub fn main() { - let (_, n, _) = C; - assert!(n != 0xBAD); - assert_eq!(n, 0x600D); -} diff --git a/tests/ui/consts/const-enum-tuplestruct2.rs b/tests/ui/consts/const-enum-tuplestruct2.rs deleted file mode 100644 index dc4453236952..000000000000 --- a/tests/ui/consts/const-enum-tuplestruct2.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -enum E { V0, V16(u16) } -struct S(E, u16, u16); -static C: S = S(E::V0, 0x600D, 0xBAD); - -pub fn main() { - let S(_, n, _) = C; - assert!(n != 0xBAD); - assert_eq!(n, 0x600D); -} diff --git a/tests/ui/consts/const-err-enum-discriminant.rs b/tests/ui/consts/const-err-enum-discriminant.rs index 556746005843..f6142707f922 100644 --- a/tests/ui/consts/const-err-enum-discriminant.rs +++ b/tests/ui/consts/const-err-enum-discriminant.rs @@ -1,5 +1,5 @@ //@ stderr-per-bitwidth - +//@ ignore-parallel-frontend different alloc ids #[derive(Copy, Clone)] union Foo { a: isize, diff --git a/tests/ui/consts/const-eval/array-len-mismatch-type.stderr b/tests/ui/consts/const-eval/array-len-mismatch-type.stderr index ce641f4a74b9..915fc8e394b3 100644 --- a/tests/ui/consts/const-eval/array-len-mismatch-type.stderr +++ b/tests/ui/consts/const-eval/array-len-mismatch-type.stderr @@ -4,6 +4,7 @@ error[E0308]: mismatched types LL | pub struct Data([[&'static str]; 5_i32]); | ^^^^^ expected `usize`, found `i32` | + = note: array length can only be `usize` help: change the type of the numeric literal from `i32` to `usize` | LL - pub struct Data([[&'static str]; 5_i32]); diff --git a/tests/ui/consts/const-eval/c-variadic-fail.rs b/tests/ui/consts/const-eval/c-variadic-fail.rs index b5a400a8bf25..2cf5d05cb248 100644 --- a/tests/ui/consts/const-eval/c-variadic-fail.rs +++ b/tests/ui/consts/const-eval/c-variadic-fail.rs @@ -1,5 +1,5 @@ //@ build-fail - +//@ ignore-parallel-frontend different alloc ids #![feature(c_variadic)] #![feature(const_c_variadic)] #![feature(const_trait_impl)] diff --git a/tests/ui/consts/const-eval/c-variadic-ignored-argument.rs b/tests/ui/consts/const-eval/c-variadic-ignored-argument.rs new file mode 100644 index 000000000000..fe700eea186e --- /dev/null +++ b/tests/ui/consts/const-eval/c-variadic-ignored-argument.rs @@ -0,0 +1,18 @@ +//@ build-pass +//@ compile-flags: --emit=obj +#![feature(c_variadic)] +#![feature(const_c_variadic)] +#![feature(const_destruct)] +#![crate_type = "lib"] + +// Regression test for when a c-variadic argument is `PassMode::Ignore`. The caller won't pass the +// argument, but the callee ABI does have the argument. Ensure that const-eval is able to handle +// this case without tripping any asserts. + +const unsafe extern "C" fn read_n(_: ...) {} + +unsafe fn read_too_many() { + const { read_n::<0>((), 1i32) } +} + +fn read_as() -> () {} diff --git a/tests/ui/consts/const-eval/const-eval-span.rs b/tests/ui/consts/const-eval/const-eval-span.rs index f1904c76b6c1..1846da22cd3d 100644 --- a/tests/ui/consts/const-eval/const-eval-span.rs +++ b/tests/ui/consts/const-eval/const-eval-span.rs @@ -7,8 +7,9 @@ enum E { V = CONSTANT, - //~^ ERROR mismatched types - //~| NOTE expected `isize`, found `S` + //~^ ERROR: mismatched types + //~| NOTE: expected `isize`, found `S` + //~| NOTE: enum variant discriminant } fn main() {} diff --git a/tests/ui/consts/const-eval/const-eval-span.stderr b/tests/ui/consts/const-eval/const-eval-span.stderr index ba11759a7106..ff17da5a04d7 100644 --- a/tests/ui/consts/const-eval/const-eval-span.stderr +++ b/tests/ui/consts/const-eval/const-eval-span.stderr @@ -3,6 +3,8 @@ error[E0308]: mismatched types | LL | V = CONSTANT, | ^^^^^^^^ expected `isize`, found `S` + | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs index 5720d6ea91ed..c6aae902c8bd 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs @@ -1,7 +1,7 @@ //@ only-x86_64 //@ stderr-per-bitwidth //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend different alloc ids #[repr(C)] union Nonsense { u: usize, diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 239bca51fc96..f8d6cc145fca 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &i32: at ., encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | LL | const BAR: &i32 = unsafe { diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index 3c6d66ac5b67..f7b652f7e43b 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &i32: at ., encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | LL | const BAR: &i32 = unsafe { diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs index c54115de2045..3ef18a5f4369 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -3,7 +3,7 @@ #![feature(core_intrinsics)] #![feature(const_heap)] use std::intrinsics; - +//@ ignore-parallel-frontend different alloc ids const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory // Make the pointer immutable to avoid errors related to mutable pointers in constants. &*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *const i32) diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs index de9fc5d09213..a377ee35d92b 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] #![feature(const_heap)] - +//@ ignore-parallel-frontend different alloc ids // Strip out raw byte dumps to make comparison platform-independent: //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index 152eeababc51..094292446409 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered a dangling reference (use-after-free) +error[E0080]: constructing invalid value of type &u8: encountered a dangling reference (use-after-free) --> $DIR/dealloc_intrinsic_dangling.rs:11:1 | LL | const _X: &'static u8 = unsafe { diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs index 5b7cd039b9ba..bc9227b31f80 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] #![feature(const_heap)] - +//@ ignore-parallel-frontend different alloc ids use std::intrinsics; const _X: () = unsafe { diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs index 75c3601f2166..8800188e9036 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] #![feature(const_heap)] - +//@ ignore-parallel-frontend different alloc ids use std::intrinsics; const _X: () = unsafe { diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.rs b/tests/ui/consts/const-eval/heap/make-global-dangling.rs index f4c5929bc416..12b9ca7a6980 100644 --- a/tests/ui/consts/const-eval/heap/make-global-dangling.rs +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.rs @@ -1,5 +1,5 @@ // Ensure that we can't call `const_make_global` on dangling pointers. - +//@ ignore-parallel-frontend different alloc ids #![feature(core_intrinsics)] #![feature(const_heap)] diff --git a/tests/ui/consts/const-eval/heap/make-global-other.rs b/tests/ui/consts/const-eval/heap/make-global-other.rs index 4e2a59de13ed..9250f7a55be4 100644 --- a/tests/ui/consts/const-eval/heap/make-global-other.rs +++ b/tests/ui/consts/const-eval/heap/make-global-other.rs @@ -1,5 +1,5 @@ // Ensure that we can't call `const_make_global` on pointers not in the current interpreter. - +//@ ignore-parallel-frontend different alloc ids #![feature(core_intrinsics)] #![feature(const_heap)] diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.rs b/tests/ui/consts/const-eval/heap/make-global-twice.rs index 0cd617cea3e6..a4d01170812c 100644 --- a/tests/ui/consts/const-eval/heap/make-global-twice.rs +++ b/tests/ui/consts/const-eval/heap/make-global-twice.rs @@ -1,5 +1,5 @@ // Ensure that we can't call `const_make_global` twice. - +//@ ignore-parallel-frontend different alloc ids #![feature(core_intrinsics)] #![feature(const_heap)] diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs index bea2a5949c26..c405f7316048 100644 --- a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs @@ -2,7 +2,7 @@ #![feature(core_intrinsics)] #![feature(const_heap)] use std::intrinsics; - +//@ ignore-parallel-frontend different alloc ids const A: &u8 = unsafe { let ptr = intrinsics::const_allocate(1, 1); *ptr = 1; diff --git a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs index 6777bee050a1..dbe507e3cd13 100644 --- a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs +++ b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs @@ -1,5 +1,5 @@ //@ build-fail - +//@ ignore-parallel-frontend post-monomorphization errors // Regression test for #66975 #![warn(unconditional_panic)] #![feature(never_type)] diff --git a/tests/ui/consts/const-eval/issue-49296.rs b/tests/ui/consts/const-eval/issue-49296.rs index a427b642899a..35797fbf248b 100644 --- a/tests/ui/consts/const-eval/issue-49296.rs +++ b/tests/ui/consts/const-eval/issue-49296.rs @@ -1,5 +1,5 @@ // issue-49296: Unsafe shenigans in constants can result in missing errors - +//@ ignore-parallel-frontend different alloc ids use std::mem::transmute; const fn wat(x: u64) -> &'static u64 { diff --git a/tests/ui/consts/const-eval/issue-50814-2.rs b/tests/ui/consts/const-eval/issue-50814-2.rs index 1b917a0916da..34a200e2887b 100644 --- a/tests/ui/consts/const-eval/issue-50814-2.rs +++ b/tests/ui/consts/const-eval/issue-50814-2.rs @@ -2,7 +2,7 @@ //@ revisions: normal mir-opt //@ [mir-opt]compile-flags: -Zmir-opt-level=4 //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend post-monomorphization errors trait C { const BOO: usize; } diff --git a/tests/ui/consts/const-eval/issue-50814.rs b/tests/ui/consts/const-eval/issue-50814.rs index 011f065ad814..3901a2c0c931 100644 --- a/tests/ui/consts/const-eval/issue-50814.rs +++ b/tests/ui/consts/const-eval/issue-50814.rs @@ -1,6 +1,6 @@ //@ build-fail //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend post-monomorphization errors trait Unsigned { const MAX: u8; } diff --git a/tests/ui/consts/const-eval/ptr_fragments_mixed.rs b/tests/ui/consts/const-eval/ptr_fragments_mixed.rs index 24169eac4780..471d46405596 100644 --- a/tests/ui/consts/const-eval/ptr_fragments_mixed.rs +++ b/tests/ui/consts/const-eval/ptr_fragments_mixed.rs @@ -1,6 +1,6 @@ //! This mixes fragments from different pointers, in a way that we should not accept. //! See . - +//@ ignore-parallel-frontend different alloc ids static A: u8 = 123; static B: u8 = 123; diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index be3b539b269a..65f815f80c6b 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .: encountered 0x00000001, but expected a valid enum tag +error[E0080]: constructing invalid value of type Enum: at ., encountered 0x00000001, but expected a valid enum tag --> $DIR/raw-bytes.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; @@ -9,7 +9,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; 01 00 00 00 │ .... } -error[E0080]: constructing invalid value at .: encountered 0x00000000, but expected a valid enum tag +error[E0080]: constructing invalid value of type Enum2: at ., encountered 0x00000000, but expected a valid enum tag --> $DIR/raw-bytes.rs:31:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; @@ -20,7 +20,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; 00 00 00 00 │ .... } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type UninhDiscriminant: at ., encountered an uninhabited enum variant --> $DIR/raw-bytes.rs:45:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; @@ -31,7 +31,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute 01 │ . } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type UninhDiscriminant: at ., encountered 0x03, but expected a valid enum tag --> $DIR/raw-bytes.rs:47:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; @@ -42,7 +42,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute 03 │ . } -error[E0080]: constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) +error[E0080]: constructing invalid value of type Option<(char, char)>: at ..0.1, encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) --> $DIR/raw-bytes.rs:53:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); @@ -53,7 +53,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran 78 00 00 00 ff ff ff ff │ x....... } -error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonNull: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:58:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; @@ -64,7 +64,7 @@ LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; 00 00 00 00 │ .... } -error[E0080]: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonZero: at .0.0, encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:61:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; @@ -75,7 +75,7 @@ LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; 00 │ . } -error[E0080]: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonZero: at .0.0, encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:63:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; @@ -86,7 +86,7 @@ LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; 00 00 00 00 │ .... } -error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 +error[E0080]: constructing invalid value of type RestrictedRange1: encountered 42, but expected something in the range 10..=30 --> $DIR/raw-bytes.rs:69:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; @@ -97,7 +97,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; 2a 00 00 00 │ *... } -error[E0080]: constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 +error[E0080]: constructing invalid value of type RestrictedRange2: encountered 20, but expected something less or equal to 10, or greater or equal to 30 --> $DIR/raw-bytes.rs:75:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; @@ -108,7 +108,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; 14 00 00 00 │ .... } -error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonNull: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:78:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { @@ -119,7 +119,7 @@ LL | const NULL_FAT_PTR: NonNull = unsafe { 00 00 00 00 ╾ALLOC_ID╼ │ ....╾──╼ } -error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) +error[E0080]: constructing invalid value of type &u16: encountered an unaligned reference (required 2 byte alignment but found 1) --> $DIR/raw-bytes.rs:85:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; @@ -130,7 +130,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; ╾ALLOC_ID╼ │ ╾──╼ } -error[E0080]: constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) +error[E0080]: constructing invalid value of type Box: encountered an unaligned box (required 2 byte alignment but found 1) --> $DIR/raw-bytes.rs:88:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; @@ -141,7 +141,7 @@ LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; ╾ALLOC_ID╼ │ ╾──╼ } -error[E0080]: constructing invalid value: encountered a null reference +error[E0080]: constructing invalid value of type &u16: encountered a null reference --> $DIR/raw-bytes.rs:91:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; @@ -152,7 +152,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; 00 00 00 00 │ .... } -error[E0080]: constructing invalid value: encountered a null box +error[E0080]: constructing invalid value of type Box: encountered a null box --> $DIR/raw-bytes.rs:94:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; @@ -163,7 +163,7 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; 00 00 00 00 │ .... } -error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) +error[E0080]: constructing invalid value of type &u8: encountered a dangling reference (0x539[noalloc] has no provenance) --> $DIR/raw-bytes.rs:97:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; @@ -174,7 +174,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; 39 05 00 00 │ 9... } -error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) +error[E0080]: constructing invalid value of type Box: encountered a dangling box (0x539[noalloc] has no provenance) --> $DIR/raw-bytes.rs:100:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; @@ -185,7 +185,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; 39 05 00 00 │ 9... } -error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered null pointer, but expected a function pointer --> $DIR/raw-bytes.rs:103:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; @@ -196,7 +196,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; 00 00 00 00 │ .... } -error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered 0xd[noalloc], but expected a function pointer --> $DIR/raw-bytes.rs:105:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; @@ -207,7 +207,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; 0d 00 00 00 │ .... } -error[E0080]: constructing invalid value: encountered ALLOC3, but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered ALLOC3, but expected a function pointer --> $DIR/raw-bytes.rs:107:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; @@ -218,7 +218,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; ╾ALLOC_ID╼ │ ╾──╼ } -error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type Bar +error[E0080]: constructing invalid value of type &Bar: encountered a reference pointing to uninhabited type Bar --> $DIR/raw-bytes.rs:113:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; @@ -229,7 +229,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; 01 00 00 00 │ .... } -error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type &str: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/raw-bytes.rs:137:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -240,7 +240,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type (&str,): at .0, encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/raw-bytes.rs:139:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); @@ -251,7 +251,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼.... } -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &MyStr: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/raw-bytes.rs:141:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; @@ -262,7 +262,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼.... } -error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected a string +error[E0080]: constructing invalid value of type &str: at ., encountered uninitialized memory, but expected a string --> $DIR/raw-bytes.rs:144:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; @@ -273,7 +273,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at ..0: encountered uninitialized memory, but expected a string +error[E0080]: constructing invalid value of type &MyStr: at ..0, encountered uninitialized memory, but expected a string --> $DIR/raw-bytes.rs:146:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; @@ -284,7 +284,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at ..0: encountered a pointer, but expected a string +error[E0080]: constructing invalid value of type &MyStr: at ..0, encountered a pointer, but expected a string --> $DIR/raw-bytes.rs:148:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; @@ -297,7 +297,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type &[u8]: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/raw-bytes.rs:152:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -308,7 +308,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &[u32]: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/raw-bytes.rs:154:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; @@ -319,7 +319,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is ╾ALLOC_ID╼ ff ff ff 7f │ ╾──╼.... } -error[E0080]: constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type Box<[u8]>: encountered a dangling box (going beyond the bounds of its allocation) --> $DIR/raw-bytes.rs:157:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -330,7 +330,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .[0]: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &[bool; 1]: at .[0], encountered 0x03, but expected a boolean --> $DIR/raw-bytes.rs:160:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; @@ -347,7 +347,7 @@ note: erroneous constant encountered LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value at ..0: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &MySlice<[bool; 1]>: at ..0, encountered 0x03, but expected a boolean --> $DIR/raw-bytes.rs:164:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); @@ -364,7 +364,7 @@ note: erroneous constant encountered LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &MySlice<[bool; 1]>: at ..1[0], encountered 0x03, but expected a boolean --> $DIR/raw-bytes.rs:167:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); @@ -381,7 +381,7 @@ note: erroneous constant encountered LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC17, but expected a vtable pointer --> $DIR/raw-bytes.rs:171:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; @@ -392,7 +392,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC19, but expected a vtable pointer --> $DIR/raw-bytes.rs:174:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; @@ -403,7 +403,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered 0x4[noalloc], but expected a vtable pointer --> $DIR/raw-bytes.rs:177:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; @@ -414,7 +414,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC22, but expected a vtable pointer --> $DIR/raw-bytes.rs:179:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; @@ -425,7 +425,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value at ..: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &dyn Trait: at .., encountered 0x03, but expected a boolean --> $DIR/raw-bytes.rs:182:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; @@ -436,7 +436,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer +error[E0080]: constructing invalid value of type *const dyn Trait: encountered null pointer, but expected a vtable pointer --> $DIR/raw-bytes.rs:185:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; @@ -447,7 +447,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value: encountered ALLOC27, but expected a vtable pointer +error[E0080]: constructing invalid value of type *const dyn Trait: encountered ALLOC27, but expected a vtable pointer --> $DIR/raw-bytes.rs:187:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; @@ -458,7 +458,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] +error[E0080]: constructing invalid value of type &[!; 1]: encountered a reference pointing to uninhabited type [!; 1] --> $DIR/raw-bytes.rs:191:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; @@ -469,7 +469,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; 01 00 00 00 │ .... } -error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` +error[E0080]: constructing invalid value of type &[!]: at .[0], encountered a value of the never type `!` --> $DIR/raw-bytes.rs:192:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; @@ -480,7 +480,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; 01 00 00 00 01 00 00 00 │ ........ } -error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` +error[E0080]: constructing invalid value of type &[!]: at .[0], encountered a value of the never type `!` --> $DIR/raw-bytes.rs:193:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; @@ -491,7 +491,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; 01 00 00 00 2a 00 00 00 │ ....*... } -error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered uninitialized memory, but expected an integer --> $DIR/raw-bytes.rs:196:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; @@ -502,7 +502,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered a pointer, but expected an integer --> $DIR/raw-bytes.rs:199:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; @@ -515,7 +515,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean +error[E0080]: constructing invalid value of type &[bool]: at .[0], encountered 0x11, but expected a boolean --> $DIR/raw-bytes.rs:202:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; @@ -526,7 +526,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u16]: at .[1], encountered uninitialized memory, but expected an integer --> $DIR/raw-bytes.rs:206:1 | LL | pub static S7: &[u16] = unsafe { @@ -537,7 +537,7 @@ LL | pub static S7: &[u16] = unsafe { ╾ALLOC_ID+0x2╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered uninitialized memory, but expected an integer --> $DIR/raw-bytes.rs:213:1 | LL | pub static R4: &[u8] = unsafe { @@ -548,7 +548,7 @@ LL | pub static R4: &[u8] = unsafe { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered a pointer, but expected an integer --> $DIR/raw-bytes.rs:218:1 | LL | pub static R5: &[u8] = unsafe { @@ -561,7 +561,7 @@ LL | pub static R5: &[u8] = unsafe { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean +error[E0080]: constructing invalid value of type &[bool]: at .[0], encountered 0x11, but expected a boolean --> $DIR/raw-bytes.rs:223:1 | LL | pub static R6: &[bool] = unsafe { diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 9950ac726ca7..d117de2f87be 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .: encountered 0x0000000000000001, but expected a valid enum tag +error[E0080]: constructing invalid value of type Enum: at ., encountered 0x0000000000000001, but expected a valid enum tag --> $DIR/raw-bytes.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; @@ -9,7 +9,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; 01 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value at .: encountered 0x0000000000000000, but expected a valid enum tag +error[E0080]: constructing invalid value of type Enum2: at ., encountered 0x0000000000000000, but expected a valid enum tag --> $DIR/raw-bytes.rs:31:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; @@ -20,7 +20,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type UninhDiscriminant: at ., encountered an uninhabited enum variant --> $DIR/raw-bytes.rs:45:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; @@ -31,7 +31,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute 01 │ . } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type UninhDiscriminant: at ., encountered 0x03, but expected a valid enum tag --> $DIR/raw-bytes.rs:47:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; @@ -42,7 +42,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute 03 │ . } -error[E0080]: constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) +error[E0080]: constructing invalid value of type Option<(char, char)>: at ..0.1, encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) --> $DIR/raw-bytes.rs:53:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); @@ -53,7 +53,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran 78 00 00 00 ff ff ff ff │ x....... } -error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonNull: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:58:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; @@ -64,7 +64,7 @@ LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonZero: at .0.0, encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:61:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; @@ -75,7 +75,7 @@ LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; 00 │ . } -error[E0080]: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonZero: at .0.0, encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:63:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; @@ -86,7 +86,7 @@ LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 +error[E0080]: constructing invalid value of type RestrictedRange1: encountered 42, but expected something in the range 10..=30 --> $DIR/raw-bytes.rs:69:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; @@ -97,7 +97,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; 2a 00 00 00 │ *... } -error[E0080]: constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 +error[E0080]: constructing invalid value of type RestrictedRange2: encountered 20, but expected something less or equal to 10, or greater or equal to 30 --> $DIR/raw-bytes.rs:75:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; @@ -108,7 +108,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; 14 00 00 00 │ .... } -error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonNull: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:78:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { @@ -119,7 +119,7 @@ LL | const NULL_FAT_PTR: NonNull = unsafe { 00 00 00 00 00 00 00 00 ╾ALLOC_ID╼ │ ........╾──────╼ } -error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) +error[E0080]: constructing invalid value of type &u16: encountered an unaligned reference (required 2 byte alignment but found 1) --> $DIR/raw-bytes.rs:85:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; @@ -130,7 +130,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; ╾ALLOC_ID╼ │ ╾──────╼ } -error[E0080]: constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) +error[E0080]: constructing invalid value of type Box: encountered an unaligned box (required 2 byte alignment but found 1) --> $DIR/raw-bytes.rs:88:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; @@ -141,7 +141,7 @@ LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; ╾ALLOC_ID╼ │ ╾──────╼ } -error[E0080]: constructing invalid value: encountered a null reference +error[E0080]: constructing invalid value of type &u16: encountered a null reference --> $DIR/raw-bytes.rs:91:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; @@ -152,7 +152,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value: encountered a null box +error[E0080]: constructing invalid value of type Box: encountered a null box --> $DIR/raw-bytes.rs:94:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; @@ -163,7 +163,7 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) +error[E0080]: constructing invalid value of type &u8: encountered a dangling reference (0x539[noalloc] has no provenance) --> $DIR/raw-bytes.rs:97:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; @@ -174,7 +174,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; 39 05 00 00 00 00 00 00 │ 9....... } -error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) +error[E0080]: constructing invalid value of type Box: encountered a dangling box (0x539[noalloc] has no provenance) --> $DIR/raw-bytes.rs:100:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; @@ -185,7 +185,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; 39 05 00 00 00 00 00 00 │ 9....... } -error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered null pointer, but expected a function pointer --> $DIR/raw-bytes.rs:103:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; @@ -196,7 +196,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered 0xd[noalloc], but expected a function pointer --> $DIR/raw-bytes.rs:105:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; @@ -207,7 +207,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; 0d 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value: encountered ALLOC3, but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered ALLOC3, but expected a function pointer --> $DIR/raw-bytes.rs:107:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; @@ -218,7 +218,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; ╾ALLOC_ID╼ │ ╾──────╼ } -error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type Bar +error[E0080]: constructing invalid value of type &Bar: encountered a reference pointing to uninhabited type Bar --> $DIR/raw-bytes.rs:113:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; @@ -229,7 +229,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; 01 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type &str: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/raw-bytes.rs:137:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -240,7 +240,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type (&str,): at .0, encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/raw-bytes.rs:139:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); @@ -251,7 +251,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &MyStr: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/raw-bytes.rs:141:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; @@ -262,7 +262,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } -error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected a string +error[E0080]: constructing invalid value of type &str: at ., encountered uninitialized memory, but expected a string --> $DIR/raw-bytes.rs:144:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; @@ -273,7 +273,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at ..0: encountered uninitialized memory, but expected a string +error[E0080]: constructing invalid value of type &MyStr: at ..0, encountered uninitialized memory, but expected a string --> $DIR/raw-bytes.rs:146:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; @@ -284,7 +284,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at ..0: encountered a pointer, but expected a string +error[E0080]: constructing invalid value of type &MyStr: at ..0, encountered a pointer, but expected a string --> $DIR/raw-bytes.rs:148:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; @@ -297,7 +297,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type &[u8]: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/raw-bytes.rs:152:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -308,7 +308,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &[u32]: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/raw-bytes.rs:154:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; @@ -319,7 +319,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........ } -error[E0080]: constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type Box<[u8]>: encountered a dangling box (going beyond the bounds of its allocation) --> $DIR/raw-bytes.rs:157:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -330,7 +330,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .[0]: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &[bool; 1]: at .[0], encountered 0x03, but expected a boolean --> $DIR/raw-bytes.rs:160:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; @@ -347,7 +347,7 @@ note: erroneous constant encountered LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value at ..0: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &MySlice<[bool; 1]>: at ..0, encountered 0x03, but expected a boolean --> $DIR/raw-bytes.rs:164:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); @@ -364,7 +364,7 @@ note: erroneous constant encountered LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &MySlice<[bool; 1]>: at ..1[0], encountered 0x03, but expected a boolean --> $DIR/raw-bytes.rs:167:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); @@ -381,7 +381,7 @@ note: erroneous constant encountered LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC17, but expected a vtable pointer --> $DIR/raw-bytes.rs:171:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; @@ -392,7 +392,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC19, but expected a vtable pointer --> $DIR/raw-bytes.rs:174:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; @@ -403,7 +403,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered 0x4[noalloc], but expected a vtable pointer --> $DIR/raw-bytes.rs:177:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; @@ -414,7 +414,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC22, but expected a vtable pointer --> $DIR/raw-bytes.rs:179:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; @@ -425,7 +425,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value at ..: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &dyn Trait: at .., encountered 0x03, but expected a boolean --> $DIR/raw-bytes.rs:182:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; @@ -436,7 +436,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer +error[E0080]: constructing invalid value of type *const dyn Trait: encountered null pointer, but expected a vtable pointer --> $DIR/raw-bytes.rs:185:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; @@ -447,7 +447,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value: encountered ALLOC27, but expected a vtable pointer +error[E0080]: constructing invalid value of type *const dyn Trait: encountered ALLOC27, but expected a vtable pointer --> $DIR/raw-bytes.rs:187:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; @@ -458,7 +458,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] +error[E0080]: constructing invalid value of type &[!; 1]: encountered a reference pointing to uninhabited type [!; 1] --> $DIR/raw-bytes.rs:191:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; @@ -469,7 +469,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; 01 00 00 00 00 00 00 00 │ ........ } -error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` +error[E0080]: constructing invalid value of type &[!]: at .[0], encountered a value of the never type `!` --> $DIR/raw-bytes.rs:192:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; @@ -480,7 +480,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ } -error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` +error[E0080]: constructing invalid value of type &[!]: at .[0], encountered a value of the never type `!` --> $DIR/raw-bytes.rs:193:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; @@ -491,7 +491,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; 01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*....... } -error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered uninitialized memory, but expected an integer --> $DIR/raw-bytes.rs:196:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; @@ -502,7 +502,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered a pointer, but expected an integer --> $DIR/raw-bytes.rs:199:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; @@ -515,7 +515,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean +error[E0080]: constructing invalid value of type &[bool]: at .[0], encountered 0x11, but expected a boolean --> $DIR/raw-bytes.rs:202:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; @@ -526,7 +526,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u16]: at .[1], encountered uninitialized memory, but expected an integer --> $DIR/raw-bytes.rs:206:1 | LL | pub static S7: &[u16] = unsafe { @@ -537,7 +537,7 @@ LL | pub static S7: &[u16] = unsafe { ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered uninitialized memory, but expected an integer --> $DIR/raw-bytes.rs:213:1 | LL | pub static R4: &[u8] = unsafe { @@ -548,7 +548,7 @@ LL | pub static R4: &[u8] = unsafe { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type &[u8]: at .[0], encountered a pointer, but expected an integer --> $DIR/raw-bytes.rs:218:1 | LL | pub static R5: &[u8] = unsafe { @@ -561,7 +561,7 @@ LL | pub static R5: &[u8] = unsafe { ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean +error[E0080]: constructing invalid value of type &[bool]: at .[0], encountered 0x11, but expected a boolean --> $DIR/raw-bytes.rs:223:1 | LL | pub static R6: &[bool] = unsafe { diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index 199f4d1ea0e1..d63e1d5b062c 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -3,7 +3,7 @@ // ignore-tidy-linelength //@ normalize-stderr: "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼" -> "╾ALLOC_ID$1╼" //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend different alloc ids #![allow(invalid_value, unnecessary_transmutes)] #![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] @@ -83,10 +83,10 @@ enum UninhDiscriminant { }; const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; -//~^ ERROR constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) +//~^ ERROR encountered an unaligned reference (required 2 byte alignment but found 1) const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; -//~^ ERROR constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) +//~^ ERROR encountered an unaligned box (required 2 byte alignment but found 1) const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR constructing invalid value diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index df7bc2fe4fb1..0998617b5b71 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -4,7 +4,7 @@ let _val = *ptr; //~NOTE: failed here //~^ERROR: based on pointer with alignment 1, but alignment 4 is required }; - +//@ ignore-parallel-frontend different alloc ids const MISALIGNED_STORE: () = unsafe { let mut mem = [0u32; 8]; let ptr = mem.as_mut_ptr().byte_add(1); diff --git a/tests/ui/consts/const-eval/read_partial_ptr.rs b/tests/ui/consts/const-eval/read_partial_ptr.rs index bccef9c0bc6c..5248f92a92db 100644 --- a/tests/ui/consts/const-eval/read_partial_ptr.rs +++ b/tests/ui/consts/const-eval/read_partial_ptr.rs @@ -1,5 +1,5 @@ //! Ensure we error when trying to load from a pointer whose provenance has been messed with. - +//@ ignore-parallel-frontend different alloc ids const PARTIAL_OVERWRITE: () = { let mut p = &42; // Overwrite one byte with a no-provenance value. diff --git a/tests/ui/consts/const-eval/transmute-const.stderr b/tests/ui/consts/const-eval/transmute-const.stderr index 53665c176a76..3b064c981f28 100644 --- a/tests/ui/consts/const-eval/transmute-const.stderr +++ b/tests/ui/consts/const-eval/transmute-const.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type bool: encountered 0x03, but expected a boolean --> $DIR/transmute-const.rs:4:1 | LL | static FOO: bool = unsafe { mem::transmute(3u8) }; diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.rs b/tests/ui/consts/const-eval/ub-enum-overwrite.rs index 005f3c78c1d7..a1bd49f53ace 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.rs +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.rs @@ -2,7 +2,7 @@ enum E { A(u8), B, } - +//@ ignore-parallel-frontend different alloc ids const _: u8 = { let mut e = E::A(1); let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() }; diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index 9c78bb6efed7..61ab3581e347 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -4,7 +4,7 @@ //@ normalize-stderr: "0x0+" -> "0x0" //@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1" //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend different alloc ids #![feature(never_type)] #![allow(invalid_value, unnecessary_transmutes)] @@ -83,7 +83,7 @@ enum UninhDiscriminant { const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; //~^ ERROR uninhabited enum variant const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; -//~^ ERROR uninhabited enum variant +//~^ ERROR expected a valid enum tag // # other diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 1efd93832291..a5ac10c7922c 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .: encountered 0x01, but expected a valid enum tag +error[E0080]: constructing invalid value of type Enum: at ., encountered 0x01, but expected a valid enum tag --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; @@ -27,7 +27,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value at .: encountered 0x0, but expected a valid enum tag +error[E0080]: constructing invalid value of type Enum2: at ., encountered 0x0, but expected a valid enum tag --> $DIR/ub-enum.rs:48:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; @@ -75,7 +75,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type UninhDiscriminant: at ., encountered an uninhabited enum variant --> $DIR/ub-enum.rs:83:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; @@ -86,7 +86,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute HEX_DUMP } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type UninhDiscriminant: at ., encountered 0x03, but expected a valid enum tag --> $DIR/ub-enum.rs:85:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; @@ -97,7 +97,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute HEX_DUMP } -error[E0080]: constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) +error[E0080]: constructing invalid value of type Option<(char, char)>: at ..0.1, encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) --> $DIR/ub-enum.rs:93:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); @@ -108,13 +108,13 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran HEX_DUMP } -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type Result<(i32, Never), (i32, !)>: at ., encountered an uninhabited enum variant --> $DIR/ub-enum.rs:98:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; | ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA1` failed here -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type Result<(i32, !), (i32, Never)>: at ., encountered an uninhabited enum variant --> $DIR/ub-enum.rs:100:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index 1e4d425d78ec..2d2d97da9787 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered ALLOC1, but expected a vtable pointer +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC1, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:18:1 | LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = @@ -9,7 +9,7 @@ LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value: encountered ALLOC3, but expected a vtable pointer +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC3, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:22:1 | LL | const INVALID_VTABLE_SIZE: &dyn Trait = @@ -20,7 +20,7 @@ LL | const INVALID_VTABLE_SIZE: &dyn Trait = ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC5, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:31:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = @@ -31,7 +31,7 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC7, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:35:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = @@ -42,7 +42,7 @@ LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC9, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:40:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = @@ -53,7 +53,7 @@ LL | const INVALID_VTABLE_UB: W<&dyn Trait> = ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──╼╾──╼ } -error[E0080]: constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type Wide<'_>: at .1, encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/ub-incorrect-vtable.rs:86:1 | LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index a068991f3242..4c8a1802317b 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered ALLOC1, but expected a vtable pointer +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC1, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:18:1 | LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = @@ -9,7 +9,7 @@ LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value: encountered ALLOC3, but expected a vtable pointer +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC3, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:22:1 | LL | const INVALID_VTABLE_SIZE: &dyn Trait = @@ -20,7 +20,7 @@ LL | const INVALID_VTABLE_SIZE: &dyn Trait = ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC5, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:31:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = @@ -31,7 +31,7 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC7, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:35:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = @@ -42,7 +42,7 @@ LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC9, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:40:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = @@ -53,7 +53,7 @@ LL | const INVALID_VTABLE_UB: W<&dyn Trait> = ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──────╼╾──────╼ } -error[E0080]: constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type Wide<'_>: at .1, encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/ub-incorrect-vtable.rs:86:1 | LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs index 4185b0261b29..09129012e083 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -12,7 +12,7 @@ //@ stderr-per-bitwidth //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend different alloc ids trait Trait {} const INVALID_VTABLE_ALIGNMENT: &dyn Trait = diff --git a/tests/ui/consts/const-eval/ub-int-array.rs b/tests/ui/consts/const-eval/ub-int-array.rs index eebbccaa7c17..151019c15083 100644 --- a/tests/ui/consts/const-eval/ub-int-array.rs +++ b/tests/ui/consts/const-eval/ub-int-array.rs @@ -18,7 +18,7 @@ const fn new(t: T) -> Self { } const UNINIT_INT_0: [u32; 3] = unsafe { - //~^ ERROR invalid value at [0] + //~^ ERROR invalid value of type [u32; 3]: at [0] mem::transmute([ MaybeUninit { uninit: () }, // Constants chosen to achieve endianness-independent hex dump. @@ -27,7 +27,7 @@ const fn new(t: T) -> Self { ]) }; const UNINIT_INT_1: [u32; 3] = unsafe { - //~^ ERROR invalid value at [1] + //~^ ERROR invalid value of type [u32; 3]: at [1] mem::transmute([ MaybeUninit::new(0u8), MaybeUninit::new(0u8), @@ -44,7 +44,7 @@ const fn new(t: T) -> Self { ]) }; const UNINIT_INT_2: [u32; 3] = unsafe { - //~^ ERROR invalid value at [2] + //~^ ERROR invalid value of type [u32; 3]: at [2] mem::transmute([ MaybeUninit::new(0u8), MaybeUninit::new(0u8), diff --git a/tests/ui/consts/const-eval/ub-int-array.stderr b/tests/ui/consts/const-eval/ub-int-array.stderr index 065bfd2c304a..253358fc2a59 100644 --- a/tests/ui/consts/const-eval/ub-int-array.stderr +++ b/tests/ui/consts/const-eval/ub-int-array.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at [0]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type [u32; 3]: at [0], encountered uninitialized memory, but expected an integer --> $DIR/ub-int-array.rs:20:1 | LL | const UNINIT_INT_0: [u32; 3] = unsafe { @@ -9,7 +9,7 @@ LL | const UNINIT_INT_0: [u32; 3] = unsafe { __ __ __ __ 11 11 11 11 22 22 22 22 │ ░░░░...."""" } -error[E0080]: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type [u32; 3]: at [1], encountered uninitialized memory, but expected an integer --> $DIR/ub-int-array.rs:29:1 | LL | const UNINIT_INT_1: [u32; 3] = unsafe { @@ -20,7 +20,7 @@ LL | const UNINIT_INT_1: [u32; 3] = unsafe { 00 00 00 00 01 __ 01 01 02 02 __ 02 │ .....░....░. } -error[E0080]: constructing invalid value at [2]: encountered uninitialized memory, but expected an integer +error[E0080]: constructing invalid value of type [u32; 3]: at [2], encountered uninitialized memory, but expected an integer --> $DIR/ub-int-array.rs:46:1 | LL | const UNINIT_INT_2: [u32; 3] = unsafe { diff --git a/tests/ui/consts/const-eval/ub-nonnull.rs b/tests/ui/consts/const-eval/ub-nonnull.rs index 851f3996cd10..daa4c40f98a9 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.rs +++ b/tests/ui/consts/const-eval/ub-nonnull.rs @@ -2,7 +2,7 @@ //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend different alloc ids #![allow(invalid_value)] // make sure we cannot allow away the errors tested here #![feature(rustc_attrs, ptr_metadata)] diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index be5c6f77a087..8f1838594407 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonNull: encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:16:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; @@ -15,7 +15,7 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer LL | let out_of_bounds_ptr = &ptr[255]; | ^^^^^^^^^ evaluation of `OUT_OF_BOUNDS_PTR` failed here -error[E0080]: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonZero: at .0.0, encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:26:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; @@ -26,7 +26,7 @@ LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; HEX_DUMP } -error[E0080]: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonZero: at .0.0, encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:28:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; @@ -47,7 +47,7 @@ LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; __ │ ░ } -error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 +error[E0080]: constructing invalid value of type RestrictedRange1: encountered 42, but expected something in the range 10..=30 --> $DIR/ub-nonnull.rs:44:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; @@ -58,7 +58,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 +error[E0080]: constructing invalid value of type RestrictedRange2: encountered 20, but expected something less or equal to 10, or greater or equal to 30 --> $DIR/ub-nonnull.rs:50:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; @@ -69,7 +69,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type NonNull: encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:53:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { @@ -80,7 +80,7 @@ LL | const NULL_FAT_PTR: NonNull = unsafe { HEX_DUMP } -error[E0080]: constructing invalid value: encountered a maybe-null pointer, but expected something that is definitely non-zero +error[E0080]: constructing invalid value of type NonNull<()>: encountered a maybe-null pointer, but expected something that is definitely non-zero --> $DIR/ub-nonnull.rs:61:1 | LL | const MAYBE_NULL_PTR: NonNull<()> = unsafe { mem::transmute((&raw const S).wrapping_add(4)) }; diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs index a5fdde1f9a4e..5cc327797a13 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.rs +++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs @@ -6,7 +6,7 @@ //@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1" #![feature(rustc_attrs)] #![allow(invalid_value)] - +//@ ignore-parallel-frontend different alloc ids use std::mem; #[repr(C)] @@ -16,10 +16,10 @@ union MaybeUninit { } const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; -//~^ ERROR constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) +//~^ ERROR encountered an unaligned reference (required 2 byte alignment but found 1) const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; -//~^ ERROR constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) +//~^ ERROR encountered an unaligned box (required 2 byte alignment but found 1) const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR invalid value diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index 349a98f11be4..17ddea05e93f 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) +error[E0080]: constructing invalid value of type &u16: encountered an unaligned reference (required 2 byte alignment but found 1) --> $DIR/ub-ref-ptr.rs:18:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; @@ -9,7 +9,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) +error[E0080]: constructing invalid value of type Box: encountered an unaligned box (required 2 byte alignment but found 1) --> $DIR/ub-ref-ptr.rs:21:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; @@ -20,7 +20,7 @@ LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered a null reference +error[E0080]: constructing invalid value of type &u16: encountered a null reference --> $DIR/ub-ref-ptr.rs:24:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; @@ -31,7 +31,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered a null box +error[E0080]: constructing invalid value of type Box: encountered a null box --> $DIR/ub-ref-ptr.rs:27:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; @@ -42,7 +42,7 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered a maybe-null box +error[E0080]: constructing invalid value of type Box<()>: encountered a maybe-null box --> $DIR/ub-ref-ptr.rs:30:1 | LL | const MAYBE_NULL_BOX: Box<()> = unsafe { mem::transmute({ @@ -92,7 +92,7 @@ note: erroneous constant encountered LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; | ^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) +error[E0080]: constructing invalid value of type &u8: encountered a dangling reference (0x539[noalloc] has no provenance) --> $DIR/ub-ref-ptr.rs:48:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; @@ -103,7 +103,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) +error[E0080]: constructing invalid value of type Box: encountered a dangling box (0x539[noalloc] has no provenance) --> $DIR/ub-ref-ptr.rs:51:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; @@ -124,7 +124,7 @@ LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered null pointer, but expected a function pointer --> $DIR/ub-ref-ptr.rs:57:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; @@ -145,7 +145,7 @@ LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered 0xd[noalloc], but expected a function pointer --> $DIR/ub-ref-ptr.rs:61:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; @@ -156,7 +156,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered ALLOC3, but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered ALLOC3, but expected a function pointer --> $DIR/ub-ref-ptr.rs:63:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; @@ -167,7 +167,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered ALLOC4+0xa, but expected a function pointer +error[E0080]: constructing invalid value of type fn(): encountered ALLOC4+0xa, but expected a function pointer --> $DIR/ub-ref-ptr.rs:65:1 | LL | const MAYBE_NULL_FN_PTR: fn() = unsafe { mem::transmute({ @@ -184,7 +184,7 @@ error[E0080]: accessing memory based on pointer with alignment 1, but alignment LL | ptr.read(); | ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here -error[E0080]: constructing invalid value: encountered a pointer with unknown absolute address, but expected something that is definitely greater or equal to 1000 +error[E0080]: constructing invalid value of type High: encountered a pointer with unknown absolute address, but expected something that is definitely greater or equal to 1000 --> $DIR/ub-ref-ptr.rs:84:1 | LL | const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) }; diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr index aca0b13bb907..244cb96b6923 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.stderr +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,10 +1,10 @@ -error[E0080]: constructing invalid value: encountered a value of uninhabited type `Bar` +error[E0080]: constructing invalid value of type Bar: encountered a value of uninhabited type `Bar` --> $DIR/ub-uninhabit.rs:20:35 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_BAD_BAD` failed here -error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type Bar +error[E0080]: constructing invalid value of type &Bar: encountered a reference pointing to uninhabited type Bar --> $DIR/ub-uninhabit.rs:23:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; @@ -15,13 +15,13 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; HEX_DUMP } -error[E0080]: constructing invalid value at [0]: encountered a value of uninhabited type `Bar` +error[E0080]: constructing invalid value of type [Bar; 1]: at [0], encountered a value of uninhabited type `Bar` --> $DIR/ub-uninhabit.rs:26:42 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_BAD_ARRAY` failed here -error[E0080]: constructing invalid value: encountered a value of the never type `!` +error[E0080]: constructing invalid value of type !: encountered a value of the never type `!` --> $DIR/ub-uninhabit.rs:32:16 | LL | let _val = intrinsics::read_via_copy(ptr); diff --git a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr index 89512c03f5e8..2e5797c65b35 100644 --- a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at ...: encountered a null reference +error[E0080]: constructing invalid value of type &dyn FnOnce(): at ..., encountered a null reference --> $DIR/ub-upvars.rs:7:1 | LL | const BAD_UPVAR: &dyn FnOnce() = &{ diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr index bf8de4817963..c45ad7856e6e 100644 --- a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at ...: encountered a null reference +error[E0080]: constructing invalid value of type &dyn FnOnce(): at ..., encountered a null reference --> $DIR/ub-upvars.rs:7:1 | LL | const BAD_UPVAR: &dyn FnOnce() = &{ diff --git a/tests/ui/consts/const-eval/ub-upvars.rs b/tests/ui/consts/const-eval/ub-upvars.rs index c5bf074ec462..7270d90bf792 100644 --- a/tests/ui/consts/const-eval/ub-upvars.rs +++ b/tests/ui/consts/const-eval/ub-upvars.rs @@ -1,7 +1,7 @@ //@ edition:2015..2021 //@ stderr-per-bitwidth #![allow(invalid_value)] // make sure we cannot allow away the errors tested here - +//@ ignore-parallel-frontend different alloc ids use std::mem; const BAD_UPVAR: &dyn FnOnce() = &{ //~ ERROR null reference diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs index 0bbb104c0322..6297d2f3d3af 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.rs +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -3,7 +3,7 @@ #![feature(ptr_metadata)] use std::{ptr, mem}; - +//@ ignore-parallel-frontend different alloc ids // Strip out raw byte dumps to make comparison platform-independent: //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index c505e5cc8a24..9603710e4fd8 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type &str: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/ub-wide-ptr.rs:40:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -9,7 +9,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; HEX_DUMP } -error[E0080]: constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type (&str,): at .0, encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/ub-wide-ptr.rs:42:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); @@ -38,7 +38,7 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &MyStr: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/ub-wide-ptr.rs:50:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; @@ -49,7 +49,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: HEX_DUMP } -error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected a string +error[E0080]: constructing invalid value of type &str: at ., encountered uninitialized memory, but expected a string --> $DIR/ub-wide-ptr.rs:54:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; @@ -60,7 +60,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: HEX_DUMP } -error[E0080]: constructing invalid value at ..0: encountered uninitialized memory, but expected a string +error[E0080]: constructing invalid value of type &MyStr: at ..0, encountered uninitialized memory, but expected a string --> $DIR/ub-wide-ptr.rs:57:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; @@ -81,7 +81,7 @@ LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { HEX_DUMP } -error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type &[u8]: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/ub-wide-ptr.rs:70:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -92,7 +92,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &[u32]: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/ub-wide-ptr.rs:73:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; @@ -112,7 +112,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type Box<[u8]>: encountered a dangling box (going beyond the bounds of its allocation) --> $DIR/ub-wide-ptr.rs:79:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; @@ -132,7 +132,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3) = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value at .[0]: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &[bool; 1]: at .[0], encountered 0x03, but expected a boolean --> $DIR/ub-wide-ptr.rs:86:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; @@ -149,7 +149,7 @@ note: erroneous constant encountered LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value at ..0: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &MySlice<[bool; 1]>: at ..0, encountered 0x03, but expected a boolean --> $DIR/ub-wide-ptr.rs:92:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); @@ -166,7 +166,7 @@ note: erroneous constant encountered LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &MySlice<[bool; 1]>: at ..1[0], encountered 0x03, but expected a boolean --> $DIR/ub-wide-ptr.rs:95:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); @@ -193,7 +193,7 @@ LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { HEX_DUMP } -error[E0080]: constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC12, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:110:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; @@ -204,7 +204,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( HEX_DUMP } -error[E0080]: constructing invalid value at .0: encountered ALLOC14, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC14, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:113:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; @@ -215,7 +215,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( HEX_DUMP } -error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered 0x4[noalloc], but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:116:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; @@ -226,7 +226,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u HEX_DUMP } -error[E0080]: constructing invalid value: encountered ALLOC17, but expected a vtable pointer +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC17, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:118:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; @@ -237,7 +237,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92 HEX_DUMP } -error[E0080]: constructing invalid value: encountered ALLOC19, but expected a vtable pointer +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC19, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; @@ -248,7 +248,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92 HEX_DUMP } -error[E0080]: constructing invalid value: encountered ALLOC21, but expected a vtable pointer +error[E0080]: constructing invalid value of type &dyn Trait: encountered ALLOC21, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:122:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; @@ -259,7 +259,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u HEX_DUMP } -error[E0080]: constructing invalid value at .0: encountered ALLOC23, but expected a vtable pointer +error[E0080]: constructing invalid value of type W<&dyn Trait>: at .0, encountered ALLOC23, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:124:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; @@ -270,7 +270,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans HEX_DUMP } -error[E0080]: constructing invalid value at ..: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type &dyn Trait: at .., encountered 0x03, but expected a boolean --> $DIR/ub-wide-ptr.rs:128:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; @@ -281,7 +281,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, HEX_DUMP } -error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer +error[E0080]: constructing invalid value of type *const dyn Trait: encountered null pointer, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:132:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; @@ -292,7 +292,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute HEX_DUMP } -error[E0080]: constructing invalid value: encountered ALLOC28, but expected a vtable pointer +error[E0080]: constructing invalid value of type *const dyn Trait: encountered ALLOC28, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:134:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; @@ -303,7 +303,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm HEX_DUMP } -error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer +error[E0080]: constructing invalid value of type *const dyn Trait: encountered null pointer, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:141:1 | LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { @@ -314,7 +314,7 @@ LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe HEX_DUMP } -error[E0080]: constructing invalid value: encountered ALLOC31, but expected a vtable pointer +error[E0080]: constructing invalid value of type *const dyn Trait: encountered ALLOC31, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:145:1 | LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { diff --git a/tests/ui/consts/const-eval/union-const-eval-field.rs b/tests/ui/consts/const-eval/union-const-eval-field.rs index 2c9061a7a50f..92d056b3b1ef 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.rs +++ b/tests/ui/consts/const-eval/union-const-eval-field.rs @@ -1,7 +1,7 @@ //@ dont-require-annotations: NOTE //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr: "([[:xdigit:]]{2}\s){4}(__\s){4}\s+│\s+([?|\.]){4}\W{4}" -> "HEX_DUMP" - +//@ ignore-parallel-frontend different alloc ids type Field1 = i32; type Field2 = f32; type Field3 = i64; diff --git a/tests/ui/consts/const-eval/union-ice.rs b/tests/ui/consts/const-eval/union-ice.rs index 7a4909e8ce28..055a130cf0e8 100644 --- a/tests/ui/consts/const-eval/union-ice.rs +++ b/tests/ui/consts/const-eval/union-ice.rs @@ -1,5 +1,5 @@ //@ only-x86_64 - +//@ ignore-parallel-frontend different alloc ids type Field1 = i32; type Field3 = i64; diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr index fb2311b9921d..95960d1c77dc 100644 --- a/tests/ui/consts/const-eval/union-ub.32bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered 0x2a, but expected a boolean +error[E0080]: constructing invalid value of type bool: encountered 0x2a, but expected a boolean --> $DIR/union-ub.rs:33:1 | LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr index fb2311b9921d..95960d1c77dc 100644 --- a/tests/ui/consts/const-eval/union-ub.64bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered 0x2a, but expected a boolean +error[E0080]: constructing invalid value of type bool: encountered 0x2a, but expected a boolean --> $DIR/union-ub.rs:33:1 | LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; diff --git a/tests/ui/consts/const-eval/union-ub.rs b/tests/ui/consts/const-eval/union-ub.rs index 0fa5d3128560..8de54f5749f3 100644 --- a/tests/ui/consts/const-eval/union-ub.rs +++ b/tests/ui/consts/const-eval/union-ub.rs @@ -1,6 +1,6 @@ //@ stderr-per-bitwidth //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend different alloc ids #[repr(C)] union DummyUnion { unit: (), diff --git a/tests/ui/consts/const-eval/valid-const.rs b/tests/ui/consts/const-eval/valid-const.rs index 777484c6b092..6f92997c90d6 100644 --- a/tests/ui/consts/const-eval/valid-const.rs +++ b/tests/ui/consts/const-eval/valid-const.rs @@ -1,10 +1,12 @@ //@ check-pass // // Some constants that *are* valid +#![feature(maybe_dangling)] use std::mem; use std::ptr::NonNull; use std::num::NonZero; +use std::mem::MaybeDangling; const NON_NULL_PTR1: NonNull = unsafe { mem::transmute(1usize) }; const NON_NULL_PTR2: NonNull = unsafe { mem::transmute(&0) }; @@ -14,4 +16,6 @@ const UNIT: () = (); +const INVALID_INSIDE_MAYBE_DANGLING: MaybeDangling<&bool> = unsafe { std::mem::transmute(&5u8) }; + fn main() {} diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr index 848c65f47645..cd59e7ba55ad 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered a value of the never type `!` +error[E0080]: constructing invalid value of type !: encountered a value of the never type `!` --> $DIR/validate_uninhabited_zsts.rs:17:33 | LL | const FOO: [empty::Empty; 3] = [foo(); 3]; @@ -10,7 +10,7 @@ note: inside `foo` LL | unsafe { std::mem::transmute(()) } | ^^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here -error[E0080]: constructing invalid value at .0: encountered a value of uninhabited type `Void` +error[E0080]: constructing invalid value of type empty::Empty: at .0, encountered a value of uninhabited type `Void` --> $DIR/validate_uninhabited_zsts.rs:20:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; diff --git a/tests/ui/consts/const-integer-bool-ops.rs b/tests/ui/consts/const-integer-bool-ops.rs index fbbd51adfe88..e1da3e750876 100644 --- a/tests/ui/consts/const-integer-bool-ops.rs +++ b/tests/ui/consts/const-integer-bool-ops.rs @@ -5,6 +5,7 @@ //~| NOTE expected `bool`, found integer //~| ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARR: [i32; X] = [99; 34]; const X1: usize = 42 || 39; @@ -14,6 +15,7 @@ //~| NOTE expected `bool`, found integer //~| ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARR1: [i32; X1] = [99; 47]; const X2: usize = -42 || -39; @@ -23,6 +25,7 @@ //~| NOTE expected `bool`, found integer //~| ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARR2: [i32; X2] = [99; 18446744073709551607]; const X3: usize = -42 && -39; @@ -32,36 +35,43 @@ //~| NOTE expected `bool`, found integer //~| ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARR3: [i32; X3] = [99; 6]; const Y: usize = 42.0 == 42.0; //~^ ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARRR: [i32; Y] = [99; 1]; const Y1: usize = 42.0 >= 42.0; //~^ ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARRR1: [i32; Y1] = [99; 1]; const Y2: usize = 42.0 <= 42.0; //~^ ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARRR2: [i32; Y2] = [99; 1]; const Y3: usize = 42.0 > 42.0; //~^ ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARRR3: [i32; Y3] = [99; 0]; const Y4: usize = 42.0 < 42.0; //~^ ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARRR4: [i32; Y4] = [99; 0]; const Y5: usize = 42.0 != 42.0; //~^ ERROR mismatched types //~| NOTE expected `usize`, found `bool` +//~| NOTE expected because const ARRR5: [i32; Y5] = [99; 0]; fn main() { diff --git a/tests/ui/consts/const-integer-bool-ops.stderr b/tests/ui/consts/const-integer-bool-ops.stderr index 4e503e5a5c0a..5212a5cfeb1e 100644 --- a/tests/ui/consts/const-integer-bool-ops.stderr +++ b/tests/ui/consts/const-integer-bool-ops.stderr @@ -14,97 +14,117 @@ error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:1:18 | LL | const X: usize = 42 && 39; - | ^^^^^^^^ expected `usize`, found `bool` + | ----- ^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:10:19 + --> $DIR/const-integer-bool-ops.rs:11:19 | LL | const X1: usize = 42 || 39; | ^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:10:25 + --> $DIR/const-integer-bool-ops.rs:11:25 | LL | const X1: usize = 42 || 39; | ^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:10:19 + --> $DIR/const-integer-bool-ops.rs:11:19 | LL | const X1: usize = 42 || 39; - | ^^^^^^^^ expected `usize`, found `bool` + | ----- ^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:19:19 + --> $DIR/const-integer-bool-ops.rs:21:19 | LL | const X2: usize = -42 || -39; | ^^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:19:26 + --> $DIR/const-integer-bool-ops.rs:21:26 | LL | const X2: usize = -42 || -39; | ^^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:19:19 + --> $DIR/const-integer-bool-ops.rs:21:19 | LL | const X2: usize = -42 || -39; - | ^^^^^^^^^^ expected `usize`, found `bool` + | ----- ^^^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:28:19 + --> $DIR/const-integer-bool-ops.rs:31:19 | LL | const X3: usize = -42 && -39; | ^^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:28:26 + --> $DIR/const-integer-bool-ops.rs:31:26 | LL | const X3: usize = -42 && -39; | ^^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:28:19 + --> $DIR/const-integer-bool-ops.rs:31:19 | LL | const X3: usize = -42 && -39; - | ^^^^^^^^^^ expected `usize`, found `bool` + | ----- ^^^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:37:18 + --> $DIR/const-integer-bool-ops.rs:41:18 | LL | const Y: usize = 42.0 == 42.0; - | ^^^^^^^^^^^^ expected `usize`, found `bool` - -error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:42:19 - | -LL | const Y1: usize = 42.0 >= 42.0; - | ^^^^^^^^^^^^ expected `usize`, found `bool` + | ----- ^^^^^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:47:19 | -LL | const Y2: usize = 42.0 <= 42.0; - | ^^^^^^^^^^^^ expected `usize`, found `bool` +LL | const Y1: usize = 42.0 >= 42.0; + | ----- ^^^^^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:52:19 + --> $DIR/const-integer-bool-ops.rs:53:19 + | +LL | const Y2: usize = 42.0 <= 42.0; + | ----- ^^^^^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:59:19 | LL | const Y3: usize = 42.0 > 42.0; - | ^^^^^^^^^^^ expected `usize`, found `bool` + | ----- ^^^^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:57:19 + --> $DIR/const-integer-bool-ops.rs:65:19 | LL | const Y4: usize = 42.0 < 42.0; - | ^^^^^^^^^^^ expected `usize`, found `bool` + | ----- ^^^^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:62:19 + --> $DIR/const-integer-bool-ops.rs:71:19 | LL | const Y5: usize = 42.0 != 42.0; - | ^^^^^^^^^^^^ expected `usize`, found `bool` + | ----- ^^^^^^^^^^^^ expected `usize`, found `bool` + | | + | expected because of the type of the constant error: aborting due to 18 previous errors diff --git a/tests/ui/consts/const-item-no-type/in-macro.rs b/tests/ui/consts/const-item-no-type/in-macro.rs index c200a1fd0b41..49bd3862852e 100644 --- a/tests/ui/consts/const-item-no-type/in-macro.rs +++ b/tests/ui/consts/const-item-no-type/in-macro.rs @@ -8,7 +8,7 @@ macro_rules! suite { )* } } - +//@ ignore-parallel-frontend different infer type: bool suite! { len; is_empty; diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index 8f54b4eda227..9b289f4306b8 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -28,7 +28,7 @@ LL | const B4: Option<&mut i32> = helper(&mut 42); | | creates a temporary value which is freed while still in use | using this value as a constant requires that borrow lasts for `'static` -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut u16: encountered mutable reference or box pointing to read-only memory --> $DIR/mut_ref_in_final.rs:27:1 | LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; @@ -39,7 +39,7 @@ LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut u16: encountered mutable reference or box pointing to read-only memory --> $DIR/mut_ref_in_final.rs:29:1 | LL | static IMMUT_MUT_REF_STATIC: &mut u16 = unsafe { mem::transmute(&13) }; @@ -120,7 +120,7 @@ LL | const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; = note: to avoid accidentally creating global mutable state, such temporaries must be immutable = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` -error[E0080]: constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) +error[E0080]: constructing invalid value of type Option<&mut i32>: at ..0, encountered a dangling reference (0x2a[noalloc] has no provenance) --> $DIR/mut_ref_in_final.rs:86:5 | LL | const INT2PTR: Option<&mut i32> = helper_int2ptr(); @@ -131,7 +131,7 @@ LL | const INT2PTR: Option<&mut i32> = helper_int2ptr(); HEX_DUMP } -error[E0080]: constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) +error[E0080]: constructing invalid value of type Option<&mut i32>: at ..0, encountered a dangling reference (0x2a[noalloc] has no provenance) --> $DIR/mut_ref_in_final.rs:87:5 | LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); @@ -142,7 +142,7 @@ LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); HEX_DUMP } -error[E0080]: constructing invalid value at ..0: encountered a dangling reference (use-after-free) +error[E0080]: constructing invalid value of type Option<&mut i32>: at ..0, encountered a dangling reference (use-after-free) --> $DIR/mut_ref_in_final.rs:93:5 | LL | const DANGLING: Option<&mut i32> = helper_dangling(); @@ -153,7 +153,7 @@ LL | const DANGLING: Option<&mut i32> = helper_dangling(); HEX_DUMP } -error[E0080]: constructing invalid value at ..0: encountered a dangling reference (use-after-free) +error[E0080]: constructing invalid value of type Option<&mut i32>: at ..0, encountered a dangling reference (use-after-free) --> $DIR/mut_ref_in_final.rs:94:5 | LL | static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); diff --git a/tests/ui/consts/const-needs_drop-monomorphic.rs b/tests/ui/consts/const-needs_drop-monomorphic.rs index 7402c680985b..f68eb4bed613 100644 --- a/tests/ui/consts/const-needs_drop-monomorphic.rs +++ b/tests/ui/consts/const-needs_drop-monomorphic.rs @@ -9,7 +9,7 @@ fn assert() {} } fn f() { Bool::<{ std::mem::needs_drop::() }>::assert(); - //~^ ERROR no function or associated item named `assert` found + //~^ ERROR no associated function or constant named `assert` found //~| ERROR unconstrained generic constant } fn main() { diff --git a/tests/ui/consts/const-needs_drop-monomorphic.stderr b/tests/ui/consts/const-needs_drop-monomorphic.stderr index 17f197cdd5d2..12ea559127ae 100644 --- a/tests/ui/consts/const-needs_drop-monomorphic.stderr +++ b/tests/ui/consts/const-needs_drop-monomorphic.stderr @@ -9,14 +9,14 @@ help: try adding a `where` bound LL | fn f() where [(); { std::mem::needs_drop::() } as usize]: { | +++++++++++++++++++++++++++++++++++++++++++++++++++++ -error[E0599]: no function or associated item named `assert` found for struct `Bool<{ std::mem::needs_drop::() }>` in the current scope +error[E0599]: no associated function or constant named `assert` found for struct `Bool<{ std::mem::needs_drop::() }>` in the current scope --> $DIR/const-needs_drop-monomorphic.rs:11:46 | LL | struct Bool {} - | -------------------------- function or associated item `assert` not found for this struct + | -------------------------- associated function or constant `assert` not found for this struct ... LL | Bool::<{ std::mem::needs_drop::() }>::assert(); - | ^^^^^^ function or associated item cannot be called on `Bool<{ std::mem::needs_drop::() }>` due to unsatisfied trait bounds + | ^^^^^^ associated function or constant cannot be called on `Bool<{ std::mem::needs_drop::() }>` due to unsatisfied trait bounds error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-result-no-expect-suggestion.stderr b/tests/ui/consts/const-result-no-expect-suggestion.stderr index 70aa306ae3c8..337065f9f5e0 100644 --- a/tests/ui/consts/const-result-no-expect-suggestion.stderr +++ b/tests/ui/consts/const-result-no-expect-suggestion.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/const-result-no-expect-suggestion.rs:5:19 | LL | const TEST: u32 = f(2); - | ^^^^ expected `u32`, found `Result` + | --- ^^^^ expected `u32`, found `Result` + | | + | expected because of the type of the constant | = note: expected type `u32` found enum `Result` diff --git a/tests/ui/consts/const-slice-array-deref.stderr b/tests/ui/consts/const-slice-array-deref.stderr index b1d069280885..e7513d01cd0e 100644 --- a/tests/ui/consts/const-slice-array-deref.stderr +++ b/tests/ui/consts/const-slice-array-deref.stderr @@ -11,7 +11,9 @@ error[E0308]: mismatched types --> $DIR/const-slice-array-deref.rs:1:20 | LL | const ONE: [u16] = [1]; - | ^^^ expected `[u16]`, found `[u16; 1]` + | ----- ^^^ expected `[u16]`, found `[u16; 1]` + | | + | expected because of the type of the constant error[E0161]: cannot move a value of type `[u16]` --> $DIR/const-slice-array-deref.rs:5:28 diff --git a/tests/ui/consts/const-tup-index-span.rs b/tests/ui/consts/const-tup-index-span.rs index 4cb7143b4351..6896625c3785 100644 --- a/tests/ui/consts/const-tup-index-span.rs +++ b/tests/ui/consts/const-tup-index-span.rs @@ -1,9 +1,10 @@ // Test spans of errors const TUP: (usize,) = 5usize << 64; -//~^ ERROR mismatched types -//~| NOTE expected `(usize,)`, found `usize` -//~| NOTE expected tuple `(usize,)` +//~^ ERROR: mismatched types +//~| NOTE: expected `(usize,)`, found `usize` +//~| NOTE: expected tuple `(usize,)` +//~| NOTE: expected because const ARR: [i32; TUP.0] = []; fn main() { diff --git a/tests/ui/consts/const-tup-index-span.stderr b/tests/ui/consts/const-tup-index-span.stderr index 792e18aa8fd4..fe4290961816 100644 --- a/tests/ui/consts/const-tup-index-span.stderr +++ b/tests/ui/consts/const-tup-index-span.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/const-tup-index-span.rs:3:23 | LL | const TUP: (usize,) = 5usize << 64; - | ^^^^^^^^^^^^ expected `(usize,)`, found `usize` + | -------- ^^^^^^^^^^^^ expected `(usize,)`, found `usize` + | | + | expected because of the type of the constant | = note: expected tuple `(usize,)` found type `usize` diff --git a/tests/ui/consts/const-type-mismatch.stderr b/tests/ui/consts/const-type-mismatch.stderr index 17bb27d4b72f..d36ef1188f41 100644 --- a/tests/ui/consts/const-type-mismatch.stderr +++ b/tests/ui/consts/const-type-mismatch.stderr @@ -2,13 +2,17 @@ error[E0308]: mismatched types --> $DIR/const-type-mismatch.rs:4:21 | LL | const TWELVE: u16 = TEN + 2; - | ^^^^^^^ expected `u16`, found `u8` + | --- ^^^^^^^ expected `u16`, found `u8` + | | + | expected because of the type of the constant error[E0308]: mismatched types --> $DIR/const-type-mismatch.rs:9:27 | LL | const ALSO_TEN: u16 = TEN; - | ^^^ expected `u16`, found `u8` + | --- ^^^ expected `u16`, found `u8` + | | + | expected because of the type of the constant error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const.rs b/tests/ui/consts/const.rs deleted file mode 100644 index 1f1c6e30b4a0..000000000000 --- a/tests/ui/consts/const.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass -#![allow(non_upper_case_globals)] - -static i: isize = 10; - -pub fn main() { println!("{}", i); } diff --git a/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr b/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr index 412caf60f7d8..8aa86c8b05f5 100644 --- a/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr +++ b/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr @@ -11,10 +11,14 @@ LL | BSTR_SIZED => {} | | | expected `&[u8]`, found `&[u8; 3]` | `BSTR_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_bstr_sized` | = note: expected reference `&[u8]` found reference `&'static [u8; 3]` +help: introduce a new binding instead + | +LL - BSTR_SIZED => {} +LL + other_bstr_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:23:9 @@ -29,10 +33,14 @@ LL | STRUCT_SIZED => {} | | | expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>` | `STRUCT_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_struct_sized` | = note: expected reference `&SomeStruct<[u8]>` found reference `&'static SomeStruct<[u8; 3]>` +help: introduce a new binding instead + | +LL - STRUCT_SIZED => {} +LL + other_struct_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:30:9 @@ -47,10 +55,14 @@ LL | BSTR_SIZED => {} | | | expected `&[u8]`, found `&[u8; 3]` | `BSTR_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_bstr_sized` | = note: expected reference `&[u8]` found reference `&'static [u8; 3]` +help: introduce a new binding instead + | +LL - BSTR_SIZED => {} +LL + other_bstr_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:37:9 @@ -65,10 +77,14 @@ LL | STRUCT_SIZED => {} | | | expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>` | `STRUCT_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_struct_sized` | = note: expected reference `&SomeStruct<[u8]>` found reference `&'static SomeStruct<[u8; 3]>` +help: introduce a new binding instead + | +LL - STRUCT_SIZED => {} +LL + other_struct_sized => {} + | error: cannot use unsized non-slice type `SomeStruct<[u8]>` in constant patterns --> $DIR/arrays-and-slices.rs:47:9 diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs index f02e780f30e3..59bd040e3744 100644 --- a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs +++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs @@ -14,7 +14,7 @@ fn main() { } match None { - ::SOME => panic!(), + ::SOME => panic!(), //~^ ERROR constant of non-structural type `CustomEq` in a pattern _ => {} } diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr index 7cada8836450..452c3ee93f35 100644 --- a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr +++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr @@ -7,28 +7,38 @@ LL | consts::SOME => panic!(), ::: $DIR/auxiliary/consts.rs:1:1 | LL | pub struct CustomEq; - | ------------------- `CustomEq` must be annotated with `#[derive(PartialEq)]` to be usable in patterns + | ------------------- `CustomEq` is not usable in patterns ... LL | pub const SOME: Option = Some(CustomEq); | -------------------------------- constant defined here | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a condition to the match arm checking for equality + | +LL - consts::SOME => panic!(), +LL + binding if binding == consts::SOME => panic!(), + | error: constant of non-structural type `CustomEq` in a pattern --> $DIR/cross-crate-fail.rs:17:9 | -LL | ::SOME => panic!(), +LL | ::SOME => panic!(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant of non-structural type | ::: $DIR/auxiliary/consts.rs:1:1 | LL | pub struct CustomEq; - | ------------------- `CustomEq` must be annotated with `#[derive(PartialEq)]` to be usable in patterns + | ------------------- `CustomEq` is not usable in patterns ... LL | const SOME: Option = Some(CustomEq); | ---------------------------- constant defined here | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a condition to the match arm checking for equality + | +LL - ::SOME => panic!(), +LL + binding if binding == ::SOME => panic!(), + | error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr index 154c94c6d385..24bc201b636d 100644 --- a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr +++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr @@ -11,6 +11,11 @@ LL | BAR_BAZ => panic!(), | ^^^^^^^ constant of non-structural type | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a condition to the match arm checking for equality + | +LL - BAR_BAZ => panic!(), +LL + binding if binding == BAR_BAZ => panic!(), + | error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr index fa16d0b06a7f..402e4aa1e148 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -14,6 +14,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; +LL + match Derive::Some(NoDerive) { binding if binding == ENUM => dbg!(ENUM), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:65:28 @@ -31,6 +36,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; +LL + match Some(NoDerive) { binding if binding == FIELD => dbg!(FIELD), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:71:27 @@ -48,6 +58,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; +LL + match Some(NoDerive) {binding if binding == INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:76:36 @@ -65,6 +80,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; +LL + match (None, Some(NoDerive)) { binding if binding == TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:81:28 @@ -82,6 +102,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; +LL + match Some(NoDerive) { binding if binding == TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:86:36 @@ -99,6 +124,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; +LL + match [None, Some(NoDerive)] { binding if binding == ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:91:33 @@ -116,6 +146,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; +LL + match [Some(NoDerive); 2] { binding if binding == REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:97:28 @@ -134,6 +169,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; +LL + match Some(NoDerive) { binding if binding == NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:102:28 @@ -151,6 +191,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; +LL + match Some(NoDerive) { binding if binding == BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; + | error: constant of non-structural type `NoDerive` in a pattern --> $DIR/reject_non_structural.rs:107:29 @@ -168,6 +213,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; +LL + match &Some(NoDerive) { binding if binding == ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; + | error: aborting due to 10 previous errors diff --git a/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.rs b/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.rs new file mode 100644 index 000000000000..71a2d06adb74 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.rs @@ -0,0 +1,50 @@ +//@ edition:2024 +// #42753 +mod partial_eq { + struct S; + impl PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } + } + + const C: S = S; + const V: Vec<()> = vec![]; + + fn foo() { + match Some(S) { + Some(C) => {} //~ ERROR: constant of non-structural type + Some(C) if true => {} //~ ERROR: constant of non-structural type + None => {} + } + if let Some(C) = Some(S) {} //~ ERROR: constant of non-structural type + if let Some(C) = Some(S) && let Some(1) = Some(2) {} //~ ERROR: constant of non-structural type + let Some(C) = Some(S) else { return; }; //~ ERROR: constant of non-structural type + match vec![] { + V => {} //~ ERROR: constant of non-structural type + _ => {} + } + if let V = vec![] {} //~ ERROR: constant of non-structural type + let V = vec![] else { return; }; //~ ERROR: constant of non-structural type + let V = Vec::new() else { return; }; //~ ERROR: constant of non-structural type + } +} + +mod not_partial_eq { + struct S; + + const C: S = S; + + fn foo() { + match Some(S) { + Some(C) => {} //~ ERROR: constant of non-structural type + Some(C) if true => {} //~ ERROR: constant of non-structural type + None => {} + } + if let Some(C) = Some(S) {} //~ ERROR: constant of non-structural type + if let Some(C) = Some(S) && let Some(1) = Some(2) {} //~ ERROR: constant of non-structural type + let Some(C) = Some(S) else { return; }; //~ ERROR: constant of non-structural type + } +} + +fn main() {} diff --git a/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.stderr b/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.stderr new file mode 100644 index 000000000000..38440af675fe --- /dev/null +++ b/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.stderr @@ -0,0 +1,282 @@ +error: constant of non-structural type `partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:16:18 + | +LL | struct S; + | -------- `partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +... +LL | const C: S = S; + | ---------- constant defined here +... +LL | Some(C) => {} + | ^ constant of non-structural type + | +note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:5:5 + | +LL | impl PartialEq for S { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - Some(C) => {} +LL + Some(binding) if binding == C => {} + | + +error: constant of non-structural type `partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:17:18 + | +LL | struct S; + | -------- `partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +... +LL | const C: S = S; + | ---------- constant defined here +... +LL | Some(C) if true => {} + | ^ constant of non-structural type + | +note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:5:5 + | +LL | impl PartialEq for S { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a check for equality to the condition of the match arm + | +LL - Some(C) if true => {} +LL + Some(binding) if true && binding == C => {} + | + +error: constant of non-structural type `partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:20:21 + | +LL | struct S; + | -------- `partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +... +LL | const C: S = S; + | ---------- constant defined here +... +LL | if let Some(C) = Some(S) {} + | ^ constant of non-structural type + | +note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:5:5 + | +LL | impl PartialEq for S { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: check for equality instead of pattern matching + | +LL - if let Some(C) = Some(S) {} +LL + if let Some(binding) = Some(S) && binding == C {} + | + +error: constant of non-structural type `partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:21:21 + | +LL | struct S; + | -------- `partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +... +LL | const C: S = S; + | ---------- constant defined here +... +LL | if let Some(C) = Some(S) && let Some(1) = Some(2) {} + | ^ constant of non-structural type + | +note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:5:5 + | +LL | impl PartialEq for S { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: check for equality instead of pattern matching + | +LL - if let Some(C) = Some(S) && let Some(1) = Some(2) {} +LL + if let Some(binding) = Some(S) && binding == C && let Some(1) = Some(2) {} + | + +error: constant of non-structural type `partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:22:18 + | +LL | struct S; + | -------- `partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +... +LL | const C: S = S; + | ---------- constant defined here +... +LL | let Some(C) = Some(S) else { return; }; + | ^ constant of non-structural type + | +note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:5:5 + | +LL | impl PartialEq for S { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: check for equality instead of pattern matching + | +LL - let Some(C) = Some(S) else { return; }; +LL + if Some(C) == Some(S) { return; }; + | + +error: constant of non-structural type `Vec<()>` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:24:13 + | +LL | const V: Vec<()> = vec![]; + | ---------------- constant defined here +... +LL | V => {} + | ^ constant of non-structural type + | + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: `Vec<()>` is not usable in patterns + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a condition to the match arm checking for equality + | +LL - V => {} +LL + binding if binding == V => {} + | + +error: constant of non-structural type `Vec<()>` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:27:16 + | +LL | const V: Vec<()> = vec![]; + | ---------------- constant defined here +... +LL | if let V = vec![] {} + | ^ constant of non-structural type + | + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: `Vec<()>` is not usable in patterns + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + +error: constant of non-structural type `Vec<()>` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:28:13 + | +LL | const V: Vec<()> = vec![]; + | ---------------- constant defined here +... +LL | let V = vec![] else { return; }; + | ^ constant of non-structural type + | + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: `Vec<()>` is not usable in patterns + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + +error: constant of non-structural type `Vec<()>` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:29:13 + | +LL | const V: Vec<()> = vec![]; + | ---------------- constant defined here +... +LL | let V = Vec::new() else { return; }; + | ^ constant of non-structural type + | + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: `Vec<()>` is not usable in patterns + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: check for equality instead of pattern matching + | +LL - let V = Vec::new() else { return; }; +LL + if V == Vec::new() { return; }; + | + +error: constant of non-structural type `not_partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:40:18 + | +LL | struct S; + | -------- `not_partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +LL | +LL | const C: S = S; + | ---------- constant defined here +... +LL | Some(C) => {} + | ^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a condition to the match arm checking for equality + | +LL - Some(C) => {} +LL + Some(binding) if binding == C => {} + | + +error: constant of non-structural type `not_partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:41:18 + | +LL | struct S; + | -------- `not_partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +LL | +LL | const C: S = S; + | ---------- constant defined here +... +LL | Some(C) if true => {} + | ^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a check for equality to the condition of the match arm + | +LL - Some(C) if true => {} +LL + Some(binding) if true && binding == C => {} + | + +error: constant of non-structural type `not_partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:44:21 + | +LL | struct S; + | -------- `not_partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +LL | +LL | const C: S = S; + | ---------- constant defined here +... +LL | if let Some(C) = Some(S) {} + | ^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: check for equality instead of pattern matching + | +LL - if let Some(C) = Some(S) {} +LL + if let Some(binding) = Some(S) && binding == C {} + | + +error: constant of non-structural type `not_partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:45:21 + | +LL | struct S; + | -------- `not_partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +LL | +LL | const C: S = S; + | ---------- constant defined here +... +LL | if let Some(C) = Some(S) && let Some(1) = Some(2) {} + | ^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: check for equality instead of pattern matching + | +LL - if let Some(C) = Some(S) && let Some(1) = Some(2) {} +LL + if let Some(binding) = Some(S) && binding == C && let Some(1) = Some(2) {} + | + +error: constant of non-structural type `not_partial_eq::S` in a pattern + --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:46:18 + | +LL | struct S; + | -------- `not_partial_eq::S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +LL | +LL | const C: S = S; + | ---------- constant defined here +... +LL | let Some(C) = Some(S) else { return; }; + | ^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: check for equality instead of pattern matching + | +LL - let Some(C) = Some(S) else { return; }; +LL + if Some(C) == Some(S) { return; }; + | + +error: aborting due to 14 previous errors + diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr index 226a9de285dc..b0150fc59666 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .: encountered 0x0a, but expected a boolean +error[E0080]: constructing invalid value of type &bool: at ., encountered 0x0a, but expected a boolean --> $DIR/const_refs_to_static_fail_invalid.rs:10:5 | LL | const C: &bool = unsafe { std::mem::transmute(&S) }; diff --git a/tests/ui/consts/const_transmute_type_id7.rs b/tests/ui/consts/const_transmute_type_id7.rs index 73b8187a8007..6863b88ca279 100644 --- a/tests/ui/consts/const_transmute_type_id7.rs +++ b/tests/ui/consts/const_transmute_type_id7.rs @@ -2,6 +2,7 @@ //! (see ) // Strip out raw byte dumps to make comparison platform-independent: +//@ normalize-stderr: "\[&\(\); \d\]" -> "ARRAY" //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" diff --git a/tests/ui/consts/const_transmute_type_id7.stderr b/tests/ui/consts/const_transmute_type_id7.stderr index 664975831f40..a1c37f2b36fe 100644 --- a/tests/ui/consts/const_transmute_type_id7.stderr +++ b/tests/ui/consts/const_transmute_type_id7.stderr @@ -1,5 +1,5 @@ -error[E0080]: constructing invalid value at [0]: encountered a maybe-null reference - --> $DIR/const_transmute_type_id7.rs:13:1 +error[E0080]: constructing invalid value of type ARRAY: at [0], encountered a maybe-null reference + --> $DIR/const_transmute_type_id7.rs:14:1 | LL | const A: [&(); 16 / size_of::<*const ()>()] = unsafe { transmute(TypeId::of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 480f1c5f460d..5329e5bc242e 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -1,6 +1,6 @@ // ignore-tidy-linelength #![feature(core_intrinsics)] - +//@ ignore-parallel-frontend different alloc ids use std::intrinsics::{copy, copy_nonoverlapping}; use std::mem; diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr index 4b034c81a61d..5b92bef890ac 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.stderr +++ b/tests/ui/consts/dangling-alloc-id-ice.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered a dangling reference (use-after-free) +error[E0080]: constructing invalid value of type &(): encountered a dangling reference (use-after-free) --> $DIR/dangling-alloc-id-ice.rs:12:1 | LL | const FOO: &() = { diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr index 248db694d525..0824afd862ad 100644 --- a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr +++ b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered a dangling reference (use-after-free) +error[E0080]: constructing invalid value of type &Wrapper: encountered a dangling reference (use-after-free) --> $DIR/dangling-zst-ice-issue-126393.rs:7:1 | LL | pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { diff --git a/tests/ui/consts/enum-discr-type-err.stderr b/tests/ui/consts/enum-discr-type-err.stderr index 9a09d6a96f1a..c676a96ad34a 100644 --- a/tests/ui/consts/enum-discr-type-err.stderr +++ b/tests/ui/consts/enum-discr-type-err.stderr @@ -10,6 +10,7 @@ LL | | B = T, LL | | } | |_- in this macro invocation | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types @@ -24,6 +25,7 @@ LL | | B = T, LL | | } | |_- in this macro invocation | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/escaping-bound-var.rs b/tests/ui/consts/escaping-bound-var.rs index a538d607d6ca..03162c74882d 100644 --- a/tests/ui/consts/escaping-bound-var.rs +++ b/tests/ui/consts/escaping-bound-var.rs @@ -1,5 +1,4 @@ #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete fn test<'a>( _: &'a (), diff --git a/tests/ui/consts/escaping-bound-var.stderr b/tests/ui/consts/escaping-bound-var.stderr index bb0d285f4d06..046c58bd23b3 100644 --- a/tests/ui/consts/escaping-bound-var.stderr +++ b/tests/ui/consts/escaping-bound-var.stderr @@ -1,14 +1,5 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/escaping-bound-var.rs:1:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error: cannot capture late-bound lifetime in constant - --> $DIR/escaping-bound-var.rs:7:13 + --> $DIR/escaping-bound-var.rs:6:13 | LL | fn test<'a>( | -- lifetime defined here @@ -17,7 +8,7 @@ LL | let x: &'a (); | ^^ error[E0308]: mismatched types - --> $DIR/escaping-bound-var.rs:6:6 + --> $DIR/escaping-bound-var.rs:5:6 | LL | fn test<'a>( | ---- implicitly returns `()` as its body has no tail or `return` expression @@ -33,6 +24,6 @@ LL | | }] { 1 }]`, found `()` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr index 96c1666a2d2e..a55a90dfb89a 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -1,10 +1,10 @@ -error[E0080]: constructing invalid value: encountered 0x03, but expected a boolean +error[E0080]: constructing invalid value of type bool: encountered 0x03, but expected a boolean --> $DIR/detect-extra-ub.rs:30:20 | LL | let _x: bool = transmute(3u8); | ^^^^^^^^^^^^^^ evaluation of `INVALID_BOOL` failed here -error[E0080]: constructing invalid value: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type usize: encountered a pointer, but expected an integer --> $DIR/detect-extra-ub.rs:35:21 | LL | let _x: usize = transmute(&3u8); @@ -13,7 +13,7 @@ LL | let _x: usize = transmute(&3u8); = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value at .: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type PtrSizedEnum: at ., encountered a pointer, but expected an integer --> $DIR/detect-extra-ub.rs:40:28 | LL | let _x: PtrSizedEnum = transmute(&3u8); @@ -22,7 +22,7 @@ LL | let _x: PtrSizedEnum = transmute(&3u8); = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value at .0: encountered a pointer, but expected an integer +error[E0080]: constructing invalid value of type (usize, usize): at .0, encountered a pointer, but expected an integer --> $DIR/detect-extra-ub.rs:46:30 | LL | let _x: (usize, usize) = transmute(x); @@ -31,13 +31,13 @@ LL | let _x: (usize, usize) = transmute(x); = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) +error[E0080]: constructing invalid value of type &u32: encountered an unaligned reference (required 4 byte alignment but found 1) --> $DIR/detect-extra-ub.rs:51:20 | LL | let _x: &u32 = transmute(&[0u8; 4]); | ^^^^^^^^^^^^^^^^^^^^ evaluation of `UNALIGNED_PTR` failed here -error[E0080]: constructing invalid value: encountered a maybe-null function pointer +error[E0080]: constructing invalid value of type fn(): encountered a maybe-null function pointer --> $DIR/detect-extra-ub.rs:57:20 | LL | let _x: fn() = transmute({ @@ -49,13 +49,13 @@ LL | | (ptr as *const u8).wrapping_add(10) LL | | }); | |______^ evaluation of `MAYBE_NULL_FN_PTR` failed here -error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant +error[E0080]: constructing invalid value of type UninhDiscriminant: at ., encountered an uninhabited enum variant --> $DIR/detect-extra-ub.rs:68:13 | LL | let v = *addr_of!(data).cast::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINHABITED_VARIANT` failed here -error[E0080]: constructing invalid value at [0]: encountered a partial pointer or a mix of pointers +error[E0080]: constructing invalid value of type [*const u8; 2]: at [0], encountered a partial pointer or a mix of pointers --> $DIR/detect-extra-ub.rs:87:16 | LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); @@ -64,7 +64,7 @@ LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &[u8]: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/detect-extra-ub.rs:101:16 | LL | let _val = &*slice; diff --git a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr index 17b32383912a..64a178b6913d 100644 --- a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type &S: at ..y..0, encountered `UnsafeCell` in read-only memory --> $DIR/interior-mut-const-via-union.rs:34:1 | LL | fn main() { diff --git a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr index c4f78e7bf9ea..f2301560faae 100644 --- a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type &S: at ..y..0, encountered `UnsafeCell` in read-only memory --> $DIR/interior-mut-const-via-union.rs:34:1 | LL | fn main() { diff --git a/tests/ui/consts/interior-mut-const-via-union.rs b/tests/ui/consts/interior-mut-const-via-union.rs index 5e624671aee0..cba3b36bd98a 100644 --- a/tests/ui/consts/interior-mut-const-via-union.rs +++ b/tests/ui/consts/interior-mut-const-via-union.rs @@ -3,7 +3,7 @@ // //@ build-fail //@ stderr-per-bitwidth - +//@ ignore-parallel-frontend different alloc ids use std::cell::Cell; use std::mem::ManuallyDrop; diff --git a/tests/ui/consts/issue-103790.rs b/tests/ui/consts/issue-103790.rs index 869a43e4018b..a85833a56537 100644 --- a/tests/ui/consts/issue-103790.rs +++ b/tests/ui/consts/issue-103790.rs @@ -5,6 +5,5 @@ //~^ ERROR the name `S` is already used for a generic parameter in this item's generic parameters //~| ERROR missing generics for struct `S` //~| ERROR cycle detected when computing type of `S::S` -//~| ERROR `()` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/consts/issue-103790.stderr b/tests/ui/consts/issue-103790.stderr index adfac02bd0ce..e442c64e70ce 100644 --- a/tests/ui/consts/issue-103790.stderr +++ b/tests/ui/consts/issue-103790.stderr @@ -36,19 +36,7 @@ LL | struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: `()` is forbidden as the type of a const generic parameter - --> $DIR/issue-103790.rs:4:19 - | -LL | struct S; - | ^^ - | - = note: the only supported types are integers, `bool`, and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0107, E0391, E0403. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/consts/issue-104396.rs b/tests/ui/consts/issue-104396.rs index f44abc359d67..dc0789eaf655 100644 --- a/tests/ui/consts/issue-104396.rs +++ b/tests/ui/consts/issue-104396.rs @@ -2,7 +2,6 @@ //@ check-pass #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete #[inline(always)] fn from_fn_1 f32>(mut f: F) -> [f32; N] { diff --git a/tests/ui/consts/issue-104396.stderr b/tests/ui/consts/issue-104396.stderr deleted file mode 100644 index 5856bee09a3f..000000000000 --- a/tests/ui/consts/issue-104396.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-104396.rs:4:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/consts/issue-104768.stderr b/tests/ui/consts/issue-104768.stderr index bd4a54de0ae4..81b4575b361b 100644 --- a/tests/ui/consts/issue-104768.stderr +++ b/tests/ui/consts/issue-104768.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/issue-104768.rs:1:15 | LL | const A: &_ = 0_u32; - | ^^^^^ expected `&_`, found `u32` + | -- ^^^^^ expected `&_`, found `u32` + | | + | expected because of the type of the constant | = note: expected reference `&'static _` found type `u32` diff --git a/tests/ui/consts/issue-39974.rs b/tests/ui/consts/issue-39974.rs index adc65d9be0d0..7d9f1b6cf474 100644 --- a/tests/ui/consts/issue-39974.rs +++ b/tests/ui/consts/issue-39974.rs @@ -1,11 +1,13 @@ const LENGTH: f64 = 2; -//~^ ERROR mismatched types -//~| NOTE expected `f64`, found integer +//~^ ERROR: mismatched types +//~| NOTE: expected `f64`, found integer +//~| NOTE: expected because struct Thing { f: [[f64; 2]; LENGTH], - //~^ ERROR mismatched types - //~| NOTE expected `usize`, found `f64` + //~^ ERROR: mismatched types + //~| NOTE: expected `usize`, found `f64` + //~| NOTE: array length } fn main() { diff --git a/tests/ui/consts/issue-39974.stderr b/tests/ui/consts/issue-39974.stderr index 1c15debb1199..784a19445055 100644 --- a/tests/ui/consts/issue-39974.stderr +++ b/tests/ui/consts/issue-39974.stderr @@ -1,14 +1,18 @@ error[E0308]: mismatched types - --> $DIR/issue-39974.rs:6:19 + --> $DIR/issue-39974.rs:7:19 | LL | f: [[f64; 2]; LENGTH], | ^^^^^^ expected `usize`, found `f64` + | + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/issue-39974.rs:1:21 | LL | const LENGTH: f64 = 2; - | ^ expected `f64`, found integer + | --- ^ expected `f64`, found integer + | | + | expected because of the type of the constant | help: use a float literal | diff --git a/tests/ui/consts/issue-63952.32bit.stderr b/tests/ui/consts/issue-63952.32bit.stderr index cf97ed6e4874..eb57a2f2ab5e 100644 --- a/tests/ui/consts/issue-63952.32bit.stderr +++ b/tests/ui/consts/issue-63952.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &[u8]: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/issue-63952.rs:17:1 | LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr index 4cea967314c0..da1d05eb5dc5 100644 --- a/tests/ui/consts/issue-63952.64bit.stderr +++ b/tests/ui/consts/issue-63952.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object +error[E0080]: constructing invalid value of type &[u8]: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/issue-63952.rs:17:1 | LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { diff --git a/tests/ui/consts/issue-63952.rs b/tests/ui/consts/issue-63952.rs index fce6013b4d31..c0ee7a5dc1e7 100644 --- a/tests/ui/consts/issue-63952.rs +++ b/tests/ui/consts/issue-63952.rs @@ -1,6 +1,6 @@ // Regression test for #63952, shouldn't hang. //@ stderr-per-bitwidth - +//@ ignore-parallel-frontend different alloc ids #[repr(C)] #[derive(Copy, Clone)] struct SliceRepr { diff --git a/tests/ui/consts/issue-64506.stderr b/tests/ui/consts/issue-64506.stderr index 9fce07c58501..bd4f8f96a279 100644 --- a/tests/ui/consts/issue-64506.stderr +++ b/tests/ui/consts/issue-64506.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .inner: encountered a value of uninhabited type `AnonPipe` +error[E0080]: constructing invalid value of type ChildStdin: at .inner, encountered a value of uninhabited type `AnonPipe` --> $DIR/issue-64506.rs:16:22 | LL | let x = unsafe { Foo { b: () }.a }; diff --git a/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr b/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr index 7078b4bd7be1..1210ae87642d 100644 --- a/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr +++ b/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr @@ -3,12 +3,16 @@ error[E0308]: mismatched types | LL | const A: [(); 0.1] = [()]; | ^^^ expected `usize`, found floating-point number + | + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/issue-69310-array-size-lit-wrong-ty.rs:11:15 | LL | const B: [(); b"a"] = [()]; | ^^^^ expected `usize`, found `&[u8; 1]` + | + = note: array length can only be `usize` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-79690.64bit.stderr b/tests/ui/consts/issue-79690.64bit.stderr index 2653ff22f120..c3f89d243335 100644 --- a/tests/ui/consts/issue-79690.64bit.stderr +++ b/tests/ui/consts/issue-79690.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) +error[E0080]: constructing invalid value of type Fat<'_>: at .1, encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/issue-79690.rs:30:1 | LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; diff --git a/tests/ui/consts/issue-79690.rs b/tests/ui/consts/issue-79690.rs index 24e3220155d1..5e1e65cdb8d5 100644 --- a/tests/ui/consts/issue-79690.rs +++ b/tests/ui/consts/issue-79690.rs @@ -1,7 +1,7 @@ //@ ignore-32bit // This test gives a different error on 32-bit architectures. //@ stderr-per-bitwidth - +//@ ignore-parallel-frontend different alloc ids union Transmute { t: T, u: U, diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr index 5008a2eada8f..586158375ecc 100644 --- a/tests/ui/consts/issue-89088.stderr +++ b/tests/ui/consts/issue-89088.stderr @@ -9,9 +9,14 @@ LL | FOO => todo!(), | --> $SRC_DIR/alloc/src/borrow.rs:LL:COL | - = note: `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns + = note: `Cow<'_, str>` is not usable in patterns | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a condition to the match arm checking for equality + | +LL - FOO => todo!(), +LL + binding if binding == FOO => todo!(), + | error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-90762.rs b/tests/ui/consts/issue-90762.rs index db40e50d4995..cc060366b80b 100644 --- a/tests/ui/consts/issue-90762.rs +++ b/tests/ui/consts/issue-90762.rs @@ -27,5 +27,5 @@ fn main() { for (i, b) in FOO.iter().enumerate() { assert!(b.load(Ordering::Relaxed), "{} not set", i); } - assert_eq!(BAR.fetch_add(1, Ordering::Relaxed), usize::max_value()); + assert_eq!(BAR.fetch_add(1, Ordering::Relaxed), usize::MAX); } diff --git a/tests/ui/consts/match_ice.stderr b/tests/ui/consts/match_ice.stderr index 95e96bbbd677..d0742e18f6bb 100644 --- a/tests/ui/consts/match_ice.stderr +++ b/tests/ui/consts/match_ice.stderr @@ -11,6 +11,11 @@ LL | C => {} | ^ constant of non-structural type | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a condition to the match arm checking for equality + | +LL - C => {} +LL + binding if binding == C => {} + | error: aborting due to 1 previous error diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 4187a9e1c2bf..68c6dd1ed600 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &&mut u32: at ., encountered mutable reference or box pointing to read-only memory --> $DIR/mutable_references.rs:13:1 | LL | static FOO: &&mut u32 = &&mut 42; @@ -9,7 +9,7 @@ LL | static FOO: &&mut u32 = &&mut 42; HEX_DUMP } -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut i32: encountered mutable reference or box pointing to read-only memory --> $DIR/mutable_references.rs:15:1 | LL | static OH_YES: &mut i32 = &mut 42; @@ -32,7 +32,7 @@ error: encountered mutable pointer in final value of static LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut i32: encountered mutable reference or box pointing to read-only memory --> $DIR/mutable_references.rs:25:1 | LL | const BLUNT: &mut i32 = &mut 42; @@ -43,7 +43,7 @@ LL | const BLUNT: &mut i32 = &mut 42; HEX_DUMP } -error[E0080]: constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type Meh: at .x., encountered `UnsafeCell` in read-only memory --> $DIR/mutable_references.rs:40:1 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; @@ -54,7 +54,7 @@ LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; HEX_DUMP } -error[E0080]: constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type Meh: at .x., encountered `UnsafeCell` in read-only memory --> $DIR/mutable_references.rs:45:1 | LL | const MUH: Meh = Meh { @@ -65,7 +65,7 @@ LL | const MUH: Meh = Meh { HEX_DUMP } -error[E0080]: constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type &dyn Sync: at ...x, encountered `UnsafeCell` in read-only memory --> $DIR/mutable_references.rs:56:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; @@ -76,7 +76,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut i32: encountered mutable reference or box pointing to read-only memory --> $DIR/mutable_references.rs:62:1 | LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr index d7c668a98121..ab2169672910 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type &Atomic: at ..v, encountered `UnsafeCell` in read-only memory --> $DIR/static-no-inner-mut.rs:8:1 | LL | static REF: &AtomicI32 = &AtomicI32::new(42); @@ -9,7 +9,7 @@ LL | static REF: &AtomicI32 = &AtomicI32::new(42); ╾ALLOC0╼ │ ╾──╼ } -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut i32: encountered mutable reference or box pointing to read-only memory --> $DIR/static-no-inner-mut.rs:11:1 | LL | static REFMUT: &mut i32 = &mut 0; @@ -20,7 +20,7 @@ LL | static REFMUT: &mut i32 = &mut 0; ╾ALLOC1╼ │ ╾──╼ } -error[E0080]: constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type &Atomic: at ..v, encountered `UnsafeCell` in read-only memory --> $DIR/static-no-inner-mut.rs:15:1 | LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; @@ -31,7 +31,7 @@ LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; ╾ALLOC2╼ │ ╾──╼ } -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut i32: encountered mutable reference or box pointing to read-only memory --> $DIR/static-no-inner-mut.rs:17:1 | LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr index f3bb49900b59..673c1b3c0b6e 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type &Atomic: at ..v, encountered `UnsafeCell` in read-only memory --> $DIR/static-no-inner-mut.rs:8:1 | LL | static REF: &AtomicI32 = &AtomicI32::new(42); @@ -9,7 +9,7 @@ LL | static REF: &AtomicI32 = &AtomicI32::new(42); ╾ALLOC0╼ │ ╾──────╼ } -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut i32: encountered mutable reference or box pointing to read-only memory --> $DIR/static-no-inner-mut.rs:11:1 | LL | static REFMUT: &mut i32 = &mut 0; @@ -20,7 +20,7 @@ LL | static REFMUT: &mut i32 = &mut 0; ╾ALLOC1╼ │ ╾──────╼ } -error[E0080]: constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type &Atomic: at ..v, encountered `UnsafeCell` in read-only memory --> $DIR/static-no-inner-mut.rs:15:1 | LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; @@ -31,7 +31,7 @@ LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; ╾ALLOC2╼ │ ╾──────╼ } -error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory +error[E0080]: constructing invalid value of type &mut i32: encountered mutable reference or box pointing to read-only memory --> $DIR/static-no-inner-mut.rs:17:1 | LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs index 0e87442f6a69..27eb9a6c7c34 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs @@ -1,6 +1,6 @@ //@ stderr-per-bitwidth //@ compile-flags: -Zunleash-the-miri-inside-of-you - +//@ ignore-parallel-frontend different alloc ids // All "inner" allocations that come with a `static` are interned immutably. This means it is // crucial that we do not accept any form of (interior) mutability there. use std::sync::atomic::*; diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs index b679493eb08e..897b37b3e65a 100644 --- a/tests/ui/consts/missing_span_in_backtrace.rs +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -1,7 +1,7 @@ //! Check what happens when the error occurs inside a std function that we can't print the span of. //@ ignore-backends: gcc //@ compile-flags: -Z ui-testing=no --diagnostic-width=80 - +//@ ignore-parallel-frontend different alloc ids use std::{ mem::{self, MaybeUninit}, ptr, diff --git a/tests/ui/consts/mono-reachable-invalid-const.rs b/tests/ui/consts/mono-reachable-invalid-const.rs index aba41dabe71f..3d76e4a65a4e 100644 --- a/tests/ui/consts/mono-reachable-invalid-const.rs +++ b/tests/ui/consts/mono-reachable-invalid-const.rs @@ -1,5 +1,5 @@ //@ build-fail - +//@ ignore-parallel-frontend post-monomorphization errors struct Bar; impl Bar { diff --git a/tests/ui/consts/nested_erroneous_ctfe.stderr b/tests/ui/consts/nested_erroneous_ctfe.stderr index db298246e7cf..b13a6dca2b38 100644 --- a/tests/ui/consts/nested_erroneous_ctfe.stderr +++ b/tests/ui/consts/nested_erroneous_ctfe.stderr @@ -6,6 +6,7 @@ LL | [9; || [9; []]]; | = note: expected type `usize` found array `[_; 0]` + = note: array length can only be `usize` error: aborting due to 1 previous error diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs index 98a50156a948..c9c34e19e4dd 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -1,5 +1,5 @@ use std::ptr; - +//@ ignore-parallel-frontend different alloc ids //@ normalize-stderr: "0xf+" -> "0xf..f" //@ normalize-stderr: "0x7f+" -> "0x7f..f" //@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes" diff --git a/tests/ui/consts/promoted-type-error-issue-133968.stderr b/tests/ui/consts/promoted-type-error-issue-133968.stderr index 24f1268e4b6e..a6f67a2056da 100644 --- a/tests/ui/consts/promoted-type-error-issue-133968.stderr +++ b/tests/ui/consts/promoted-type-error-issue-133968.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/promoted-type-error-issue-133968.rs:4:29 | LL | static STR: &'static [u8] = "a b"; - | ^^^^^ expected `&[u8]`, found `&str` + | ------------- ^^^^^ expected `&[u8]`, found `&str` + | | + | expected because of the type of the static | = note: expected reference `&'static [u8]` found reference `&'static str` diff --git a/tests/ui/consts/recursive-zst-static.rs b/tests/ui/consts/recursive-zst-static.rs index 853af6d70eb0..003707aeeab6 100644 --- a/tests/ui/consts/recursive-zst-static.rs +++ b/tests/ui/consts/recursive-zst-static.rs @@ -1,6 +1,6 @@ //@ revisions: default unleash //@[unleash]compile-flags: -Zunleash-the-miri-inside-of-you - +//@ ignore-parallel-frontend query cycle // This test ensures that we do not allow ZST statics to initialize themselves without ever // actually creating a value of that type. This is important, as the ZST may have private fields // that users can reasonably expect to only get initialized by their own code. Thus unsafe code diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.rs b/tests/ui/consts/refs_check_const_eq-issue-88384.rs index 46cb62751717..506bec349eba 100644 --- a/tests/ui/consts/refs_check_const_eq-issue-88384.rs +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.rs @@ -1,6 +1,5 @@ #![feature(fn_traits)] #![feature(adt_const_params, unsized_const_params)] -//~^ WARNING the feature `unsized_const_params` is incomplete #[derive(PartialEq, Eq)] struct CompileTimeSettings { diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr index 62c5c5276411..ac4cb059ea19 100644 --- a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr @@ -1,14 +1,5 @@ -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/refs_check_const_eq-issue-88384.rs:2:30 - | -LL | #![feature(adt_const_params, unsized_const_params)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0741]: `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter - --> $DIR/refs_check_const_eq-issue-88384.rs:10:21 + --> $DIR/refs_check_const_eq-issue-88384.rs:9:21 | LL | struct Foo; | ^^^^^^^^^^^^^^^^^^^ @@ -20,7 +11,7 @@ LL | struct CompileTimeSettings { | error[E0741]: `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter - --> $DIR/refs_check_const_eq-issue-88384.rs:13:15 + --> $DIR/refs_check_const_eq-issue-88384.rs:12:15 | LL | impl Foo { | ^^^^^^^^^^^^^^^^^^^ @@ -31,6 +22,6 @@ LL + #[derive(ConstParamTy)] LL | struct CompileTimeSettings { | -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.rs b/tests/ui/consts/required-consts/collect-in-called-fn.rs index 2045b8266c79..d07c0927a16a 100644 --- a/tests/ui/consts/required-consts/collect-in-called-fn.rs +++ b/tests/ui/consts/required-consts/collect-in-called-fn.rs @@ -4,7 +4,7 @@ //@[opt] compile-flags: -O //! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is //! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090) - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.rs b/tests/ui/consts/required-consts/collect-in-dead-closure.rs index 5f8b6bbb174c..825336e9d3ef 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-closure.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-closure.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.rs b/tests/ui/consts/required-consts/collect-in-dead-drop.rs index f7293d162df7..fa9b8730c11c 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-drop.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-drop.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs index e6be9f56cb7a..a76481b67313 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs @@ -4,7 +4,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs index a86902af5267..4fe05db34d78 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs index 4cdb27413540..a6132ef1fe07 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs @@ -4,7 +4,7 @@ //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. #![feature(type_alias_impl_trait)] - +//@ ignore-parallel-frontend post-monomorphization errors mod m { struct Fail(T); impl Fail { diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.rs b/tests/ui/consts/required-consts/collect-in-dead-fn.rs index 0c4795801068..f4627323249d 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fn.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs index 04544cb41398..8808a4e26f0c 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Late(T); impl Late { const FAIL: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs b/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs index 4cdb50f4385a..1a9b99f9868f 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-forget.rs b/tests/ui/consts/required-consts/collect-in-dead-forget.rs index 7586004116c3..bc717edbe73e 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-forget.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-forget.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This passes without optimizations, so it can (and should) also pass with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.rs b/tests/ui/consts/required-consts/collect-in-dead-move.rs index 4e2d959db32c..05491136e8d5 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-move.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-move.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.rs b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs index d4ad73083773..1ca52064a3fd 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-vtable.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! This fails without optimizations, so it should also fail with optimizations. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.rs b/tests/ui/consts/required-consts/collect-in-promoted-const.rs index c47572093869..415f22fd05dd 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.rs +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.rs @@ -3,7 +3,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! Make sure we error on erroneous consts even if they get promoted. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR evaluation panicked: explicit panic diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs index 9309457e22a4..2d63c620a038 100644 --- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs +++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs @@ -2,7 +2,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! Make sure we error on erroneous consts even if they are unused. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR explicit panic diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.rs b/tests/ui/consts/required-consts/interpret-in-promoted.rs index b223e6d16aa1..cbb1a309006c 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.rs +++ b/tests/ui/consts/required-consts/interpret-in-promoted.rs @@ -2,7 +2,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend post-monomorphization errors //! Make sure we evaluate const fn calls even if they get promoted and their result ignored. const unsafe fn ub() { diff --git a/tests/ui/consts/required-consts/interpret-in-static.rs b/tests/ui/consts/required-consts/interpret-in-static.rs index 19ad6be1c9fa..edc7b1d01fd6 100644 --- a/tests/ui/consts/required-consts/interpret-in-static.rs +++ b/tests/ui/consts/required-consts/interpret-in-static.rs @@ -2,7 +2,7 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O //! Make sure we error on erroneous consts even if they are unused. - +//@ ignore-parallel-frontend post-monomorphization errors struct Fail(T); impl Fail { const C: () = panic!(); //~ERROR explicit panic diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.rs b/tests/ui/consts/static-default-lifetime/generic-associated-const.rs index 721920bd810c..8fabaa43f5a2 100644 --- a/tests/ui/consts/static-default-lifetime/generic-associated-const.rs +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.rs @@ -1,6 +1,5 @@ #![deny(elided_lifetimes_in_associated_constant)] #![feature(generic_const_items)] -//~^ WARN the feature `generic_const_items` is incomplete struct A; impl A { diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr index 3680ef61e0c4..fe858d685f7f 100644 --- a/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/generic-associated-const.rs:15:29 + --> $DIR/generic-associated-const.rs:14:29 | LL | const GAC_LIFETIME<'a>: &str = ""; | ^ expected named lifetime parameter @@ -9,23 +9,14 @@ help: consider using the `'a` lifetime LL | const GAC_LIFETIME<'a>: &'a str = ""; | ++ -warning: the feature `generic_const_items` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/generic-associated-const.rs:2:12 - | -LL | #![feature(generic_const_items)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #113521 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `&` without an explicit lifetime name cannot be used here - --> $DIR/generic-associated-const.rs:8:29 + --> $DIR/generic-associated-const.rs:7:29 | LL | const GAC_LIFETIME<'a>: &str = ""; | ^ | note: cannot automatically infer `'static` because of other lifetimes in scope - --> $DIR/generic-associated-const.rs:8:24 + --> $DIR/generic-associated-const.rs:7:24 | LL | const GAC_LIFETIME<'a>: &str = ""; | ^^ @@ -41,6 +32,6 @@ help: use the `'static` lifetime LL | const GAC_LIFETIME<'a>: &'static str = ""; | +++++++ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/consts/trait_specialization.rs b/tests/ui/consts/trait_specialization.rs index 1360fabd1fe1..1ea56b5a4453 100644 --- a/tests/ui/consts/trait_specialization.rs +++ b/tests/ui/consts/trait_specialization.rs @@ -4,7 +4,7 @@ // Tests that specialization does not cause optimizations running on polymorphic MIR to resolve // to a `default` implementation. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Marker {} diff --git a/tests/ui/consts/trait_specialization.stderr b/tests/ui/consts/trait_specialization.stderr deleted file mode 100644 index ce52cf17b89e..000000000000 --- a/tests/ui/consts/trait_specialization.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/trait_specialization.rs:7:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/consts/validate_never_arrays.stderr b/tests/ui/consts/validate_never_arrays.stderr index 3c405e8d3cd0..517b632bdd7b 100644 --- a/tests/ui/consts/validate_never_arrays.stderr +++ b/tests/ui/consts/validate_never_arrays.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] +error[E0080]: constructing invalid value of type &[!; 1]: encountered a reference pointing to uninhabited type [!; 1] --> $DIR/validate_never_arrays.rs:6:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; @@ -9,7 +9,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; HEX_DUMP } -error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` +error[E0080]: constructing invalid value of type &[!]: at .[0], encountered a value of the never type `!` --> $DIR/validate_never_arrays.rs:9:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; @@ -20,7 +20,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; HEX_DUMP } -error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` +error[E0080]: constructing invalid value of type &[!]: at .[0], encountered a value of the never type `!` --> $DIR/validate_never_arrays.rs:10:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; diff --git a/tests/ui/contracts/incomplete-feature.rs b/tests/ui/contracts/incomplete-feature.rs index f1351e2f87e3..c10774b251ab 100644 --- a/tests/ui/contracts/incomplete-feature.rs +++ b/tests/ui/contracts/incomplete-feature.rs @@ -4,6 +4,7 @@ // This test specifically checks that the [incomplete_features] warning is // emitted when the `contracts` feature gate is enabled, so that it can be // marked as `expect`ed in other tests in order to reduce duplication. +#![warn(incomplete_features)] #![feature(contracts)] //~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] extern crate core; diff --git a/tests/ui/contracts/incomplete-feature.stderr b/tests/ui/contracts/incomplete-feature.stderr index 7683926df073..137b13fb834f 100644 --- a/tests/ui/contracts/incomplete-feature.stderr +++ b/tests/ui/contracts/incomplete-feature.stderr @@ -1,11 +1,15 @@ warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/incomplete-feature.rs:7:12 + --> $DIR/incomplete-feature.rs:8:12 | LL | #![feature(contracts)] | ^^^^^^^^^ | = note: see issue #128044 for more information - = note: `#[warn(incomplete_features)]` on by default +note: the lint level is defined here + --> $DIR/incomplete-feature.rs:7:9 + | +LL | #![warn(incomplete_features)] + | ^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/ui/coverage-attr/bad-syntax.rs b/tests/ui/coverage-attr/bad-syntax.rs index 062e82ee4b61..ef7b41db3440 100644 --- a/tests/ui/coverage-attr/bad-syntax.rs +++ b/tests/ui/coverage-attr/bad-syntax.rs @@ -6,12 +6,12 @@ // Tests the error messages produced (or not produced) by various unusual // uses of the `#[coverage(..)]` attribute. -#[coverage(off)] //~ ERROR multiple `coverage` attributes #[coverage(off)] +#[coverage(off)] //~ ERROR multiple `coverage` attributes fn multiple_consistent() {} -#[coverage(off)] //~ ERROR multiple `coverage` attributes -#[coverage(on)] +#[coverage(off)] +#[coverage(on)] //~ ERROR multiple `coverage` attributes fn multiple_inconsistent() {} #[coverage] //~ ERROR malformed `coverage` attribute input diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr index ecf3ed83bca7..4a356221ff60 100644 --- a/tests/ui/coverage-attr/bad-syntax.stderr +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -1,26 +1,26 @@ error: multiple `coverage` attributes - --> $DIR/bad-syntax.rs:9:1 + --> $DIR/bad-syntax.rs:10:1 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/bad-syntax.rs:10:1 + --> $DIR/bad-syntax.rs:9:1 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ error: multiple `coverage` attributes - --> $DIR/bad-syntax.rs:13:1 - | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here --> $DIR/bad-syntax.rs:14:1 | LL | #[coverage(on)] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/bad-syntax.rs:13:1 + | +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ error[E0539]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:17:1 diff --git a/tests/ui/cross/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs b/tests/ui/cross-crate/auxiliary/extern_macro_crate.rs similarity index 100% rename from tests/ui/cross/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs rename to tests/ui/cross-crate/auxiliary/extern_macro_crate.rs diff --git a/tests/ui/cross/cross-crate-macro-backtrace/main.rs b/tests/ui/cross-crate/cross-crate-macro-backtrace.rs similarity index 100% rename from tests/ui/cross/cross-crate-macro-backtrace/main.rs rename to tests/ui/cross-crate/cross-crate-macro-backtrace.rs diff --git a/tests/ui/cross/cross-crate-macro-backtrace/main.stderr b/tests/ui/cross-crate/cross-crate-macro-backtrace.stderr similarity index 88% rename from tests/ui/cross/cross-crate-macro-backtrace/main.stderr rename to tests/ui/cross-crate/cross-crate-macro-backtrace.stderr index d6f20b1f8e9f..9d6a2fbbf002 100644 --- a/tests/ui/cross/cross-crate-macro-backtrace/main.stderr +++ b/tests/ui/cross-crate/cross-crate-macro-backtrace.stderr @@ -1,5 +1,5 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/main.rs:6:5 + --> $DIR/cross-crate-macro-backtrace.rs:6:5 | LL | myprintln!("{}"); | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cross/cross-borrow-trait.rs b/tests/ui/cross/cross-borrow-trait.rs deleted file mode 100644 index 88ea78e44b3a..000000000000 --- a/tests/ui/cross/cross-borrow-trait.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Test that cross-borrowing (implicitly converting from `Box` to `&T`) is -// forbidden when `T` is a trait. - -//@ dont-require-annotations: NOTE - -struct Foo; -trait Trait { fn foo(&self) {} } -impl Trait for Foo {} - -pub fn main() { - let x: Box = Box::new(Foo); - let _y: &dyn Trait = x; //~ ERROR E0308 - //~| NOTE expected reference `&dyn Trait` - //~| NOTE found struct `Box` -} diff --git a/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.rs b/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.rs index 9a72b65da883..3324444d3351 100644 --- a/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.rs +++ b/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.rs @@ -1,6 +1,6 @@ // Test a supertrait cycle where the first trait we find (`A`) is not // a direct participant in the cycle. - +//@ ignore-parallel-frontend query cycle trait A: B { } diff --git a/tests/ui/cycle-trait/issue-12511.rs b/tests/ui/cycle-trait/issue-12511.rs index ea83e3fd9dc2..1d33b03c57a2 100644 --- a/tests/ui/cycle-trait/issue-12511.rs +++ b/tests/ui/cycle-trait/issue-12511.rs @@ -1,7 +1,7 @@ trait T1 : T2 { //~^ ERROR cycle detected } - +//@ ignore-parallel-frontend query cycle trait T2 : T1 { } diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs index 0a7ec5ab5c1b..5d801f26de16 100644 --- a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs +++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs @@ -7,7 +7,7 @@ impl<'a> InvariantRef<'a, ()> { pub const NEW: Self = InvariantRef::new(&()); - //~^ ERROR: no function or associated item named `new` found + //~^ ERROR: no associated function or constant named `new` found } trait Trait { diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr index ae5d0e8fa296..6cf844f29b06 100644 --- a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr +++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr @@ -43,14 +43,14 @@ help: consider introducing lifetime `'a` here LL | impl<'a> Trait for Z { | ++++ -error[E0599]: no function or associated item named `new` found for struct `InvariantRef<'a, T>` in the current scope +error[E0599]: no associated function or constant named `new` found for struct `InvariantRef<'a, T>` in the current scope --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41 | LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); - | -------------------------------------- function or associated item `new` not found for this struct + | -------------------------------------- associated function or constant `new` not found for this struct ... LL | pub const NEW: Self = InvariantRef::new(&()); - | ^^^ function or associated item not found in `InvariantRef<'_, _>` + | ^^^ associated function or constant not found in `InvariantRef<'_, _>` error[E0277]: the trait bound `u8: Trait` is not satisfied --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12 diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs index dd0ee2c732f5..7efbb3795185 100644 --- a/tests/ui/delegation/explicit-paths-pass.rs +++ b/tests/ui/delegation/explicit-paths-pass.rs @@ -17,11 +17,8 @@ impl Trait for F {} mod to_reuse { pub fn foo(x: i32) -> i32 { x + 1 } - pub fn zero_args() -> i32 { 15 } } -reuse to_reuse::zero_args { self } - struct S(F); impl Trait for S { reuse Trait::bar { self.0 } @@ -49,5 +46,4 @@ fn main() { #[inline] reuse to_reuse::foo; assert_eq!(43, foo(42)); - assert_eq!(15, zero_args()); } diff --git a/tests/ui/delegation/generics/const-type-ice-153433.rs b/tests/ui/delegation/generics/const-type-ice-153433.rs new file mode 100644 index 000000000000..edd6d0542a99 --- /dev/null +++ b/tests/ui/delegation/generics/const-type-ice-153433.rs @@ -0,0 +1,8 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +fn main() { + fn foo Foo>() {} + //~^ ERROR: cannot find trait `Foo` in this scope + reuse foo as bar; +} diff --git a/tests/ui/delegation/generics/const-type-ice-153433.stderr b/tests/ui/delegation/generics/const-type-ice-153433.stderr new file mode 100644 index 000000000000..3b537e2f8988 --- /dev/null +++ b/tests/ui/delegation/generics/const-type-ice-153433.stderr @@ -0,0 +1,9 @@ +error[E0405]: cannot find trait `Foo` in this scope + --> $DIR/const-type-ice-153433.rs:5:33 + | +LL | fn foo Foo>() {} + | ^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/delegation/generics/const-type-ice-153499.rs b/tests/ui/delegation/generics/const-type-ice-153499.rs new file mode 100644 index 000000000000..debda0d04a18 --- /dev/null +++ b/tests/ui/delegation/generics/const-type-ice-153499.rs @@ -0,0 +1,13 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait<'a, T, const F: fn(&CStr) -> usize> { + //~^ ERROR: cannot find type `CStr` in this scope + //~| ERROR: using function pointers as const generic parameters is forbidden + fn foo<'x: 'x, A, B>(&self) {} +} + +reuse Trait::foo; +//~^ ERROR: using function pointers as const generic parameters is forbidden + +fn main() {} diff --git a/tests/ui/delegation/generics/const-type-ice-153499.stderr b/tests/ui/delegation/generics/const-type-ice-153499.stderr new file mode 100644 index 000000000000..02fd7197dcdc --- /dev/null +++ b/tests/ui/delegation/generics/const-type-ice-153499.stderr @@ -0,0 +1,30 @@ +error[E0425]: cannot find type `CStr` in this scope + --> $DIR/const-type-ice-153499.rs:4:33 + | +LL | trait Trait<'a, T, const F: fn(&CStr) -> usize> { + | ^^^^ not found in this scope + | +help: consider importing this struct + | +LL + use std::ffi::CStr; + | + +error: using function pointers as const generic parameters is forbidden + --> $DIR/const-type-ice-153499.rs:4:29 + | +LL | trait Trait<'a, T, const F: fn(&CStr) -> usize> { + | ^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + +error: using function pointers as const generic parameters is forbidden + --> $DIR/const-type-ice-153499.rs:10:14 + | +LL | reuse Trait::foo; + | ^^^ + | + = note: the only supported types are integers, `bool`, and `char` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/generics/const-type-ice-154334.rs b/tests/ui/delegation/generics/const-type-ice-154334.rs new file mode 100644 index 000000000000..91cf1d3a0a63 --- /dev/null +++ b/tests/ui/delegation/generics/const-type-ice-154334.rs @@ -0,0 +1,11 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib + +#![feature(min_generic_const_args)] +#![feature(fn_delegation)] +#![feature(adt_const_params)] +#![feature(unsized_const_params)] +trait Trait<'a, T, const N: str> { + fn foo<'v, A, B>(&self) {} +} +reuse Trait::foo; diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.rs b/tests/ui/delegation/generics/free-fn-to-free-fn.rs index 285059e63a75..67f7a12d710d 100644 --- a/tests/ui/delegation/generics/free-fn-to-free-fn.rs +++ b/tests/ui/delegation/generics/free-fn-to-free-fn.rs @@ -16,8 +16,8 @@ pub fn bounds(_: T) {} reuse to_reuse::bounds; fn main() { - // FIXME(fn_delegation): proper support for late bound lifetimes. late::<'static>(&0u8); + //~^ ERROR: function takes 0 lifetime arguments but 1 lifetime argument was supplied struct S; bounds(S); diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.stderr b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr index 6b6acfc3afff..db88b8d4f8b7 100644 --- a/tests/ui/delegation/generics/free-fn-to-free-fn.stderr +++ b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr @@ -1,3 +1,17 @@ +error[E0107]: function takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/free-fn-to-free-fn.rs:19:5 + | +LL | late::<'static>(&0u8); + | ^^^^----------- help: remove the unnecessary generics + | | + | expected 0 lifetime arguments + | +note: function defined here, with 0 lifetime parameters + --> $DIR/free-fn-to-free-fn.rs:15:17 + | +LL | reuse to_reuse::late; + | ^^^^ + error[E0277]: the trait bound `S: Clone` is not satisfied --> $DIR/free-fn-to-free-fn.rs:23:12 | @@ -20,6 +34,7 @@ LL + #[derive(Clone)] LL | struct S; | -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0107, E0277. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr b/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr index ead3c30a6886..a20b28c16402 100644 --- a/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr +++ b/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr @@ -23,7 +23,6 @@ LL | reuse >::foo as generic_arguments2; | ^^^ | | | expected `&u8`, found `&Self` - | found this type parameter | arguments to this function are incorrect | = note: expected reference `&u8` diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.stderr b/tests/ui/delegation/generics/generics-gen-args-errors.stderr index 78aefbc6604c..6c57c3bc8d51 100644 --- a/tests/ui/delegation/generics/generics-gen-args-errors.stderr +++ b/tests/ui/delegation/generics/generics-gen-args-errors.stderr @@ -537,10 +537,8 @@ LL | bar::<1, 2, 3, 4, 5, 6>(); note: function defined here, with 3 generic parameters: `T`, `U`, `N` --> $DIR/generics-gen-args-errors.rs:8:18 | -LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} - | - - -------------- LL | reuse foo as bar; - | ^^^ + | --- ^^^ error[E0107]: function takes 2 lifetime arguments but 5 lifetime arguments were supplied --> $DIR/generics-gen-args-errors.rs:17:9 @@ -553,10 +551,8 @@ LL | bar::<'static, 'static, 'static, 'static, 'static>(); note: function defined here, with 2 lifetime parameters: `'a`, `'b` --> $DIR/generics-gen-args-errors.rs:8:18 | -LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} - | -- -- LL | reuse foo as bar; - | ^^^ + | --- ^^^ error[E0747]: constant provided when a type was expected --> $DIR/generics-gen-args-errors.rs:20:23 @@ -575,10 +571,8 @@ LL | bar::<_, _, _, _, _>(); note: function defined here, with 3 generic parameters: `T`, `U`, `N` --> $DIR/generics-gen-args-errors.rs:8:18 | -LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} - | - - -------------- LL | reuse foo as bar; - | ^^^ + | --- ^^^ error[E0747]: unresolved item provided when a constant was expected --> $DIR/generics-gen-args-errors.rs:28:25 diff --git a/tests/ui/delegation/generics/impl-trait-wrong-args-count.rs b/tests/ui/delegation/generics/impl-trait-wrong-args-count.rs deleted file mode 100644 index 8c9b7d5a9e4e..000000000000 --- a/tests/ui/delegation/generics/impl-trait-wrong-args-count.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![feature(fn_delegation)] -#![allow(incomplete_features)] - -mod to_reuse { - pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} - pub fn bar1(x: &super::XX) {} - pub fn bar2(x: &super::XX) {} -} - -trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized { - fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} - fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} - fn bar2(&self) {} - fn bar3(&self) {} - fn bar4(&self) {} -} - -struct X<'x1, 'x2, 'x3, 'x4, X1, X2, const X3: usize>( - &'x1 X1, &'x2 X2, &'x3 X1, &'x4 [usize; X3]); -type XX = X::<'static, 'static, 'static, 'static, i32, i32, 3>; - -impl<'a, 'b, 'c, A, B, const N: usize> Trait<'a, 'b, 'c, A, B, N> for XX { - reuse to_reuse::bar; - //~^ ERROR: function takes at most 2 generic arguments but 3 generic arguments were supplied - - reuse to_reuse::bar1; - //~^ ERROR: function takes 0 generic arguments but 3 generic arguments were supplied - - reuse to_reuse::bar2; - //~^ ERROR: type annotations needed - //~| ERROR: type annotations needed - - reuse to_reuse::bar2:: as bar3; - - reuse to_reuse::bar2:: as bar4; - //~^ ERROR: method `bar4` has 0 type parameters but its trait declaration has 3 type parameters -} - -fn main() { -} diff --git a/tests/ui/delegation/generics/impl-trait-wrong-args-count.stderr b/tests/ui/delegation/generics/impl-trait-wrong-args-count.stderr deleted file mode 100644 index 2a94ac0bfe03..000000000000 --- a/tests/ui/delegation/generics/impl-trait-wrong-args-count.stderr +++ /dev/null @@ -1,74 +0,0 @@ -error[E0049]: method `bar4` has 0 type parameters but its trait declaration has 3 type parameters - --> $DIR/impl-trait-wrong-args-count.rs:35:21 - | -LL | fn bar4(&self) {} - | - - - - | | - | expected 3 type parameters -... -LL | reuse to_reuse::bar2:: as bar4; - | ^^^^ found 0 type parameters - -error[E0107]: function takes at most 2 generic arguments but 3 generic arguments were supplied - --> $DIR/impl-trait-wrong-args-count.rs:23:21 - | -LL | fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} - | ----------------- help: remove the unnecessary generic argument -... -LL | reuse to_reuse::bar; - | ^^^ expected at most 2 generic arguments - | -note: function defined here, with at most 2 generic parameters: `A`, `B` - --> $DIR/impl-trait-wrong-args-count.rs:5:12 - | -LL | pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} - | ^^^ - - - -error[E0107]: function takes 0 generic arguments but 3 generic arguments were supplied - --> $DIR/impl-trait-wrong-args-count.rs:26:21 - | -LL | reuse to_reuse::bar1; - | ^^^^ expected 0 generic arguments - | -note: function defined here, with 0 generic parameters - --> $DIR/impl-trait-wrong-args-count.rs:6:12 - | -LL | pub fn bar1(x: &super::XX) {} - | ^^^^ - -error[E0284]: type annotations needed - --> $DIR/impl-trait-wrong-args-count.rs:29:21 - | -LL | reuse to_reuse::bar2; - | ^^^^ cannot infer the value of the const parameter `X` declared on the function `bar2` - | -note: required by a const generic parameter in `bar2` - --> $DIR/impl-trait-wrong-args-count.rs:7:35 - | -LL | pub fn bar2(x: &super::XX) {} - | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar2` -help: consider specifying the generic arguments - | -LL | reuse to_reuse::bar2::; - | ++++++++++++++++++++++++++ - -error[E0284]: type annotations needed - --> $DIR/impl-trait-wrong-args-count.rs:29:21 - | -LL | reuse to_reuse::bar2; - | ^^^^ cannot infer the value of the const parameter `Y` declared on the function `bar2` - | -note: required by a const generic parameter in `bar2` - --> $DIR/impl-trait-wrong-args-count.rs:7:51 - | -LL | pub fn bar2(x: &super::XX) {} - | ^^^^^^^^^^^^^ required by this const generic parameter in `bar2` -help: consider specifying the generic arguments - | -LL | reuse to_reuse::bar2::; - | ++++++++++++++++++++++++++ - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0049, E0107, E0284. -For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/generics/mapping/free-to-free-pass.rs b/tests/ui/delegation/generics/mapping/free-to-free-pass.rs index aafdd5617d02..c67e4c02a1b7 100644 --- a/tests/ui/delegation/generics/mapping/free-to-free-pass.rs +++ b/tests/ui/delegation/generics/mapping/free-to-free-pass.rs @@ -78,18 +78,16 @@ pub fn check() { } } -// FIXME(fn_delegation): Uncomment this test when impl Traits in function params are supported +mod test_7 { + fn foo(t: T, u: U, f: impl FnOnce(T, U) -> U) -> U { + f(t, u) + } -// mod test_7 { -// fn foo(t: T, u: U, f: impl FnOnce(T, U) -> U) -> U { -// f(t, u) -// } - -// pub fn check() { -// reuse foo as bar; -// assert_eq!(bar::(1, 2, |x, y| y), 2); -// } -// } + pub fn check() { + reuse foo as bar; + assert_eq!(bar::(1, 2, |_, y| y), 2); + } +} // Testing reuse of local fn with delegation parent generic params specified, // late-bound lifetimes + types + consts, reusing with user args, @@ -126,7 +124,7 @@ pub fn main() { test_4::check::(); test_5::check::(); test_6::check::(); - // test_7::check(); + test_7::check(); test_8::check::(); test_9::check::(); } diff --git a/tests/ui/delegation/generics/stability-implications-non-local-defid.rs b/tests/ui/delegation/generics/stability-implications-non-local-defid.rs new file mode 100644 index 000000000000..f8b7874f2806 --- /dev/null +++ b/tests/ui/delegation/generics/stability-implications-non-local-defid.rs @@ -0,0 +1,21 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![feature(staged_api)] +#![unstable(feature = "foo", issue = "none")] + +pub mod m { + #[unstable(feature = "foo", issue = "none")] + pub struct W { + pub inner: std::iter::Map, + } + + #[unstable(feature = "foo", issue = "none")] + impl B> Iterator for W { + type Item = B; + reuse Iterator::{next, fold} { self.inner } + } +} + +fn main() {} diff --git a/tests/ui/delegation/generics/synth-params-ice-143498.rs b/tests/ui/delegation/generics/synth-params-ice-143498.rs new file mode 100644 index 000000000000..652059b37ec6 --- /dev/null +++ b/tests/ui/delegation/generics/synth-params-ice-143498.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes +//@ edition:2024 + +#![feature(fn_delegation)] +#![feature(iter_advance_by)] +#![feature(iter_array_chunks)] +#![feature(iterator_try_collect)] +#![feature(iterator_try_reduce)] +#![feature(iter_collect_into)] +#![feature(iter_intersperse)] +#![feature(iter_is_partitioned)] +#![feature(iter_map_windows)] +#![feature(iter_next_chunk)] +#![feature(iter_order_by)] +#![feature(iter_partition_in_place)] +#![feature(trusted_random_access)] +#![feature(try_find)] +#![allow(incomplete_features)] + +impl X { +//~^ ERROR: cannot find type `X` in this scope + reuse< std::fmt::Debug as Iterator >::*; + //~^ ERROR: expected method or associated constant, found associated type `Iterator::Item` + //~| ERROR: expected a type, found a trait +} + +pub fn main() {} diff --git a/tests/ui/delegation/generics/synth-params-ice-143498.stderr b/tests/ui/delegation/generics/synth-params-ice-143498.stderr new file mode 100644 index 000000000000..14b03991d9e6 --- /dev/null +++ b/tests/ui/delegation/generics/synth-params-ice-143498.stderr @@ -0,0 +1,27 @@ +error[E0425]: cannot find type `X` in this scope + --> $DIR/synth-params-ice-143498.rs:20:6 + | +LL | impl X { + | ^ not found in this scope + +error[E0575]: expected method or associated constant, found associated type `Iterator::Item` + --> $DIR/synth-params-ice-143498.rs:22:10 + | +LL | reuse< std::fmt::Debug as Iterator >::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a method or associated constant + +error[E0782]: expected a type, found a trait + --> $DIR/synth-params-ice-143498.rs:22:12 + | +LL | reuse< std::fmt::Debug as Iterator >::*; + | ^^^^^^^^^^^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | reuse< dyn std::fmt::Debug as Iterator >::*; + | +++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0425, E0575, E0782. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs b/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs new file mode 100644 index 000000000000..7cb98ff307fd --- /dev/null +++ b/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs @@ -0,0 +1,111 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +// Testing delegation from trait impl to free functions. +mod test_1 { + mod to_reuse { + pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} + pub fn bar1(x: &super::XX) {} + pub fn bar2(x: &super::XX) {} + } + + trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized { + fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} + fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} + fn bar2(&self) {} + fn bar3(&self) {} + fn bar4(&self) {} + } + + struct X<'x1, 'x2, 'x3, 'x4, X1, X2, const X3: usize>( + &'x1 X1, &'x2 X2, &'x3 X1, &'x4 [usize; X3]); + type XX = X::<'static, 'static, 'static, 'static, i32, i32, 3>; + + impl<'a, 'b, 'c, A, B, const N: usize> Trait<'a, 'b, 'c, A, B, N> for XX { + reuse to_reuse::bar; + //~^ ERROR: function takes at most 2 generic arguments but 3 generic arguments were supplied + + reuse to_reuse::bar1; + //~^ ERROR: function takes 0 generic arguments but 3 generic arguments were supplied + + reuse to_reuse::bar2; + //~^ ERROR: type annotations needed + //~| ERROR: type annotations needed + + reuse to_reuse::bar2:: as bar3; + + reuse to_reuse::bar2:: as bar4; + } +} + +// Testing delegations of trait impl to other different trait +// with errors in Trait1 generics count. +mod test_2 { + trait Trait { + fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar2() {} + fn bar3() {} + fn bar4() {} + } + + trait Trait1 { + fn bar<'x: 'x, AA, BB, const NN: usize>() {} + } + + struct X; + + impl Trait1 for X {} + + impl Trait for X { + reuse ::bar; + //~^ ERROR: missing generics for trait + + reuse >::bar as bar1; + + reuse >::bar::<'static, u32, u32, 1> as bar2; + + reuse ::bar::<'static, u32, u32, 1> as bar3; + //~^ ERROR: missing generics for trait + + reuse ::bar as bar4; + //~^ ERROR: missing generics for trait + } +} + +// Testing delegations of trait impl to other different trait +// with Trait1::bar and Trait1::foo wrong generics count. +mod test_3 { + trait Trait { + fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar2() {} + fn bar3() {} + } + + trait Trait1 { + fn bar() {} + fn foo() {} + } + + struct X; + + impl Trait1 for X {} + + impl Trait for X { + reuse >::bar; + //~^ ERROR: associated function takes 0 generic arguments but 3 generic arguments were supplied + + reuse >::bar as bar1; + //~^ ERROR: associated function takes 0 generic arguments but 3 generic arguments were supplied + + reuse >::foo as bar2; + //~^ ERROR: type annotations needed + + reuse >::foo as bar3; + //~^ ERROR: associated function takes at most 2 generic arguments but 3 generic arguments were supplied + } +} + +fn main() { +} diff --git a/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr new file mode 100644 index 000000000000..9234771ca11f --- /dev/null +++ b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr @@ -0,0 +1,156 @@ +error[E0107]: function takes at most 2 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:25:25 + | +LL | reuse to_reuse::bar; + | ^^^ + | | + | expected at most 2 generic arguments + | help: remove the unnecessary generic argument + | +note: function defined here, with at most 2 generic parameters: `A`, `B` + --> $DIR/trait-impl-wrong-args-count.rs:7:16 + | +LL | pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} + | ^^^ - - + +error[E0107]: function takes 0 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:28:25 + | +LL | reuse to_reuse::bar1; + | ^^^^ expected 0 generic arguments + | +note: function defined here, with 0 generic parameters + --> $DIR/trait-impl-wrong-args-count.rs:8:16 + | +LL | pub fn bar1(x: &super::XX) {} + | ^^^^ + +error[E0284]: type annotations needed + --> $DIR/trait-impl-wrong-args-count.rs:31:25 + | +LL | reuse to_reuse::bar2; + | ^^^^ cannot infer the value of the const parameter `X` declared on the function `bar2` + | +note: required by a const generic parameter in `bar2` + --> $DIR/trait-impl-wrong-args-count.rs:9:39 + | +LL | pub fn bar2(x: &super::XX) {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar2` +help: consider specifying the generic arguments + | +LL | reuse to_reuse::bar2::; + | ++++++++++++++++++++++++++ + +error[E0284]: type annotations needed + --> $DIR/trait-impl-wrong-args-count.rs:31:25 + | +LL | reuse to_reuse::bar2; + | ^^^^ cannot infer the value of the const parameter `Y` declared on the function `bar2` + | +note: required by a const generic parameter in `bar2` + --> $DIR/trait-impl-wrong-args-count.rs:9:55 + | +LL | pub fn bar2(x: &super::XX) {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `bar2` +help: consider specifying the generic arguments + | +LL | reuse to_reuse::bar2::; + | ++++++++++++++++++++++++++ + +error[E0107]: missing generics for trait `test_2::Trait1` + --> $DIR/trait-impl-wrong-args-count.rs:61:21 + | +LL | reuse ::bar; + | ^^^^^^ expected 2 generic arguments + | +note: trait defined here, with 2 generic parameters: `A`, `B` + --> $DIR/trait-impl-wrong-args-count.rs:52:11 + | +LL | trait Trait1 { + | ^^^^^^ - - +help: add missing generic arguments + | +LL | reuse >::bar; + | ++++++ + +error[E0107]: missing generics for trait `test_2::Trait1` + --> $DIR/trait-impl-wrong-args-count.rs:68:21 + | +LL | reuse ::bar::<'static, u32, u32, 1> as bar3; + | ^^^^^^ expected 2 generic arguments + | +note: trait defined here, with 2 generic parameters: `A`, `B` + --> $DIR/trait-impl-wrong-args-count.rs:52:11 + | +LL | trait Trait1 { + | ^^^^^^ - - +help: add missing generic arguments + | +LL | reuse >::bar::<'static, u32, u32, 1> as bar3; + | ++++++ + +error[E0107]: missing generics for trait `test_2::Trait1` + --> $DIR/trait-impl-wrong-args-count.rs:71:21 + | +LL | reuse ::bar as bar4; + | ^^^^^^ expected 2 generic arguments + | +note: trait defined here, with 2 generic parameters: `A`, `B` + --> $DIR/trait-impl-wrong-args-count.rs:52:11 + | +LL | trait Trait1 { + | ^^^^^^ - - +help: add missing generic arguments + | +LL | reuse >::bar as bar4; + | ++++++ + +error[E0107]: associated function takes 0 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:96:40 + | +LL | reuse >::bar; + | ^^^ expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $DIR/trait-impl-wrong-args-count.rs:87:12 + | +LL | fn bar() {} + | ^^^ + +error[E0107]: associated function takes 0 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:99:40 + | +LL | reuse >::bar as bar1; + | ^^^ expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $DIR/trait-impl-wrong-args-count.rs:87:12 + | +LL | fn bar() {} + | ^^^ + +error[E0282]: type annotations needed + --> $DIR/trait-impl-wrong-args-count.rs:102:40 + | +LL | reuse >::foo as bar2; + | ^^^ cannot infer type of the type parameter `X` declared on the associated function `foo` + +error[E0107]: associated function takes at most 2 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:105:40 + | +LL | reuse >::foo as bar3; + | ^^^ + | | + | expected at most 2 generic arguments + | help: remove the unnecessary generic argument + | +note: associated function defined here, with at most 2 generic parameters: `X`, `Y` + --> $DIR/trait-impl-wrong-args-count.rs:88:12 + | +LL | fn foo() {} + | ^^^ - - + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0107, E0282, E0284. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/delegation/ice-non-fn-target-in-trait-impl.rs b/tests/ui/delegation/ice-non-fn-target-in-trait-impl.rs new file mode 100644 index 000000000000..ebb826f832bc --- /dev/null +++ b/tests/ui/delegation/ice-non-fn-target-in-trait-impl.rs @@ -0,0 +1,20 @@ +// Regression test for #153743 and #153744. +// Delegation to a module or crate root inside a trait impl +// should emit a resolution error, not ICE. + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn bar(); + fn bar2(); +} + +impl Trait for () { + reuse std::path::<> as bar; + //~^ ERROR expected function, found module `std::path` + reuse core::<> as bar2; + //~^ ERROR expected function, found crate `core` +} + +fn main() {} diff --git a/tests/ui/delegation/ice-non-fn-target-in-trait-impl.stderr b/tests/ui/delegation/ice-non-fn-target-in-trait-impl.stderr new file mode 100644 index 000000000000..bed13b0a3a9b --- /dev/null +++ b/tests/ui/delegation/ice-non-fn-target-in-trait-impl.stderr @@ -0,0 +1,15 @@ +error[E0423]: expected function, found module `std::path` + --> $DIR/ice-non-fn-target-in-trait-impl.rs:14:11 + | +LL | reuse std::path::<> as bar; + | ^^^^^^^^^^^^^ not a function + +error[E0423]: expected function, found crate `core` + --> $DIR/ice-non-fn-target-in-trait-impl.rs:16:11 + | +LL | reuse core::<> as bar2; + | ^^^^^^^^ not a function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/delegation/inner-attr.rs b/tests/ui/delegation/inner-attr.rs index 6c996807d6ba..501118713d12 100644 --- a/tests/ui/delegation/inner-attr.rs +++ b/tests/ui/delegation/inner-attr.rs @@ -4,5 +4,6 @@ fn a() {} reuse a as b { #![rustc_dummy] self } //~ ERROR an inner attribute is not permitted in this context +//~^ ERROR: this function takes 0 arguments but 1 argument was supplied fn main() {} diff --git a/tests/ui/delegation/inner-attr.stderr b/tests/ui/delegation/inner-attr.stderr index 257ab760ffc1..226a48ecf9a4 100644 --- a/tests/ui/delegation/inner-attr.stderr +++ b/tests/ui/delegation/inner-attr.stderr @@ -3,11 +3,29 @@ error: an inner attribute is not permitted in this context | LL | reuse a as b { #![rustc_dummy] self } | ^^^^^^^^^^^^^^^ -LL | +... LL | fn main() {} | ------------ the inner attribute doesn't annotate this function | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -error: aborting due to 1 previous error +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/inner-attr.rs:6:7 + | +LL | reuse a as b { #![rustc_dummy] self } + | ^ ---- unexpected argument + | +note: function defined here + --> $DIR/inner-attr.rs:4:4 + | +LL | fn a() {} + | ^ +help: remove the extra argument + | +LL - reuse a as b { #![rustc_dummy] self } +LL + reuse self } + | +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/delegation/reuse-trait-path-with-empty-generics.rs b/tests/ui/delegation/reuse-trait-path-with-empty-generics.rs new file mode 100644 index 000000000000..08645e150044 --- /dev/null +++ b/tests/ui/delegation/reuse-trait-path-with-empty-generics.rs @@ -0,0 +1,14 @@ +//@ needs-rustc-debug-assertions +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn bar4(); +} + +impl Trait for () { + reuse Trait::<> as bar4; + //~^ ERROR expected function, found trait `Trait` +} + +fn main() {} diff --git a/tests/ui/delegation/reuse-trait-path-with-empty-generics.stderr b/tests/ui/delegation/reuse-trait-path-with-empty-generics.stderr new file mode 100644 index 000000000000..eaed6cb33c50 --- /dev/null +++ b/tests/ui/delegation/reuse-trait-path-with-empty-generics.stderr @@ -0,0 +1,9 @@ +error[E0423]: expected function, found trait `Trait` + --> $DIR/reuse-trait-path-with-empty-generics.rs:10:11 + | +LL | reuse Trait::<> as bar4; + | ^^^^^^^^^ not a function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/delegation/unsupported.current.stderr b/tests/ui/delegation/unsupported.current.stderr index 9bc2eec068fe..657f99027173 100644 --- a/tests/ui/delegation/unsupported.current.stderr +++ b/tests/ui/delegation/unsupported.current.stderr @@ -29,18 +29,13 @@ note: ...which requires comparing an impl and trait method signature, inferring LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle - = note: cycle used when checking effective visibilities +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:33:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0283]: type annotations needed - --> $DIR/unsupported.rs:54:18 - | -LL | reuse Trait::foo; - | ^^^ cannot infer type - | - = note: cannot satisfy `_: effects::Trait` +error: aborting due to 2 previous errors -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0283, E0391. -For more information about an error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.next.stderr b/tests/ui/delegation/unsupported.next.stderr index 08bc49513bad..90b17752cd8b 100644 --- a/tests/ui/delegation/unsupported.next.stderr +++ b/tests/ui/delegation/unsupported.next.stderr @@ -25,18 +25,9 @@ note: ...which requires comparing an impl and trait method signature, inferring LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle - = note: cycle used when checking effective visibilities + = note: cycle used when computing implied outlives bounds for `::opaque_ret::{anon_assoc#0}` (hack disabled = false) = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0283]: type annotations needed - --> $DIR/unsupported.rs:54:18 - | -LL | reuse Trait::foo; - | ^^^ cannot infer type - | - = note: cannot satisfy `_: effects::Trait` +error: aborting due to 2 previous errors -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0283, E0391. -For more information about an error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index 1681888e34ea..af3b87ee7c8c 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -2,7 +2,7 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver //@ check-fail - +//@ ignore-parallel-frontend query cycle // Next solver revision included because of trait-system-refactor-initiative#234. // If we end up in a query cycle, it should be okay as long as results are the same. @@ -52,7 +52,6 @@ const trait Trait { } reuse Trait::foo; - //~^ ERROR type annotations needed } fn main() {} diff --git a/tests/ui/delegation/zero-args-delegations-ice-154332.rs b/tests/ui/delegation/zero-args-delegations-ice-154332.rs new file mode 100644 index 000000000000..c684803014ad --- /dev/null +++ b/tests/ui/delegation/zero-args-delegations-ice-154332.rs @@ -0,0 +1,30 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod test_ice { + fn a() {} + + reuse a as b { //~ ERROR: this function takes 0 arguments but 1 argument was supplied + let closure = || { + fn foo<'a, 'b, T: Clone, const N: usize, U: Clone>(_t: &'a T, _u: &'b U) {} + + reuse foo:: as bar; + bar(&"".to_string(), &"".to_string()); + }; + + closure(); + } +} + +mod test_2 { + mod to_reuse { + pub fn zero_args() -> i32 { + 15 + } + } + + reuse to_reuse::zero_args { self } + //~^ ERROR: this function takes 0 arguments but 1 argument was supplied +} + +fn main() {} diff --git a/tests/ui/delegation/zero-args-delegations-ice-154332.stderr b/tests/ui/delegation/zero-args-delegations-ice-154332.stderr new file mode 100644 index 000000000000..dcac56e0b2ba --- /dev/null +++ b/tests/ui/delegation/zero-args-delegations-ice-154332.stderr @@ -0,0 +1,43 @@ +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/zero-args-delegations-ice-154332.rs:7:11 + | +LL | reuse a as b { + | ___________^______- +LL | | let closure = || { +LL | | fn foo<'a, 'b, T: Clone, const N: usize, U: Clone>(_t: &'a T, _u: &'b U) {} +... | +LL | | closure(); +LL | | } + | |_____- unexpected argument of type `()` + | +note: function defined here + --> $DIR/zero-args-delegations-ice-154332.rs:5:8 + | +LL | fn a() {} + | ^ +help: remove the extra argument + | +LL - reuse a as b { +LL + reuse { + | + +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/zero-args-delegations-ice-154332.rs:26:21 + | +LL | reuse to_reuse::zero_args { self } + | ^^^^^^^^^ ---- unexpected argument + | +note: function defined here + --> $DIR/zero-args-delegations-ice-154332.rs:21:16 + | +LL | pub fn zero_args() -> i32 { + | ^^^^^^^^^ +help: remove the extra argument + | +LL - reuse to_reuse::zero_args { self } +LL + reuse to_reuse::zero_argself } + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs b/tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs index 9a7a10529fa6..8b87499966de 100644 --- a/tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs +++ b/tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs @@ -1,6 +1,6 @@ // Test that when a trait impl changes, fns whose body uses that trait // must also be recompiled. - +//@ ignore-parallel-frontend dep graph //@ incremental //@ compile-flags: -Z query-dep-graph @@ -26,7 +26,7 @@ mod x { mod y { use crate::Foo; - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK pub fn use_char_assoc() { // Careful here: in the representation, ::T gets // normalized away, so at a certain point we had no edge to diff --git a/tests/ui/dep-graph/dep-graph-assoc-type-codegen.stderr b/tests/ui/dep-graph/dep-graph-assoc-type-codegen.stderr index b0372051f026..1a56d3181884 100644 --- a/tests/ui/dep-graph/dep-graph-assoc-type-codegen.stderr +++ b/tests/ui/dep-graph/dep-graph-assoc-type-codegen.stderr @@ -1,8 +1,8 @@ error: OK --> $DIR/dep-graph-assoc-type-codegen.rs:29:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/dep-graph/dep-graph-caller-callee.rs b/tests/ui/dep-graph/dep-graph-caller-callee.rs index b1318a169d9c..43d10cd57cdb 100644 --- a/tests/ui/dep-graph/dep-graph-caller-callee.rs +++ b/tests/ui/dep-graph/dep-graph-caller-callee.rs @@ -3,7 +3,7 @@ //@ incremental //@ compile-flags: -Z query-dep-graph - +//@ ignore-parallel-frontend dep graph #![feature(rustc_attrs)] #![allow(dead_code)] @@ -18,7 +18,7 @@ mod y { use crate::x; // These dependencies SHOULD exist: - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK pub fn y() { x::x(); } @@ -29,7 +29,7 @@ mod z { // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. - #[rustc_then_this_would_need(typeck)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_root)] //~ ERROR no path pub fn z() { y::y(); } diff --git a/tests/ui/dep-graph/dep-graph-caller-callee.stderr b/tests/ui/dep-graph/dep-graph-caller-callee.stderr index 33fe91b3500a..379e23fc9a27 100644 --- a/tests/ui/dep-graph/dep-graph-caller-callee.stderr +++ b/tests/ui/dep-graph/dep-graph-caller-callee.stderr @@ -1,14 +1,14 @@ error: OK --> $DIR/dep-graph-caller-callee.rs:21:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ -error: no path from `x` to `typeck` +error: no path from `x` to `typeck_root` --> $DIR/dep-graph-caller-callee.rs:32:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/dep-graph/dep-graph-struct-signature.rs b/tests/ui/dep-graph/dep-graph-struct-signature.rs index eea81b26f9f6..abef7d2e9884 100644 --- a/tests/ui/dep-graph/dep-graph-struct-signature.rs +++ b/tests/ui/dep-graph/dep-graph-struct-signature.rs @@ -1,6 +1,6 @@ // Test cases where a changing struct appears in the signature of fns // and methods. - +//@ ignore-parallel-frontend dep graph //@ incremental //@ compile-flags: -Z query-dep-graph @@ -34,11 +34,11 @@ trait Bar { } #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK fn some_fn(x: WillChange) { } #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK fn new_foo(x: u32, y: u32) -> WillChange { WillChange { x: x, y: y } } @@ -46,14 +46,14 @@ fn new_foo(x: u32, y: u32) -> WillChange { #[rustc_then_this_would_need(type_of)] //~ ERROR OK impl WillChange { #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK fn new(x: u32, y: u32) -> WillChange { loop { } } } #[rustc_then_this_would_need(type_of)] //~ ERROR OK impl WillChange { #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK fn method(&self, x: u32) { } } @@ -82,6 +82,6 @@ trait A { fn b(x: WontChange) { } #[rustc_then_this_would_need(fn_sig)] //~ ERROR no path from `WillChange` - #[rustc_then_this_would_need(typeck)] //~ ERROR no path from `WillChange` + #[rustc_then_this_would_need(typeck_root)] //~ ERROR no path from `WillChange` fn c(x: u32) { } } diff --git a/tests/ui/dep-graph/dep-graph-struct-signature.stderr b/tests/ui/dep-graph/dep-graph-struct-signature.stderr index 98efedc7244c..24d35b87820d 100644 --- a/tests/ui/dep-graph/dep-graph-struct-signature.stderr +++ b/tests/ui/dep-graph/dep-graph-struct-signature.stderr @@ -25,8 +25,8 @@ LL | #[rustc_then_this_would_need(fn_sig)] error: OK --> $DIR/dep-graph-struct-signature.rs:37:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:40:34 @@ -37,8 +37,8 @@ LL | #[rustc_then_this_would_need(fn_sig)] error: OK --> $DIR/dep-graph-struct-signature.rs:41:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:46:34 @@ -88,11 +88,11 @@ error: no path from `WillChange` to `fn_sig` LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^ -error: no path from `WillChange` to `typeck` +error: no path from `WillChange` to `typeck_root` --> $DIR/dep-graph-struct-signature.rs:85:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:32:38 @@ -115,8 +115,8 @@ LL | #[rustc_then_this_would_need(fn_sig)] error: OK --> $DIR/dep-graph-struct-signature.rs:49:38 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:55:38 @@ -127,8 +127,8 @@ LL | #[rustc_then_this_would_need(fn_sig)] error: OK --> $DIR/dep-graph-struct-signature.rs:56:38 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: aborting due to 22 previous errors diff --git a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs index eab4c7921057..ccdd2ff570f6 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs +++ b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs @@ -1,6 +1,6 @@ // Test that adding an impl to a trait `Foo` DOES affect functions // that only use `Bar` if they have methods in common. - +//@ ignore-parallel-frontend dep graph //@ incremental //@ compile-flags: -Z query-dep-graph @@ -30,7 +30,7 @@ impl Bar for char { } mod y { use crate::{Foo, Bar}; - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK pub fn with_char() { char::method('a'); } @@ -39,7 +39,7 @@ pub fn with_char() { mod z { use crate::y; - #[rustc_then_this_would_need(typeck)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_root)] //~ ERROR no path pub fn z() { y::with_char(); } diff --git a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr index 293f918a3187..9802d5acce18 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr +++ b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr @@ -1,14 +1,14 @@ error: OK --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:33:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ -error: no path from `x::` to `typeck` +error: no path from `x::` to `typeck_root` --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:42:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs index 859505a4a7a1..c86923c0468b 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs +++ b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs @@ -29,7 +29,7 @@ impl Bar for char { } mod y { use crate::{Foo, Bar}; - #[rustc_then_this_would_need(typeck)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_root)] //~ ERROR no path pub fn call_bar() { char::bar('a'); } @@ -38,7 +38,7 @@ pub fn call_bar() { mod z { use crate::y; - #[rustc_then_this_would_need(typeck)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_root)] //~ ERROR no path pub fn z() { y::call_bar(); } diff --git a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr index 46cb0e9ea86f..7d7ff0543cb3 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr +++ b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr @@ -1,14 +1,14 @@ -error: no path from `x::` to `typeck` +error: no path from `x::` to `typeck_root` --> $DIR/dep-graph-trait-impl-two-traits.rs:32:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ -error: no path from `x::` to `typeck` +error: no path from `x::` to `typeck_root` --> $DIR/dep-graph-trait-impl-two-traits.rs:41:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/dep-graph/dep-graph-trait-impl.rs b/tests/ui/dep-graph/dep-graph-trait-impl.rs index 5cf0d34e0070..952ccf61c7d5 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl.rs +++ b/tests/ui/dep-graph/dep-graph-trait-impl.rs @@ -1,6 +1,6 @@ // Test that when a trait impl changes, fns whose body uses that trait // must also be recompiled. - +//@ ignore-parallel-frontend dep graph //@ incremental //@ compile-flags: -Z query-dep-graph @@ -25,22 +25,22 @@ impl Foo for u32 { } mod y { use crate::Foo; - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK pub fn with_char() { char::method('a'); } - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK pub fn take_foo_with_char() { take_foo::('a'); } - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK pub fn with_u32() { u32::method(22); } - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK pub fn take_foo_with_u32() { take_foo::(22); } @@ -53,7 +53,7 @@ mod z { // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. - #[rustc_then_this_would_need(typeck)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_root)] //~ ERROR no path pub fn z() { y::with_char(); y::with_u32(); diff --git a/tests/ui/dep-graph/dep-graph-trait-impl.stderr b/tests/ui/dep-graph/dep-graph-trait-impl.stderr index a5fce64c3a1c..8a205feb774b 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl.stderr +++ b/tests/ui/dep-graph/dep-graph-trait-impl.stderr @@ -1,32 +1,32 @@ error: OK --> $DIR/dep-graph-trait-impl.rs:28:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:33:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:38:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:43:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ -error: no path from `x::` to `typeck` +error: no path from `x::` to `typeck_root` --> $DIR/dep-graph-trait-impl.rs:56:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/dep-graph/dep-graph-type-alias.rs b/tests/ui/dep-graph/dep-graph-type-alias.rs index 30cef4b27ef0..8d0407a74ca8 100644 --- a/tests/ui/dep-graph/dep-graph-type-alias.rs +++ b/tests/ui/dep-graph/dep-graph-type-alias.rs @@ -1,5 +1,5 @@ // Test that changing what a `type` points to does not go unnoticed. - +//@ ignore-parallel-frontend dep graph //@ incremental //@ compile-flags: -Z query-dep-graph @@ -42,7 +42,7 @@ trait Trait { #[rustc_then_this_would_need(type_of)] //~ ERROR no path impl SomeType { #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_root)] //~ ERROR OK fn method(&self, _: TypeAlias) {} } @@ -50,7 +50,7 @@ fn method(&self, _: TypeAlias) {} type TypeAlias2 = TypeAlias; #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK -#[rustc_then_this_would_need(typeck)] //~ ERROR OK +#[rustc_then_this_would_need(typeck_root)] //~ ERROR OK fn function(_: TypeAlias) { } diff --git a/tests/ui/dep-graph/dep-graph-type-alias.stderr b/tests/ui/dep-graph/dep-graph-type-alias.stderr index 9f24c1113b98..63312a5f249d 100644 --- a/tests/ui/dep-graph/dep-graph-type-alias.stderr +++ b/tests/ui/dep-graph/dep-graph-type-alias.stderr @@ -49,8 +49,8 @@ LL | #[rustc_then_this_would_need(fn_sig)] error: OK --> $DIR/dep-graph-type-alias.rs:53:30 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:36:34 @@ -67,8 +67,8 @@ LL | #[rustc_then_this_would_need(fn_sig)] error: OK --> $DIR/dep-graph-type-alias.rs:45:34 | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^ +LL | #[rustc_then_this_would_need(typeck_root)] + | ^^^^^^^^^^^ error: aborting due to 12 previous errors diff --git a/tests/ui/dep-graph/dep-graph-variance-alias.rs b/tests/ui/dep-graph/dep-graph-variance-alias.rs index 8a67fe6d7271..5e86e77b24a2 100644 --- a/tests/ui/dep-graph/dep-graph-variance-alias.rs +++ b/tests/ui/dep-graph/dep-graph-variance-alias.rs @@ -1,6 +1,6 @@ // Test that changing what a `type` points to does not go unnoticed // by the variance analysis. - +//@ ignore-parallel-frontend dep graph //@ incremental //@ compile-flags: -Z query-dep-graph diff --git a/tests/ui/derives/derives-span-Clone-enum-struct-variant.rs b/tests/ui/derives/derives-span-Clone-enum-struct-variant.rs deleted file mode 100644 index b556d442420e..000000000000 --- a/tests/ui/derives/derives-span-Clone-enum-struct-variant.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Clone)] -enum Enum { - A { - x: Error //~ ERROR - } -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Clone-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Clone-enum-struct-variant.stderr deleted file mode 100644 index 9aeb3a8c03d2..000000000000 --- a/tests/ui/derives/derives-span-Clone-enum-struct-variant.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Clone` is not satisfied - --> $DIR/derives-span-Clone-enum-struct-variant.rs:9:6 - | -LL | #[derive(Clone)] - | ----- in this derive macro expansion -... -LL | x: Error - | ^^^^^^^^ the trait `Clone` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Clone)]` - | -LL + #[derive(Clone)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Clone-enum.rs b/tests/ui/derives/derives-span-Clone-enum.rs deleted file mode 100644 index 9bb4f486c3ef..000000000000 --- a/tests/ui/derives/derives-span-Clone-enum.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Clone)] -enum Enum { - A( - Error //~ ERROR - ) -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Clone-enum.stderr b/tests/ui/derives/derives-span-Clone-enum.stderr deleted file mode 100644 index 6b4f22416631..000000000000 --- a/tests/ui/derives/derives-span-Clone-enum.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Clone` is not satisfied - --> $DIR/derives-span-Clone-enum.rs:9:6 - | -LL | #[derive(Clone)] - | ----- in this derive macro expansion -... -LL | Error - | ^^^^^ the trait `Clone` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Clone)]` - | -LL + #[derive(Clone)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Clone-struct.rs b/tests/ui/derives/derives-span-Clone-struct.rs deleted file mode 100644 index f151636f848a..000000000000 --- a/tests/ui/derives/derives-span-Clone-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Clone)] -struct Struct { - x: Error //~ ERROR -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Clone-struct.stderr b/tests/ui/derives/derives-span-Clone-struct.stderr deleted file mode 100644 index 17e3f0eccf92..000000000000 --- a/tests/ui/derives/derives-span-Clone-struct.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Clone` is not satisfied - --> $DIR/derives-span-Clone-struct.rs:8:5 - | -LL | #[derive(Clone)] - | ----- in this derive macro expansion -LL | struct Struct { -LL | x: Error - | ^^^^^^^^ the trait `Clone` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Clone)]` - | -LL + #[derive(Clone)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Clone-tuple-struct.rs b/tests/ui/derives/derives-span-Clone-tuple-struct.rs deleted file mode 100644 index 7a62885324eb..000000000000 --- a/tests/ui/derives/derives-span-Clone-tuple-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Clone)] -struct Struct( - Error //~ ERROR -); - -fn main() {} diff --git a/tests/ui/derives/derives-span-Clone-tuple-struct.stderr b/tests/ui/derives/derives-span-Clone-tuple-struct.stderr deleted file mode 100644 index f8380d197b06..000000000000 --- a/tests/ui/derives/derives-span-Clone-tuple-struct.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Clone` is not satisfied - --> $DIR/derives-span-Clone-tuple-struct.rs:8:5 - | -LL | #[derive(Clone)] - | ----- in this derive macro expansion -LL | struct Struct( -LL | Error - | ^^^^^ the trait `Clone` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Clone)]` - | -LL + #[derive(Clone)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Clone.rs b/tests/ui/derives/derives-span-Clone.rs new file mode 100644 index 000000000000..985fbd36db6d --- /dev/null +++ b/tests/ui/derives/derives-span-Clone.rs @@ -0,0 +1,30 @@ +//! Check that all the derives have spans that point to the fields, +//! rather than the #[derive(Clone)] line. + +struct Error; + +#[derive(Clone)] +enum EnumStructVariant { + A { + x: Error, //~ ERROR + }, +} + +#[derive(Clone)] +enum EnumTupleVariant { + A( + Error, //~ ERROR + ), +} + +#[derive(Clone)] +struct Struct { + x: Error, //~ ERROR +} + +#[derive(Clone)] +struct TupleStruct( + Error, //~ ERROR +); + +fn main() {} diff --git a/tests/ui/derives/derives-span-Clone.stderr b/tests/ui/derives/derives-span-Clone.stderr new file mode 100644 index 000000000000..daf8ef209819 --- /dev/null +++ b/tests/ui/derives/derives-span-Clone.stderr @@ -0,0 +1,63 @@ +error[E0277]: the trait bound `Error: Clone` is not satisfied + --> $DIR/derives-span-Clone.rs:9:9 + | +LL | #[derive(Clone)] + | ----- in this derive macro expansion +... +LL | x: Error, + | ^^^^^^^^ the trait `Clone` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Clone` is not satisfied + --> $DIR/derives-span-Clone.rs:16:9 + | +LL | #[derive(Clone)] + | ----- in this derive macro expansion +... +LL | Error, + | ^^^^^ the trait `Clone` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Clone` is not satisfied + --> $DIR/derives-span-Clone.rs:22:5 + | +LL | #[derive(Clone)] + | ----- in this derive macro expansion +LL | struct Struct { +LL | x: Error, + | ^^^^^^^^ the trait `Clone` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Clone` is not satisfied + --> $DIR/derives-span-Clone.rs:27:5 + | +LL | #[derive(Clone)] + | ----- in this derive macro expansion +LL | struct TupleStruct( +LL | Error, + | ^^^^^ the trait `Clone` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Error; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Debug-enum-struct-variant.rs b/tests/ui/derives/derives-span-Debug-enum-struct-variant.rs deleted file mode 100644 index 949597bc8f6e..000000000000 --- a/tests/ui/derives/derives-span-Debug-enum-struct-variant.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Debug)] -enum Enum { - A { - x: Error //~ ERROR - } -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr deleted file mode 100644 index 147910b715f5..000000000000 --- a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: `Error` doesn't implement `Debug` - --> $DIR/derives-span-Debug-enum-struct-variant.rs:9:6 - | -LL | #[derive(Debug)] - | ----- in this derive macro expansion -... -LL | x: Error - | ^^^^^^^^ the trait `Debug` is not implemented for `Error` - | - = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` -help: consider annotating `Error` with `#[derive(Debug)]` - | -LL + #[derive(Debug)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Debug-enum.rs b/tests/ui/derives/derives-span-Debug-enum.rs deleted file mode 100644 index b2a39708ceb9..000000000000 --- a/tests/ui/derives/derives-span-Debug-enum.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Debug)] -enum Enum { - A( - Error //~ ERROR - ) -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Debug-enum.stderr b/tests/ui/derives/derives-span-Debug-enum.stderr deleted file mode 100644 index 6f97ceb02d3a..000000000000 --- a/tests/ui/derives/derives-span-Debug-enum.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: `Error` doesn't implement `Debug` - --> $DIR/derives-span-Debug-enum.rs:9:6 - | -LL | #[derive(Debug)] - | ----- in this derive macro expansion -... -LL | Error - | ^^^^^ the trait `Debug` is not implemented for `Error` - | - = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` -help: consider annotating `Error` with `#[derive(Debug)]` - | -LL + #[derive(Debug)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Debug-struct.rs b/tests/ui/derives/derives-span-Debug-struct.rs deleted file mode 100644 index cf91c9436a62..000000000000 --- a/tests/ui/derives/derives-span-Debug-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Debug)] -struct Struct { - x: Error //~ ERROR -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Debug-struct.stderr b/tests/ui/derives/derives-span-Debug-struct.stderr deleted file mode 100644 index 46d69a892f25..000000000000 --- a/tests/ui/derives/derives-span-Debug-struct.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: `Error` doesn't implement `Debug` - --> $DIR/derives-span-Debug-struct.rs:8:5 - | -LL | #[derive(Debug)] - | ----- in this derive macro expansion -LL | struct Struct { -LL | x: Error - | ^^^^^^^^ the trait `Debug` is not implemented for `Error` - | - = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` -help: consider annotating `Error` with `#[derive(Debug)]` - | -LL + #[derive(Debug)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Debug-tuple-struct.rs b/tests/ui/derives/derives-span-Debug-tuple-struct.rs deleted file mode 100644 index cea973c91a78..000000000000 --- a/tests/ui/derives/derives-span-Debug-tuple-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Debug)] -struct Struct( - Error //~ ERROR -); - -fn main() {} diff --git a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr deleted file mode 100644 index a3feeff6df37..000000000000 --- a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: `Error` doesn't implement `Debug` - --> $DIR/derives-span-Debug-tuple-struct.rs:8:5 - | -LL | #[derive(Debug)] - | ----- in this derive macro expansion -LL | struct Struct( -LL | Error - | ^^^^^ the trait `Debug` is not implemented for `Error` - | - = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` -help: consider annotating `Error` with `#[derive(Debug)]` - | -LL + #[derive(Debug)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Debug.rs b/tests/ui/derives/derives-span-Debug.rs new file mode 100644 index 000000000000..1bc10a04c6f1 --- /dev/null +++ b/tests/ui/derives/derives-span-Debug.rs @@ -0,0 +1,29 @@ +//! Check that all the derives have spans that point to the fields, +//! rather than the #[derive(Debug)] line. + +struct Error; + +#[derive(Debug)] +enum EnumStructVariant { + A { + x: Error, //~ ERROR + }, +} + +#[derive(Debug)] +enum EnumTupleVariant { + A( + Error, //~ ERROR + ), +} +#[derive(Debug)] +struct Struct { + x: Error, //~ ERROR +} + +#[derive(Debug)] +struct TupleStruct( + Error, //~ ERROR +); + +fn main() {} diff --git a/tests/ui/derives/derives-span-Debug.stderr b/tests/ui/derives/derives-span-Debug.stderr new file mode 100644 index 000000000000..e4a2560db451 --- /dev/null +++ b/tests/ui/derives/derives-span-Debug.stderr @@ -0,0 +1,67 @@ +error[E0277]: `Error` doesn't implement `Debug` + --> $DIR/derives-span-Debug.rs:9:9 + | +LL | #[derive(Debug)] + | ----- in this derive macro expansion +... +LL | x: Error, + | ^^^^^^^^ the trait `Debug` is not implemented for `Error` + | + = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` +help: consider annotating `Error` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | struct Error; + | + +error[E0277]: `Error` doesn't implement `Debug` + --> $DIR/derives-span-Debug.rs:16:9 + | +LL | #[derive(Debug)] + | ----- in this derive macro expansion +... +LL | Error, + | ^^^^^ the trait `Debug` is not implemented for `Error` + | + = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` +help: consider annotating `Error` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | struct Error; + | + +error[E0277]: `Error` doesn't implement `Debug` + --> $DIR/derives-span-Debug.rs:21:5 + | +LL | #[derive(Debug)] + | ----- in this derive macro expansion +LL | struct Struct { +LL | x: Error, + | ^^^^^^^^ the trait `Debug` is not implemented for `Error` + | + = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` +help: consider annotating `Error` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | struct Error; + | + +error[E0277]: `Error` doesn't implement `Debug` + --> $DIR/derives-span-Debug.rs:26:5 + | +LL | #[derive(Debug)] + | ----- in this derive macro expansion +LL | struct TupleStruct( +LL | Error, + | ^^^^^ the trait `Debug` is not implemented for `Error` + | + = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` +help: consider annotating `Error` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | struct Error; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Default-struct.rs b/tests/ui/derives/derives-span-Default-struct.rs deleted file mode 100644 index 71fd5829e758..000000000000 --- a/tests/ui/derives/derives-span-Default-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Default)] -struct Struct { - x: Error //~ ERROR -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Default-struct.stderr b/tests/ui/derives/derives-span-Default-struct.stderr deleted file mode 100644 index 442081f78ce7..000000000000 --- a/tests/ui/derives/derives-span-Default-struct.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Default` is not satisfied - --> $DIR/derives-span-Default-struct.rs:8:5 - | -LL | #[derive(Default)] - | ------- in this derive macro expansion -LL | struct Struct { -LL | x: Error - | ^^^^^^^^ the trait `Default` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Default)]` - | -LL + #[derive(Default)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Default-tuple-struct.rs b/tests/ui/derives/derives-span-Default-tuple-struct.rs deleted file mode 100644 index 463f7d230ca4..000000000000 --- a/tests/ui/derives/derives-span-Default-tuple-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Default)] -struct Struct( - Error //~ ERROR -); - -fn main() {} diff --git a/tests/ui/derives/derives-span-Default-tuple-struct.stderr b/tests/ui/derives/derives-span-Default-tuple-struct.stderr deleted file mode 100644 index e786ec1e9dab..000000000000 --- a/tests/ui/derives/derives-span-Default-tuple-struct.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Default` is not satisfied - --> $DIR/derives-span-Default-tuple-struct.rs:8:5 - | -LL | #[derive(Default)] - | ------- in this derive macro expansion -LL | struct Struct( -LL | Error - | ^^^^^ the trait `Default` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Default)]` - | -LL + #[derive(Default)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Default.rs b/tests/ui/derives/derives-span-Default.rs new file mode 100644 index 000000000000..7ea91acf823d --- /dev/null +++ b/tests/ui/derives/derives-span-Default.rs @@ -0,0 +1,16 @@ +//! Check that all the derives have spans that point to the fields, +//! rather than the #[derive(Default)] line. + +struct Error; + +#[derive(Default)] +struct Struct { + x: Error, //~ ERROR +} + +#[derive(Default)] +struct TupleStruct( + Error, //~ ERROR +); + +fn main() {} diff --git a/tests/ui/derives/derives-span-Default.stderr b/tests/ui/derives/derives-span-Default.stderr new file mode 100644 index 000000000000..9c606171cde8 --- /dev/null +++ b/tests/ui/derives/derives-span-Default.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `Error: Default` is not satisfied + --> $DIR/derives-span-Default.rs:8:5 + | +LL | #[derive(Default)] + | ------- in this derive macro expansion +LL | struct Struct { +LL | x: Error, + | ^^^^^^^^ the trait `Default` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Default)]` + | +LL + #[derive(Default)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Default` is not satisfied + --> $DIR/derives-span-Default.rs:13:5 + | +LL | #[derive(Default)] + | ------- in this derive macro expansion +LL | struct TupleStruct( +LL | Error, + | ^^^^^ the trait `Default` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Default)]` + | +LL + #[derive(Default)] +LL | struct Error; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Eq-enum-struct-variant.rs b/tests/ui/derives/derives-span-Eq-enum-struct-variant.rs deleted file mode 100644 index d2dab8687f77..000000000000 --- a/tests/ui/derives/derives-span-Eq-enum-struct-variant.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(PartialEq)] -struct Error; - -#[derive(Eq,PartialEq)] -enum Enum { - A { - x: Error //~ ERROR - } -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr deleted file mode 100644 index 42dc8d46b575..000000000000 --- a/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0277]: the trait bound `Error: Eq` is not satisfied - --> $DIR/derives-span-Eq-enum-struct-variant.rs:9:6 - | -LL | #[derive(Eq,PartialEq)] - | -- in this derive macro expansion -... -LL | x: Error - | ^^^^^^^^ the trait `Eq` is not implemented for `Error` - | -note: required by a bound in `std::cmp::AssertParamIsEq` - --> $SRC_DIR/core/src/cmp.rs:LL:COL -help: consider annotating `Error` with `#[derive(Eq)]` - | -LL + #[derive(Eq)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Eq-enum.rs b/tests/ui/derives/derives-span-Eq-enum.rs deleted file mode 100644 index c6c0d4321083..000000000000 --- a/tests/ui/derives/derives-span-Eq-enum.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(PartialEq)] -struct Error; - -#[derive(Eq,PartialEq)] -enum Enum { - A( - Error //~ ERROR - ) -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Eq-enum.stderr b/tests/ui/derives/derives-span-Eq-enum.stderr deleted file mode 100644 index ef1d9e3242ad..000000000000 --- a/tests/ui/derives/derives-span-Eq-enum.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0277]: the trait bound `Error: Eq` is not satisfied - --> $DIR/derives-span-Eq-enum.rs:9:6 - | -LL | #[derive(Eq,PartialEq)] - | -- in this derive macro expansion -... -LL | Error - | ^^^^^ the trait `Eq` is not implemented for `Error` - | -note: required by a bound in `std::cmp::AssertParamIsEq` - --> $SRC_DIR/core/src/cmp.rs:LL:COL -help: consider annotating `Error` with `#[derive(Eq)]` - | -LL + #[derive(Eq)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Eq-struct.rs b/tests/ui/derives/derives-span-Eq-struct.rs deleted file mode 100644 index df310039847d..000000000000 --- a/tests/ui/derives/derives-span-Eq-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(PartialEq)] -struct Error; - -#[derive(Eq,PartialEq)] -struct Struct { - x: Error //~ ERROR -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Eq-struct.stderr b/tests/ui/derives/derives-span-Eq-struct.stderr deleted file mode 100644 index bae7bb0361df..000000000000 --- a/tests/ui/derives/derives-span-Eq-struct.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0277]: the trait bound `Error: Eq` is not satisfied - --> $DIR/derives-span-Eq-struct.rs:8:5 - | -LL | #[derive(Eq,PartialEq)] - | -- in this derive macro expansion -LL | struct Struct { -LL | x: Error - | ^^^^^^^^ the trait `Eq` is not implemented for `Error` - | -note: required by a bound in `std::cmp::AssertParamIsEq` - --> $SRC_DIR/core/src/cmp.rs:LL:COL -help: consider annotating `Error` with `#[derive(Eq)]` - | -LL + #[derive(Eq)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Eq-tuple-struct.rs b/tests/ui/derives/derives-span-Eq-tuple-struct.rs deleted file mode 100644 index abf6526b9007..000000000000 --- a/tests/ui/derives/derives-span-Eq-tuple-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(PartialEq)] -struct Error; - -#[derive(Eq,PartialEq)] -struct Struct( - Error //~ ERROR -); - -fn main() {} diff --git a/tests/ui/derives/derives-span-Eq-tuple-struct.stderr b/tests/ui/derives/derives-span-Eq-tuple-struct.stderr deleted file mode 100644 index 13396cb27246..000000000000 --- a/tests/ui/derives/derives-span-Eq-tuple-struct.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0277]: the trait bound `Error: Eq` is not satisfied - --> $DIR/derives-span-Eq-tuple-struct.rs:8:5 - | -LL | #[derive(Eq,PartialEq)] - | -- in this derive macro expansion -LL | struct Struct( -LL | Error - | ^^^^^ the trait `Eq` is not implemented for `Error` - | -note: required by a bound in `std::cmp::AssertParamIsEq` - --> $SRC_DIR/core/src/cmp.rs:LL:COL -help: consider annotating `Error` with `#[derive(Eq)]` - | -LL + #[derive(Eq)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Eq.rs b/tests/ui/derives/derives-span-Eq.rs new file mode 100644 index 000000000000..d2c889c10b9e --- /dev/null +++ b/tests/ui/derives/derives-span-Eq.rs @@ -0,0 +1,31 @@ +//! Check that all the derives have spans that point to the fields, +//! rather than the #[derive(Eq)] line. + +#[derive(PartialEq)] +struct Error; + +#[derive(Eq, PartialEq)] +enum EnumStructVariant { + A { + x: Error, //~ ERROR + }, +} + +#[derive(Eq, PartialEq)] +enum EnumTupleVariant { + A( + Error, //~ ERROR + ), +} + +#[derive(Eq, PartialEq)] +struct Struct { + x: Error, //~ ERROR +} + +#[derive(Eq, PartialEq)] +struct TupleStruct( + Error, //~ ERROR +); + +fn main() {} diff --git a/tests/ui/derives/derives-span-Eq.stderr b/tests/ui/derives/derives-span-Eq.stderr new file mode 100644 index 000000000000..02da9e2ade45 --- /dev/null +++ b/tests/ui/derives/derives-span-Eq.stderr @@ -0,0 +1,71 @@ +error[E0277]: the trait bound `Error: Eq` is not satisfied + --> $DIR/derives-span-Eq.rs:10:9 + | +LL | #[derive(Eq, PartialEq)] + | -- in this derive macro expansion +... +LL | x: Error, + | ^^^^^^^^ the trait `Eq` is not implemented for `Error` + | +note: required by a bound in `std::cmp::AssertParamIsEq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL +help: consider annotating `Error` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Eq` is not satisfied + --> $DIR/derives-span-Eq.rs:17:9 + | +LL | #[derive(Eq, PartialEq)] + | -- in this derive macro expansion +... +LL | Error, + | ^^^^^ the trait `Eq` is not implemented for `Error` + | +note: required by a bound in `std::cmp::AssertParamIsEq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL +help: consider annotating `Error` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Eq` is not satisfied + --> $DIR/derives-span-Eq.rs:23:5 + | +LL | #[derive(Eq, PartialEq)] + | -- in this derive macro expansion +LL | struct Struct { +LL | x: Error, + | ^^^^^^^^ the trait `Eq` is not implemented for `Error` + | +note: required by a bound in `std::cmp::AssertParamIsEq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL +help: consider annotating `Error` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Eq` is not satisfied + --> $DIR/derives-span-Eq.rs:28:5 + | +LL | #[derive(Eq, PartialEq)] + | -- in this derive macro expansion +LL | struct TupleStruct( +LL | Error, + | ^^^^^ the trait `Eq` is not implemented for `Error` + | +note: required by a bound in `std::cmp::AssertParamIsEq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL +help: consider annotating `Error` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct Error; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Hash-enum-struct-variant.rs b/tests/ui/derives/derives-span-Hash-enum-struct-variant.rs deleted file mode 100644 index 3018a7b6d03e..000000000000 --- a/tests/ui/derives/derives-span-Hash-enum-struct-variant.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Hash)] -enum Enum { - A { - x: Error //~ ERROR - } -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Hash-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Hash-enum-struct-variant.stderr deleted file mode 100644 index 9854b61d31bb..000000000000 --- a/tests/ui/derives/derives-span-Hash-enum-struct-variant.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Hash` is not satisfied - --> $DIR/derives-span-Hash-enum-struct-variant.rs:9:6 - | -LL | #[derive(Hash)] - | ---- in this derive macro expansion -... -LL | x: Error - | ^^^^^^^^ the trait `Hash` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Hash)]` - | -LL + #[derive(Hash)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Hash-enum.rs b/tests/ui/derives/derives-span-Hash-enum.rs deleted file mode 100644 index 8ce7df18f06f..000000000000 --- a/tests/ui/derives/derives-span-Hash-enum.rs +++ /dev/null @@ -1,12 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -struct Error; - -#[derive(Hash)] -enum Enum { - A( - Error //~ ERROR - ) -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Hash-enum.stderr b/tests/ui/derives/derives-span-Hash-enum.stderr deleted file mode 100644 index 60e7d0cf1ff9..000000000000 --- a/tests/ui/derives/derives-span-Hash-enum.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Hash` is not satisfied - --> $DIR/derives-span-Hash-enum.rs:8:6 - | -LL | #[derive(Hash)] - | ---- in this derive macro expansion -... -LL | Error - | ^^^^^ the trait `Hash` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Hash)]` - | -LL + #[derive(Hash)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Hash-struct.rs b/tests/ui/derives/derives-span-Hash-struct.rs deleted file mode 100644 index fa5e2af6be87..000000000000 --- a/tests/ui/derives/derives-span-Hash-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Hash)] -struct Struct { - x: Error //~ ERROR -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Hash-struct.stderr b/tests/ui/derives/derives-span-Hash-struct.stderr deleted file mode 100644 index 3851cf8ce8b0..000000000000 --- a/tests/ui/derives/derives-span-Hash-struct.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Hash` is not satisfied - --> $DIR/derives-span-Hash-struct.rs:8:5 - | -LL | #[derive(Hash)] - | ---- in this derive macro expansion -LL | struct Struct { -LL | x: Error - | ^^^^^^^^ the trait `Hash` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Hash)]` - | -LL + #[derive(Hash)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Hash-tuple-struct.rs b/tests/ui/derives/derives-span-Hash-tuple-struct.rs deleted file mode 100644 index 3822bce1466e..000000000000 --- a/tests/ui/derives/derives-span-Hash-tuple-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(Hash)] -struct Struct( - Error //~ ERROR -); - -fn main() {} diff --git a/tests/ui/derives/derives-span-Hash-tuple-struct.stderr b/tests/ui/derives/derives-span-Hash-tuple-struct.stderr deleted file mode 100644 index e5a3e7a55664..000000000000 --- a/tests/ui/derives/derives-span-Hash-tuple-struct.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Hash` is not satisfied - --> $DIR/derives-span-Hash-tuple-struct.rs:8:5 - | -LL | #[derive(Hash)] - | ---- in this derive macro expansion -LL | struct Struct( -LL | Error - | ^^^^^ the trait `Hash` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Hash)]` - | -LL + #[derive(Hash)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Hash.rs b/tests/ui/derives/derives-span-Hash.rs new file mode 100644 index 000000000000..73dacb67c6b6 --- /dev/null +++ b/tests/ui/derives/derives-span-Hash.rs @@ -0,0 +1,30 @@ +//! Check that all the derives have spans that point to the fields, +//! rather than the #[derive(Hash)] line. + +struct Error; + +#[derive(Hash)] +enum EnumStructVariant { + A { + x: Error, //~ ERROR + }, +} + +#[derive(Hash)] +enum EnumTupleVariant { + A( + Error, //~ ERROR + ), +} + +#[derive(Hash)] +struct Struct { + x: Error, //~ ERROR +} + +#[derive(Hash)] +struct TupleStruct( + Error, //~ ERROR +); + +fn main() {} diff --git a/tests/ui/derives/derives-span-Hash.stderr b/tests/ui/derives/derives-span-Hash.stderr new file mode 100644 index 000000000000..41ba8d42ac5a --- /dev/null +++ b/tests/ui/derives/derives-span-Hash.stderr @@ -0,0 +1,63 @@ +error[E0277]: the trait bound `Error: Hash` is not satisfied + --> $DIR/derives-span-Hash.rs:9:9 + | +LL | #[derive(Hash)] + | ---- in this derive macro expansion +... +LL | x: Error, + | ^^^^^^^^ the trait `Hash` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Hash)]` + | +LL + #[derive(Hash)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Hash` is not satisfied + --> $DIR/derives-span-Hash.rs:16:9 + | +LL | #[derive(Hash)] + | ---- in this derive macro expansion +... +LL | Error, + | ^^^^^ the trait `Hash` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Hash)]` + | +LL + #[derive(Hash)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Hash` is not satisfied + --> $DIR/derives-span-Hash.rs:22:5 + | +LL | #[derive(Hash)] + | ---- in this derive macro expansion +LL | struct Struct { +LL | x: Error, + | ^^^^^^^^ the trait `Hash` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Hash)]` + | +LL + #[derive(Hash)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Hash` is not satisfied + --> $DIR/derives-span-Hash.rs:27:5 + | +LL | #[derive(Hash)] + | ---- in this derive macro expansion +LL | struct TupleStruct( +LL | Error, + | ^^^^^ the trait `Hash` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Hash)]` + | +LL + #[derive(Hash)] +LL | struct Error; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Ord-enum-struct-variant.rs b/tests/ui/derives/derives-span-Ord-enum-struct-variant.rs deleted file mode 100644 index 62355cc2d961..000000000000 --- a/tests/ui/derives/derives-span-Ord-enum-struct-variant.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(Eq,PartialOrd,PartialEq)] -struct Error; - -#[derive(Ord,Eq,PartialOrd,PartialEq)] -enum Enum { - A { - x: Error //~ ERROR - } -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Ord-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Ord-enum-struct-variant.stderr deleted file mode 100644 index e253a9173fc5..000000000000 --- a/tests/ui/derives/derives-span-Ord-enum-struct-variant.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Ord` is not satisfied - --> $DIR/derives-span-Ord-enum-struct-variant.rs:9:6 - | -LL | #[derive(Ord,Eq,PartialOrd,PartialEq)] - | --- in this derive macro expansion -... -LL | x: Error - | ^^^^^^^^ the trait `Ord` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Ord)]` - | -LL + #[derive(Ord)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Ord-enum.rs b/tests/ui/derives/derives-span-Ord-enum.rs deleted file mode 100644 index 72738931d10f..000000000000 --- a/tests/ui/derives/derives-span-Ord-enum.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(Eq,PartialOrd,PartialEq)] -struct Error; - -#[derive(Ord,Eq,PartialOrd,PartialEq)] -enum Enum { - A( - Error //~ ERROR - ) -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Ord-enum.stderr b/tests/ui/derives/derives-span-Ord-enum.stderr deleted file mode 100644 index 8a92458b51ca..000000000000 --- a/tests/ui/derives/derives-span-Ord-enum.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Ord` is not satisfied - --> $DIR/derives-span-Ord-enum.rs:9:6 - | -LL | #[derive(Ord,Eq,PartialOrd,PartialEq)] - | --- in this derive macro expansion -... -LL | Error - | ^^^^^ the trait `Ord` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Ord)]` - | -LL + #[derive(Ord)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Ord-struct.rs b/tests/ui/derives/derives-span-Ord-struct.rs deleted file mode 100644 index 53d4c2c22b55..000000000000 --- a/tests/ui/derives/derives-span-Ord-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(Eq,PartialOrd,PartialEq)] -struct Error; - -#[derive(Ord,Eq,PartialOrd,PartialEq)] -struct Struct { - x: Error //~ ERROR -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-Ord-struct.stderr b/tests/ui/derives/derives-span-Ord-struct.stderr deleted file mode 100644 index ae110d51196f..000000000000 --- a/tests/ui/derives/derives-span-Ord-struct.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Ord` is not satisfied - --> $DIR/derives-span-Ord-struct.rs:8:5 - | -LL | #[derive(Ord,Eq,PartialOrd,PartialEq)] - | --- in this derive macro expansion -LL | struct Struct { -LL | x: Error - | ^^^^^^^^ the trait `Ord` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Ord)]` - | -LL + #[derive(Ord)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Ord-tuple-struct.rs b/tests/ui/derives/derives-span-Ord-tuple-struct.rs deleted file mode 100644 index 4e09c2709864..000000000000 --- a/tests/ui/derives/derives-span-Ord-tuple-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(Eq,PartialOrd,PartialEq)] -struct Error; - -#[derive(Ord,Eq,PartialOrd,PartialEq)] -struct Struct( - Error //~ ERROR -); - -fn main() {} diff --git a/tests/ui/derives/derives-span-Ord-tuple-struct.stderr b/tests/ui/derives/derives-span-Ord-tuple-struct.stderr deleted file mode 100644 index e2a6d5266b71..000000000000 --- a/tests/ui/derives/derives-span-Ord-tuple-struct.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `Error: Ord` is not satisfied - --> $DIR/derives-span-Ord-tuple-struct.rs:8:5 - | -LL | #[derive(Ord,Eq,PartialOrd,PartialEq)] - | --- in this derive macro expansion -LL | struct Struct( -LL | Error - | ^^^^^ the trait `Ord` is not implemented for `Error` - | -help: consider annotating `Error` with `#[derive(Ord)]` - | -LL + #[derive(Ord)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-Ord.rs b/tests/ui/derives/derives-span-Ord.rs new file mode 100644 index 000000000000..91c3b50a030d --- /dev/null +++ b/tests/ui/derives/derives-span-Ord.rs @@ -0,0 +1,31 @@ +//! Check that all the derives have spans that point to the fields, +//! rather than the #[derive(Ord)] line. + +#[derive(Eq, PartialOrd, PartialEq)] +struct Error; + +#[derive(Ord, Eq, PartialOrd, PartialEq)] +enum EnumStructVariant { + A { + x: Error, //~ ERROR + }, +} + +#[derive(Ord, Eq, PartialOrd, PartialEq)] +enum EnumTupleVariant { + A( + Error, //~ ERROR + ), +} + +#[derive(Ord, Eq, PartialOrd, PartialEq)] +struct Struct { + x: Error, //~ ERROR +} + +#[derive(Ord, Eq, PartialOrd, PartialEq)] +struct TupleStruct( + Error, //~ ERROR +); + +fn main() {} diff --git a/tests/ui/derives/derives-span-Ord.stderr b/tests/ui/derives/derives-span-Ord.stderr new file mode 100644 index 000000000000..b0aaad19003d --- /dev/null +++ b/tests/ui/derives/derives-span-Ord.stderr @@ -0,0 +1,63 @@ +error[E0277]: the trait bound `Error: Ord` is not satisfied + --> $DIR/derives-span-Ord.rs:10:9 + | +LL | #[derive(Ord, Eq, PartialOrd, PartialEq)] + | --- in this derive macro expansion +... +LL | x: Error, + | ^^^^^^^^ the trait `Ord` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Ord)]` + | +LL + #[derive(Ord)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Ord` is not satisfied + --> $DIR/derives-span-Ord.rs:17:9 + | +LL | #[derive(Ord, Eq, PartialOrd, PartialEq)] + | --- in this derive macro expansion +... +LL | Error, + | ^^^^^ the trait `Ord` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Ord)]` + | +LL + #[derive(Ord)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Ord` is not satisfied + --> $DIR/derives-span-Ord.rs:23:5 + | +LL | #[derive(Ord, Eq, PartialOrd, PartialEq)] + | --- in this derive macro expansion +LL | struct Struct { +LL | x: Error, + | ^^^^^^^^ the trait `Ord` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Ord)]` + | +LL + #[derive(Ord)] +LL | struct Error; + | + +error[E0277]: the trait bound `Error: Ord` is not satisfied + --> $DIR/derives-span-Ord.rs:28:5 + | +LL | #[derive(Ord, Eq, PartialOrd, PartialEq)] + | --- in this derive macro expansion +LL | struct TupleStruct( +LL | Error, + | ^^^^^ the trait `Ord` is not implemented for `Error` + | +help: consider annotating `Error` with `#[derive(Ord)]` + | +LL + #[derive(Ord)] +LL | struct Error; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.rs b/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.rs deleted file mode 100644 index 67a27729db7e..000000000000 --- a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(PartialEq)] -enum Enum { - A { - x: Error //~ ERROR - } -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr b/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr deleted file mode 100644 index 09104289c64a..000000000000 --- a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0369]: binary operation `==` cannot be applied to type `&Error` - --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:9:6 - | -LL | #[derive(PartialEq)] - | --------- in this derive macro expansion -... -LL | x: Error - | ^^^^^^^^ - | -note: an implementation of `PartialEq` might be missing for `Error` - --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1 - | -LL | struct Error; - | ^^^^^^^^^^^^ must implement `PartialEq` -help: consider annotating `Error` with `#[derive(PartialEq)]` - | -LL + #[derive(PartialEq)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/derives/derives-span-PartialEq-enum.rs b/tests/ui/derives/derives-span-PartialEq-enum.rs deleted file mode 100644 index 0becc7e0d10f..000000000000 --- a/tests/ui/derives/derives-span-PartialEq-enum.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(PartialEq)] -enum Enum { - A( - Error //~ ERROR - ) -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-PartialEq-enum.stderr b/tests/ui/derives/derives-span-PartialEq-enum.stderr deleted file mode 100644 index 40dca92ef23c..000000000000 --- a/tests/ui/derives/derives-span-PartialEq-enum.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0369]: binary operation `==` cannot be applied to type `&Error` - --> $DIR/derives-span-PartialEq-enum.rs:9:6 - | -LL | #[derive(PartialEq)] - | --------- in this derive macro expansion -... -LL | Error - | ^^^^^ - | -note: an implementation of `PartialEq` might be missing for `Error` - --> $DIR/derives-span-PartialEq-enum.rs:4:1 - | -LL | struct Error; - | ^^^^^^^^^^^^ must implement `PartialEq` -help: consider annotating `Error` with `#[derive(PartialEq)]` - | -LL + #[derive(PartialEq)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/derives/derives-span-PartialEq-struct.rs b/tests/ui/derives/derives-span-PartialEq-struct.rs deleted file mode 100644 index c92ef5fadf73..000000000000 --- a/tests/ui/derives/derives-span-PartialEq-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(PartialEq)] -struct Struct { - x: Error //~ ERROR -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-PartialEq-struct.stderr b/tests/ui/derives/derives-span-PartialEq-struct.stderr deleted file mode 100644 index cfd9fc41d061..000000000000 --- a/tests/ui/derives/derives-span-PartialEq-struct.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0369]: binary operation `==` cannot be applied to type `Error` - --> $DIR/derives-span-PartialEq-struct.rs:8:5 - | -LL | #[derive(PartialEq)] - | --------- in this derive macro expansion -LL | struct Struct { -LL | x: Error - | ^^^^^^^^ - | -note: an implementation of `PartialEq` might be missing for `Error` - --> $DIR/derives-span-PartialEq-struct.rs:4:1 - | -LL | struct Error; - | ^^^^^^^^^^^^ must implement `PartialEq` -help: consider annotating `Error` with `#[derive(PartialEq)]` - | -LL + #[derive(PartialEq)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/derives/derives-span-PartialEq-tuple-struct.rs b/tests/ui/derives/derives-span-PartialEq-tuple-struct.rs deleted file mode 100644 index 10ac347aa0be..000000000000 --- a/tests/ui/derives/derives-span-PartialEq-tuple-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - - -struct Error; - -#[derive(PartialEq)] -struct Struct( - Error //~ ERROR -); - -fn main() {} diff --git a/tests/ui/derives/derives-span-PartialEq-tuple-struct.stderr b/tests/ui/derives/derives-span-PartialEq-tuple-struct.stderr deleted file mode 100644 index 4e35cbb534d9..000000000000 --- a/tests/ui/derives/derives-span-PartialEq-tuple-struct.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0369]: binary operation `==` cannot be applied to type `Error` - --> $DIR/derives-span-PartialEq-tuple-struct.rs:8:5 - | -LL | #[derive(PartialEq)] - | --------- in this derive macro expansion -LL | struct Struct( -LL | Error - | ^^^^^ - | -note: an implementation of `PartialEq` might be missing for `Error` - --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1 - | -LL | struct Error; - | ^^^^^^^^^^^^ must implement `PartialEq` -help: consider annotating `Error` with `#[derive(PartialEq)]` - | -LL + #[derive(PartialEq)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/derives/derives-span-PartialEq.rs b/tests/ui/derives/derives-span-PartialEq.rs new file mode 100644 index 000000000000..ef79f095f46e --- /dev/null +++ b/tests/ui/derives/derives-span-PartialEq.rs @@ -0,0 +1,29 @@ +//! Check that all the derives have spans that point to the fields, +//! rather than the #[derive(PartialEq)] line. + +struct Error; + +#[derive(PartialEq)] +enum EnumStructVariant { + A { + x: Error, //~ ERROR + }, +} + +#[derive(PartialEq)] +enum EnumTupleVariant { + A( + Error, //~ ERROR + ), +} +#[derive(PartialEq)] +struct Struct { + x: Error, //~ ERROR +} + +#[derive(PartialEq)] +struct TupleStruct( + Error, //~ ERROR +); + +fn main() {} diff --git a/tests/ui/derives/derives-span-PartialEq.stderr b/tests/ui/derives/derives-span-PartialEq.stderr new file mode 100644 index 000000000000..c2e928885ce2 --- /dev/null +++ b/tests/ui/derives/derives-span-PartialEq.stderr @@ -0,0 +1,83 @@ +error[E0369]: binary operation `==` cannot be applied to type `&Error` + --> $DIR/derives-span-PartialEq.rs:9:9 + | +LL | #[derive(PartialEq)] + | --------- in this derive macro expansion +... +LL | x: Error, + | ^^^^^^^^ + | +note: an implementation of `PartialEq` might be missing for `Error` + --> $DIR/derives-span-PartialEq.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^ must implement `PartialEq` +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct Error; + | + +error[E0369]: binary operation `==` cannot be applied to type `&Error` + --> $DIR/derives-span-PartialEq.rs:16:9 + | +LL | #[derive(PartialEq)] + | --------- in this derive macro expansion +... +LL | Error, + | ^^^^^ + | +note: an implementation of `PartialEq` might be missing for `Error` + --> $DIR/derives-span-PartialEq.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^ must implement `PartialEq` +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct Error; + | + +error[E0369]: binary operation `==` cannot be applied to type `Error` + --> $DIR/derives-span-PartialEq.rs:21:5 + | +LL | #[derive(PartialEq)] + | --------- in this derive macro expansion +LL | struct Struct { +LL | x: Error, + | ^^^^^^^^ + | +note: an implementation of `PartialEq` might be missing for `Error` + --> $DIR/derives-span-PartialEq.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^ must implement `PartialEq` +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct Error; + | + +error[E0369]: binary operation `==` cannot be applied to type `Error` + --> $DIR/derives-span-PartialEq.rs:26:5 + | +LL | #[derive(PartialEq)] + | --------- in this derive macro expansion +LL | struct TupleStruct( +LL | Error, + | ^^^^^ + | +note: an implementation of `PartialEq` might be missing for `Error` + --> $DIR/derives-span-PartialEq.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^ must implement `PartialEq` +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct Error; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.rs b/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.rs deleted file mode 100644 index a769c137657c..000000000000 --- a/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(PartialEq)] -struct Error; - -#[derive(PartialOrd,PartialEq)] -enum Enum { - A { - x: Error //~ ERROR can't compare `Error` with `Error` - } -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr b/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr deleted file mode 100644 index 7fe09d45cc1b..000000000000 --- a/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: can't compare `Error` with `Error` - --> $DIR/derives-span-PartialOrd-enum-struct-variant.rs:9:6 - | -LL | #[derive(PartialOrd,PartialEq)] - | ---------- in this derive macro expansion -... -LL | x: Error - | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` - | - = help: the trait `PartialOrd` is not implemented for `Error` -help: consider annotating `Error` with `#[derive(PartialOrd)]` - | -LL + #[derive(PartialOrd)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-PartialOrd-enum.rs b/tests/ui/derives/derives-span-PartialOrd-enum.rs deleted file mode 100644 index 4f0d794e42d7..000000000000 --- a/tests/ui/derives/derives-span-PartialOrd-enum.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(PartialEq)] -struct Error; - -#[derive(PartialOrd,PartialEq)] -enum Enum { - A( - Error //~ ERROR can't compare `Error` with `Error` - ) -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-PartialOrd-enum.stderr b/tests/ui/derives/derives-span-PartialOrd-enum.stderr deleted file mode 100644 index 2a14e6e96187..000000000000 --- a/tests/ui/derives/derives-span-PartialOrd-enum.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: can't compare `Error` with `Error` - --> $DIR/derives-span-PartialOrd-enum.rs:9:6 - | -LL | #[derive(PartialOrd,PartialEq)] - | ---------- in this derive macro expansion -... -LL | Error - | ^^^^^ no implementation for `Error < Error` and `Error > Error` - | - = help: the trait `PartialOrd` is not implemented for `Error` -help: consider annotating `Error` with `#[derive(PartialOrd)]` - | -LL + #[derive(PartialOrd)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-PartialOrd-struct.rs b/tests/ui/derives/derives-span-PartialOrd-struct.rs deleted file mode 100644 index da857c674357..000000000000 --- a/tests/ui/derives/derives-span-PartialOrd-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(PartialEq)] -struct Error; - -#[derive(PartialOrd,PartialEq)] -struct Struct { - x: Error //~ ERROR can't compare `Error` with `Error` -} - -fn main() {} diff --git a/tests/ui/derives/derives-span-PartialOrd-struct.stderr b/tests/ui/derives/derives-span-PartialOrd-struct.stderr deleted file mode 100644 index 0904e3ace8f0..000000000000 --- a/tests/ui/derives/derives-span-PartialOrd-struct.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: can't compare `Error` with `Error` - --> $DIR/derives-span-PartialOrd-struct.rs:8:5 - | -LL | #[derive(PartialOrd,PartialEq)] - | ---------- in this derive macro expansion -LL | struct Struct { -LL | x: Error - | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` - | - = help: the trait `PartialOrd` is not implemented for `Error` -help: consider annotating `Error` with `#[derive(PartialOrd)]` - | -LL + #[derive(PartialOrd)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-PartialOrd-tuple-struct.rs b/tests/ui/derives/derives-span-PartialOrd-tuple-struct.rs deleted file mode 100644 index 61d507670880..000000000000 --- a/tests/ui/derives/derives-span-PartialOrd-tuple-struct.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' - -#[derive(PartialEq)] -struct Error; - -#[derive(PartialOrd,PartialEq)] -struct Struct( - Error //~ ERROR can't compare `Error` with `Error` -); - -fn main() {} diff --git a/tests/ui/derives/derives-span-PartialOrd-tuple-struct.stderr b/tests/ui/derives/derives-span-PartialOrd-tuple-struct.stderr deleted file mode 100644 index 501fea02e8ef..000000000000 --- a/tests/ui/derives/derives-span-PartialOrd-tuple-struct.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: can't compare `Error` with `Error` - --> $DIR/derives-span-PartialOrd-tuple-struct.rs:8:5 - | -LL | #[derive(PartialOrd,PartialEq)] - | ---------- in this derive macro expansion -LL | struct Struct( -LL | Error - | ^^^^^ no implementation for `Error < Error` and `Error > Error` - | - = help: the trait `PartialOrd` is not implemented for `Error` -help: consider annotating `Error` with `#[derive(PartialOrd)]` - | -LL + #[derive(PartialOrd)] -LL | struct Error; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/derives-span-PartialOrd.rs b/tests/ui/derives/derives-span-PartialOrd.rs new file mode 100644 index 000000000000..7f7f188b1abb --- /dev/null +++ b/tests/ui/derives/derives-span-PartialOrd.rs @@ -0,0 +1,31 @@ +//! Check that all the derives have spans that point to the fields, +//! rather than the #[derive(PartialOrd)] line. + +#[derive(PartialEq)] +struct Error; + +#[derive(PartialOrd, PartialEq)] +enum EnumStructVariant { + A { + x: Error, //~ ERROR + }, +} + +#[derive(PartialOrd, PartialEq)] +enum EnumTupleVariant { + A( + Error, //~ ERROR + ), +} + +#[derive(PartialOrd, PartialEq)] +struct Struct { + x: Error, //~ ERROR +} + +#[derive(PartialOrd, PartialEq)] +struct TupleStruct( + Error, //~ ERROR +); + +fn main() {} diff --git a/tests/ui/derives/derives-span-PartialOrd.stderr b/tests/ui/derives/derives-span-PartialOrd.stderr new file mode 100644 index 000000000000..3429ee19ccf6 --- /dev/null +++ b/tests/ui/derives/derives-span-PartialOrd.stderr @@ -0,0 +1,67 @@ +error[E0277]: can't compare `Error` with `Error` + --> $DIR/derives-span-PartialOrd.rs:10:9 + | +LL | #[derive(PartialOrd, PartialEq)] + | ---------- in this derive macro expansion +... +LL | x: Error, + | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` + | + = help: the trait `PartialOrd` is not implemented for `Error` +help: consider annotating `Error` with `#[derive(PartialOrd)]` + | +LL + #[derive(PartialOrd)] +LL | struct Error; + | + +error[E0277]: can't compare `Error` with `Error` + --> $DIR/derives-span-PartialOrd.rs:17:9 + | +LL | #[derive(PartialOrd, PartialEq)] + | ---------- in this derive macro expansion +... +LL | Error, + | ^^^^^ no implementation for `Error < Error` and `Error > Error` + | + = help: the trait `PartialOrd` is not implemented for `Error` +help: consider annotating `Error` with `#[derive(PartialOrd)]` + | +LL + #[derive(PartialOrd)] +LL | struct Error; + | + +error[E0277]: can't compare `Error` with `Error` + --> $DIR/derives-span-PartialOrd.rs:23:5 + | +LL | #[derive(PartialOrd, PartialEq)] + | ---------- in this derive macro expansion +LL | struct Struct { +LL | x: Error, + | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` + | + = help: the trait `PartialOrd` is not implemented for `Error` +help: consider annotating `Error` with `#[derive(PartialOrd)]` + | +LL + #[derive(PartialOrd)] +LL | struct Error; + | + +error[E0277]: can't compare `Error` with `Error` + --> $DIR/derives-span-PartialOrd.rs:28:5 + | +LL | #[derive(PartialOrd, PartialEq)] + | ---------- in this derive macro expansion +LL | struct TupleStruct( +LL | Error, + | ^^^^^ no implementation for `Error < Error` and `Error > Error` + | + = help: the trait `PartialOrd` is not implemented for `Error` +help: consider annotating `Error` with `#[derive(PartialOrd)]` + | +LL + #[derive(PartialOrd)] +LL | struct Error; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/derives/deriving-primitive.rs b/tests/ui/derives/deriving-primitive.rs deleted file mode 100644 index 1173eca640fc..000000000000 --- a/tests/ui/derives/deriving-primitive.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[derive(FromPrimitive)] //~ ERROR cannot find derive macro `FromPrimitive` in this scope - //~| ERROR cannot find derive macro `FromPrimitive` in this scope -enum Foo {} - -fn main() {} diff --git a/tests/ui/derives/deriving-primitive.stderr b/tests/ui/derives/deriving-primitive.stderr deleted file mode 100644 index b39637825e56..000000000000 --- a/tests/ui/derives/deriving-primitive.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: cannot find derive macro `FromPrimitive` in this scope - --> $DIR/deriving-primitive.rs:1:10 - | -LL | #[derive(FromPrimitive)] - | ^^^^^^^^^^^^^ - -error: cannot find derive macro `FromPrimitive` in this scope - --> $DIR/deriving-primitive.rs:1:10 - | -LL | #[derive(FromPrimitive)] - | ^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/derives/issue-36617.stderr b/tests/ui/derives/issue-36617.stderr index 3de1d87c5046..f76c5dfc7e06 100644 --- a/tests/ui/derives/issue-36617.stderr +++ b/tests/ui/derives/issue-36617.stderr @@ -5,7 +5,7 @@ LL | #![derive(Copy)] | ^^^^^^^^^^^^^^^^ ... LL | fn main() {} - | ---- the inner attribute doesn't annotate this function + | ------------ the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | @@ -20,7 +20,7 @@ LL | #![test] | ^^^^^^^^ ... LL | fn main() {} - | ---- the inner attribute doesn't annotate this function + | ------------ the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | @@ -35,7 +35,7 @@ LL | #![test_case] | ^^^^^^^^^^^^^ ... LL | fn main() {} - | ---- the inner attribute doesn't annotate this function + | ------------ the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | @@ -50,7 +50,7 @@ LL | #![bench] | ^^^^^^^^^ ... LL | fn main() {} - | ---- the inner attribute doesn't annotate this function + | ------------ the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | @@ -65,7 +65,7 @@ LL | #![global_allocator] | ^^^^^^^^^^^^^^^^^^^^ ... LL | fn main() {} - | ---- the inner attribute doesn't annotate this function + | ------------ the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | diff --git a/tests/ui/diagnostic-width/long-span.long.stderr b/tests/ui/diagnostic-width/long-span.long.stderr index 252b17912dee..526719678afe 100644 --- a/tests/ui/diagnostic-width/long-span.long.stderr +++ b/tests/ui/diagnostic-width/long-span.long.stderr @@ -9,8 +9,10 @@ LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, error[E0308]: mismatched types ╭▸ $DIR/long-span.rs:9:15 │ -LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0]; - ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` +LL │ …t D: u8 = [0, 0, 0, 0, 0, 0, 0, 0… 0, 0, 0, 0, 0, 0, 0, 0, 0]; + │ ┬─ ━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` + │ │ + ╰╴ expected because of the type of the constant error: aborting due to 2 previous errors diff --git a/tests/ui/diagnostic-width/long-span.longest.stderr b/tests/ui/diagnostic-width/long-span.longest.stderr index 2e77c3689223..0b1ca9a22fd6 100644 --- a/tests/ui/diagnostic-width/long-span.longest.stderr +++ b/tests/ui/diagnostic-width/long-span.longest.stderr @@ -9,8 +9,10 @@ LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0 error[E0308]: mismatched types --> $DIR/long-span.rs:9:15 | -LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` +LL | ...D: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,..., 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` + | | + | expected because of the type of the constant error: aborting due to 2 previous errors diff --git a/tests/ui/diagnostic-width/long-span.short.stderr b/tests/ui/diagnostic-width/long-span.short.stderr index b4803e31aaab..bd86a048c434 100644 --- a/tests/ui/diagnostic-width/long-span.short.stderr +++ b/tests/ui/diagnostic-width/long-span.short.stderr @@ -9,8 +9,10 @@ LL │ …u8 = [0, 0, 0…0] + [0, 0, 0…0]; error[E0308]: mismatched types ╭▸ $DIR/long-span.rs:9:15 │ -LL │ …u8 = [0, 0, 0…0]; - ╰╴ ━━━━━━━━…━━ expected `u8`, found `[{integer}; 1680]` +LL │ …t D: u8 = [0,…, 0, 0]; + │ ┬─ ━━━…━━━━━━━ expected `u8`, found `[{integer}; 1680]` + │ │ + ╰╴ expected because of the type of the constant error: aborting due to 2 previous errors diff --git a/tests/ui/diagnostic-width/long-span.shortest.stderr b/tests/ui/diagnostic-width/long-span.shortest.stderr index 1de1a4acd929..4d9e413287b6 100644 --- a/tests/ui/diagnostic-width/long-span.shortest.stderr +++ b/tests/ui/diagnostic-width/long-span.shortest.stderr @@ -9,8 +9,10 @@ LL | ... = [0, 0, 0...0] + [0, 0, 0...0]; error[E0308]: mismatched types --> $DIR/long-span.rs:9:15 | -LL | ... = [0, 0, 0...0]; - | ^^^^^^^^...^^ expected `u8`, found `[{integer}; 1680]` +LL | ...D: u8 = [0,..., 0, 0]; + | -- ^^^...^^^^^^^ expected `u8`, found `[{integer}; 1680]` + | | + | expected because of the type of the constant error: aborting due to 2 previous errors diff --git a/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs b/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs new file mode 100644 index 000000000000..6cff8f4a19b5 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs @@ -0,0 +1,8 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo", + label = "Bar", +)] +#[derive(Debug)] +pub struct Foo; diff --git a/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs new file mode 100644 index 000000000000..69c61e62cfc6 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs @@ -0,0 +1,14 @@ +//@ aux-build:other.rs + +extern crate other; + +use other::Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr new file mode 100644 index 000000000000..8cfe8d6af3f6 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr @@ -0,0 +1,21 @@ +error[E0382]: Foo + --> $DIR/error_is_shown_in_downstream_crates.rs:12:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/error_is_shown_in_downstream_crates.rs:7:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs b/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs new file mode 100644 index 000000000000..e6112e783bd1 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs @@ -0,0 +1,17 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo", + label = "Bar", +)] +#[derive(Debug)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr b/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr new file mode 100644 index 000000000000..483ff5a407bb --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr @@ -0,0 +1,29 @@ +error[E0382]: Foo + --> $DIR/on_move_simple.rs:15:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/on_move_simple.rs:10:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/on_move_simple.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs new file mode 100644 index 000000000000..f2025c2b2271 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs @@ -0,0 +1,32 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo for {Self}", + label = "Bar for {Self}", +)] +#[derive(Debug)] +struct Foo; + +#[diagnostic::on_move( + message="Foo for {X}", + label="Bar for {X}", +)] +struct MyType { + _x: X, +} + +fn takes_foo(_: Foo) {} + +fn takes_mytype(_: MyType) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo for Foo + + let mytype = MyType { _x: 0 }; + takes_mytype(mytype); + let baz = mytype; + //~^ERROR Foo for i32 +} diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr new file mode 100644 index 000000000000..6868f1571be8 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr @@ -0,0 +1,55 @@ +error[E0382]: Foo for Foo + --> $DIR/on_move_with_format.rs:25:15 + | +LL | let foo = Foo; + | --- Bar for Foo +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/on_move_with_format.rs:18:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/on_move_with_format.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error[E0382]: Foo for i32 + --> $DIR/on_move_with_format.rs:30:15 + | +LL | let mytype = MyType { _x: 0 }; + | ------ Bar for i32 +LL | takes_mytype(mytype); + | ------ value moved here +LL | let baz = mytype; + | ^^^^^^ value used here after move + | +note: consider changing this parameter type in function `takes_mytype` to borrow instead if owning the value isn't necessary + --> $DIR/on_move_with_format.rs:20:23 + | +LL | fn takes_mytype(_: MyType) {} + | ------------ ^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function +note: if `MyType` implemented `Clone`, you could clone the value + --> $DIR/on_move_with_format.rs:14:1 + | +LL | struct MyType { + | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_mytype(mytype); + | ------ you could clone this value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs new file mode 100644 index 000000000000..1af3daf0f315 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs @@ -0,0 +1,22 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "first message", + label = "first label", +)] +#[diagnostic::on_move( + message = "second message", + //~^ WARN `message` is ignored due to previous definition of `message` [malformed_diagnostic_attributes] + label = "second label", + //~^ WARN `label` is ignored due to previous definition of `label` [malformed_diagnostic_attributes] +)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR first message +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr new file mode 100644 index 000000000000..f02f97014981 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr @@ -0,0 +1,49 @@ +warning: `message` is ignored due to previous definition of `message` + --> $DIR/report_warning_on_duplicated_options.rs:8:5 + | +LL | message = "first message", + | ------------------------- `message` is first declared here +... +LL | message = "second message", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `message` is later redundantly declared here + | + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +warning: `label` is ignored due to previous definition of `label` + --> $DIR/report_warning_on_duplicated_options.rs:10:5 + | +LL | label = "first label", + | --------------------- `label` is first declared here +... +LL | label = "second label", + | ^^^^^^^^^^^^^^^^^^^^^^ `label` is later redundantly declared here + +error[E0382]: first message + --> $DIR/report_warning_on_duplicated_options.rs:20:15 + | +LL | let foo = Foo; + | --- first label +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_duplicated_options.rs:15:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_duplicated_options.rs:13:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs new file mode 100644 index 000000000000..f403ad1ff480 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs @@ -0,0 +1,18 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo {Baz}", + //~^WARN unknown parameter `Baz` + label = "Bar", +)] +#[derive(Debug)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr new file mode 100644 index 000000000000..efb43c3562a4 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr @@ -0,0 +1,38 @@ +warning: unknown parameter `Baz` + --> $DIR/report_warning_on_invalid_formats.rs:4:21 + | +LL | message = "Foo {Baz}", + | ^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: Foo {Baz} + --> $DIR/report_warning_on_invalid_formats.rs:16:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_invalid_formats.rs:11:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_invalid_formats.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs new file mode 100644 index 000000000000..2050403210d5 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs @@ -0,0 +1,14 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move = "foo"] +//~^WARN missing options for `on_move` attribute [malformed_diagnostic_attributes] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr new file mode 100644 index 000000000000..39992b02e580 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr @@ -0,0 +1,38 @@ +warning: missing options for `on_move` attribute + --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:3:1 + | +LL | #[diagnostic::on_move = "foo"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: at least one of the `message`, `note` and `label` options are expected + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: use of moved value: `foo` + --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:12:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:7:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:5:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs new file mode 100644 index 000000000000..b5bb103d3f27 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs @@ -0,0 +1,18 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( +//~^ WARN expected a literal or missing delimiter [malformed_diagnostic_attributes] +//~| HELP only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma + message = "Foo" + label = "Bar", +)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr new file mode 100644 index 000000000000..00d0657bfcbd --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr @@ -0,0 +1,44 @@ +warning: expected a literal or missing delimiter + --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:3:22 + | +LL | #[diagnostic::on_move( + | ______________________^ +LL | | +LL | | +LL | | message = "Foo" +LL | | label = "Bar", +LL | | )] + | |_^ + | + = help: only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: use of moved value: `foo` + --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:16:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:11:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs new file mode 100644 index 000000000000..c676b87ad857 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs @@ -0,0 +1,18 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( +//~^ WARN expected a literal or missing delimiter [malformed_diagnostic_attributes] +//~| HELP only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma + message = Foo, + label = "Bar", +)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr new file mode 100644 index 000000000000..6dc230b68c5f --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr @@ -0,0 +1,44 @@ +warning: expected a literal or missing delimiter + --> $DIR/report_warning_on_malformed_options_without_literals.rs:3:22 + | +LL | #[diagnostic::on_move( + | ______________________^ +LL | | +LL | | +LL | | message = Foo, +LL | | label = "Bar", +LL | | )] + | |_^ + | + = help: only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: use of moved value: `foo` + --> $DIR/report_warning_on_malformed_options_without_literals.rs:16:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_malformed_options_without_literals.rs:11:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_malformed_options_without_literals.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs new file mode 100644 index 000000000000..e5603fd24ec9 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs @@ -0,0 +1,14 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move] +//~^WARN missing options for `on_move` attribute [malformed_diagnostic_attributes] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr new file mode 100644 index 000000000000..f4e6d69faecb --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr @@ -0,0 +1,38 @@ +warning: missing options for `on_move` attribute + --> $DIR/report_warning_on_missing_options.rs:3:1 + | +LL | #[diagnostic::on_move] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: at least one of the `message`, `note` and `label` options are expected + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: use of moved value: `foo` + --> $DIR/report_warning_on_missing_options.rs:12:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_missing_options.rs:7:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_missing_options.rs:5:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs new file mode 100644 index 000000000000..33e78ea5fc1f --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs @@ -0,0 +1,23 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo", + label = "Bar", +)] +struct Foo; + +#[diagnostic::on_move( +//~^WARN `#[diagnostic::on_move]` can only be applied to enums, structs or unions + message = "Foo", + label = "Bar", +)] +trait MyTrait {} + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr new file mode 100644 index 000000000000..29c987fba48f --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr @@ -0,0 +1,41 @@ +warning: `#[diagnostic::on_move]` can only be applied to enums, structs or unions + --> $DIR/report_warning_on_non_adt.rs:9:1 + | +LL | / #[diagnostic::on_move( +LL | | +LL | | message = "Foo", +LL | | label = "Bar", +LL | | )] + | |__^ + | + = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: Foo + --> $DIR/report_warning_on_non_adt.rs:21:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_non_adt.rs:16:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_non_adt.rs:7:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs new file mode 100644 index 000000000000..651f6184cfac --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs @@ -0,0 +1,19 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo", + label = "Bar", + baz="Baz" + //~^WARN unknown or malformed `on_move` attribute + //~|HELP only `message`, `note` and `label` are allowed as options. Their values must be string literals +)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr new file mode 100644 index 000000000000..a09b8a96d2d1 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr @@ -0,0 +1,38 @@ +warning: unknown or malformed `on_move` attribute + --> $DIR/report_warning_on_unknown_options.rs:6:5 + | +LL | baz="Baz" + | ^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options. Their values must be string literals + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: Foo + --> $DIR/report_warning_on_unknown_options.rs:17:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_unknown_options.rs:12:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_unknown_options.rs:10:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs index e64e60f30c0c..09c2a05cd009 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -26,12 +26,15 @@ impl Bar for i32 {} // cannot use special rustc_on_unimplement symbols // in the format string #[diagnostic::on_unimplemented( - message = "{from_desugaring}{direct}{cause}{integral}{integer}", + message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", //~^WARN there is no parameter `from_desugaring` on trait `Baz` //~|WARN there is no parameter `direct` on trait `Baz` //~|WARN there is no parameter `cause` on trait `Baz` //~|WARN there is no parameter `integral` on trait `Baz` //~|WARN there is no parameter `integer` on trait `Baz` + //~|WARN there is no parameter `r#struct` on trait `Baz` + //~|WARN there is no parameter `r#enum` on trait `Baz` + //~|WARN there is no parameter `union` on trait `Baz` label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" //~^WARN there is no parameter `float` on trait `Baz` //~|WARN there is no parameter `_Self` on trait `Baz` @@ -52,5 +55,5 @@ fn main() { takes_bar(()); //~^ERROR the trait bound `(): Bar` is not satisfied takes_baz(()); - //~^ERROR {from_desugaring}{direct}{cause}{integral}{integer} + //~^ERROR {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union} } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index 862f805e15ba..58d2bdbfc4d6 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -9,7 +9,7 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl warning: there is no parameter `from_desugaring` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:17 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -18,7 +18,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `direct` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:34 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -26,7 +26,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `cause` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:42 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -34,7 +34,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `integral` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:49 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -42,13 +42,37 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `integer` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:59 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument +warning: there is no parameter `r#struct` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:68 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", + | ^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `r#enum` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:76 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", + | ^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `union` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:82 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", + | ^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:15 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ @@ -56,7 +80,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:22 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ @@ -64,7 +88,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:29 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:29 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^^^^^^^ @@ -72,7 +96,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:42 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:42 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ @@ -80,7 +104,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:49 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:49 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^^^^^^^ @@ -88,7 +112,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `This` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:62 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:62 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^ @@ -129,7 +153,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = help: only `message`, `note` and `label` are allowed as options error[E0277]: trait has `()` and `i32` as params - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:53:15 | LL | takes_foo(()); | --------- ^^ trait has `()` and `i32` as params @@ -144,13 +168,13 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:45:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:48:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^^^^^^ required by this bound in `takes_foo` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:15 | LL | takes_bar(()); | --------- ^^ the trait `Bar` is not implemented for `()` @@ -163,13 +187,13 @@ help: the trait `Bar` is implemented for `i32` LL | impl Bar for i32 {} | ^^^^^^^^^^^^^^^^ note: required by a bound in `takes_bar` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:49:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` -error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer} - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:15 +error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union} + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:57:15 | LL | takes_baz(()); | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}{This} @@ -178,16 +202,16 @@ LL | takes_baz(()); | = help: the trait `Baz` is not implemented for `()` help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:43:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `takes_baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:47:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:22 | LL | fn takes_baz(_: impl Baz) {} | ^^^ required by this bound in `takes_baz` -error: aborting due to 3 previous errors; 16 warnings emitted +error: aborting due to 3 previous errors; 19 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/did_you_mean/bad-assoc-pat.rs b/tests/ui/did_you_mean/bad-assoc-pat.rs index 3f912f7ffc63..911eeb0994e4 100644 --- a/tests/ui/did_you_mean/bad-assoc-pat.rs +++ b/tests/ui/did_you_mean/bad-assoc-pat.rs @@ -2,25 +2,25 @@ fn main() { match 0u8 { [u8]::AssocItem => {} //~^ ERROR missing angle brackets in associated item path - //~| ERROR no associated item named `AssocItem` found + //~| ERROR no associated function or constant named `AssocItem` found (u8, u8)::AssocItem => {} //~^ ERROR missing angle brackets in associated item path - //~| ERROR no associated item named `AssocItem` found + //~| ERROR no associated function or constant named `AssocItem` found _::AssocItem => {} //~^ ERROR missing angle brackets in associated item path - //~| ERROR no associated item named `AssocItem` found + //~| ERROR no associated function or constant named `AssocItem` found } match &0u8 { &(u8,)::AssocItem => {} //~^ ERROR missing angle brackets in associated item path - //~| ERROR no associated item named `AssocItem` found + //~| ERROR no associated function or constant named `AssocItem` found } } macro_rules! pat { ($ty: ty) => ($ty::AssocItem) //~^ ERROR missing angle brackets in associated item path - //~| ERROR no associated item named `AssocItem` found + //~| ERROR no associated function or constant named `AssocItem` found } macro_rules! ty { () => (u8) @@ -31,6 +31,6 @@ fn check_macros() { pat!(u8) => {} ty!()::AssocItem => {} //~^ ERROR missing angle brackets in associated item path - //~| ERROR no associated item named `AssocItem` found + //~| ERROR no associated function or constant named `AssocItem` found } } diff --git a/tests/ui/did_you_mean/bad-assoc-pat.stderr b/tests/ui/did_you_mean/bad-assoc-pat.stderr index 8bdeb8ffdd0a..aff3d97eadae 100644 --- a/tests/ui/did_you_mean/bad-assoc-pat.stderr +++ b/tests/ui/did_you_mean/bad-assoc-pat.stderr @@ -68,46 +68,46 @@ help: types that don't start with an identifier need to be surrounded with angle LL | ($ty: ty) => (<$ty>::AssocItem) | + + -error[E0599]: no associated item named `AssocItem` found for slice `[u8]` in the current scope +error[E0599]: no associated function or constant named `AssocItem` found for slice `[u8]` in the current scope --> $DIR/bad-assoc-pat.rs:3:15 | LL | [u8]::AssocItem => {} - | ^^^^^^^^^ associated item not found in `[u8]` + | ^^^^^^^^^ associated function or constant not found in `[u8]` -error[E0599]: no associated item named `AssocItem` found for tuple `(u8, u8)` in the current scope +error[E0599]: no associated function or constant named `AssocItem` found for tuple `(u8, u8)` in the current scope --> $DIR/bad-assoc-pat.rs:6:19 | LL | (u8, u8)::AssocItem => {} - | ^^^^^^^^^ associated item not found in `(u8, u8)` + | ^^^^^^^^^ associated function or constant not found in `(u8, u8)` -error[E0599]: no associated item named `AssocItem` found for type `_` in the current scope +error[E0599]: no associated function or constant named `AssocItem` found for type `_` in the current scope --> $DIR/bad-assoc-pat.rs:9:12 | LL | _::AssocItem => {} - | ^^^^^^^^^ associated item not found in `_` + | ^^^^^^^^^ associated function or constant not found in `_` -error[E0599]: no associated item named `AssocItem` found for tuple `(u8,)` in the current scope +error[E0599]: no associated function or constant named `AssocItem` found for tuple `(u8,)` in the current scope --> $DIR/bad-assoc-pat.rs:14:17 | LL | &(u8,)::AssocItem => {} - | ^^^^^^^^^ associated item not found in `(u8,)` + | ^^^^^^^^^ associated function or constant not found in `(u8,)` -error[E0599]: no associated item named `AssocItem` found for type `u8` in the current scope +error[E0599]: no associated function or constant named `AssocItem` found for type `u8` in the current scope --> $DIR/bad-assoc-pat.rs:21:24 | LL | ($ty: ty) => ($ty::AssocItem) - | ^^^^^^^^^ associated item not found in `u8` + | ^^^^^^^^^ associated function or constant not found in `u8` ... LL | pat!(u8) => {} | -------- in this macro invocation | = note: this error originates in the macro `pat` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: no associated item named `AssocItem` found for type `u8` in the current scope +error[E0599]: no associated function or constant named `AssocItem` found for type `u8` in the current scope --> $DIR/bad-assoc-pat.rs:32:16 | LL | ty!()::AssocItem => {} - | ^^^^^^^^^ associated item not found in `u8` + | ^^^^^^^^^ associated function or constant not found in `u8` error: aborting due to 12 previous errors diff --git a/tests/ui/did_you_mean/brackets-to-braces-single-element.stderr b/tests/ui/did_you_mean/brackets-to-braces-single-element.stderr index d4aeb1eee96a..83a34e2bcd07 100644 --- a/tests/ui/did_you_mean/brackets-to-braces-single-element.stderr +++ b/tests/ui/did_you_mean/brackets-to-braces-single-element.stderr @@ -14,7 +14,9 @@ error[E0308]: mismatched types --> $DIR/brackets-to-braces-single-element.rs:4:19 | LL | const B: &[u32] = &{ 1 }; - | ^^^^^^ expected `&[u32]`, found `&{integer}` + | ------ ^^^^^^ expected `&[u32]`, found `&{integer}` + | | + | expected because of the type of the constant | = note: expected reference `&'static [u32]` found reference `&{integer}` diff --git a/tests/ui/did_you_mean/compatible-variants-in-pat.rs b/tests/ui/did_you_mean/compatible-variants-in-pat.rs index 09e12dab2d3f..5633c28be208 100644 --- a/tests/ui/did_you_mean/compatible-variants-in-pat.rs +++ b/tests/ui/did_you_mean/compatible-variants-in-pat.rs @@ -21,7 +21,6 @@ fn b(s: Option) { S => { //~^ ERROR mismatched types //~| HELP try wrapping - //~| HELP introduce a new binding instead } _ => {} } @@ -32,7 +31,6 @@ fn c(s: Result) { S => { //~^ ERROR mismatched types //~| HELP try wrapping - //~| HELP introduce a new binding instead } _ => {} } diff --git a/tests/ui/did_you_mean/compatible-variants-in-pat.stderr b/tests/ui/did_you_mean/compatible-variants-in-pat.stderr index 09cf094e6bd7..f18965f5d080 100644 --- a/tests/ui/did_you_mean/compatible-variants-in-pat.stderr +++ b/tests/ui/did_you_mean/compatible-variants-in-pat.stderr @@ -14,16 +14,10 @@ LL | Foo::Bar(Bar { x }) => { error[E0308]: mismatched types --> $DIR/compatible-variants-in-pat.rs:21:9 | -LL | struct S; - | -------- unit struct defined here -... LL | match s { | - this expression has type `Option` LL | S => { - | ^ - | | - | expected `Option`, found `S` - | `S` is interpreted as a unit struct, not a new binding + | ^ expected `Option`, found `S` | = note: expected enum `Option` found struct `S` @@ -31,25 +25,14 @@ help: try wrapping the pattern in `Some` | LL | Some(S) => { | +++++ + -help: introduce a new binding instead - | -LL - S => { -LL + other_s => { - | error[E0308]: mismatched types - --> $DIR/compatible-variants-in-pat.rs:32:9 + --> $DIR/compatible-variants-in-pat.rs:31:9 | -LL | struct S; - | -------- unit struct defined here -... LL | match s { | - this expression has type `Result` LL | S => { - | ^ - | | - | expected `Result`, found `S` - | `S` is interpreted as a unit struct, not a new binding + | ^ expected `Result`, found `S` | = note: expected enum `Result` found struct `S` @@ -59,11 +42,6 @@ LL | Ok(S) => { | +++ + LL | Err(S) => { | ++++ + -help: introduce a new binding instead - | -LL - S => { -LL + other_s => { - | error: aborting due to 3 previous errors diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr index 4a38546e2a88..0c07e5afb671 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr @@ -11,14 +11,14 @@ help: the trait `Foo` is not implemented for `Bar` | LL | struct Bar; | ^^^^^^^^^^ -help: the following other types implement trait `Foo` +help: `Bar` implements trait `Foo` --> $DIR/issue-21659-show-relevant-trait-impls-1.rs:15:1 | LL | impl Foo for Bar {} - | ^^^^^^^^^^^^^^^^^^^^^ `Bar` implements `Foo` + | ^^^^^^^^^^^^^^^^^^^^^ `Foo` LL | LL | impl Foo for Bar {} - | ^^^^^^^^^^^^^^^^^^^^ `Bar` implements `Foo` + | ^^^^^^^^^^^^^^^^^^^^ `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr index 8d1c05e7b544..cb4ca9082b44 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr @@ -11,13 +11,13 @@ help: the trait `Foo` is not implemented for `Bar` | LL | struct Bar; | ^^^^^^^^^^ - = help: the following other types implement trait `Foo`: - `Bar` implements `Foo` - `Bar` implements `Foo` - `Bar` implements `Foo` - `Bar` implements `Foo` - `Bar` implements `Foo` - `Bar` implements `Foo` + = help: `Bar` implements trait `Foo`: + Foo + Foo + Foo + Foo + Foo + Foo error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index 8bacae9e96a7..4bb816bdb80e 100644 --- a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -6,12 +6,12 @@ LL | Foo::::bar(&1i8); | | | required by a bound introduced by this call | - = help: the following other types implement trait `Foo`: - `i8` implements `Foo` - `i8` implements `Foo` - `i8` implements `Foo` - `i8` implements `Foo` - `i8` implements `Foo` + = help: `i8` implements trait `Foo`: + Foo + Foo + Foo + Foo + Foo error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 @@ -21,17 +21,17 @@ LL | Foo::::bar(&1u8); | | | required by a bound introduced by this call | -help: the following other types implement trait `Foo` +help: `u8` implements trait `Foo` --> $DIR/issue-39802-show-5-trait-impls.rs:11:1 | LL | impl Foo for u8 {} - | ^^^^^^^^^^^^^^^^^^^^ `u8` implements `Foo` + | ^^^^^^^^^^^^^^^^^^^^ `Foo` LL | impl Foo for u8 {} - | ^^^^^^^^^^^^^^^^^^^^ `u8` implements `Foo` + | ^^^^^^^^^^^^^^^^^^^^ `Foo` LL | impl Foo for u8 {} - | ^^^^^^^^^^^^^^^^^^^^ `u8` implements `Foo` + | ^^^^^^^^^^^^^^^^^^^^ `Foo` LL | impl Foo for u8 {} - | ^^^^^^^^^^^^^^^^^^^^^ `u8` implements `Foo` + | ^^^^^^^^^^^^^^^^^^^^^ `Foo` error[E0277]: the trait bound `bool: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:26:21 @@ -41,13 +41,13 @@ LL | Foo::::bar(&true); | | | required by a bound introduced by this call | - = help: the following other types implement trait `Foo`: - `bool` implements `Foo` - `bool` implements `Foo` - `bool` implements `Foo` - `bool` implements `Foo` - `bool` implements `Foo` - `bool` implements `Foo` + = help: `bool` implements trait `Foo`: + Foo + Foo + Foo + Foo + Foo + Foo error: aborting due to 3 previous errors diff --git a/tests/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr b/tests/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr index 45c7a8bb475a..4e7797c93b51 100644 --- a/tests/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr +++ b/tests/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr @@ -4,8 +4,7 @@ error[E0509]: cannot move out of type `X`, which implements the `Drop` trait LL | let X { x: y } = x; | - ^ cannot move out of here | | - | data moved here - | move occurs because `y` has type `String`, which does not implement the `Copy` trait + | data moved here because `y` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr b/tests/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr index 837904cbae07..0b5f80fc5608 100644 --- a/tests/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr +++ b/tests/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr @@ -5,10 +5,7 @@ LL | match x { | ^ cannot move out of here LL | LL | X { x: y } => println!("contents: {}", y) - | - - | | - | data moved here - | move occurs because `y` has type `String`, which does not implement the `Copy` trait + | - data moved here because `y` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/issues/issue-4735.rs b/tests/ui/drop/drop-noncopyable-raw-pointer.rs similarity index 83% rename from tests/ui/issues/issue-4735.rs rename to tests/ui/drop/drop-noncopyable-raw-pointer.rs index 1ca145bae420..8e980a23c904 100644 --- a/tests/ui/issues/issue-4735.rs +++ b/tests/ui/drop/drop-noncopyable-raw-pointer.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass use std::mem::transmute; diff --git a/tests/ui/dyn-compatibility/associated-consts.stderr b/tests/ui/dyn-compatibility/associated-consts.stderr index a92557ea7b8b..11d02dd2904c 100644 --- a/tests/ui/dyn-compatibility/associated-consts.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/associated-consts.rs:8:35 + --> $DIR/associated-consts.rs:8:31 | LL | fn make_bar(t: &T) -> &dyn Bar { - | ^^^ `Bar` is not dyn compatible + | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit diff --git a/tests/ui/dyn-drop/dyn-drop.rs b/tests/ui/dyn-drop/dyn-drop.rs deleted file mode 100644 index f336949d2cb7..000000000000 --- a/tests/ui/dyn-drop/dyn-drop.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![deny(dyn_drop)] -fn foo(_: Box) {} //~ ERROR -fn bar(_: &dyn Drop) {} //~ERROR -fn baz(_: *mut dyn Drop) {} //~ ERROR -struct Foo { - _x: Box //~ ERROR -} -trait Bar { - type T: ?Sized; -} -struct Baz {} -impl Bar for Baz { - type T = dyn Drop; //~ ERROR -} -fn main() {} diff --git a/tests/ui/dyn-keyword/dyn-drop.rs b/tests/ui/dyn-keyword/dyn-drop.rs new file mode 100644 index 000000000000..81753c94a775 --- /dev/null +++ b/tests/ui/dyn-keyword/dyn-drop.rs @@ -0,0 +1,15 @@ +#![deny(dyn_drop)] +fn foo(_: Box) {} //~ ERROR: types that do not implement `Drop` can still have drop glue, +fn bar(_: &dyn Drop) {} //~ ERROR: types that do not implement `Drop` can still have drop glue, +fn baz(_: *mut dyn Drop) {} //~ ERROR: types that do not implement `Drop` can still have drop glue, +struct Foo { + _x: Box, //~ ERROR: types that do not implement `Drop` can still have drop glue, +} +trait Bar { + type T: ?Sized; +} +struct Baz {} +impl Bar for Baz { + type T = dyn Drop; //~ ERROR: types that do not implement `Drop` can still have drop glue, +} +fn main() {} diff --git a/tests/ui/dyn-drop/dyn-drop.stderr b/tests/ui/dyn-keyword/dyn-drop.stderr similarity index 88% rename from tests/ui/dyn-drop/dyn-drop.stderr rename to tests/ui/dyn-keyword/dyn-drop.stderr index 8210d8a4c48f..969327ecb84e 100644 --- a/tests/ui/dyn-drop/dyn-drop.stderr +++ b/tests/ui/dyn-keyword/dyn-drop.stderr @@ -23,16 +23,16 @@ LL | fn baz(_: *mut dyn Drop) {} | ^^^^ error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped - --> $DIR/dyn-drop.rs:6:15 + --> $DIR/dyn-drop.rs:6:17 | -LL | _x: Box - | ^^^^ +LL | _x: Box, + | ^^^^ error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped - --> $DIR/dyn-drop.rs:13:16 + --> $DIR/dyn-drop.rs:13:18 | -LL | type T = dyn Drop; - | ^^^^ +LL | type T = dyn Drop; + | ^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs new file mode 100644 index 000000000000..23b930cddaa1 --- /dev/null +++ b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs @@ -0,0 +1,11 @@ +#![feature(extern_item_impls)] + +// Regression test for : + +struct Foo(i32); + +#[eii] +pub fn Foo(x: u64) {} +//~^ ERROR the name `Foo` is defined multiple times + +fn main() {} diff --git a/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr new file mode 100644 index 000000000000..e95ab395ff24 --- /dev/null +++ b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr @@ -0,0 +1,14 @@ +error[E0428]: the name `Foo` is defined multiple times + --> $DIR/eii-declaration-conflicts-with-constructor.rs:8:1 + | +LL | struct Foo(i32); + | ---------------- previous definition of the value `Foo` here +... +LL | pub fn Foo(x: u64) {} + | ^^^^^^^^^^^^^^^^^^ `Foo` redefined here + | + = note: `Foo` must be defined only once in the value namespace of this module + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/empty/auxiliary/two_macros.rs b/tests/ui/empty/auxiliary/two_macros.rs deleted file mode 100644 index 2330c75c8e0c..000000000000 --- a/tests/ui/empty/auxiliary/two_macros.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[macro_export] -macro_rules! macro_one { () => ("one") } - -#[macro_export] -macro_rules! macro_two { () => ("two") } diff --git a/tests/ui/empty/empty-linkname.rs b/tests/ui/empty/empty-linkname.rs deleted file mode 100644 index 7113d913cd0f..000000000000 --- a/tests/ui/empty/empty-linkname.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[link(name = "")] //~ ERROR: link name must not be empty -extern "C" {} - -fn main() {} diff --git a/tests/ui/empty/empty-linkname.stderr b/tests/ui/empty/empty-linkname.stderr deleted file mode 100644 index 9fbcbc3ca9dc..000000000000 --- a/tests/ui/empty/empty-linkname.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0454]: link name must not be empty - --> $DIR/empty-linkname.rs:1:15 - | -LL | #[link(name = "")] - | ^^ empty link name - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0454`. diff --git a/tests/ui/empty/issue-37026.rs b/tests/ui/empty/issue-37026.rs deleted file mode 100644 index 2b9dfdcb0f17..000000000000 --- a/tests/ui/empty/issue-37026.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ aux-build:empty-struct.rs - -extern crate empty_struct; - -fn main() { - let empty_struct::XEmpty2 = (); //~ ERROR mismatched types - let empty_struct::XEmpty6(..) = (); //~ ERROR mismatched types -} diff --git a/tests/ui/enum-discriminant/discriminant-ill-typed.rs b/tests/ui/enum-discriminant/discriminant-ill-typed.rs index e3cbd01a1ddf..1e456425cdd8 100644 --- a/tests/ui/enum-discriminant/discriminant-ill-typed.rs +++ b/tests/ui/enum-discriminant/discriminant-ill-typed.rs @@ -13,8 +13,9 @@ enum A { Ok = i8::MAX - 1, Ok2, OhNo = 0_u8, - //~^ ERROR mismatched types - //~| NOTE expected `i8`, found `u8` + //~^ ERROR: mismatched types + //~| NOTE: expected `i8`, found `u8` + //~| NOTE: enum variant discriminant } let x = A::Ok; @@ -26,8 +27,9 @@ enum A { Ok = u8::MAX - 1, Ok2, OhNo = 0_i8, - //~^ ERROR mismatched types - //~| NOTE expected `u8`, found `i8` + //~^ ERROR: mismatched types + //~| NOTE: expected `u8`, found `i8` + //~| NOTE: enum variant discriminant } let x = A::Ok; @@ -39,8 +41,9 @@ enum A { Ok = i16::MAX - 1, Ok2, OhNo = 0_u16, - //~^ ERROR mismatched types - //~| NOTE expected `i16`, found `u16` + //~^ ERROR: mismatched types + //~| NOTE: expected `i16`, found `u16` + //~| NOTE: enum variant discriminant } let x = A::Ok; @@ -52,8 +55,9 @@ enum A { Ok = u16::MAX - 1, Ok2, OhNo = 0_i16, - //~^ ERROR mismatched types - //~| NOTE expected `u16`, found `i16` + //~^ ERROR: mismatched types + //~| NOTE: expected `u16`, found `i16` + //~| NOTE: enum variant discriminant } let x = A::Ok; @@ -65,8 +69,9 @@ enum A { Ok = i32::MAX - 1, Ok2, OhNo = 0_u32, - //~^ ERROR mismatched types - //~| NOTE expected `i32`, found `u32` + //~^ ERROR: mismatched types + //~| NOTE: expected `i32`, found `u32` + //~| NOTE: enum variant discriminant } let x = A::Ok; @@ -78,8 +83,9 @@ enum A { Ok = u32::MAX - 1, Ok2, OhNo = 0_i32, - //~^ ERROR mismatched types - //~| NOTE expected `u32`, found `i32` + //~^ ERROR: mismatched types + //~| NOTE: expected `u32`, found `i32` + //~| NOTE: enum variant discriminant } let x = A::Ok; @@ -91,8 +97,9 @@ enum A { Ok = i64::MAX - 1, Ok2, OhNo = 0_u64, - //~^ ERROR mismatched types - //~| NOTE expected `i64`, found `u64` + //~^ ERROR: mismatched types + //~| NOTE: expected `i64`, found `u64` + //~| NOTE: enum variant discriminant } let x = A::Ok; @@ -104,8 +111,9 @@ enum A { Ok = u64::MAX - 1, Ok2, OhNo = 0_i64, - //~^ ERROR mismatched types - //~| NOTE expected `u64`, found `i64` + //~^ ERROR: mismatched types + //~| NOTE: expected `u64`, found `i64` + //~| NOTE: enum variant discriminant } let x = A::Ok; diff --git a/tests/ui/enum-discriminant/discriminant-ill-typed.stderr b/tests/ui/enum-discriminant/discriminant-ill-typed.stderr index e9508b7fe962..794447295320 100644 --- a/tests/ui/enum-discriminant/discriminant-ill-typed.stderr +++ b/tests/ui/enum-discriminant/discriminant-ill-typed.stderr @@ -4,6 +4,7 @@ error[E0308]: mismatched types LL | OhNo = 0_u8, | ^^^^ expected `i8`, found `u8` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `u8` to `i8` | LL - OhNo = 0_u8, @@ -11,11 +12,12 @@ LL + OhNo = 0_i8, | error[E0308]: mismatched types - --> $DIR/discriminant-ill-typed.rs:28:16 + --> $DIR/discriminant-ill-typed.rs:29:16 | LL | OhNo = 0_i8, | ^^^^ expected `u8`, found `i8` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `i8` to `u8` | LL - OhNo = 0_i8, @@ -23,11 +25,12 @@ LL + OhNo = 0_u8, | error[E0308]: mismatched types - --> $DIR/discriminant-ill-typed.rs:41:16 + --> $DIR/discriminant-ill-typed.rs:43:16 | LL | OhNo = 0_u16, | ^^^^^ expected `i16`, found `u16` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `u16` to `i16` | LL - OhNo = 0_u16, @@ -35,11 +38,12 @@ LL + OhNo = 0_i16, | error[E0308]: mismatched types - --> $DIR/discriminant-ill-typed.rs:54:16 + --> $DIR/discriminant-ill-typed.rs:57:16 | LL | OhNo = 0_i16, | ^^^^^ expected `u16`, found `i16` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `i16` to `u16` | LL - OhNo = 0_i16, @@ -47,11 +51,12 @@ LL + OhNo = 0_u16, | error[E0308]: mismatched types - --> $DIR/discriminant-ill-typed.rs:67:16 + --> $DIR/discriminant-ill-typed.rs:71:16 | LL | OhNo = 0_u32, | ^^^^^ expected `i32`, found `u32` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `u32` to `i32` | LL - OhNo = 0_u32, @@ -59,11 +64,12 @@ LL + OhNo = 0_i32, | error[E0308]: mismatched types - --> $DIR/discriminant-ill-typed.rs:80:16 + --> $DIR/discriminant-ill-typed.rs:85:16 | LL | OhNo = 0_i32, | ^^^^^ expected `u32`, found `i32` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `i32` to `u32` | LL - OhNo = 0_i32, @@ -71,11 +77,12 @@ LL + OhNo = 0_u32, | error[E0308]: mismatched types - --> $DIR/discriminant-ill-typed.rs:93:16 + --> $DIR/discriminant-ill-typed.rs:99:16 | LL | OhNo = 0_u64, | ^^^^^ expected `i64`, found `u64` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `u64` to `i64` | LL - OhNo = 0_u64, @@ -83,11 +90,12 @@ LL + OhNo = 0_i64, | error[E0308]: mismatched types - --> $DIR/discriminant-ill-typed.rs:106:16 + --> $DIR/discriminant-ill-typed.rs:113:16 | LL | OhNo = 0_i64, | ^^^^^ expected `u64`, found `i64` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `i64` to `u64` | LL - OhNo = 0_i64, diff --git a/tests/ui/structs-enums/auxiliary/namespaced_enum_emulate_flat.rs b/tests/ui/enum/auxiliary/namespaced_enum_emulate_flat.rs similarity index 100% rename from tests/ui/structs-enums/auxiliary/namespaced_enum_emulate_flat.rs rename to tests/ui/enum/auxiliary/namespaced_enum_emulate_flat.rs diff --git a/tests/ui/structs-enums/auxiliary/namespaced_enums.rs b/tests/ui/enum/auxiliary/namespaced_enums.rs similarity index 100% rename from tests/ui/structs-enums/auxiliary/namespaced_enums.rs rename to tests/ui/enum/auxiliary/namespaced_enums.rs diff --git a/tests/ui/enum/closure-in-enum-issue-48838.stderr b/tests/ui/enum/closure-in-enum-issue-48838.stderr index 17e6c3433343..6c84efe73e42 100644 --- a/tests/ui/enum/closure-in-enum-issue-48838.stderr +++ b/tests/ui/enum/closure-in-enum-issue-48838.stderr @@ -6,6 +6,7 @@ LL | Square = |x| x, | = note: expected type `isize` found closure `{closure@$DIR/closure-in-enum-issue-48838.rs:2:14: 2:17}` + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` error: aborting due to 1 previous error diff --git a/tests/ui/structs-enums/enum-clike-ffi-as-int.rs b/tests/ui/enum/enum-clike-ffi-as-int.rs similarity index 100% rename from tests/ui/structs-enums/enum-clike-ffi-as-int.rs rename to tests/ui/enum/enum-clike-ffi-as-int.rs diff --git a/tests/ui/structs-enums/enum-discrim-manual-sizing.rs b/tests/ui/enum/enum-discrim-manual-sizing.rs similarity index 100% rename from tests/ui/structs-enums/enum-discrim-manual-sizing.rs rename to tests/ui/enum/enum-discrim-manual-sizing.rs diff --git a/tests/ui/structs-enums/enum-discrim-range-overflow.rs b/tests/ui/enum/enum-discrim-range-overflow.rs similarity index 96% rename from tests/ui/structs-enums/enum-discrim-range-overflow.rs rename to tests/ui/enum/enum-discrim-range-overflow.rs index 91be8014ebda..641e5566bee3 100644 --- a/tests/ui/structs-enums/enum-discrim-range-overflow.rs +++ b/tests/ui/enum/enum-discrim-range-overflow.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(overflowing_literals)] diff --git a/tests/ui/structs-enums/enum-discrim-width-stuff.rs b/tests/ui/enum/enum-discrim-width-stuff.rs similarity index 100% rename from tests/ui/structs-enums/enum-discrim-width-stuff.rs rename to tests/ui/enum/enum-discrim-width-stuff.rs diff --git a/tests/ui/enum/enum-discriminant-missing-variant.rs b/tests/ui/enum/enum-discriminant-missing-variant.rs index 1bdbfb1fbcd4..45c2b3744434 100644 --- a/tests/ui/enum/enum-discriminant-missing-variant.rs +++ b/tests/ui/enum/enum-discriminant-missing-variant.rs @@ -1,6 +1,6 @@ //! regression test for issue pub enum SomeEnum { - B = SomeEnum::A, //~ ERROR no variant or associated item named `A` found + B = SomeEnum::A, //~ ERROR no variant, associated function, or constant named `A` found } fn main() {} diff --git a/tests/ui/enum/enum-discriminant-missing-variant.stderr b/tests/ui/enum/enum-discriminant-missing-variant.stderr index ef98a93e86f6..653a87a5ebd8 100644 --- a/tests/ui/enum/enum-discriminant-missing-variant.stderr +++ b/tests/ui/enum/enum-discriminant-missing-variant.stderr @@ -1,10 +1,10 @@ -error[E0599]: no variant or associated item named `A` found for enum `SomeEnum` in the current scope +error[E0599]: no variant, associated function, or constant named `A` found for enum `SomeEnum` in the current scope --> $DIR/enum-discriminant-missing-variant.rs:3:19 | LL | pub enum SomeEnum { - | ----------------- variant or associated item `A` not found for this enum + | ----------------- variant, associated function, or constant `A` not found for this enum LL | B = SomeEnum::A, - | ^ variant or associated item not found in `SomeEnum` + | ^ variant, associated function, or constant not found in `SomeEnum` | help: there is a variant with a similar name | diff --git a/tests/ui/enum/enum-discriminant-type-mismatch-8761.rs b/tests/ui/enum/enum-discriminant-type-mismatch-8761.rs index ae09b919dc15..63973be83774 100644 --- a/tests/ui/enum/enum-discriminant-type-mismatch-8761.rs +++ b/tests/ui/enum/enum-discriminant-type-mismatch-8761.rs @@ -1,11 +1,13 @@ // https://github.com/rust-lang/rust/issues/8761 enum Foo { A = 1i64, - //~^ ERROR mismatched types - //~| NOTE expected `isize`, found `i64` + //~^ ERROR: mismatched types + //~| NOTE: expected `isize`, found `i64` + //~| NOTE: enum variant discriminant B = 2u8 - //~^ ERROR mismatched types - //~| NOTE expected `isize`, found `u8` + //~^ ERROR: mismatched types + //~| NOTE: expected `isize`, found `u8` + //~| NOTE: enum variant discriminant } fn main() {} diff --git a/tests/ui/enum/enum-discriminant-type-mismatch-8761.stderr b/tests/ui/enum/enum-discriminant-type-mismatch-8761.stderr index f1645183e176..d256a2ed644b 100644 --- a/tests/ui/enum/enum-discriminant-type-mismatch-8761.stderr +++ b/tests/ui/enum/enum-discriminant-type-mismatch-8761.stderr @@ -4,6 +4,7 @@ error[E0308]: mismatched types LL | A = 1i64, | ^^^^ expected `isize`, found `i64` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `i64` to `isize` | LL - A = 1i64, @@ -11,11 +12,12 @@ LL + A = 1isize, | error[E0308]: mismatched types - --> $DIR/enum-discriminant-type-mismatch-8761.rs:6:9 + --> $DIR/enum-discriminant-type-mismatch-8761.rs:7:9 | LL | B = 2u8 | ^^^ expected `isize`, found `u8` | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` help: change the type of the numeric literal from `u8` to `isize` | LL - B = 2u8 diff --git a/tests/ui/structs-enums/enum-disr-val-pretty.rs b/tests/ui/enum/enum-disr-val-pretty.rs similarity index 100% rename from tests/ui/structs-enums/enum-disr-val-pretty.rs rename to tests/ui/enum/enum-disr-val-pretty.rs diff --git a/tests/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs b/tests/ui/enum/enum-nullable-simplifycfg-misopt.rs similarity index 100% rename from tests/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs rename to tests/ui/enum/enum-nullable-simplifycfg-misopt.rs diff --git a/tests/ui/structs-enums/enum-univariant-repr.rs b/tests/ui/enum/enum-univariant-repr.rs similarity index 100% rename from tests/ui/structs-enums/enum-univariant-repr.rs rename to tests/ui/enum/enum-univariant-repr.rs diff --git a/tests/ui/structs-enums/enum-variants.rs b/tests/ui/enum/enum-variants.rs similarity index 100% rename from tests/ui/structs-enums/enum-variants.rs rename to tests/ui/enum/enum-variants.rs diff --git a/tests/ui/structs-enums/namespaced-enum-emulate-flat-xc.rs b/tests/ui/enum/namespaced-enum-emulate-flat-xc.rs similarity index 100% rename from tests/ui/structs-enums/namespaced-enum-emulate-flat-xc.rs rename to tests/ui/enum/namespaced-enum-emulate-flat-xc.rs diff --git a/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs b/tests/ui/enum/namespaced-enum-emulate-flat.rs similarity index 96% rename from tests/ui/structs-enums/namespaced-enum-emulate-flat.rs rename to tests/ui/enum/namespaced-enum-emulate-flat.rs index 774cfa1a3808..2bc23d94b4d9 100644 --- a/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs +++ b/tests/ui/enum/namespaced-enum-emulate-flat.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] pub use Foo::*; diff --git a/tests/ui/structs-enums/namespaced-enum-glob-import-xcrate.rs b/tests/ui/enum/namespaced-enum-glob-import-xcrate.rs similarity index 100% rename from tests/ui/structs-enums/namespaced-enum-glob-import-xcrate.rs rename to tests/ui/enum/namespaced-enum-glob-import-xcrate.rs diff --git a/tests/ui/structs-enums/namespaced-enum-glob-import.rs b/tests/ui/enum/namespaced-enum-glob-import.rs similarity index 96% rename from tests/ui/structs-enums/namespaced-enum-glob-import.rs rename to tests/ui/enum/namespaced-enum-glob-import.rs index 82742a934c41..52bfa9d4ab72 100644 --- a/tests/ui/structs-enums/namespaced-enum-glob-import.rs +++ b/tests/ui/enum/namespaced-enum-glob-import.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] mod m2 { diff --git a/tests/ui/structs-enums/namespaced-enums-xcrate.rs b/tests/ui/enum/namespaced-enums-xcrate.rs similarity index 100% rename from tests/ui/structs-enums/namespaced-enums-xcrate.rs rename to tests/ui/enum/namespaced-enums-xcrate.rs diff --git a/tests/ui/structs-enums/namespaced-enums.rs b/tests/ui/enum/namespaced-enums.rs similarity index 92% rename from tests/ui/structs-enums/namespaced-enums.rs rename to tests/ui/enum/namespaced-enums.rs index 3e2e0b5ffa8f..f3f1a3bd44e5 100644 --- a/tests/ui/structs-enums/namespaced-enums.rs +++ b/tests/ui/enum/namespaced-enums.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] enum Foo { diff --git a/tests/ui/structs-enums/struct-like-variant-construct.rs b/tests/ui/enum/struct-like-variant-construct.rs similarity index 100% rename from tests/ui/structs-enums/struct-like-variant-construct.rs rename to tests/ui/enum/struct-like-variant-construct.rs diff --git a/tests/ui/structs-enums/struct-like-variant-match.rs b/tests/ui/enum/struct-like-variant-match.rs similarity index 100% rename from tests/ui/structs-enums/struct-like-variant-match.rs rename to tests/ui/enum/struct-like-variant-match.rs diff --git a/tests/ui/env-macro/env-cargo-var-typo-issue-148439.rs b/tests/ui/env-macro/env-cargo-var-typo-issue-148439.rs index f859decd09ec..f72b43bb2543 100644 --- a/tests/ui/env-macro/env-cargo-var-typo-issue-148439.rs +++ b/tests/ui/env-macro/env-cargo-var-typo-issue-148439.rs @@ -1,4 +1,5 @@ //@ edition: 2021 +//@ compile-flags: --crate-type=lib // Regression test for issue #148439 // Ensure that when using misspelled Cargo environment variables in env!(), @@ -44,7 +45,14 @@ fn test_cargo_unknown_var() { // Cargo-prefixed but not similar to any known variable let _ = env!("CARGO_SOMETHING_TOTALLY_UNKNOWN"); //~^ ERROR environment variable `CARGO_SOMETHING_TOTALLY_UNKNOWN` not defined at compile time + //~| HELP `CARGO_SOMETHING_TOTALLY_UNKNOWN` may not be available for the current Cargo target //~| HELP Cargo sets build script variables at run time. Use `std::env::var("CARGO_SOMETHING_TOTALLY_UNKNOWN")` instead } -fn main() {} +fn test_cargo_conditional_var() { + // Only set for binairies + let _ = env!("CARGO_BIN_NAME"); + //~^ ERROR environment variable `CARGO_BIN_NAME` not defined at compile time + //~| HELP `CARGO_BIN_NAME` may not be available for the current Cargo target + //~| HELP Cargo sets build script variables at run time. Use `std::env::var("CARGO_BIN_NAME")` instead +} diff --git a/tests/ui/env-macro/env-cargo-var-typo-issue-148439.stderr b/tests/ui/env-macro/env-cargo-var-typo-issue-148439.stderr index e16c4d9a1f4c..50a4cf1a616b 100644 --- a/tests/ui/env-macro/env-cargo-var-typo-issue-148439.stderr +++ b/tests/ui/env-macro/env-cargo-var-typo-issue-148439.stderr @@ -1,5 +1,5 @@ error: environment variable `CARGO_PACKAGE_VERSION` not defined at compile time - --> $DIR/env-cargo-var-typo-issue-148439.rs:7:13 + --> $DIR/env-cargo-var-typo-issue-148439.rs:8:13 | LL | let _ = env!("CARGO_PACKAGE_VERSION"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let _ = env!("CARGO_PACKAGE_VERSION"); = help: there is a similar Cargo environment variable: `CARGO_PKG_VERSION` error: environment variable `CARGO_PACKAGE_NAME` not defined at compile time - --> $DIR/env-cargo-var-typo-issue-148439.rs:13:13 + --> $DIR/env-cargo-var-typo-issue-148439.rs:14:13 | LL | let _ = env!("CARGO_PACKAGE_NAME"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | let _ = env!("CARGO_PACKAGE_NAME"); = help: there is a similar Cargo environment variable: `CARGO_PKG_NAME` error: environment variable `CARGO_PACKAGE_AUTHORS` not defined at compile time - --> $DIR/env-cargo-var-typo-issue-148439.rs:19:13 + --> $DIR/env-cargo-var-typo-issue-148439.rs:20:13 | LL | let _ = env!("CARGO_PACKAGE_AUTHORS"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | let _ = env!("CARGO_PACKAGE_AUTHORS"); = help: there is a similar Cargo environment variable: `CARGO_PKG_AUTHORS` error: environment variable `CARGO_MANIFEST_DIRECTORY` not defined at compile time - --> $DIR/env-cargo-var-typo-issue-148439.rs:25:13 + --> $DIR/env-cargo-var-typo-issue-148439.rs:26:13 | LL | let _ = env!("CARGO_MANIFEST_DIRECTORY"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | let _ = env!("CARGO_MANIFEST_DIRECTORY"); = help: there is a similar Cargo environment variable: `CARGO_MANIFEST_DIR` error: environment variable `CARGO_PKG_VERSIO` not defined at compile time - --> $DIR/env-cargo-var-typo-issue-148439.rs:31:13 + --> $DIR/env-cargo-var-typo-issue-148439.rs:32:13 | LL | let _ = env!("CARGO_PKG_VERSIO"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | let _ = env!("CARGO_PKG_VERSIO"); = help: there is a similar Cargo environment variable: `CARGO_PKG_VERSION` error: environment variable `MY_CUSTOM_VAR` not defined at compile time - --> $DIR/env-cargo-var-typo-issue-148439.rs:38:13 + --> $DIR/env-cargo-var-typo-issue-148439.rs:39:13 | LL | let _ = env!("MY_CUSTOM_VAR"); | ^^^^^^^^^^^^^^^^^^^^^ @@ -47,12 +47,22 @@ LL | let _ = env!("MY_CUSTOM_VAR"); = help: use `std::env::var("MY_CUSTOM_VAR")` to read the variable at run time error: environment variable `CARGO_SOMETHING_TOTALLY_UNKNOWN` not defined at compile time - --> $DIR/env-cargo-var-typo-issue-148439.rs:45:13 + --> $DIR/env-cargo-var-typo-issue-148439.rs:46:13 | LL | let _ = env!("CARGO_SOMETHING_TOTALLY_UNKNOWN"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: `CARGO_SOMETHING_TOTALLY_UNKNOWN` may not be available for the current Cargo target = help: Cargo sets build script variables at run time. Use `std::env::var("CARGO_SOMETHING_TOTALLY_UNKNOWN")` instead -error: aborting due to 7 previous errors +error: environment variable `CARGO_BIN_NAME` not defined at compile time + --> $DIR/env-cargo-var-typo-issue-148439.rs:54:13 + | +LL | let _ = env!("CARGO_BIN_NAME"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `CARGO_BIN_NAME` may not be available for the current Cargo target + = help: Cargo sets build script variables at run time. Use `std::env::var("CARGO_BIN_NAME")` instead + +error: aborting due to 8 previous errors diff --git a/tests/ui/env-macro/env-not-defined-default.stderr b/tests/ui/env-macro/env-not-defined-default.stderr index 77ba00e45c1c..8340bb0e8fba 100644 --- a/tests/ui/env-macro/env-not-defined-default.stderr +++ b/tests/ui/env-macro/env-not-defined-default.stderr @@ -4,6 +4,7 @@ error: environment variable `CARGO__HOPEFULLY_NOT_DEFINED__` not defined at comp LL | env!("CARGO__HOPEFULLY_NOT_DEFINED__"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: `CARGO__HOPEFULLY_NOT_DEFINED__` may not be available for the current Cargo target = help: Cargo sets build script variables at run time. Use `std::env::var("CARGO__HOPEFULLY_NOT_DEFINED__")` instead error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0520.rs b/tests/ui/error-codes/E0520.rs index ead78b7ffa2c..b746ca63590e 100644 --- a/tests/ui/error-codes/E0520.rs +++ b/tests/ui/error-codes/E0520.rs @@ -1,5 +1,4 @@ #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait SpaceLlama { fn fly(&self); diff --git a/tests/ui/error-codes/E0520.stderr b/tests/ui/error-codes/E0520.stderr index 83319203023f..c47b3e77c77a 100644 --- a/tests/ui/error-codes/E0520.stderr +++ b/tests/ui/error-codes/E0520.stderr @@ -1,15 +1,5 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/E0520.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0520]: `fly` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/E0520.rs:17:5 + --> $DIR/E0520.rs:16:5 | LL | impl SpaceLlama for T { | ------------------------------- parent `impl` is here @@ -19,6 +9,6 @@ LL | default fn fly(&self) {} | = note: to specialize, `fly` in the parent `impl` must be marked `default` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0520`. diff --git a/tests/ui/error-codes/E0599.stderr b/tests/ui/error-codes/E0599.stderr index 5c1c71d39f71..724bce4502b7 100644 --- a/tests/ui/error-codes/E0599.stderr +++ b/tests/ui/error-codes/E0599.stderr @@ -1,11 +1,11 @@ -error[E0599]: no associated item named `NotEvenReal` found for struct `Foo` in the current scope +error[E0599]: no associated function or constant named `NotEvenReal` found for struct `Foo` in the current scope --> $DIR/E0599.rs:4:20 | LL | struct Foo; - | ---------- associated item `NotEvenReal` not found for this struct + | ---------- associated function or constant `NotEvenReal` not found for this struct ... LL | || if let Foo::NotEvenReal() = Foo {}; - | ^^^^^^^^^^^ associated item not found in `Foo` + | ^^^^^^^^^^^ associated function or constant not found in `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0771.rs b/tests/ui/error-codes/E0771.rs index a932c5ef9815..6d86d4a54e78 100644 --- a/tests/ui/error-codes/E0771.rs +++ b/tests/ui/error-codes/E0771.rs @@ -1,5 +1,4 @@ #![feature(adt_const_params, unsized_const_params)] -//~^ WARN the feature `unsized_const_params` is incomplete fn function_with_str<'a, const STRING: &'a str>() {} //~ ERROR E0770 diff --git a/tests/ui/error-codes/E0771.stderr b/tests/ui/error-codes/E0771.stderr index dfeaa347941c..93782079d06f 100644 --- a/tests/ui/error-codes/E0771.stderr +++ b/tests/ui/error-codes/E0771.stderr @@ -1,18 +1,9 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/E0771.rs:4:41 + --> $DIR/E0771.rs:3:41 | LL | fn function_with_str<'a, const STRING: &'a str>() {} | ^^ the type must not depend on the parameter `'a` -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/E0771.rs:1:30 - | -LL | #![feature(adt_const_params, unsized_const_params)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0770`. diff --git a/tests/ui/error-emitter/multiline-removal-suggestion.rs b/tests/ui/error-emitter/multiline-removal-suggestion.rs index 72e9ea357c9e..36127ab13123 100644 --- a/tests/ui/error-emitter/multiline-removal-suggestion.rs +++ b/tests/ui/error-emitter/multiline-removal-suggestion.rs @@ -56,3 +56,4 @@ fn bay() -> Vec<(bool, HashSet)> { .collect() } fn main() {} +//@ ignore-parallel-frontend invalid svg(multiple threads trying to write to the same file) diff --git a/tests/ui/expr/issue-22933-2.rs b/tests/ui/expr/issue-22933-2.rs index dfd84b9a79d4..3f593cae6dfc 100644 --- a/tests/ui/expr/issue-22933-2.rs +++ b/tests/ui/expr/issue-22933-2.rs @@ -2,7 +2,7 @@ enum Delicious { Pie = 0x1, Apple = 0x2, ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - //~^ ERROR no variant or associated item named `PIE` found + //~^ ERROR no variant, associated function, or constant named `PIE` found } fn main() {} diff --git a/tests/ui/expr/issue-22933-2.stderr b/tests/ui/expr/issue-22933-2.stderr index 07f095f643ee..0b7416b77c04 100644 --- a/tests/ui/expr/issue-22933-2.stderr +++ b/tests/ui/expr/issue-22933-2.stderr @@ -1,11 +1,11 @@ -error[E0599]: no variant or associated item named `PIE` found for enum `Delicious` in the current scope +error[E0599]: no variant, associated function, or constant named `PIE` found for enum `Delicious` in the current scope --> $DIR/issue-22933-2.rs:4:55 | LL | enum Delicious { - | -------------- variant or associated item `PIE` not found for this enum + | -------------- variant, associated function, or constant `PIE` not found for this enum ... LL | ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - | ^^^ variant or associated item not found in `Delicious` + | ^^^ variant, associated function, or constant not found in `Delicious` | help: there is a variant with a similar name | diff --git a/tests/ui/feature-gates/duplicate-features.stderr b/tests/ui/feature-gates/duplicate-features.stderr index f667a5b9623f..81a9eeb9650c 100644 --- a/tests/ui/feature-gates/duplicate-features.stderr +++ b/tests/ui/feature-gates/duplicate-features.stderr @@ -1,10 +1,12 @@ -error[E0636]: the feature `if_let` has already been enabled +error: the feature `if_let` has already been enabled --> $DIR/duplicate-features.rs:7:12 | LL | #![feature(if_let)] | ^^^^^^ + | + = note: `#[deny(duplicate_features)]` on by default -error[E0636]: the feature `rust1` has already been enabled +error: the feature `rust1` has already been enabled --> $DIR/duplicate-features.rs:4:12 | LL | #![feature(rust1)] @@ -12,4 +14,3 @@ LL | #![feature(rust1)] error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0636`. diff --git a/tests/ui/feature-gates/feature-gate-box_patterns.rs b/tests/ui/feature-gates/feature-gate-box_patterns.rs index 8bec16a974e8..9ff6604c9520 100644 --- a/tests/ui/feature-gates/feature-gate-box_patterns.rs +++ b/tests/ui/feature-gates/feature-gate-box_patterns.rs @@ -1,4 +1,9 @@ fn main() { let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental - println!("x: {}", x); + let _: char = x; + + struct Packet { x: Box } + + let Packet { box x } = Packet { x: Box::new(0) }; //~ ERROR box pattern syntax is experimental + let _: i32 = x; } diff --git a/tests/ui/feature-gates/feature-gate-box_patterns.stderr b/tests/ui/feature-gates/feature-gate-box_patterns.stderr index fb61b2b1810a..6f5ee20925ee 100644 --- a/tests/ui/feature-gates/feature-gate-box_patterns.stderr +++ b/tests/ui/feature-gates/feature-gate-box_patterns.stderr @@ -8,6 +8,16 @@ LL | let box x = Box::new('c'); = help: add `#![feature(box_patterns)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error[E0658]: box pattern syntax is experimental + --> $DIR/feature-gate-box_patterns.rs:7:18 + | +LL | let Packet { box x } = Packet { x: Box::new(0) }; + | ^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs new file mode 100644 index 000000000000..a1f3b1fbbc86 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs @@ -0,0 +1,18 @@ +//! This is an unusual feature gate test, as it doesn't test the feature +//! gate, but the fact that not adding the feature gate will cause the +//! diagnostic to not emit the custom diagnostic message +//! +#[diagnostic::on_move( + message = "Foo" +)] +#[derive(Debug)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr new file mode 100644 index 000000000000..9ba6f272cf92 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr @@ -0,0 +1,29 @@ +error[E0382]: use of moved value: `foo` + --> $DIR/feature-gate-diagnostic-on-move.rs:16:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/feature-gate-diagnostic-on-move.rs:11:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/feature-gate-diagnostic-on-move.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr b/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr index 34a56fe342e2..e699c5d77b42 100644 --- a/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr +++ b/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr @@ -1,5 +1,5 @@ error[E0658]: the `#[force_target_feature]` attribute is an experimental feature - --> $DIR/feature-gate-effective-target-features.rs:13:5 + --> $DIR/feature-gate-effective-target-features.rs:14:5 | LL | #[unsafe(force_target_feature(enable = "avx2"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | #[unsafe(force_target_feature(enable = "avx2"))] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/feature-gate-effective-target-features.rs:21:5 + --> $DIR/feature-gate-effective-target-features.rs:22:5 | LL | #[target_feature(enable = "avx2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method @@ -18,13 +18,13 @@ LL | fn foo(&self) {} | ------------- not an `unsafe` function error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/feature-gate-effective-target-features.rs:23:5 + --> $DIR/feature-gate-effective-target-features.rs:24:5 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait - --> $DIR/feature-gate-effective-target-features.rs:7:5 + --> $DIR/feature-gate-effective-target-features.rs:8:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr b/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr index d51956fa4d2b..bf9f5d73e057 100644 --- a/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr +++ b/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr @@ -1,14 +1,18 @@ warning: the feature `effective_target_features` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/feature-gate-effective-target-features.rs:3:30 + --> $DIR/feature-gate-effective-target-features.rs:4:30 | LL | #![cfg_attr(feature, feature(effective_target_features))] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #143352 for more information - = note: `#[warn(incomplete_features)]` on by default +note: the lint level is defined here + --> $DIR/feature-gate-effective-target-features.rs:3:9 + | +LL | #![warn(incomplete_features)] + | ^^^^^^^^^^^^^^^^^^^ error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/feature-gate-effective-target-features.rs:21:5 + --> $DIR/feature-gate-effective-target-features.rs:22:5 | LL | #[target_feature(enable = "avx2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method @@ -17,13 +21,13 @@ LL | fn foo(&self) {} | ------------- not an `unsafe` function error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/feature-gate-effective-target-features.rs:23:5 + --> $DIR/feature-gate-effective-target-features.rs:24:5 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait - --> $DIR/feature-gate-effective-target-features.rs:7:5 + --> $DIR/feature-gate-effective-target-features.rs:8:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-effective-target-features.rs b/tests/ui/feature-gates/feature-gate-effective-target-features.rs index d383897e4382..a8be61167aa2 100644 --- a/tests/ui/feature-gates/feature-gate-effective-target-features.rs +++ b/tests/ui/feature-gates/feature-gate-effective-target-features.rs @@ -1,5 +1,6 @@ //@ revisions: default feature //@ only-x86_64 +#![warn(incomplete_features)] #![cfg_attr(feature, feature(effective_target_features))] //[feature]~^ WARN the feature `effective_target_features` is incomplete and may not be safe to use and/or cause compiler crashes diff --git a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr index 7e8ea5e948dc..627010a93547 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr @@ -19,7 +19,27 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:16:11 + --> $DIR/feature-gate-f128.rs:13:12 + | +LL | let d: f128 = 1i64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:16:12 + | +LL | let e: f128 = 1u64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:21:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -29,7 +49,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:19:8 + --> $DIR/feature-gate-f128.rs:24:8 | LL | a: f128, | ^^^^ @@ -58,6 +78,17 @@ LL | let c = 0f128; = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 6 previous errors +error[E0658]: use of unstable library feature `f128` + --> $DIR/feature-gate-f128.rs:13:24 + | +LL | let d: f128 = 1i64.into(); + | ^^^^ + | + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `f128` to implement `From` + = note: required for `i64` to implement `Into` + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr index 7e8ea5e948dc..627010a93547 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr @@ -19,7 +19,27 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:16:11 + --> $DIR/feature-gate-f128.rs:13:12 + | +LL | let d: f128 = 1i64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:16:12 + | +LL | let e: f128 = 1u64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:21:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -29,7 +49,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:19:8 + --> $DIR/feature-gate-f128.rs:24:8 | LL | a: f128, | ^^^^ @@ -58,6 +78,17 @@ LL | let c = 0f128; = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 6 previous errors +error[E0658]: use of unstable library feature `f128` + --> $DIR/feature-gate-f128.rs:13:24 + | +LL | let d: f128 = 1i64.into(); + | ^^^^ + | + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `f128` to implement `From` + = note: required for `i64` to implement `Into` + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs index dcbe60e934ae..13851b72c70f 100644 --- a/tests/ui/feature-gates/feature-gate-f128.rs +++ b/tests/ui/feature-gates/feature-gate-f128.rs @@ -10,6 +10,11 @@ pub fn main() { let a: f128 = 100.0; //~ ERROR the type `f128` is unstable let b = 0.0f128; //~ ERROR the type `f128` is unstable let c = 0f128; //~ ERROR the type `f128` is unstable + let d: f128 = 1i64.into(); + //~^ ERROR the type `f128` is unstable + //~| ERROR use of unstable library feature `f128` + let e: f128 = 1u64.into(); + //~^ ERROR the type `f128` is unstable foo(1.23); } diff --git a/tests/ui/feature-gates/feature-gate-macro-guard-matcher.rs b/tests/ui/feature-gates/feature-gate-macro-guard-matcher.rs new file mode 100644 index 000000000000..662161f19fac --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-guard-matcher.rs @@ -0,0 +1,5 @@ +fn main() { + macro_rules! m { + ($x:guard) => {}; //~ ERROR `guard` fragments in macro are unstable + } +} diff --git a/tests/ui/feature-gates/feature-gate-macro-guard-matcher.stderr b/tests/ui/feature-gates/feature-gate-macro-guard-matcher.stderr new file mode 100644 index 000000000000..0977f944f74f --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-guard-matcher.stderr @@ -0,0 +1,13 @@ +error[E0658]: `guard` fragments in macro are unstable + --> $DIR/feature-gate-macro-guard-matcher.rs:3:10 + | +LL | ($x:guard) => {}; + | ^^^^^^^^ + | + = note: see issue #153104 for more information + = help: add `#![feature(macro_guard_matcher)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-try_blocks.stderr b/tests/ui/feature-gates/feature-gate-try_blocks.stderr index dbef7fbe9d25..0a7580df61c0 100644 --- a/tests/ui/feature-gates/feature-gate-try_blocks.stderr +++ b/tests/ui/feature-gates/feature-gate-try_blocks.stderr @@ -8,7 +8,7 @@ LL | | x LL | | }; | |_____^ | - = note: see issue #31436 for more information + = note: see issue #154391 for more information = help: add `#![feature(try_blocks)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs index 2b0bbaa08357..27e8b5126f80 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs @@ -1,7 +1,7 @@ //@ compile-flags: --crate-type=lib //@ revisions: with_gate without_gate //@ [with_gate] check-pass - +#![warn(incomplete_features)] #![cfg_attr(with_gate, feature(unsafe_fields))] //[with_gate]~ WARNING #[cfg(false)] diff --git a/tests/ui/feature-gates/feature-gate-unsafe_fields.with_gate.stderr b/tests/ui/feature-gates/feature-gate-unsafe_fields.with_gate.stderr index a7deeb057d86..4220930d4668 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_fields.with_gate.stderr +++ b/tests/ui/feature-gates/feature-gate-unsafe_fields.with_gate.stderr @@ -5,7 +5,11 @@ LL | #![cfg_attr(with_gate, feature(unsafe_fields))] | ^^^^^^^^^^^^^ | = note: see issue #132922 for more information - = note: `#[warn(incomplete_features)]` on by default +note: the lint level is defined here + --> $DIR/feature-gate-unsafe_fields.rs:4:9 + | +LL | #![warn(incomplete_features)] + | ^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/ui/feature-gates/incomplete-features.rs b/tests/ui/feature-gates/incomplete-features.rs new file mode 100644 index 000000000000..7f8f1a46ebcb --- /dev/null +++ b/tests/ui/feature-gates/incomplete-features.rs @@ -0,0 +1,13 @@ +//! Make sure that incomplete features emit the `incomplete_features` lint. + +// gate-test-test_incomplete_feature + +//@ check-pass +//@ revisions: warn expect + +#![cfg_attr(warn, warn(incomplete_features))] +#![cfg_attr(expect, expect(incomplete_features))] + +#![feature(test_incomplete_feature)] //[warn]~ WARN the feature `test_incomplete_feature` is incomplete + +fn main() {} diff --git a/tests/ui/feature-gates/incomplete-features.warn.stderr b/tests/ui/feature-gates/incomplete-features.warn.stderr new file mode 100644 index 000000000000..7dda9f3648da --- /dev/null +++ b/tests/ui/feature-gates/incomplete-features.warn.stderr @@ -0,0 +1,14 @@ +warning: the feature `test_incomplete_feature` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/incomplete-features.rs:11:12 + | +LL | #![feature(test_incomplete_feature)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/incomplete-features.rs:8:24 + | +LL | #![cfg_attr(warn, warn(incomplete_features))] + | ^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr b/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr index 912c2746f383..c51d615846f5 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr @@ -5,7 +5,7 @@ LL | #![bench = "4100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn main() {} - | ---- the inner attribute doesn't annotate this function + | ------------ the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index 1560f2b5f4a7..66d36d9a5d6d 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs @@ -37,7 +37,7 @@ #[inline] //~^ ERROR attribute cannot be used on mod inline { - //~^ NOTE the inner attribute doesn't annotate this module + //~^ NOTE the inner attribute doesn't annotate this item mod inner { #![inline] } //~^ ERROR attribute cannot be used on diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 662776e58026..db56f22acfba 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -24,6 +24,21 @@ LL | #![rustc_main] | = help: `#[rustc_main]` can only be applied to functions +error: `repr` attribute cannot be used at crate level + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:16:1 + | +LL | #![repr()] + | ^^^^^^^^^^ +... +LL | mod inline { + | ------------ the inner attribute doesn't annotate this item + | +help: perhaps you meant to use an outer attribute + | +LL - #![repr()] +LL + #[repr()] + | + error: `#[path]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:20:1 | @@ -243,21 +258,6 @@ help: remove the `#[no_mangle]` attribute LL - #![no_mangle] | -error: `repr` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:16:1 - | -LL | #![repr()] - | ^^^^^^^^^^ -... -LL | mod inline { - | ------ the inner attribute doesn't annotate this module - | -help: perhaps you meant to use an outer attribute - | -LL - #![repr()] -LL + #[repr()] - | - error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25 | diff --git a/tests/ui/feature-gates/issue-43106-gating-of-test.rs b/tests/ui/feature-gates/issue-43106-gating-of-test.rs index 38c92d933fdd..cc4c73d916bd 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-test.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-test.rs @@ -1,6 +1,5 @@ // The non-crate level cases are in issue-43106-gating-of-builtin-attrs.rs. -#![allow(soft_unstable)] #![test = "4200"] //~^ ERROR `test` attribute cannot be used at crate level fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-test.stderr b/tests/ui/feature-gates/issue-43106-gating-of-test.stderr index 2fc220dc47bd..8af140bc93d9 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-test.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-test.stderr @@ -1,11 +1,11 @@ error: `test` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-test.rs:4:1 + --> $DIR/issue-43106-gating-of-test.rs:3:1 | LL | #![test = "4200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn main() {} - | ---- the inner attribute doesn't annotate this function + | ------------ the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | diff --git a/tests/ui/feature-gates/soft-feature-gate-auto_traits.rs b/tests/ui/feature-gates/soft-feature-gate-auto_traits.rs new file mode 100644 index 000000000000..0ccbaf1e476a --- /dev/null +++ b/tests/ui/feature-gates/soft-feature-gate-auto_traits.rs @@ -0,0 +1,12 @@ +// For historical reasons, auto traits don't have a proper pre-expansion feature gate. +// We're now at least issuing a *warning* for those that only exist before macro expansion. +// FIXME(#154045): Turn their post-expansion feature gate into a proper pre-expansion one. +// As part of this, move these test cases into `feature-gate-auto-traits.rs`. +//@ check-pass + +#[cfg(false)] +auto trait Foo {} +//~^ WARN `auto` traits are unstable +//~| WARN unstable syntax can change at any point in the future + +fn main() {} diff --git a/tests/ui/auto-traits/pre-cfg.stderr b/tests/ui/feature-gates/soft-feature-gate-auto_traits.stderr similarity index 92% rename from tests/ui/auto-traits/pre-cfg.stderr rename to tests/ui/feature-gates/soft-feature-gate-auto_traits.stderr index 648f9464d61d..20811aadda92 100644 --- a/tests/ui/auto-traits/pre-cfg.stderr +++ b/tests/ui/feature-gates/soft-feature-gate-auto_traits.stderr @@ -1,5 +1,5 @@ warning: `auto` traits are unstable - --> $DIR/pre-cfg.rs:4:1 + --> $DIR/soft-feature-gate-auto_traits.rs:8:1 | LL | auto trait Foo {} | ^^^^ diff --git a/tests/ui/feature-gates/soft-feature-gate-box_patterns.rs b/tests/ui/feature-gates/soft-feature-gate-box_patterns.rs new file mode 100644 index 000000000000..8ab0e80e6be3 --- /dev/null +++ b/tests/ui/feature-gates/soft-feature-gate-box_patterns.rs @@ -0,0 +1,17 @@ +// For historical reasons, box patterns don't have a proper pre-expansion feature gate. +// We're now at least issuing a *warning* for those that only exist before macro expansion. +// FIXME(#154045): Turn their post-expansion feature gate into a proper pre-expansion one. +// As part of this, move these test cases into `feature-gate-box_patterns.rs`. +//@ check-pass + +fn main() { + #[cfg(false)] + let box x; + //~^ WARN box pattern syntax is experimental + //~| WARN unstable syntax can change at any point in the future + + #[cfg(false)] + let Packet { box x }; + //~^ WARN box pattern syntax is experimental + //~| WARN unstable syntax can change at any point in the future +} diff --git a/tests/ui/feature-gates/soft-feature-gate-box_patterns.stderr b/tests/ui/feature-gates/soft-feature-gate-box_patterns.stderr new file mode 100644 index 000000000000..a8399b5f01f8 --- /dev/null +++ b/tests/ui/feature-gates/soft-feature-gate-box_patterns.stderr @@ -0,0 +1,26 @@ +warning: box pattern syntax is experimental + --> $DIR/soft-feature-gate-box_patterns.rs:9:9 + | +LL | let box x; + | ^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: box pattern syntax is experimental + --> $DIR/soft-feature-gate-box_patterns.rs:14:18 + | +LL | let Packet { box x }; + | ^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 2 warnings emitted + diff --git a/tests/ui/feature-gates/soft-feature-gate-decl_macro.rs b/tests/ui/feature-gates/soft-feature-gate-decl_macro.rs new file mode 100644 index 000000000000..7d2d48503797 --- /dev/null +++ b/tests/ui/feature-gates/soft-feature-gate-decl_macro.rs @@ -0,0 +1,17 @@ +// For historical reasons, decl macros 2.0 don't have a proper pre-expansion feature gate. +// We're now at least issuing a *warning* for those that only exist before macro expansion. +// FIXME(#154045): Turn their post-expansion feature gate into a proper pre-expansion one. +// As part of this, move these test cases into `feature-gate-decl_macro.rs`. +//@ check-pass + +#[cfg(false)] +macro make() {} +//~^ WARN `macro` is experimental +//~| WARN unstable syntax can change at any point in the future + +#[cfg(false)] +macro create { () => {} } +//~^ WARN `macro` is experimental +//~| WARN unstable syntax can change at any point in the future + +fn main() {} diff --git a/tests/ui/feature-gates/soft-feature-gate-decl_macro.stderr b/tests/ui/feature-gates/soft-feature-gate-decl_macro.stderr new file mode 100644 index 000000000000..71521626f69b --- /dev/null +++ b/tests/ui/feature-gates/soft-feature-gate-decl_macro.stderr @@ -0,0 +1,26 @@ +warning: `macro` is experimental + --> $DIR/soft-feature-gate-decl_macro.rs:8:1 + | +LL | macro make() {} + | ^^^^^^^^^^^^^^^ + | + = note: see issue #39412 for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: `macro` is experimental + --> $DIR/soft-feature-gate-decl_macro.rs:13:1 + | +LL | macro create { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #39412 for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 2 warnings emitted + diff --git a/tests/ui/feature-gates/soft-feature-gate-trait_alias.rs b/tests/ui/feature-gates/soft-feature-gate-trait_alias.rs new file mode 100644 index 000000000000..553e88375a2a --- /dev/null +++ b/tests/ui/feature-gates/soft-feature-gate-trait_alias.rs @@ -0,0 +1,17 @@ +// For historical reasons, trait aliases don't have a proper pre-expansion feature gate. +// We're now at least issuing a *warning* for those that only exist before macro expansion. +// FIXME(#154045): Turn their post-expansion feature gate into a proper pre-expansion one. +// As part of this, move these test cases into `feature-gate-trait-alias.rs`. +//@ check-pass + +#[cfg(false)] +trait Trait =; +//~^ WARN trait aliases are experimental +//~| WARN unstable syntax can change at any point in the future + +#[cfg(false)] +trait Trait = Bound where T: Bound; +//~^ WARN trait aliases are experimental +//~| WARN unstable syntax can change at any point in the future + +fn main() {} diff --git a/tests/ui/feature-gates/soft-feature-gate-trait_alias.stderr b/tests/ui/feature-gates/soft-feature-gate-trait_alias.stderr new file mode 100644 index 000000000000..e50d4c36d122 --- /dev/null +++ b/tests/ui/feature-gates/soft-feature-gate-trait_alias.stderr @@ -0,0 +1,26 @@ +warning: trait aliases are experimental + --> $DIR/soft-feature-gate-trait_alias.rs:8:1 + | +LL | trait Trait =; + | ^^^^^^^^^^^^^^ + | + = note: see issue #41517 for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: trait aliases are experimental + --> $DIR/soft-feature-gate-trait_alias.rs:13:1 + | +LL | trait Trait = Bound where T: Bound; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 2 warnings emitted + diff --git a/tests/ui/feature-gates/soft-feature-gate-try_blocks.rs b/tests/ui/feature-gates/soft-feature-gate-try_blocks.rs new file mode 100644 index 000000000000..aa51e60d56b4 --- /dev/null +++ b/tests/ui/feature-gates/soft-feature-gate-try_blocks.rs @@ -0,0 +1,13 @@ +// For historical reasons, try blocks don't have a proper pre-expansion feature gate. +// We're now at least issuing a *warning* for those that only exist before macro expansion. +// FIXME(#154045): Turn their post-expansion feature gate into a proper pre-expansion one. +// As part of this, move these test cases into `feature-gate-try_blocks.rs`. +//@ edition: 2018 +//@ check-pass + +fn main() { + #[cfg(false)] + try {} + //~^ WARN `try` blocks are unstable + //~| WARN unstable syntax can change at any point +} diff --git a/tests/ui/try-block/try-block-homogeneous-pre-expansion.stderr b/tests/ui/feature-gates/soft-feature-gate-try_blocks.stderr similarity index 75% rename from tests/ui/try-block/try-block-homogeneous-pre-expansion.stderr rename to tests/ui/feature-gates/soft-feature-gate-try_blocks.stderr index dc92d7e64aff..2b20f40e09d0 100644 --- a/tests/ui/try-block/try-block-homogeneous-pre-expansion.stderr +++ b/tests/ui/feature-gates/soft-feature-gate-try_blocks.stderr @@ -1,10 +1,10 @@ warning: `try` blocks are unstable - --> $DIR/try-block-homogeneous-pre-expansion.rs:9:5 + --> $DIR/soft-feature-gate-try_blocks.rs:10:5 | LL | try {} | ^^^^^^ | - = note: see issue #31436 for more information + = note: see issue #154391 for more information = help: add `#![feature(try_blocks)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = warning: unstable syntax can change at any point in the future, causing a hard error! diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs index fb7361f9cbad..5727d5d7b859 100644 --- a/tests/ui/float/classify-runtime-const.rs +++ b/tests/ui/float/classify-runtime-const.rs @@ -2,7 +2,11 @@ //@ revisions: opt noopt ctfe //@[opt] compile-flags: -O //@[noopt] compile-flags: -Zmir-opt-level=0 +//@ min-llvm-version: 22 +//@ compile-flags: --check-cfg=cfg(target_has_reliable_f16) // ignore-tidy-linelength +#![feature(cfg_target_has_reliable_f16_f128)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] // This tests the float classification functions, for regular runtime code and for const evaluation. @@ -50,6 +54,13 @@ macro_rules! assert_test { macro_rules! suite { ( $tyname:ident => $( $tt:tt )* ) => { + #[cfg(target_has_reliable_f16)] + fn f16() { + #[allow(unused)] + type $tyname = f16; + suite_inner!(f16 => $($tt)*); + } + fn f32() { #[allow(unused)] type $tyname = f32; @@ -121,7 +132,9 @@ macro_rules! suite_inner { } fn main() { + #[cfg(target_has_reliable_f16)] + f16(); f32(); f64(); - // FIXME(f16_f128): also test f16 and f128 + // FIXME(f128): also test f128 } diff --git a/tests/ui/float/minmax.rs b/tests/ui/float/minmax.rs new file mode 100644 index 000000000000..e6bac901d792 --- /dev/null +++ b/tests/ui/float/minmax.rs @@ -0,0 +1,22 @@ +//FIXME(llvm21) This should be a library test, but old LLVM miscompiles things so we can't just +// test this properly everywhere. Once we require LLVM 22, remove this test and enable the +// commented-out tests in `library/coretests/tests/floats/mod.rs` instead. +//@ min-llvm-version: 22 +//@ run-pass + +use std::hint::black_box; + +const SNAN32: f32 = f32::from_bits(f32::NAN.to_bits() - 1); +const SNAN64: f64 = f64::from_bits(f64::NAN.to_bits() - 1); + +fn main() { + assert_eq!(SNAN32.min(black_box(9.0)), 9.0f32); + assert_eq!(black_box(SNAN32).min(-9.0), -9.0f32); + assert_eq!((9.0f32).min(black_box(SNAN32)), 9.0f32); + assert_eq!(black_box(-9.0f32).min(SNAN32), -9.0f32); + + assert_eq!(SNAN64.min(black_box(9.0)), 9.0f64); + assert_eq!(black_box(SNAN64).min(-9.0), -9.0f64); + assert_eq!((9.0f64).min(black_box(SNAN64)), 9.0f64); + assert_eq!(black_box(-9.0f64).min(SNAN64), -9.0f64); +} diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr index d913b2e91ca0..58ed71fad4a6 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr @@ -4,7 +4,7 @@ error[E0283]: type annotations needed LL | cmp_eq | ^^^^^^ cannot infer type of the type parameter `A` declared on the function `cmp_eq` | - = note: cannot satisfy `_: Scalar` + = note: the type must implement `Scalar` note: required by a bound in `cmp_eq` --> $DIR/ambig-hr-projection-issue-93340.rs:10:22 | diff --git a/tests/ui/generic-associated-types/bugs/issue-88382.stderr b/tests/ui/generic-associated-types/bugs/issue-88382.stderr index ce20a4eeac04..dcadd5ce8deb 100644 --- a/tests/ui/generic-associated-types/bugs/issue-88382.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-88382.stderr @@ -4,7 +4,7 @@ error[E0283]: type annotations needed LL | do_something(SomeImplementation(), test); | ^^^^ cannot infer type of the type parameter `I` declared on the function `test` | - = note: cannot satisfy `_: Iterable` + = note: the type must implement `Iterable` help: the trait `Iterable` is implemented for `SomeImplementation` --> $DIR/issue-88382.rs:13:1 | diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs index d7dff329df1e..ec6dfb87f61b 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs @@ -29,5 +29,5 @@ fn new() -> P::Pointer { fn main() { let mut list = RcNode::::new(); - //~^ ERROR the variant or associated item `new` exists for enum `Node`, but its trait bounds were not satisfied + //~^ ERROR the variant, associated function, or constant `new` exists for enum `Node`, but its trait bounds were not satisfied } diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr index b31689dbf736..674e28829073 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr @@ -15,14 +15,14 @@ help: consider relaxing the implicit `Sized` restriction LL | type Pointer: Deref + ?Sized; | ++++++++ -error[E0599]: the variant or associated item `new` exists for enum `Node`, but its trait bounds were not satisfied +error[E0599]: the variant, associated function, or constant `new` exists for enum `Node`, but its trait bounds were not satisfied --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:31:35 | LL | enum Node { - | ------------------------------ variant or associated item `new` not found for this enum + | ------------------------------ variant, associated function, or constant `new` not found for this enum ... LL | let mut list = RcNode::::new(); - | ^^^ variant or associated item cannot be called on `Node` due to unsatisfied trait bounds + | ^^^ variant, associated function, or constant cannot be called on `Node` due to unsatisfied trait bounds | note: trait bound `(dyn Deref> + 'static): Sized` was not satisfied --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:23:29 diff --git a/tests/ui/generic-associated-types/issue-87429-specialization.rs b/tests/ui/generic-associated-types/issue-87429-specialization.rs index 87e91162a863..4a1e6aa6b332 100644 --- a/tests/ui/generic-associated-types/issue-87429-specialization.rs +++ b/tests/ui/generic-associated-types/issue-87429-specialization.rs @@ -1,7 +1,6 @@ //@ check-fail #![feature(specialization)] -//~^ WARN incomplete trait Family { type Member<'a>: for<'b> PartialEq>; diff --git a/tests/ui/generic-associated-types/issue-87429-specialization.stderr b/tests/ui/generic-associated-types/issue-87429-specialization.stderr index 44f871e71c57..dbe97bdb7431 100644 --- a/tests/ui/generic-associated-types/issue-87429-specialization.stderr +++ b/tests/ui/generic-associated-types/issue-87429-specialization.stderr @@ -1,22 +1,12 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-87429-specialization.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: can't compare `Foo` with `Foo` - --> $DIR/issue-87429-specialization.rs:20:31 + --> $DIR/issue-87429-specialization.rs:19:31 | LL | default type Member<'a> = Foo; | ^^^ no implementation for `Foo == Foo` | = help: the trait `PartialEq` is not implemented for `Foo` note: required by a bound in `Family::Member` - --> $DIR/issue-87429-specialization.rs:7:22 + --> $DIR/issue-87429-specialization.rs:6:22 | LL | type Member<'a>: for<'b> PartialEq>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family::Member` @@ -26,6 +16,6 @@ LL + #[derive(PartialEq)] LL | struct Foo; | -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generic-associated-types/unknown-lifetime-ice-119827.rs b/tests/ui/generic-associated-types/unknown-lifetime-ice-119827.rs index f74d7cf28111..94f832f494a2 100644 --- a/tests/ui/generic-associated-types/unknown-lifetime-ice-119827.rs +++ b/tests/ui/generic-associated-types/unknown-lifetime-ice-119827.rs @@ -4,7 +4,7 @@ trait Foo { where Self: 'c; } - +//@ ignore-parallel-frontend query cycle impl Foo for Box {} fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-bindings.rs b/tests/ui/generic-const-items/assoc-const-bindings.rs index c187c87c7763..2ebdda28a69f 100644 --- a/tests/ui/generic-const-items/assoc-const-bindings.rs +++ b/tests/ui/generic-const-items/assoc-const-bindings.rs @@ -1,7 +1,7 @@ //@ check-pass #![feature(generic_const_items, min_generic_const_args)] -#![feature(adt_const_params, unsized_const_params, generic_const_parameter_types)] +#![feature(adt_const_params, const_param_ty_trait, generic_const_parameter_types)] #![expect(incomplete_features)] use std::marker::{ConstParamTy, ConstParamTy_}; diff --git a/tests/ui/generic-const-items/assoc-const-missing-type.stderr b/tests/ui/generic-const-items/assoc-const-missing-type.stderr index 7c79133d64ec..b7fb625a9ea5 100644 --- a/tests/ui/generic-const-items/assoc-const-missing-type.stderr +++ b/tests/ui/generic-const-items/assoc-const-missing-type.stderr @@ -2,8 +2,9 @@ error[E0308]: mismatched types --> $DIR/assoc-const-missing-type.rs:12:18 | LL | const K = (); - | - ^^ expected type parameter `T`, found `()` - | | + | - - ^^ expected type parameter `T`, found `()` + | | | + | | expected because of the type of the associated constant | expected this type parameter | = note: expected type parameter `T` diff --git a/tests/ui/generics/generic-struct-self-unconstrained-inference-vars-69306.stderr b/tests/ui/generics/generic-struct-self-unconstrained-inference-vars-69306.stderr index f2fd4340a580..8bc0f0a5e92f 100644 --- a/tests/ui/generics/generic-struct-self-unconstrained-inference-vars-69306.stderr +++ b/tests/ui/generics/generic-struct-self-unconstrained-inference-vars-69306.stderr @@ -22,7 +22,9 @@ error[E0308]: mismatched types LL | impl S0 { | - found this type parameter LL | const C: S0 = Self(0); - | ^^^^^^^ expected `S0`, found `S0` + | ------ ^^^^^^^ expected `S0`, found `S0` + | | + | expected because of the type of the associated constant | = note: expected struct `S0` found struct `S0` @@ -89,7 +91,9 @@ error[E0308]: mismatched types LL | impl S1 { | - found this type parameter LL | const C: S1 = Self(0, 1); - | ^^^^^^^^^^ expected `S1`, found `S1` + | ---------- ^^^^^^^^^^ expected `S1`, found `S1` + | | + | expected because of the type of the associated constant | = note: expected struct `S1` found struct `S1` diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr index b27a2dcceb13..f8fcb73db447 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.stderr +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -1,4 +1,4 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied --> $DIR/structually-relate-aliases.rs:13:36 | diff --git a/tests/ui/higher-ranked/trait-bounds/issue-95230.rs b/tests/ui/higher-ranked/trait-bounds/issue-95230.rs index 821a04ff0655..b0f623ce3321 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-95230.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-95230.rs @@ -5,6 +5,6 @@ pub struct Bar where for<'a> &'a mut Self:; -//~^ ERROR overflow evaluating the requirement `for<'a> &'a mut Bar well-formed` +//~^ ERROR: overflow evaluating whether `&'a mut Bar` is well-formed fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/issue-95230.stderr b/tests/ui/higher-ranked/trait-bounds/issue-95230.stderr index 7070af75d290..9e85c689f69d 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-95230.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-95230.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `for<'a> &'a mut Bar well-formed` +error[E0275]: overflow evaluating whether `&'a mut Bar` is well-formed --> $DIR/issue-95230.rs:7:13 | LL | for<'a> &'a mut Self:; diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout index 28a5c70a02d7..689453326c0b 100644 --- a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout +++ b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout @@ -7,15 +7,17 @@ // Don't break whenever Symbol numbering changes //@ normalize-stdout: "\d+#" -> "0#" -#![feature /* 0#0 */(decl_macro)] -#![feature /* 0#0 */(no_core)] +#![feature /* 0#0 */(decl_macro /* 0#0 */)] +#![feature /* 0#0 */(no_core /* 0#0 */)] #![no_core /* 0#0 */] macro lifetime_hygiene /* 0#0 */ { - ($f:ident<$a:lifetime>) => { fn $f<$a, 'a>() {} } + ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 */>) + => + { fn /* 0#0 */ $f /* 0#0 */<$a /* 0#0 */, 'a /* 0#0 */>() {} } } fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {} diff --git a/tests/ui/hygiene/unpretty-debug-metavars.rs b/tests/ui/hygiene/unpretty-debug-metavars.rs new file mode 100644 index 000000000000..41bf75cd0d98 --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-metavars.rs @@ -0,0 +1,26 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, metavar parameters in macro-generated macro_rules! definitions +// were missing hygiene annotations, making identical `$marg` bindings +// indistinguishable. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature(no_core)] +#![no_core] + +macro_rules! make_macro { + (@inner $name:ident ($dol:tt) $a:ident) => { + macro_rules! $name { + ($dol $a : expr, $dol marg : expr) => {} + } + }; + ($name:ident) => { + make_macro!{@inner $name ($) marg} + }; +} + +make_macro!(add2); diff --git a/tests/ui/hygiene/unpretty-debug-metavars.stdout b/tests/ui/hygiene/unpretty-debug-metavars.stdout new file mode 100644 index 000000000000..89658bc909a1 --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-metavars.stdout @@ -0,0 +1,53 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, metavar parameters in macro-generated macro_rules! definitions +// were missing hygiene annotations, making identical `$marg` bindings +// indistinguishable. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature /* 0#0 */(no_core /* 0#0 */)] +#![no_core /* 0#0 */] + +macro_rules! make_macro + /* + 0#0 + */ { + (@inner /* 0#0 */ $name /* 0#0 */:ident /* 0#0 + */($dol /* 0#0 */:tt /* 0#0 */) $a /* 0#0 */:ident /* 0#0 */) + => + { + macro_rules /* 0#0 */! $name /* 0#0 */ + { + ($dol /* 0#0 */ $a /* 0#0 */ : expr /* 0#0 */, $dol /* + 0#0 */ marg /* 0#0 */ : expr /* 0#0 */) => {} + } + }; ($name /* 0#0 */:ident /* 0#0 */) => + { + make_macro /* 0#0 + */!{@inner /* 0#0 */ $name /* 0#0 */($) marg /* 0#0 */} + }; +} +macro_rules! add2 + /* + 0#0 + */ { + ($ marg /* 0#1 */ : expr /* 0#2 */, $marg /* 0#2 */ : expr /* + 0#2 */) => {} +} + + +/* +Expansions: +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "make_macro") +crate0::{{expn2}}: parent: crate0::{{expn1}}, call_site_ctxt: #1, def_site_ctxt: #0, kind: Macro(Bang, "make_macro") + +SyntaxContexts: +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque) +#2: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque) +*/ diff --git a/tests/ui/hygiene/unpretty-debug-shadow.rs b/tests/ui/hygiene/unpretty-debug-shadow.rs new file mode 100644 index 000000000000..2aa68c8aec11 --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-shadow.rs @@ -0,0 +1,20 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, tokens in macro_rules! bodies were missing hygiene annotations, +// making it impossible to see how a macro's reference to a shadowed variable +// is distinguished from the shadowing binding. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature(no_core)] +#![no_core] + +fn f() { + let x = 0; + macro_rules! use_x { () => { x }; } + let x = 1; + use_x!(); +} diff --git a/tests/ui/hygiene/unpretty-debug-shadow.stdout b/tests/ui/hygiene/unpretty-debug-shadow.stdout new file mode 100644 index 000000000000..36076b6a968f --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-shadow.stdout @@ -0,0 +1,30 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, tokens in macro_rules! bodies were missing hygiene annotations, +// making it impossible to see how a macro's reference to a shadowed variable +// is distinguished from the shadowing binding. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature /* 0#0 */(no_core /* 0#0 */)] +#![no_core /* 0#0 */] + +fn f /* 0#0 */() { + let x /* 0#0 */ = 0; + macro_rules! use_x /* 0#0 */ { () => { x /* 0#0 */ }; } + let x /* 0#0 */ = 1; + x /* 0#1 */; +} + +/* +Expansions: +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "use_x") + +SyntaxContexts: +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque) +*/ diff --git a/tests/ui/hygiene/unpretty-debug.stdout b/tests/ui/hygiene/unpretty-debug.stdout index f35bd7a7cb2c..ac6051e2d542 100644 --- a/tests/ui/hygiene/unpretty-debug.stdout +++ b/tests/ui/hygiene/unpretty-debug.stdout @@ -5,10 +5,16 @@ //@ normalize-stdout: "\d+#" -> "0#" // minimal junk -#![feature /* 0#0 */(no_core)] +#![feature /* 0#0 */(no_core /* 0#0 */)] #![no_core /* 0#0 */] -macro_rules! foo /* 0#0 */ { ($x: ident) => { y + $x } } +macro_rules! foo + /* + 0#0 + */ { + ($x /* 0#0 */: ident /* 0#0 */) => + { y /* 0#0 */ + $x /* 0#0 */ } +} fn bar /* 0#0 */() { let x /* 0#0 */ = 1; diff --git a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.rs b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.rs index d6490d5b4f97..dc47eba2b3c6 100644 --- a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.rs +++ b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.rs @@ -1,5 +1,6 @@ //@ compile-flags: --crate-type=lib //@ revisions: with_gate without_gate +#![warn(incomplete_features)] #![cfg_attr(with_gate, feature(impl_restriction))] //[with_gate]~^ WARN the feature `impl_restriction` is incomplete and may not be safe to use and/or cause compiler crashes #![feature(auto_traits, const_trait_impl)] diff --git a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.with_gate.stderr b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.with_gate.stderr index ad183b23e013..834cc99f0755 100644 --- a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.with_gate.stderr +++ b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.with_gate.stderr @@ -1,5 +1,5 @@ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:8:14 + --> $DIR/recover-incorrect-impl-restriction.rs:9:14 | LL | pub impl(crate::foo) trait Baz {} | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | pub impl(in crate::foo) trait Baz {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:10:21 + --> $DIR/recover-incorrect-impl-restriction.rs:11:21 | LL | pub unsafe impl(crate::foo) trait BazUnsafe {} | ^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | pub unsafe impl(in crate::foo) trait BazUnsafe {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:12:19 + --> $DIR/recover-incorrect-impl-restriction.rs:13:19 | LL | pub auto impl(crate::foo) trait BazAuto {} | ^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | pub auto impl(in crate::foo) trait BazAuto {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:14:20 + --> $DIR/recover-incorrect-impl-restriction.rs:15:20 | LL | pub const impl(crate::foo) trait BazConst {} | ^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | pub const impl(in crate::foo) trait BazConst {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:16:27 + --> $DIR/recover-incorrect-impl-restriction.rs:17:27 | LL | pub const unsafe impl(crate::foo) trait BazConstUnsafe {} | ^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | pub const unsafe impl(in crate::foo) trait BazConstUnsafe {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:18:26 + --> $DIR/recover-incorrect-impl-restriction.rs:19:26 | LL | pub unsafe auto impl(crate::foo) trait BazUnsafeAuto {} | ^^^^^^^^^^ @@ -95,13 +95,17 @@ LL | pub unsafe auto impl(in crate::foo) trait BazUnsafeAuto {} | ++ warning: the feature `impl_restriction` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/recover-incorrect-impl-restriction.rs:3:32 + --> $DIR/recover-incorrect-impl-restriction.rs:4:32 | LL | #![cfg_attr(with_gate, feature(impl_restriction))] | ^^^^^^^^^^^^^^^^ | = note: see issue #105077 for more information - = note: `#[warn(incomplete_features)]` on by default +note: the lint level is defined here + --> $DIR/recover-incorrect-impl-restriction.rs:3:9 + | +LL | #![warn(incomplete_features)] + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors; 1 warning emitted diff --git a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.without_gate.stderr b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.without_gate.stderr index d949172ffb45..223a7cd47cfb 100644 --- a/tests/ui/impl-restriction/recover-incorrect-impl-restriction.without_gate.stderr +++ b/tests/ui/impl-restriction/recover-incorrect-impl-restriction.without_gate.stderr @@ -1,5 +1,5 @@ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:8:14 + --> $DIR/recover-incorrect-impl-restriction.rs:9:14 | LL | pub impl(crate::foo) trait Baz {} | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | pub impl(in crate::foo) trait Baz {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:10:21 + --> $DIR/recover-incorrect-impl-restriction.rs:11:21 | LL | pub unsafe impl(crate::foo) trait BazUnsafe {} | ^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | pub unsafe impl(in crate::foo) trait BazUnsafe {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:12:19 + --> $DIR/recover-incorrect-impl-restriction.rs:13:19 | LL | pub auto impl(crate::foo) trait BazAuto {} | ^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | pub auto impl(in crate::foo) trait BazAuto {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:14:20 + --> $DIR/recover-incorrect-impl-restriction.rs:15:20 | LL | pub const impl(crate::foo) trait BazConst {} | ^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | pub const impl(in crate::foo) trait BazConst {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:16:27 + --> $DIR/recover-incorrect-impl-restriction.rs:17:27 | LL | pub const unsafe impl(crate::foo) trait BazConstUnsafe {} | ^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | pub const unsafe impl(in crate::foo) trait BazConstUnsafe {} | ++ error: incorrect `impl` restriction - --> $DIR/recover-incorrect-impl-restriction.rs:18:26 + --> $DIR/recover-incorrect-impl-restriction.rs:19:26 | LL | pub unsafe auto impl(crate::foo) trait BazUnsafeAuto {} | ^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | pub unsafe auto impl(in crate::foo) trait BazUnsafeAuto {} | ++ error[E0658]: `impl` restrictions are experimental - --> $DIR/recover-incorrect-impl-restriction.rs:8:9 + --> $DIR/recover-incorrect-impl-restriction.rs:9:9 | LL | pub impl(crate::foo) trait Baz {} | ^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | pub impl(crate::foo) trait Baz {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/recover-incorrect-impl-restriction.rs:10:16 + --> $DIR/recover-incorrect-impl-restriction.rs:11:16 | LL | pub unsafe impl(crate::foo) trait BazUnsafe {} | ^^^^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL | pub unsafe impl(crate::foo) trait BazUnsafe {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/recover-incorrect-impl-restriction.rs:12:14 + --> $DIR/recover-incorrect-impl-restriction.rs:13:14 | LL | pub auto impl(crate::foo) trait BazAuto {} | ^^^^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL | pub auto impl(crate::foo) trait BazAuto {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/recover-incorrect-impl-restriction.rs:14:15 + --> $DIR/recover-incorrect-impl-restriction.rs:15:15 | LL | pub const impl(crate::foo) trait BazConst {} | ^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | pub const impl(crate::foo) trait BazConst {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/recover-incorrect-impl-restriction.rs:16:22 + --> $DIR/recover-incorrect-impl-restriction.rs:17:22 | LL | pub const unsafe impl(crate::foo) trait BazConstUnsafe {} | ^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | pub const unsafe impl(crate::foo) trait BazConstUnsafe {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/recover-incorrect-impl-restriction.rs:18:21 + --> $DIR/recover-incorrect-impl-restriction.rs:19:21 | LL | pub unsafe auto impl(crate::foo) trait BazUnsafeAuto {} | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-restriction/restriction_resolution_errors.rs b/tests/ui/impl-restriction/restriction_resolution_errors.rs new file mode 100644 index 000000000000..b36f2cf9bdfb --- /dev/null +++ b/tests/ui/impl-restriction/restriction_resolution_errors.rs @@ -0,0 +1,85 @@ +#![feature(impl_restriction)] +#![expect(incomplete_features)] + +pub mod a { + pub enum E {} + pub mod d {} + pub mod b { + pub mod c {} + + // We do not use crate-relative paths here, since we follow the + // "uniform paths" approach used for type/expression paths. + pub impl(in a::b) trait T1 {} //~ ERROR cannot find module or crate `a` in this scope [E0433] + + pub impl(in ::std) trait T2 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub impl(in self::c) trait T3 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub impl(in super::d) trait T4 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub impl(in crate::c) trait T5 {} //~ ERROR cannot find module `c` in the crate root [E0433] + + pub impl(in super::E) trait T6 {} //~ ERROR expected module, found enum `super::E` [E0577] + + pub impl(in super::super::super) trait T7 {} //~ ERROR too many leading `super` keywords [E0433] + + // OK paths + pub impl(crate) trait T8 {} + pub impl(self) trait T9 {} + pub impl(super) trait T10 {} + pub impl(in crate::a) trait T11 {} + pub impl(in super::super) trait T12 {} + + // Check if we can resolve paths referring to modules declared later. + pub impl(in self::f) trait L1 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub impl(in super::G) trait L2 {} //~ ERROR expected module, found enum `super::G` [E0577] + + pub impl(in super::h) trait L3 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub mod f {} + } + + pub enum G {} + pub mod h {} +} + +pub impl(in crate::a) trait T13 {} //~ ERROR trait implementation can only be restricted to ancestor modules + +pub impl(in crate::a::E) trait T14 {} //~ ERROR expected module, found enum `crate::a::E` [E0577] + +pub impl(crate) trait T15 {} +pub impl(self) trait T16 {} + +pub impl(super) trait T17 {} //~ ERROR too many leading `super` keywords [E0433] + +// Check if we can resolve paths referring to modules declared later. +pub impl(in crate::j) trait L4 {} //~ ERROR trait implementation can only be restricted to ancestor modules + +pub impl(in crate::I) trait L5 {} //~ ERROR expected module, found enum `crate::I` [E0577] + +pub enum I {} +pub mod j {} + +// Check if we can resolve `use`d paths. +mod m1 { + pub impl(in crate::m2) trait U1 {} // OK +} + +use m1 as m2; + +mod m3 { + mod m4 { + pub impl(in crate::m2) trait U2 {} //~ ERROR trait implementation can only be restricted to ancestor modules + pub impl(in m6) trait U3 {} // OK + pub impl(in m6::m5) trait U4 {} //~ ERROR trait implementation can only be restricted to ancestor modules + pub impl(in m7) trait U5 {} //~ ERROR expected module, found enum `m7` [E0577] + + use crate::m3 as m6; + use crate::m3::E as m7; + } + mod m5 {} + pub enum E {} +} + +fn main() {} diff --git a/tests/ui/impl-restriction/restriction_resolution_errors.stderr b/tests/ui/impl-restriction/restriction_resolution_errors.stderr new file mode 100644 index 000000000000..540803285c1b --- /dev/null +++ b/tests/ui/impl-restriction/restriction_resolution_errors.stderr @@ -0,0 +1,140 @@ +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:14:21 + | +LL | pub impl(in ::std) trait T2 {} + | ^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:16:21 + | +LL | pub impl(in self::c) trait T3 {} + | ^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:18:21 + | +LL | pub impl(in super::d) trait T4 {} + | ^^^^^^^^ + +error[E0433]: too many leading `super` keywords + --> $DIR/restriction_resolution_errors.rs:24:35 + | +LL | pub impl(in super::super::super) trait T7 {} + | ^^^^^ there are too many leading `super` keywords + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:34:21 + | +LL | pub impl(in self::f) trait L1 {} + | ^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:38:21 + | +LL | pub impl(in super::h) trait L3 {} + | ^^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:47:13 + | +LL | pub impl(in crate::a) trait T13 {} + | ^^^^^^^^ + +error[E0433]: too many leading `super` keywords + --> $DIR/restriction_resolution_errors.rs:54:10 + | +LL | pub impl(super) trait T17 {} + | ^^^^^ there are too many leading `super` keywords + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:57:13 + | +LL | pub impl(in crate::j) trait L4 {} + | ^^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:73:21 + | +LL | pub impl(in crate::m2) trait U2 {} + | ^^^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:75:21 + | +LL | pub impl(in m6::m5) trait U4 {} + | ^^^^^^ + +error[E0433]: cannot find module or crate `a` in this scope + --> $DIR/restriction_resolution_errors.rs:12:21 + | +LL | pub impl(in a::b) trait T1 {} + | ^ use of unresolved module or unlinked crate `a` + | +help: there is a crate or module with a similar name + | +LL - pub impl(in a::b) trait T1 {} +LL + pub impl(in c::b) trait T1 {} + | +help: consider importing this module + | +LL + use a; + | + +error[E0433]: cannot find module `c` in the crate root + --> $DIR/restriction_resolution_errors.rs:20:28 + | +LL | pub impl(in crate::c) trait T5 {} + | ^ not found in the crate root + +error[E0577]: expected module, found enum `super::E` + --> $DIR/restriction_resolution_errors.rs:22:21 + | +LL | pub impl(in super::E) trait T6 {} + | ^^^^^^^^ not a module + +error[E0577]: expected module, found enum `super::G` + --> $DIR/restriction_resolution_errors.rs:36:21 + | +LL | pub impl(in super::G) trait L2 {} + | ^^^^^^^^ not a module + +error[E0577]: expected module, found enum `crate::a::E` + --> $DIR/restriction_resolution_errors.rs:49:13 + | +LL | pub mod b { + | --------- similarly named module `b` defined here +... +LL | pub impl(in crate::a::E) trait T14 {} + | ^^^^^^^^^^^ + | +help: a module with a similar name exists + | +LL - pub impl(in crate::a::E) trait T14 {} +LL + pub impl(in crate::a::b) trait T14 {} + | + +error[E0577]: expected module, found enum `crate::I` + --> $DIR/restriction_resolution_errors.rs:59:13 + | +LL | pub mod a { + | --------- similarly named module `a` defined here +... +LL | pub impl(in crate::I) trait L5 {} + | ^^^^^^^^ + | +help: a module with a similar name exists + | +LL - pub impl(in crate::I) trait L5 {} +LL + pub impl(in crate::a) trait L5 {} + | + +error[E0577]: expected module, found enum `m7` + --> $DIR/restriction_resolution_errors.rs:76:21 + | +LL | pub impl(in m7) trait U5 {} + | ^^ not a module + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0433, E0577. +For more information about an error, try `rustc --explain E0433`. diff --git a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.rs b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.rs index 62622e1d5586..ce36a49b145b 100644 --- a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.rs +++ b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.rs @@ -1,5 +1,6 @@ //@ compile-flags: --crate-type=lib //@ revisions: with_gate without_gate +#![warn(incomplete_features)] #![cfg_attr(with_gate, feature(impl_restriction))] //[with_gate]~^ WARN the feature `impl_restriction` is incomplete and may not be safe to use and/or cause compiler crashes #![feature(auto_traits, const_trait_impl, trait_alias)] diff --git a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.with_gate.stderr b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.with_gate.stderr index 70287aca42aa..7be030052df5 100644 --- a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.with_gate.stderr +++ b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.with_gate.stderr @@ -1,83 +1,87 @@ error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:7:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:8:1 | LL | impl(crate) trait Alias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `auto` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:10:1 | LL | auto impl(in crate) trait AutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:10:1 | LL | auto impl(in crate) trait AutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `unsafe` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:13:1 | LL | unsafe impl(self) trait UnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:13:1 | LL | unsafe impl(self) trait UnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:16:1 | LL | const impl(in self) trait ConstAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:19:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:20:5 | LL | impl(super) trait InnerAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `unsafe` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:22:5 | LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:22:5 | LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `auto` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:25:5 | LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` error: trait aliases cannot be `unsafe` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:25:5 | LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:25:5 | LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted warning: the feature `impl_restriction` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:3:32 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:4:32 | LL | #![cfg_attr(with_gate, feature(impl_restriction))] | ^^^^^^^^^^^^^^^^ | = note: see issue #105077 for more information - = note: `#[warn(incomplete_features)]` on by default +note: the lint level is defined here + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:3:9 + | +LL | #![warn(incomplete_features)] + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 12 previous errors; 1 warning emitted diff --git a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.without_gate.stderr b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.without_gate.stderr index 7bff90396708..c99bfce5da2c 100644 --- a/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.without_gate.stderr +++ b/tests/ui/impl-restriction/trait-alias-cannot-be-impl-restricted.without_gate.stderr @@ -1,77 +1,77 @@ error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:7:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:8:1 | LL | impl(crate) trait Alias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `auto` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:10:1 | LL | auto impl(in crate) trait AutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:10:1 | LL | auto impl(in crate) trait AutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `unsafe` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:13:1 | LL | unsafe impl(self) trait UnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:13:1 | LL | unsafe impl(self) trait UnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:16:1 | LL | const impl(in self) trait ConstAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:19:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:20:5 | LL | impl(super) trait InnerAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `unsafe` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:22:5 | LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:22:5 | LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error: trait aliases cannot be `auto` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:25:5 | LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto` error: trait aliases cannot be `unsafe` - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:25:5 | LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe` error: trait aliases cannot be `impl`-restricted - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:25:5 | LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted error[E0658]: `impl` restrictions are experimental - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:7:1 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:8:1 | LL | impl(crate) trait Alias = Copy; | ^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | impl(crate) trait Alias = Copy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:6 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:10:6 | LL | auto impl(in crate) trait AutoAlias = Copy; | ^^^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | auto impl(in crate) trait AutoAlias = Copy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:8 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:13:8 | LL | unsafe impl(self) trait UnsafeAlias = Copy; | ^^^^^^^^^^ @@ -101,7 +101,7 @@ LL | unsafe impl(self) trait UnsafeAlias = Copy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:7 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:16:7 | LL | const impl(in self) trait ConstAlias = Copy; | ^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | const impl(in self) trait ConstAlias = Copy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:19:5 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:20:5 | LL | impl(super) trait InnerAlias = Copy; | ^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | impl(super) trait InnerAlias = Copy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:21:18 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:22:18 | LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; | ^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | const unsafe impl(in crate::foo) trait InnerConstUnsafeAlias = Copy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl` restrictions are experimental - --> $DIR/trait-alias-cannot-be-impl-restricted.rs:24:17 + --> $DIR/trait-alias-cannot-be-impl-restricted.rs:25:17 | LL | unsafe auto impl(in crate::foo) trait InnerUnsafeAutoAlias = Copy; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs index de4f523c23aa..5f9fe0d141ff 100644 --- a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs +++ b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs @@ -1,6 +1,6 @@ use std::cell::Cell; use std::rc::Rc; - +//@ ignore-parallel-frontend query cycle fn send(_: T) {} fn main() {} @@ -8,7 +8,7 @@ fn main() {} // Cycles should work as the deferred obligations are // independently resolved and only require the concrete // return type, which can't depend on the obligation. -fn cycle1() -> impl Clone { +fn cycle1() -> impl Clone { //~ ERROR: cycle detected send(cycle2().clone()); Rc::new(Cell::new(5)) @@ -16,7 +16,6 @@ fn cycle1() -> impl Clone { fn cycle2() -> impl Clone { send(cycle1().clone()); - //~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits Rc::new(String::from("foo")) } diff --git a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr index cc9939f2d57f..ae1051699988 100644 --- a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr +++ b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr @@ -1,22 +1,84 @@ -error: cannot check whether the hidden type of opaque type satisfies auto traits - --> $DIR/auto-trait-leak.rs:18:10 - | -LL | send(cycle1().clone()); - | ---- ^^^^^^^^^^^^^^^^ - | | - | required by a bound introduced by this call - | - = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule -note: opaque type is declared here +error[E0391]: cycle detected when computing type of opaque `cycle1::{opaque#0}` --> $DIR/auto-trait-leak.rs:11:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ -note: required by a bound in `send` - --> $DIR/auto-trait-leak.rs:4:12 | -LL | fn send(_: T) {} - | ^^^^ required by this bound in `send` +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `cycle1` contains FFI-unwind calls... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:5 + | +LL | send(cycle2().clone()); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`... +note: ...which requires computing type of opaque `cycle2::{opaque#0}`... + --> $DIR/auto-trait-leak.rs:17:16 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `cycle2` contains FFI-unwind calls... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:18:5 + | +LL | send(cycle1().clone()); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `cycle1::{opaque#0}: core::marker::Send`... + = note: ...which again requires computing type of opaque `cycle1::{opaque#0}`, completing the cycle +note: cycle used when computing type of `cycle1::{opaque#0}` + --> $DIR/auto-trait-leak.rs:11:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/equality-rpass.rs b/tests/ui/impl-trait/equality-rpass.rs index da750f4ef1ba..d5cac80a08d7 100644 --- a/tests/ui/impl-trait/equality-rpass.rs +++ b/tests/ui/impl-trait/equality-rpass.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo: std::fmt::Debug + Eq {} diff --git a/tests/ui/impl-trait/equality-rpass.stderr b/tests/ui/impl-trait/equality-rpass.stderr deleted file mode 100644 index bde8362fdf81..000000000000 --- a/tests/ui/impl-trait/equality-rpass.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/equality-rpass.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/equality.rs b/tests/ui/impl-trait/equality.rs index 07fc4a5d41ac..4a315639bde9 100644 --- a/tests/ui/impl-trait/equality.rs +++ b/tests/ui/impl-trait/equality.rs @@ -1,6 +1,6 @@ //@ dont-require-annotations: NOTE -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo: Copy + ToString {} diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr index 7f965b9609a9..3c765da66bdc 100644 --- a/tests/ui/impl-trait/equality.stderr +++ b/tests/ui/impl-trait/equality.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/equality.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/equality.rs:17:5 | @@ -48,7 +38,7 @@ help: the following other types implement trait `Add` = note: `&u32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/equality2.rs b/tests/ui/impl-trait/equality2.rs index 808c600ecb7b..44d356e0e262 100644 --- a/tests/ui/impl-trait/equality2.rs +++ b/tests/ui/impl-trait/equality2.rs @@ -1,6 +1,6 @@ //@ dont-require-annotations: NOTE -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo: Copy + ToString {} diff --git a/tests/ui/impl-trait/equality2.stderr b/tests/ui/impl-trait/equality2.stderr index 2fa7eb288ff8..ce0ccea20afb 100644 --- a/tests/ui/impl-trait/equality2.stderr +++ b/tests/ui/impl-trait/equality2.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/equality2.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/equality2.rs:27:18 | @@ -72,6 +62,6 @@ LL | x.0); found opaque type `impl Foo` (`u32`) = note: distinct uses of `impl Trait` result in different opaque types -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs index 351cdad4ee11..ba6dfd4dfa8f 100644 --- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs +++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs @@ -1,7 +1,6 @@ //@ compile-flags: -Znext-solver #![feature(lazy_type_alias)] -//~^ WARN the feature `lazy_type_alias` is incomplete trait Foo {} diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr index a95670ced867..03c5d7a56769 100644 --- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr +++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr @@ -1,53 +1,44 @@ -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/alias-bounds-when-not-wf.rs:3:12 - | -LL | #![feature(lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `usize: Foo` is not satisfied - --> $DIR/alias-bounds-when-not-wf.rs:16:15 + --> $DIR/alias-bounds-when-not-wf.rs:15:15 | LL | fn hello(_: W>) {} | ^^^^^^^^ the trait `Foo` is not implemented for `usize` | help: this trait has no implementations, consider adding one - --> $DIR/alias-bounds-when-not-wf.rs:6:1 + --> $DIR/alias-bounds-when-not-wf.rs:5:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `A` - --> $DIR/alias-bounds-when-not-wf.rs:8:11 + --> $DIR/alias-bounds-when-not-wf.rs:7:11 | LL | type A = T; | ^^^ required by this bound in `A` error[E0277]: the trait bound `usize: Foo` is not satisfied - --> $DIR/alias-bounds-when-not-wf.rs:16:10 + --> $DIR/alias-bounds-when-not-wf.rs:15:10 | LL | fn hello(_: W>) {} | ^ the trait `Foo` is not implemented for `usize` | help: this trait has no implementations, consider adding one - --> $DIR/alias-bounds-when-not-wf.rs:6:1 + --> $DIR/alias-bounds-when-not-wf.rs:5:1 | LL | trait Foo {} | ^^^^^^^^^ error[E0277]: the trait bound `usize: Foo` is not satisfied - --> $DIR/alias-bounds-when-not-wf.rs:16:1 + --> $DIR/alias-bounds-when-not-wf.rs:15:1 | LL | fn hello(_: W>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `usize` | help: this trait has no implementations, consider adding one - --> $DIR/alias-bounds-when-not-wf.rs:6:1 + --> $DIR/alias-bounds-when-not-wf.rs:5:1 | LL | trait Foo {} | ^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr index f0a20367a4a1..87640517ddb2 100644 --- a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr @@ -57,66 +57,6 @@ LL | fn foo(b: bool) -> impl Sized { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `::foo::{anon_assoc#0}` - --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^ - | -note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires computing type of `::foo::{opaque#0}`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^ -note: ...which requires computing type of opaque `::foo::{opaque#0}`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^ -note: ...which requires borrow-checking `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires checking if `::foo` contains FFI-unwind calls... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires match-checking `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `::foo`... - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `::foo::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `::foo` is compatible with trait definition - --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 - | -LL | fn foo(b: bool) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr b/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr index c08fc511500c..14baf9459857 100644 --- a/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr +++ b/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr @@ -4,7 +4,7 @@ error[E0283]: type annotations needed LL | ().publish_typed(); | ^^^^^^^^^^^^^ cannot infer type of the type parameter `F` declared on the method `publish_typed` | - = note: cannot satisfy `_: Clone` + = note: the type must implement `Clone` = note: opaque types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl` note: required by a bound in `TypedClient::publish_typed::{anon_assoc#0}` --> $DIR/not-inferred-generic.rs:4:12 diff --git a/tests/ui/impl-trait/issues/issue-62742.rs b/tests/ui/impl-trait/issues/issue-62742.rs index c64278c2c5be..052917085abc 100644 --- a/tests/ui/impl-trait/issues/issue-62742.rs +++ b/tests/ui/impl-trait/issues/issue-62742.rs @@ -2,7 +2,7 @@ fn a() { WrongImpl::foo(0i32); - //~^ ERROR the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied + //~^ ERROR the associated function or constant `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied //~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied } diff --git a/tests/ui/impl-trait/issues/issue-62742.stderr b/tests/ui/impl-trait/issues/issue-62742.stderr index a1fedb8fb7b8..4899a96aece6 100644 --- a/tests/ui/impl-trait/issues/issue-62742.stderr +++ b/tests/ui/impl-trait/issues/issue-62742.stderr @@ -16,17 +16,17 @@ note: required by a bound in `SafeImpl` LL | pub struct SafeImpl>(PhantomData<(A, T)>); | ^^^^^^ required by this bound in `SafeImpl` -error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied +error[E0599]: the associated function or constant `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied --> $DIR/issue-62742.rs:4:16 | LL | WrongImpl::foo(0i32); - | ^^^ function or associated item cannot be called on `SafeImpl<_, RawImpl<_>>` due to unsatisfied trait bounds + | ^^^ associated function or constant cannot be called on `SafeImpl<_, RawImpl<_>>` due to unsatisfied trait bounds ... LL | pub struct RawImpl(PhantomData); | --------------------- doesn't satisfy `RawImpl<_>: Raw<_>` ... LL | pub struct SafeImpl>(PhantomData<(A, T)>); - | ----------------------------------------- function or associated item `foo` not found for this struct + | ----------------------------------------- associated function or constant `foo` not found for this struct | note: trait bound `RawImpl<_>: Raw<_>` was not satisfied --> $DIR/issue-62742.rs:35:20 @@ -60,17 +60,17 @@ note: required by a bound in `SafeImpl` LL | pub struct SafeImpl>(PhantomData<(A, T)>); | ^^^^^^ required by this bound in `SafeImpl` -error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied +error[E0599]: the associated function or constant `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied --> $DIR/issue-62742.rs:10:22 | LL | WrongImpl::<()>::foo(0i32); - | ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds + | ^^^ associated function or constant cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds ... LL | pub struct RawImpl(PhantomData); | --------------------- doesn't satisfy `RawImpl<()>: Raw<()>` ... LL | pub struct SafeImpl>(PhantomData<(A, T)>); - | ----------------------------------------- function or associated item `foo` not found for this struct + | ----------------------------------------- associated function or constant `foo` not found for this struct | note: trait bound `RawImpl<()>: Raw<()>` was not satisfied --> $DIR/issue-62742.rs:35:20 diff --git a/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr b/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr index 6866f3f5350b..8abced84ab86 100644 --- a/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr +++ b/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr @@ -7,7 +7,7 @@ LL | LL | loop {} | ------- return type was inferred to be `!` here | - = note: cannot satisfy `_: Future` + = note: the type must implement `Future` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/where-allowed-2.stderr b/tests/ui/impl-trait/where-allowed-2.stderr index 83364e6e7724..d731e5ce9e57 100644 --- a/tests/ui/impl-trait/where-allowed-2.stderr +++ b/tests/ui/impl-trait/where-allowed-2.stderr @@ -4,7 +4,7 @@ error[E0283]: type annotations needed LL | fn in_adt_in_return() -> Vec { panic!() } | ^^^^^^^^^^ cannot infer type | - = note: cannot satisfy `_: Debug` + = note: the type must implement `Debug` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 2d97215de3bb..2d925165d583 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -374,7 +374,7 @@ error[E0283]: type annotations needed LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ cannot infer type | - = note: cannot satisfy `_: Debug` + = note: the type must implement `Debug` error[E0283]: type annotations needed --> $DIR/where-allowed.rs:65:46 diff --git a/tests/ui/imports/ambiguous-trait-in-scope.stderr b/tests/ui/imports/ambiguous-trait-in-scope.stderr index cac1f4bb73fb..9360e104bf24 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.stderr +++ b/tests/ui/imports/ambiguous-trait-in-scope.stderr @@ -7,9 +7,9 @@ LL | use m2::*; LL | 0u8.method1(); | ^^^^^^^ | + = help: Import `Trait` explicitly = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #147992 - = help: Import `Trait` explicitly = note: `#[warn(ambiguous_glob_imported_traits)]` (part of `#[warn(future_incompatible)]`) on by default error[E0599]: no method named `method2` found for type `u8` in the current scope @@ -49,9 +49,9 @@ LL | use m2::*; LL | 0u8.method2(); | ^^^^^^^ | + = help: Import `Trait` explicitly = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #147992 - = help: Import `Trait` explicitly warning: Use of ambiguously glob imported trait `Trait` --> $DIR/ambiguous-trait-in-scope.rs:49:9 @@ -62,9 +62,9 @@ LL | use m2_reexport::*; LL | 0u8.method1(); | ^^^^^^^ | + = help: Import `Trait` explicitly = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #147992 - = help: Import `Trait` explicitly error[E0599]: no method named `method2` found for type `u8` in the current scope --> $DIR/ambiguous-trait-in-scope.rs:51:9 @@ -88,9 +88,9 @@ LL | use ambig_reexport::*; LL | 0u8.method1(); | ^^^^^^^ | + = help: Import `Trait` explicitly = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #147992 - = help: Import `Trait` explicitly error[E0599]: no method named `method2` found for type `u8` in the current scope --> $DIR/ambiguous-trait-in-scope.rs:58:9 @@ -115,9 +115,9 @@ LL | use external::m2::*; LL | 0u8.method1(); | ^^^^^^^ | + = help: Import `Trait` explicitly = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #147992 - = help: Import `Trait` explicitly error[E0599]: no method named `method2` found for type `u8` in the current scope --> $DIR/ambiguous-trait-in-scope.rs:66:9 @@ -142,9 +142,9 @@ LL | use external::m2_reexport::*; LL | 0u8.method1(); | ^^^^^^^ | + = help: Import `Trait` explicitly = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #147992 - = help: Import `Trait` explicitly error[E0599]: no method named `method2` found for type `u8` in the current scope --> $DIR/ambiguous-trait-in-scope.rs:74:9 @@ -168,9 +168,9 @@ LL | use external::ambig_reexport::*; LL | 0u8.method1(); | ^^^^^^^ | + = help: Import `Trait` explicitly = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #147992 - = help: Import `Trait` explicitly error[E0599]: no method named `method2` found for type `u8` in the current scope --> $DIR/ambiguous-trait-in-scope.rs:81:9 diff --git a/tests/ui/imports/import-trait-method.stderr b/tests/ui/imports/import-trait-method.stderr index 8fe774111b96..1cb2d734a925 100644 --- a/tests/ui/imports/import-trait-method.stderr +++ b/tests/ui/imports/import-trait-method.stderr @@ -14,7 +14,7 @@ error[E0283]: type annotations needed LL | fn main() { foo(); } | ^^^^^ cannot infer type | - = note: cannot satisfy `_: Foo` + = note: the type must implement `Foo` error: aborting due to 2 previous errors diff --git a/tests/ui/imports/inconsistent-resolution-153842.rs b/tests/ui/imports/inconsistent-resolution-153842.rs new file mode 100644 index 000000000000..85fff361e31d --- /dev/null +++ b/tests/ui/imports/inconsistent-resolution-153842.rs @@ -0,0 +1,17 @@ +mod a { + pub use crate::s::Trait as s; + //~^ ERROR cannot determine resolution for the import + //~| ERROR cannot determine resolution for the import + //~| ERROR unresolved imports `crate::s::Trait`, `a::s` +} + +mod b { + pub mod s { + pub trait Trait {} + } +} + +use a::s; +use b::*; + +fn main() {} diff --git a/tests/ui/imports/inconsistent-resolution-153842.stderr b/tests/ui/imports/inconsistent-resolution-153842.stderr new file mode 100644 index 000000000000..2b686ff3f76e --- /dev/null +++ b/tests/ui/imports/inconsistent-resolution-153842.stderr @@ -0,0 +1,26 @@ +error: cannot determine resolution for the import + --> $DIR/inconsistent-resolution-153842.rs:2:13 + | +LL | pub use crate::s::Trait as s; + | ^^^^^^^^^^^^^^^^^^^^ + +error: cannot determine resolution for the import + --> $DIR/inconsistent-resolution-153842.rs:2:13 + | +LL | pub use crate::s::Trait as s; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0432]: unresolved imports `crate::s::Trait`, `a::s` + --> $DIR/inconsistent-resolution-153842.rs:2:13 + | +LL | pub use crate::s::Trait as s; + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | use a::s; + | ^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/issue-28134.rs b/tests/ui/imports/issue-28134.rs index aef2fe8facdc..01d7274098cd 100644 --- a/tests/ui/imports/issue-28134.rs +++ b/tests/ui/imports/issue-28134.rs @@ -1,5 +1,4 @@ //@ compile-flags: --test -#![allow(soft_unstable)] #![test] //~^ ERROR `test` attribute cannot be used at crate level diff --git a/tests/ui/imports/issue-28134.stderr b/tests/ui/imports/issue-28134.stderr index e47aa15e87a9..33df87e3a747 100644 --- a/tests/ui/imports/issue-28134.stderr +++ b/tests/ui/imports/issue-28134.stderr @@ -1,5 +1,5 @@ error: `test` attribute cannot be used at crate level - --> $DIR/issue-28134.rs:4:1 + --> $DIR/issue-28134.rs:3:1 | LL | #![test] | ^^^^^^^^ diff --git a/tests/ui/include-macros/invalid-utf8-binary-file.rs b/tests/ui/include-macros/invalid-utf8-binary-file.rs index c733f07c26f0..24d99c11c237 100644 --- a/tests/ui/include-macros/invalid-utf8-binary-file.rs +++ b/tests/ui/include-macros/invalid-utf8-binary-file.rs @@ -7,6 +7,5 @@ #![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] //~^ ERROR: wasn't a utf-8 file -//~| ERROR: attribute value must be a literal fn main() {} diff --git a/tests/ui/include-macros/invalid-utf8-binary-file.stderr b/tests/ui/include-macros/invalid-utf8-binary-file.stderr index 232cb5042b72..4ac4def1b00a 100644 --- a/tests/ui/include-macros/invalid-utf8-binary-file.stderr +++ b/tests/ui/include-macros/invalid-utf8-binary-file.stderr @@ -6,11 +6,5 @@ LL | #![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] | = note: invalid utf-8 at byte `$BYTE` -error: attribute value must be a literal - --> $DIR/invalid-utf8-binary-file.rs:8:10 - | -LL | #![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/indexing/index-help.stderr b/tests/ui/indexing/index-help.stderr index 8fc91c1bf395..65faaec41258 100644 --- a/tests/ui/indexing/index-help.stderr +++ b/tests/ui/indexing/index-help.stderr @@ -5,13 +5,13 @@ LL | x[0i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `Vec<{integer}>` to implement `Index` error: aborting due to 1 previous error diff --git a/tests/ui/indexing/indexing-integral-types.stderr b/tests/ui/indexing/indexing-integral-types.stderr index 3dfc5f5e26e0..604161325afc 100644 --- a/tests/ui/indexing/indexing-integral-types.stderr +++ b/tests/ui/indexing/indexing-integral-types.stderr @@ -5,13 +5,13 @@ LL | v[3u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[isize]>` is not implemented for `u8` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `Vec` to implement `Index` error[E0277]: the type `[isize]` cannot be indexed by `i8` @@ -21,13 +21,13 @@ LL | v[3i8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[isize]>` is not implemented for `i8` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `Vec` to implement `Index` error[E0277]: the type `[isize]` cannot be indexed by `u32` @@ -37,13 +37,13 @@ LL | v[3u32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[isize]>` is not implemented for `u32` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `Vec` to implement `Index` error[E0277]: the type `[isize]` cannot be indexed by `i32` @@ -53,13 +53,13 @@ LL | v[3i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[isize]>` is not implemented for `i32` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `Vec` to implement `Index` error[E0277]: the type `[u8]` cannot be indexed by `u8` @@ -69,13 +69,13 @@ LL | s.as_bytes()[3u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[u8]>` is not implemented for `u8` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `[u8]` to implement `Index` error[E0277]: the type `[u8]` cannot be indexed by `i8` @@ -85,13 +85,13 @@ LL | s.as_bytes()[3i8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[u8]>` is not implemented for `i8` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `[u8]` to implement `Index` error[E0277]: the type `[u8]` cannot be indexed by `u32` @@ -101,13 +101,13 @@ LL | s.as_bytes()[3u32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[u8]>` is not implemented for `u32` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `[u8]` to implement `Index` error[E0277]: the type `[u8]` cannot be indexed by `i32` @@ -117,13 +117,13 @@ LL | s.as_bytes()[3i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[u8]>` is not implemented for `i32` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `[u8]` to implement `Index` error: aborting due to 8 previous errors diff --git a/tests/ui/indexing/indexing-requires-a-uint.stderr b/tests/ui/indexing/indexing-requires-a-uint.stderr index e5f9f7854f7b..9e974c8c9bbc 100644 --- a/tests/ui/indexing/indexing-requires-a-uint.stderr +++ b/tests/ui/indexing/indexing-requires-a-uint.stderr @@ -5,13 +5,13 @@ LL | [0][0u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `[{integer}]` to implement `Index` error[E0308]: mismatched types diff --git a/tests/ui/inference/array-len-mismatch.stderr b/tests/ui/inference/array-len-mismatch.stderr index 7146e3803d53..94813d404b2b 100644 --- a/tests/ui/inference/array-len-mismatch.stderr +++ b/tests/ui/inference/array-len-mismatch.stderr @@ -3,18 +3,28 @@ error[E0308]: mismatched types | LL | let wrong: [u8; 3] = [10, 20]; | ------- ^^^^^^^^ expected an array with a size of 3, found one with a size of 2 - | | | - | | help: consider specifying the actual array length: `2` + | | | expected due to this + | +help: consider specifying the actual array length + | +LL - let wrong: [u8; 3] = [10, 20]; +LL + let wrong: [u8; 2] = [10, 20]; + | error[E0308]: mismatched types --> $DIR/array-len-mismatch.rs:9:26 | LL | let wrong: [u8; 3] = returns_arr(); | ------- ^^^^^^^^^^^^^ expected an array with a size of 3, found one with a size of 2 - | | | - | | help: consider specifying the actual array length: `2` + | | | expected due to this + | +help: consider specifying the actual array length + | +LL - let wrong: [u8; 3] = returns_arr(); +LL + let wrong: [u8; 2] = returns_arr(); + | error: aborting due to 2 previous errors diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed b/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed new file mode 100644 index 000000000000..9a494391f0e4 --- /dev/null +++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed @@ -0,0 +1,13 @@ +//@ run-rustfix +fn main() { + let v = vec![1, 2]; + let sum: i32 = v //~ ERROR: type annotations needed + .iter() + .map(|val| *val) + .sum(); // `sum::` needs `T` to be specified + // In this case any integer would fit, but we resolve to `i32` because that's what `{integer}` + // got coerced to. If the user needs further hinting that they can change the integer type, that + // can come from other suggestions. (#100802) + let bool = sum > 0; + assert_eq!(bool, true); +} diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs b/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs new file mode 100644 index 000000000000..013a2f914858 --- /dev/null +++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs @@ -0,0 +1,13 @@ +//@ run-rustfix +fn main() { + let v = vec![1, 2]; + let sum = v //~ ERROR: type annotations needed + .iter() + .map(|val| *val) + .sum(); // `sum::` needs `T` to be specified + // In this case any integer would fit, but we resolve to `i32` because that's what `{integer}` + // got coerced to. If the user needs further hinting that they can change the integer type, that + // can come from other suggestions. (#100802) + let bool = sum > 0; + assert_eq!(bool, true); +} diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr b/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr new file mode 100644 index 000000000000..594b6f0181db --- /dev/null +++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr @@ -0,0 +1,26 @@ +error[E0283]: type annotations needed + --> $DIR/cannot-infer-iterator-sum-return-type.rs:4:9 + | +LL | let sum = v + | ^^^ +... +LL | .sum(); // `sum::` needs `T` to be specified + | --- type must be known at this point + | + = note: the type must implement `Sum` +help: the trait `Sum` is implemented for `i32` + --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation +note: required by a bound in `std::iter::Iterator::sum` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + = note: this error originates in the macro `integer_sum_product` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider giving `sum` an explicit type, where the type for type parameter `S` is specified + | +LL | let sum: i32 = v + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/inference/erase-type-params-in-label.stderr b/tests/ui/inference/erase-type-params-in-label.stderr index 1ec8a33eb820..5056d6358686 100644 --- a/tests/ui/inference/erase-type-params-in-label.stderr +++ b/tests/ui/inference/erase-type-params-in-label.stderr @@ -4,7 +4,7 @@ error[E0283]: type annotations needed for `Foo` LL | let foo = foo(1, ""); | ^^^ ---------- type must be known at this point | - = note: cannot satisfy `_: Default` + = note: the type must implement `Default` note: required by a bound in `foo` --> $DIR/erase-type-params-in-label.rs:25:17 | @@ -21,7 +21,7 @@ error[E0283]: type annotations needed for `Bar` LL | let bar = bar(1, ""); | ^^^ ---------- type must be known at this point | - = note: cannot satisfy `_: Default` + = note: the type must implement `Default` note: required by a bound in `bar` --> $DIR/erase-type-params-in-label.rs:14:17 | diff --git a/tests/ui/inference/issue-86162-1.stderr b/tests/ui/inference/issue-86162-1.stderr index fe3cee771609..d36ea12f6f04 100644 --- a/tests/ui/inference/issue-86162-1.stderr +++ b/tests/ui/inference/issue-86162-1.stderr @@ -6,7 +6,7 @@ LL | foo(gen()); //<- Do not suggest `foo::()`! | | | required by a bound introduced by this call | - = note: cannot satisfy `_: Clone` + = note: the type must implement `Clone` note: required by a bound in `foo` --> $DIR/issue-86162-1.rs:3:16 | diff --git a/tests/ui/inference/issue-86162-2.stderr b/tests/ui/inference/issue-86162-2.stderr index 7b45b196629e..adbc585d4692 100644 --- a/tests/ui/inference/issue-86162-2.stderr +++ b/tests/ui/inference/issue-86162-2.stderr @@ -6,7 +6,7 @@ LL | Foo::bar(gen()); //<- Do not suggest `Foo::bar::()`! | | | required by a bound introduced by this call | - = note: cannot satisfy `_: Clone` + = note: the type must implement `Clone` note: required by a bound in `Foo::bar` --> $DIR/issue-86162-2.rs:8:20 | diff --git a/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.stderr b/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.stderr index 455304524edc..bf67c10098d5 100644 --- a/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.stderr +++ b/tests/ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.stderr @@ -6,7 +6,7 @@ LL | (S {}).owo(None) | | | required by a bound introduced by this call | - = note: cannot satisfy `_: T` + = note: the type must implement `T` note: required by a bound in `S::owo` --> $DIR/issue-113264-incorrect-impl-trait-in-path-suggestion.rs:6:35 | diff --git a/tests/ui/inference/question-mark-type-infer.rs b/tests/ui/inference/question-mark-type-infer.rs index 10560f85ed48..b04868c5324f 100644 --- a/tests/ui/inference/question-mark-type-infer.rs +++ b/tests/ui/inference/question-mark-type-infer.rs @@ -10,6 +10,20 @@ fn g() -> Result, ()> { l.iter().map(f).collect()? //~^ ERROR type annotations needed } +fn h() -> Result<(), ()> { + let l = [1, 2, 3, 4]; + // The resulting binding doesn't have a type, so we need to guess the `Ok` type too. + let x = l.iter().map(f).collect()?; + //~^ ERROR type annotations needed + Ok(()) +} +fn i() -> Result<(), ()> { + let l = [1, 2, 3, 4]; + // The resulting binding already has a type, so we don't need to specify the `Ok` type. + let x: Vec = l.iter().map(f).collect()?; + //~^ ERROR type annotations needed + Ok(()) +} fn main() { g(); diff --git a/tests/ui/inference/question-mark-type-infer.stderr b/tests/ui/inference/question-mark-type-infer.stderr index 45303a2c87ff..b531d42ff93c 100644 --- a/tests/ui/inference/question-mark-type-infer.stderr +++ b/tests/ui/inference/question-mark-type-infer.stderr @@ -4,14 +4,42 @@ error[E0283]: type annotations needed LL | l.iter().map(f).collect()? | ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect` | - = note: cannot satisfy `_: FromIterator>` + = note: the type must implement `FromIterator>` note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL help: consider specifying the generic argument | -LL | l.iter().map(f).collect::>()? - | ++++++++++ +LL | l.iter().map(f).collect::>()? + | ++++++++++++++++ -error: aborting due to 1 previous error +error[E0283]: type annotations needed + --> $DIR/question-mark-type-infer.rs:16:29 + | +LL | let x = l.iter().map(f).collect()?; + | ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect` + | + = note: the type must implement `FromIterator>` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider specifying the generic argument + | +LL | let x = l.iter().map(f).collect::>()?; + | ++++++++++++++++ + +error[E0283]: type annotations needed + --> $DIR/question-mark-type-infer.rs:23:39 + | +LL | let x: Vec = l.iter().map(f).collect()?; + | ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect` + | + = note: the type must implement `FromIterator>` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider specifying the generic argument + | +LL | let x: Vec = l.iter().map(f).collect::>()?; + | ++++++++++++++++ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/inference/question-mark-type-inference-in-chain.rs b/tests/ui/inference/question-mark-type-inference-in-chain.rs new file mode 100644 index 000000000000..f3e36b7c4016 --- /dev/null +++ b/tests/ui/inference/question-mark-type-inference-in-chain.rs @@ -0,0 +1,84 @@ +// #129269 +use std::fmt::Display; + +#[derive(Debug)] +struct AnotherError; +type Result = core::result::Result; + +#[derive(Debug)] +pub struct Error; + +impl From for Error { + fn from(_: AnotherError) -> Self { Error } +} + +impl std::error::Error for Error {} + +impl Display for Error { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +#[derive(Ord, PartialEq, PartialOrd, Eq)] +pub struct Version {} + +fn parse(_s: &str) -> std::result::Result { + todo!() +} + +pub fn error1(lines: &[&str]) -> Result> { + let mut tags = lines.iter().map(|e| parse(e)).collect()?; + //~^ ERROR: type annotations needed + //~| HELP: consider giving `tags` an explicit type + + tags.sort(); //~ NOTE: type must be known at this point + + Ok(tags) +} + +pub fn error2(lines: &[&str]) -> Result> { + let mut tags: Vec = lines.iter().map(|e| parse(e)).collect()?; + //~^ ERROR: type annotations needed + //~| NOTE: cannot infer type of the type parameter `B` + //~| NOTE: the type must implement `FromIterator>` + //~| NOTE: required by a bound in `collect` + //~| HELP: consider specifying the generic argument + tags.sort(); + + Ok(tags) +} + +pub fn error3(lines: &[&str]) -> Result> { + let mut tags = lines.iter().map(|e| parse(e)).collect::>()?; + //~^ ERROR: the `?` operator can only be applied to values that implement `Try` + //~| NOTE: the `?` operator cannot be applied to type `Vec>` + //~| HELP: the nightly-only, unstable trait `Try` is not implemented + //~| NOTE: in this expansion of desugaring of operator `?` + //~| NOTE: in this expansion of desugaring of operator `?` + tags.sort(); + + Ok(tags) +} + +pub fn error4(lines: &[&str]) -> Result> { + let mut tags = lines + //~^ NOTE: this expression has type `&[&str]` + .iter() + //~^ NOTE: `Iterator::Item` is `&&str` here + .map(|e| parse(e)) + //~^ NOTE: the method call chain might not have had the expected associated types + //~| NOTE: `Iterator::Item` changed to `Result` here + .collect::>>()?; + //~^ ERROR: a value of type `std::result::Result, AnotherError>` cannot be built from an iterator over elements of type `std::result::Result` + //~| NOTE: value of type `std::result::Result, AnotherError>` cannot be built from `std::iter::Iterator>` + //~| NOTE: required by a bound introduced by this call + //~| HELP: the trait + //~| HELP: for that trait implementation, expected `AnotherError`, found `Error` + //~| NOTE: required by a bound in `collect` + tags.sort(); + + Ok(tags) +} + +fn main() {} diff --git a/tests/ui/inference/question-mark-type-inference-in-chain.stderr b/tests/ui/inference/question-mark-type-inference-in-chain.stderr new file mode 100644 index 000000000000..af8a5c8aebad --- /dev/null +++ b/tests/ui/inference/question-mark-type-inference-in-chain.stderr @@ -0,0 +1,66 @@ +error[E0282]: type annotations needed + --> $DIR/question-mark-type-inference-in-chain.rs:31:9 + | +LL | let mut tags = lines.iter().map(|e| parse(e)).collect()?; + | ^^^^^^^^ +... +LL | tags.sort(); + | ---- type must be known at this point + | +help: consider giving `tags` an explicit type + | +LL | let mut tags: Vec<_> = lines.iter().map(|e| parse(e)).collect()?; + | ++++++++ + +error[E0283]: type annotations needed + --> $DIR/question-mark-type-inference-in-chain.rs:41:65 + | +LL | let mut tags: Vec = lines.iter().map(|e| parse(e)).collect()?; + | ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect` + | + = note: the type must implement `FromIterator>` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider specifying the generic argument + | +LL | let mut tags: Vec = lines.iter().map(|e| parse(e)).collect::>()?; + | ++++++++++++++++ + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/question-mark-type-inference-in-chain.rs:53:20 + | +LL | let mut tags = lines.iter().map(|e| parse(e)).collect::>()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `Vec>` + | + = help: the nightly-only, unstable trait `Try` is not implemented for `Vec>` + +error[E0277]: a value of type `std::result::Result, AnotherError>` cannot be built from an iterator over elements of type `std::result::Result` + --> $DIR/question-mark-type-inference-in-chain.rs:72:20 + | +LL | .collect::>>()?; + | ------- ^^^^^^^^^^^^^^^^^^^^ value of type `std::result::Result, AnotherError>` cannot be built from `std::iter::Iterator>` + | | + | required by a bound introduced by this call + | +help: the trait `FromIterator>` is not implemented for `std::result::Result, AnotherError>` + but trait `FromIterator>` is implemented for it + --> $SRC_DIR/core/src/result.rs:LL:COL + = help: for that trait implementation, expected `AnotherError`, found `Error` +note: the method call chain might not have had the expected associated types + --> $DIR/question-mark-type-inference-in-chain.rs:69:10 + | +LL | let mut tags = lines + | ----- this expression has type `&[&str]` +LL | +LL | .iter() + | ------ `Iterator::Item` is `&&str` here +LL | +LL | .map(|e| parse(e)) + | ^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `Result` here +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0282, E0283. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/inference/useless-turbofish-suggestion.rs b/tests/ui/inference/useless-turbofish-suggestion.rs new file mode 100644 index 000000000000..64dbfff64c52 --- /dev/null +++ b/tests/ui/inference/useless-turbofish-suggestion.rs @@ -0,0 +1,33 @@ +// Regression test for #153732. +// +// When a method call already has turbofish type arguments, don't suggest +// rewriting them — the suggestion just rewrites user syntax into +// fully-qualified form without resolving anything. +// +// When a turbofish is present, the diagnostic points at the specific +// uninferred generic argument rather than the method name. + +struct S; + +impl S { + fn f(self, _a: A) -> B { + todo!() + } +} + +fn turbofish_second_arg() { + S.f::(42); + //~^ ERROR type annotations needed +} + +fn turbofish_first_arg() { + S.f::<_, _>(42); + //~^ ERROR type annotations needed +} + +fn without_turbofish() { + S.f(42); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/inference/useless-turbofish-suggestion.stderr b/tests/ui/inference/useless-turbofish-suggestion.stderr new file mode 100644 index 000000000000..ccd30b415f65 --- /dev/null +++ b/tests/ui/inference/useless-turbofish-suggestion.stderr @@ -0,0 +1,26 @@ +error[E0282]: type annotations needed + --> $DIR/useless-turbofish-suggestion.rs:19:16 + | +LL | S.f::(42); + | ^ cannot infer type of the type parameter `B` declared on the method `f` + +error[E0282]: type annotations needed + --> $DIR/useless-turbofish-suggestion.rs:24:14 + | +LL | S.f::<_, _>(42); + | ^ cannot infer type of the type parameter `B` declared on the method `f` + +error[E0282]: type annotations needed + --> $DIR/useless-turbofish-suggestion.rs:29:7 + | +LL | S.f(42); + | ^ cannot infer type of the type parameter `B` declared on the method `f` + | +help: consider specifying the generic arguments + | +LL | S.f::(42); + | ++++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/infinite/infinite-trait-alias-recursion.rs b/tests/ui/infinite/infinite-trait-alias-recursion.rs index 0bd4624de3f1..df884cca22b7 100644 --- a/tests/ui/infinite/infinite-trait-alias-recursion.rs +++ b/tests/ui/infinite/infinite-trait-alias-recursion.rs @@ -1,5 +1,5 @@ #![feature(trait_alias)] - +//@ ignore-parallel-frontend query cycle trait T1 = T2; //~^ ERROR cycle detected when computing the implied predicates of `T1` diff --git a/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs b/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs index cf9ea0db4cbe..6a43c4ac7872 100644 --- a/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs +++ b/tests/ui/infinite/infinite-type-alias-mutual-recursion.rs @@ -1,5 +1,5 @@ //@ revisions: feature gated - +//@ ignore-parallel-frontend query cycle #![cfg_attr(feature, feature(lazy_type_alias))] #![allow(incomplete_features)] diff --git a/tests/ui/inline-const/required-const.rs b/tests/ui/inline-const/required-const.rs index 8f640e933d01..437652532ec5 100644 --- a/tests/ui/inline-const/required-const.rs +++ b/tests/ui/inline-const/required-const.rs @@ -1,6 +1,6 @@ //@ build-fail //@ compile-flags: -Zmir-opt-level=3 - +//@ ignore-parallel-frontend post-monomorphization errors fn foo() { if false { const { panic!() } //~ ERROR E0080 diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.rs b/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.rs new file mode 100644 index 000000000000..6a32cd97c50b --- /dev/null +++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.rs @@ -0,0 +1,18 @@ +//@ check-fail + +#![feature(repr_simd, intrinsics, core_intrinsics)] +#![allow(warnings)] +#![crate_type = "rlib"] + +// Bad monomorphizations could previously cause LLVM asserts even though the +// error was caught in the compiler. + +use std::intrinsics; + +#[derive(Copy, Clone)] +pub struct Foo(i64); + +pub unsafe fn test_fadd_fast(a: Foo, b: Foo) -> Foo { + intrinsics::fadd_fast(a, b) + //~^ ERROR the trait bound `Foo: intrinsics::bounds::FloatPrimitive` is not satisfied +} diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.stderr b/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.stderr new file mode 100644 index 000000000000..db2a222c8f2c --- /dev/null +++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.stderr @@ -0,0 +1,30 @@ +error[E0277]: the trait bound `Foo: intrinsics::bounds::FloatPrimitive` is not satisfied + --> $DIR/bad-intrinsic-monomorphization-bounds.rs:16:5 + | +LL | intrinsics::fadd_fast(a, b) + | ^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the nightly-only, unstable trait `intrinsics::bounds::FloatPrimitive` is not implemented for `Foo` + --> $DIR/bad-intrinsic-monomorphization-bounds.rs:13:1 + | +LL | pub struct Foo(i64); + | ^^^^^^^^^^^^^^ +help: the following other types implement trait `intrinsics::bounds::FloatPrimitive` + --> $SRC_DIR/core/src/intrinsics/bounds.rs:LL:COL + | + = note: `f16` + ::: $SRC_DIR/core/src/intrinsics/bounds.rs:LL:COL + | + = note: `f32` + ::: $SRC_DIR/core/src/intrinsics/bounds.rs:LL:COL + | + = note: `f64` + ::: $SRC_DIR/core/src/intrinsics/bounds.rs:LL:COL + | + = note: `f128` +note: required by a bound in `fadd_fast` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs b/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs index d68cbf26ef11..8849ed2a67ad 100644 --- a/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs +++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization.rs @@ -17,11 +17,6 @@ pub fn test_cttz(v: Foo) -> u32 { //~^ ERROR `cttz` intrinsic: expected basic integer type, found `Foo` } -pub unsafe fn test_fadd_fast(a: Foo, b: Foo) -> Foo { - intrinsics::fadd_fast(a, b) - //~^ ERROR `fadd_fast` intrinsic: expected basic float type, found `Foo` -} - pub unsafe fn test_simd_add(a: Foo, b: Foo) -> Foo { intrinsics::simd::simd_add(a, b) //~^ ERROR `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo` diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr b/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr index 51ef71c9e298..329bf214c03d 100644 --- a/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr +++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr @@ -1,21 +1,15 @@ error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo` - --> $DIR/bad-intrinsic-monomorphization.rs:26:5 + --> $DIR/bad-intrinsic-monomorphization.rs:21:5 | LL | intrinsics::simd::simd_add(a, b) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `fadd_fast` intrinsic: expected basic float type, found `Foo` - --> $DIR/bad-intrinsic-monomorphization.rs:21:5 - | -LL | intrinsics::fadd_fast(a, b) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0511]: invalid monomorphization of `cttz` intrinsic: expected basic integer type, found `Foo` --> $DIR/bad-intrinsic-monomorphization.rs:16:5 | LL | intrinsics::cttz(v) | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0511`. diff --git a/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr b/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr index aee60c94f106..e07f35648827 100644 --- a/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr +++ b/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr @@ -1,4 +1,4 @@ thread 'main' ($TID) panicked at $DIR/const-eval-select-backtrace-std.rs:6:8: -start byte index 1 is out of bounds of `` +start byte index 1 is out of bounds for string of length 0 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs index ed15f5bba962..d2e5e158b722 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs @@ -1,6 +1,6 @@ //@ normalize-stderr: "[[:xdigit:]]{2} __ ([[:xdigit:]]{2}\s){2}" -> "HEX_DUMP" #![feature(core_intrinsics)] - +//@ ignore-parallel-frontend different alloc ids const RAW_EQ_PADDING: bool = unsafe { std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) //~^ ERROR requires initialized memory diff --git a/tests/ui/invalid/foo.natvis.xml b/tests/ui/invalid/foo.natvis.xml deleted file mode 100644 index c341a403902b..000000000000 --- a/tests/ui/invalid/foo.natvis.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/ui/invalid/invalid-path-in-const.rs b/tests/ui/invalid/invalid-path-in-const.rs deleted file mode 100644 index 51eb86072119..000000000000 --- a/tests/ui/invalid/invalid-path-in-const.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - fn f(a: [u8; u32::DOESNOTEXIST]) {} - //~^ ERROR no associated item named `DOESNOTEXIST` found for type `u32` -} diff --git a/tests/ui/invalid/invalid-path-in-const.stderr b/tests/ui/invalid/invalid-path-in-const.stderr deleted file mode 100644 index 31528ab856e6..000000000000 --- a/tests/ui/invalid/invalid-path-in-const.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0599]: no associated item named `DOESNOTEXIST` found for type `u32` in the current scope - --> $DIR/invalid-path-in-const.rs:2:23 - | -LL | fn f(a: [u8; u32::DOESNOTEXIST]) {} - | ^^^^^^^^^^^^ associated item not found in `u32` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/issues/issue-17252.rs b/tests/ui/issues/issue-17252.rs index 5941e10f8b06..dd002bfd187a 100644 --- a/tests/ui/issues/issue-17252.rs +++ b/tests/ui/issues/issue-17252.rs @@ -1,5 +1,5 @@ const FOO: usize = FOO; //~ ERROR E0391 - +//@ ignore-parallel-frontend query cycle fn main() { let _x: [u8; FOO]; // caused stack overflow prior to fix let _y: usize = 1 + { diff --git a/tests/ui/issues/issue-23041.stderr b/tests/ui/issues/issue-23041.stderr index bd0e457fa9da..b348a8695f6f 100644 --- a/tests/ui/issues/issue-23041.stderr +++ b/tests/ui/issues/issue-23041.stderr @@ -1,14 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/issue-23041.rs:6:7 + --> $DIR/issue-23041.rs:6:22 | LL | b.downcast_ref::_>(); - | ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the method `downcast_ref` - | -help: consider specifying the generic argument - | -LL - b.downcast_ref::_>(); -LL + b.downcast_ref:: _>(); - | + | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the method `downcast_ref` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-28586.rs b/tests/ui/issues/issue-28586.rs index c543ef9b0e3d..9520e0e51a15 100644 --- a/tests/ui/issues/issue-28586.rs +++ b/tests/ui/issues/issue-28586.rs @@ -2,6 +2,6 @@ pub trait Foo {} impl Foo for [u8; usize::BYTES] {} -//~^ ERROR no associated item named `BYTES` found +//~^ ERROR no associated function or constant named `BYTES` found fn main() { } diff --git a/tests/ui/issues/issue-28586.stderr b/tests/ui/issues/issue-28586.stderr index 33f40a341c8f..dda147954fac 100644 --- a/tests/ui/issues/issue-28586.stderr +++ b/tests/ui/issues/issue-28586.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `BYTES` found for type `usize` in the current scope +error[E0599]: no associated function or constant named `BYTES` found for type `usize` in the current scope --> $DIR/issue-28586.rs:4:26 | LL | impl Foo for [u8; usize::BYTES] {} - | ^^^^^ associated item not found in `usize` + | ^^^^^ associated function or constant not found in `usize` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-28971.rs b/tests/ui/issues/issue-28971.rs index 8e7a2fe0ef20..e6a504f52e0c 100644 --- a/tests/ui/issues/issue-28971.rs +++ b/tests/ui/issues/issue-28971.rs @@ -5,7 +5,7 @@ fn main(){ foo(|| { match Foo::Bar(1) { Foo::Baz(..) => (), - //~^ ERROR no variant or associated item named `Baz` found + //~^ ERROR no variant, associated function, or constant named `Baz` found _ => (), } }); diff --git a/tests/ui/issues/issue-28971.stderr b/tests/ui/issues/issue-28971.stderr index fd689a2b36ee..de3fff0a49e3 100644 --- a/tests/ui/issues/issue-28971.stderr +++ b/tests/ui/issues/issue-28971.stderr @@ -1,11 +1,11 @@ -error[E0599]: no variant or associated item named `Baz` found for enum `Foo` in the current scope +error[E0599]: no variant, associated function, or constant named `Baz` found for enum `Foo` in the current scope --> $DIR/issue-28971.rs:7:18 | LL | enum Foo { - | -------- variant or associated item `Baz` not found for this enum + | -------- variant, associated function, or constant `Baz` not found for this enum ... LL | Foo::Baz(..) => (), - | ^^^ variant or associated item not found in `Foo` + | ^^^ variant, associated function, or constant not found in `Foo` | help: there is a variant with a similar name | diff --git a/tests/ui/issues/issue-30123.rs b/tests/ui/issues/issue-30123.rs index f6511b5f290d..88fab44741f2 100644 --- a/tests/ui/issues/issue-30123.rs +++ b/tests/ui/issues/issue-30123.rs @@ -5,5 +5,5 @@ fn main() { let ug = Graph::::new_undirected(); - //~^ ERROR no function or associated item named `new_undirected` found + //~^ ERROR no associated function or constant named `new_undirected` found } diff --git a/tests/ui/issues/issue-30123.stderr b/tests/ui/issues/issue-30123.stderr index 3ed1f34c44aa..1e2747407d1d 100644 --- a/tests/ui/issues/issue-30123.stderr +++ b/tests/ui/issues/issue-30123.stderr @@ -1,16 +1,15 @@ -error[E0599]: no function or associated item named `new_undirected` found for struct `issue_30123_aux::Graph` in the current scope +error[E0599]: no associated function or constant named `new_undirected` found for struct `issue_30123_aux::Graph` in the current scope --> $DIR/issue-30123.rs:7:33 | LL | let ug = Graph::::new_undirected(); - | ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph` + | ^^^^^^^^^^^^^^ associated function or constant not found in `issue_30123_aux::Graph` | note: if you're trying to build a new `issue_30123_aux::Graph`, consider using `issue_30123_aux::Graph::::new` which returns `issue_30123_aux::Graph<_, _>` --> $DIR/auxiliary/issue-30123-aux.rs:14:5 | LL | pub fn new() -> Self { | ^^^^^^^^^^^^^^^^^^^^ - = note: the function or associated item was found for - - `issue_30123_aux::Graph` + = note: the associated function or constant was found for `issue_30123_aux::Graph` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-31910.rs b/tests/ui/issues/issue-31910.rs index fc82fda0ccd8..697bbf6fe6d1 100644 --- a/tests/ui/issues/issue-31910.rs +++ b/tests/ui/issues/issue-31910.rs @@ -1,9 +1,10 @@ enum Enum { - //~^ ERROR `T` is never used - //~| NOTE unused type parameter + //~^ ERROR: `T` is never used + //~| NOTE: unused type parameter X = Trait::Number, - //~^ ERROR mismatched types - //~| NOTE expected `isize`, found `i32` + //~^ ERROR: mismatched types + //~| NOTE: expected `isize`, found `i32` + //~| NOTE: enum variant discriminant } trait Trait { diff --git a/tests/ui/issues/issue-31910.stderr b/tests/ui/issues/issue-31910.stderr index 56e4cee53d63..765db15e8285 100644 --- a/tests/ui/issues/issue-31910.stderr +++ b/tests/ui/issues/issue-31910.stderr @@ -3,6 +3,8 @@ error[E0308]: mismatched types | LL | X = Trait::Number, | ^^^^^^^^^^^^^ expected `isize`, found `i32` + | + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` error[E0392]: type parameter `T` is never used --> $DIR/issue-31910.rs:1:11 diff --git a/tests/ui/issues/issue-33504.stderr b/tests/ui/issues/issue-33504.stderr index f3e1ca08b6fc..e5a2eea751d0 100644 --- a/tests/ui/issues/issue-33504.stderr +++ b/tests/ui/issues/issue-33504.stderr @@ -9,7 +9,12 @@ LL | let Test = 1; | | | expected integer, found `Test` | `Test` is interpreted as a unit struct, not a new binding - | help: introduce a new binding instead: `other_test` + | +help: introduce a new binding instead + | +LL - let Test = 1; +LL + let other_test = 1; + | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-34373.rs b/tests/ui/issues/issue-34373.rs index 765bfc20a451..02e1048e5a33 100644 --- a/tests/ui/issues/issue-34373.rs +++ b/tests/ui/issues/issue-34373.rs @@ -1,12 +1,11 @@ #![allow(warnings)] - +//@ ignore-parallel-frontend query cycle trait Trait { fn foo(_: T) {} } pub struct Foo>>; //~^ ERROR cycle detected when computing type of `Foo::T` -//~| ERROR type parameter `T` is never used type DefaultFoo = Foo; fn main() { diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index 6d68de8fb3b8..995f2f4022b6 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -5,7 +5,7 @@ LL | pub struct Foo>>; | ^^^^^^^^^^ | note: ...which requires expanding type alias `DefaultFoo`... - --> $DIR/issue-34373.rs:10:19 + --> $DIR/issue-34373.rs:9:19 | LL | type DefaultFoo = Foo; | ^^^ @@ -17,16 +17,6 @@ LL | pub struct Foo>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0392]: type parameter `T` is never used - --> $DIR/issue-34373.rs:7:16 - | -LL | pub struct Foo>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused type parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0391, E0392. -For more information about an error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs deleted file mode 100644 index 0e1f19a75bae..000000000000 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs +++ /dev/null @@ -1,14 +0,0 @@ -struct P { child: Option> } -trait PTrait { - fn getChildOption(&self) -> Option>; -} - -impl PTrait for P { - fn getChildOption(&self) -> Option> { - static childVal: Box

= self.child.get(); - //~^ ERROR attempt to use a non-constant value in a constant - panic!(); - } -} - -fn main() {} diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr deleted file mode 100644 index 06e0192d9574..000000000000 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/issue-3668.rs:8:34 - | -LL | static childVal: Box

= self.child.get(); - | ^^^^ non-constant value - | -help: consider using `let` instead of `static` - | -LL - static childVal: Box

= self.child.get(); -LL + let childVal: Box

= self.child.get(); + //~^ ERROR attempt to use a non-constant value in a constant + panic!(); + } +} + +fn main() {} diff --git a/tests/ui/statics/static-in-method-cannot-use-self.stderr b/tests/ui/statics/static-in-method-cannot-use-self.stderr new file mode 100644 index 000000000000..d5db956cf16f --- /dev/null +++ b/tests/ui/statics/static-in-method-cannot-use-self.stderr @@ -0,0 +1,15 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/static-in-method-cannot-use-self.rs:12:35 + | +LL | static childVal: Box

= self.child.get(); + | ^^^^ non-constant value + | +help: consider using `let` instead of `static` + | +LL - static childVal: Box

= self.child.get(); +LL + let childVal: Box

= self.child.get(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/issues/issue-39367.rs b/tests/ui/statics/static-lazy-init-with-arena-set.rs similarity index 53% rename from tests/ui/issues/issue-39367.rs rename to tests/ui/statics/static-lazy-init-with-arena-set.rs index 68b4d28aae3b..009d1d939360 100644 --- a/tests/ui/issues/issue-39367.rs +++ b/tests/ui/statics/static-lazy-init-with-arena-set.rs @@ -1,11 +1,16 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/39367 +//! +//! Tests that lazy static initialization using `Once` and `transmute` +//! works correctly with a struct that has a default type parameter. //@ run-pass use std::ops::Deref; -struct ArenaSet::Target>(U, &'static V) - where V: 'static + ?Sized; +struct ArenaSet::Target>(U, &'static V) +where + V: 'static + ?Sized; -static Z: [u8; 4] = [1,2,3,4]; +static Z: [u8; 4] = [1, 2, 3, 4]; fn arena() -> &'static ArenaSet> { fn __static_ref_initialize() -> ArenaSet> { @@ -13,17 +18,17 @@ fn __static_ref_initialize() -> ArenaSet> { } unsafe { use std::sync::Once; - fn require_sync(_: &T) { } + fn require_sync(_: &T) {} unsafe fn __stability() -> &'static ArenaSet> { use std::mem::transmute; static mut DATA: *const ArenaSet> = std::ptr::null_mut(); static mut ONCE: Once = Once::new(); ONCE.call_once(|| { - //~^ WARN creating a shared reference to mutable static [static_mut_refs] - DATA = transmute - ::>>, *const ArenaSet>> - (Box::new(__static_ref_initialize())); + //~^ WARN creating a shared reference to mutable static [static_mut_refs] + DATA = transmute::>>, *const ArenaSet>>(Box::new( + __static_ref_initialize(), + )); }); &*DATA diff --git a/tests/ui/issues/issue-39367.stderr b/tests/ui/statics/static-lazy-init-with-arena-set.stderr similarity index 72% rename from tests/ui/issues/issue-39367.stderr rename to tests/ui/statics/static-lazy-init-with-arena-set.stderr index e94c961f431d..134129f814aa 100644 --- a/tests/ui/issues/issue-39367.stderr +++ b/tests/ui/statics/static-lazy-init-with-arena-set.stderr @@ -1,11 +1,11 @@ warning: creating a shared reference to mutable static - --> $DIR/issue-39367.rs:22:13 + --> $DIR/static-lazy-init-with-arena-set.rs:27:13 | LL | / ONCE.call_once(|| { LL | | -LL | | DATA = transmute -LL | | ::>>, *const ArenaSet>> -LL | | (Box::new(__static_ref_initialize())); +LL | | DATA = transmute::>>, *const ArenaSet>>(Box::new( +LL | | __static_ref_initialize(), +LL | | )); LL | | }); | |______________^ shared reference to mutable static | diff --git a/tests/ui/issues/issue-46604.rs b/tests/ui/statics/static-mut-borrow-of-temporary.rs similarity index 75% rename from tests/ui/issues/issue-46604.rs rename to tests/ui/statics/static-mut-borrow-of-temporary.rs index e15f0b52da2f..8f679d27059a 100644 --- a/tests/ui/issues/issue-46604.rs +++ b/tests/ui/statics/static-mut-borrow-of-temporary.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/46604 +//! static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR mutable borrows of temporaries fn write>(buffer: T) { } diff --git a/tests/ui/issues/issue-46604.stderr b/tests/ui/statics/static-mut-borrow-of-temporary.stderr similarity index 91% rename from tests/ui/issues/issue-46604.stderr rename to tests/ui/statics/static-mut-borrow-of-temporary.stderr index 21abc498de12..a3d06011bbfb 100644 --- a/tests/ui/issues/issue-46604.stderr +++ b/tests/ui/statics/static-mut-borrow-of-temporary.stderr @@ -1,5 +1,5 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed - --> $DIR/issue-46604.rs:1:25 + --> $DIR/static-mut-borrow-of-temporary.rs:3:25 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; | ^^^^^^^^^^^^^^^^^^^^ this mutable borrow refers to such a temporary @@ -9,7 +9,7 @@ LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item - --> $DIR/issue-46604.rs:6:5 + --> $DIR/static-mut-borrow-of-temporary.rs:8:5 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; | --------------------- this `static` cannot be written to diff --git a/tests/ui/issues/issue-29821.rs b/tests/ui/statics/static-mut-with-assoc-type-field.rs similarity index 68% rename from tests/ui/issues/issue-29821.rs rename to tests/ui/statics/static-mut-with-assoc-type-field.rs index 508009337a5a..347c50e1e3b6 100644 --- a/tests/ui/issues/issue-29821.rs +++ b/tests/ui/statics/static-mut-with-assoc-type-field.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/29821 +//! //@ build-pass pub trait Foo { @@ -5,7 +7,7 @@ pub trait Foo { } pub struct Bar { - id: F::FooAssoc + id: F::FooAssoc, } pub struct Baz; diff --git a/tests/ui/issues/issue-25901.rs b/tests/ui/statics/static-ref-deref-non-const-trait.rs similarity index 52% rename from tests/ui/issues/issue-25901.rs rename to tests/ui/statics/static-ref-deref-non-const-trait.rs index d40b869cd0cd..6d7b375ecb10 100644 --- a/tests/ui/issues/issue-25901.rs +++ b/tests/ui/statics/static-ref-deref-non-const-trait.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/25901 +//! struct A; struct B; @@ -8,7 +10,10 @@ impl Deref for A { type Target = B; - fn deref(&self)->&B { static B_: B = B; &B_ } + fn deref(&self) -> &B { + static B_: B = B; + &B_ + } } -fn main(){} +fn main() {} diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/statics/static-ref-deref-non-const-trait.stderr similarity index 86% rename from tests/ui/issues/issue-25901.stderr rename to tests/ui/statics/static-ref-deref-non-const-trait.stderr index 9b65366b969a..88ddffecc928 100644 --- a/tests/ui/issues/issue-25901.stderr +++ b/tests/ui/statics/static-ref-deref-non-const-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `A: const Deref` is not satisfied - --> $DIR/issue-25901.rs:4:24 + --> $DIR/static-ref-deref-non-const-trait.rs:6:24 | LL | static S: &'static B = &A; | ^^ diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index 4762784574dc..80871083e1c1 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -43,13 +43,13 @@ LL | static NEVER: !; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 -error[E0080]: constructing invalid value: encountered a value of uninhabited type `Void` +error[E0080]: constructing invalid value of type Void: encountered a value of uninhabited type `Void` --> $DIR/uninhabited-static.rs:12:31 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `VOID2` failed here -error[E0080]: constructing invalid value: encountered a value of uninhabited type `Void` +error[E0080]: constructing invalid value of type Void: encountered a value of uninhabited type `Void` --> $DIR/uninhabited-static.rs:15:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; diff --git a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr index 4b1cd8a5a125..4df97a655d62 100644 --- a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr +++ b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr @@ -1,15 +1,15 @@ -error[E0599]: no function or associated item named `from_mut` found for struct `Atomic` in the current scope +error[E0599]: no associated function or constant named `from_mut` found for struct `Atomic` in the current scope --> $DIR/atomic-from-mut-not-available.rs:24:36 | LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64); - | ^^^^^^^^ function or associated item not found in `Atomic` + | ^^^^^^^^ associated function or constant not found in `Atomic` | note: if you're trying to build a new `Atomic`, consider using `Atomic::::new` which returns `Atomic` --> $SRC_DIR/core/src/sync/atomic.rs:LL:COL ::: $SRC_DIR/core/src/sync/atomic.rs:LL:COL | = note: in this macro invocation - = note: the function or associated item was found for + = note: the associated function or constant was found for - `Atomic<*mut T>` - `Atomic` - `Atomic` diff --git a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.rs b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.rs index 519b6977dcb5..b7c7f0ed9824 100644 --- a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.rs +++ b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.rs @@ -22,6 +22,6 @@ fn main() { core::sync::atomic::AtomicU64::from_mut(&mut 0u64); - //[alignment_mismatch]~^ ERROR no function or associated item named `from_mut` found for struct `Atomic` + //[alignment_mismatch]~^ ERROR no associated function or constant named `from_mut` found for struct `Atomic` //[alignment_matches]~^^ ERROR use of unstable library feature `atomic_from_mut` } diff --git a/tests/ui/str/str-idx.stderr b/tests/ui/str/str-idx.stderr index 97a083ba8ba8..84f698a6e662 100644 --- a/tests/ui/str/str-idx.stderr +++ b/tests/ui/str/str-idx.stderr @@ -7,13 +7,13 @@ LL | let _: u8 = s[4]; = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` for more information, see chapter 8 in The Book: -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `str` to implement `Index<{integer}>` error[E0277]: the type `str` cannot be indexed by `{integer}` @@ -27,13 +27,13 @@ LL | let _ = s.get(4); = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` for more information, see chapter 8 in The Book: -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` note: required by a bound in `core::str::::get` --> $SRC_DIR/core/src/str/mod.rs:LL:COL @@ -48,13 +48,13 @@ LL | let _ = s.get_unchecked(4); = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` for more information, see chapter 8 in The Book: -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` note: required by a bound in `core::str::::get_unchecked` --> $SRC_DIR/core/src/str/mod.rs:LL:COL diff --git a/tests/ui/str/str-mut-idx.stderr b/tests/ui/str/str-mut-idx.stderr index c9bd66dfbc8a..87b78915075d 100644 --- a/tests/ui/str/str-mut-idx.stderr +++ b/tests/ui/str/str-mut-idx.stderr @@ -31,13 +31,13 @@ LL | s[1usize] = bot(); | ^^^^^^ string indices are ranges of `usize` | = help: the trait `SliceIndex` is not implemented for `usize` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `str` to implement `Index` error[E0277]: the type `str` cannot be indexed by `{integer}` @@ -51,13 +51,13 @@ LL | s.get_mut(1); = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` for more information, see chapter 8 in The Book: -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` note: required by a bound in `core::str::::get_mut` --> $SRC_DIR/core/src/str/mod.rs:LL:COL @@ -72,13 +72,13 @@ LL | s.get_unchecked_mut(1); = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` for more information, see chapter 8 in The Book: -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` note: required by a bound in `core::str::::get_unchecked_mut` --> $SRC_DIR/core/src/str/mod.rs:LL:COL diff --git a/tests/ui/structs-enums/auxiliary/cci_class.rs b/tests/ui/structs-enums/auxiliary/cci_class.rs deleted file mode 100644 index de2945d74604..000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod kitties { - pub struct cat { - meows : usize, - - pub how_hungry : isize, - } - - pub fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } - } -} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_2.rs b/tests/ui/structs-enums/auxiliary/cci_class_2.rs deleted file mode 100644 index c3de3150e697..000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class_2.rs +++ /dev/null @@ -1,19 +0,0 @@ -pub mod kitties { - pub struct cat { - meows : usize, - - pub how_hungry : isize, - - } - - impl cat { - pub fn speak(&self) {} - } - - pub fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } - } -} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_3.rs b/tests/ui/structs-enums/auxiliary/cci_class_3.rs deleted file mode 100644 index fb7fad0b5a2e..000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class_3.rs +++ /dev/null @@ -1,19 +0,0 @@ -pub mod kitties { - pub struct cat { - meows : usize, - - pub how_hungry : isize, - } - - impl cat { - pub fn speak(&mut self) { self.meows += 1; } - pub fn meow_count(&mut self) -> usize { self.meows } - } - - pub fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } - } -} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_4.rs b/tests/ui/structs-enums/auxiliary/cci_class_4.rs index 85aa3bc8c0df..fff7b7809571 100644 --- a/tests/ui/structs-enums/auxiliary/cci_class_4.rs +++ b/tests/ui/structs-enums/auxiliary/cci_class_4.rs @@ -1,41 +1,54 @@ -pub mod kitties { - pub struct cat { - meows : usize, +use std::fmt; - pub how_hungry : isize, - pub name : String, +#[derive(Clone)] +pub struct Cat { + meows: usize, + + pub how_hungry: isize, + pub name: String, +} + +impl Cat { + pub fn speak(&mut self) { + self.meow(); } - impl cat { - pub fn speak(&mut self) { self.meow(); } - - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } else { - println!("Not hungry!"); - return false; - } + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } else { + println!("Not hungry!"); + return false; } } - impl cat { - pub fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } + pub fn noop(&self) {} +} + +impl Cat { + pub fn meow(&mut self) { + println!("Meow"); + self.meows += 1; + if self.meows % 5 == 0 { + self.how_hungry += 1; } } - - pub fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } + pub fn meow_count(&self) -> usize { + self.meows + } +} + +pub fn cat(in_x: usize, in_y: isize, in_name: String) -> Cat { + Cat { meows: in_x, how_hungry: in_y, name: in_name } +} +pub fn cat_unnamed(in_x: usize, in_y: isize) -> Cat { + Cat { meows: in_x, how_hungry: in_y, name: String::new() } +} + +impl fmt::Display for Cat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) } } diff --git a/tests/ui/structs-enums/auxiliary/cci_class_cast.rs b/tests/ui/structs-enums/auxiliary/cci_class_cast.rs deleted file mode 100644 index dfc3c56ddee7..000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class_cast.rs +++ /dev/null @@ -1,50 +0,0 @@ -pub mod kitty { - use std::fmt; - - pub struct cat { - meows : usize, - pub how_hungry : isize, - pub name : String, - } - - impl fmt::Display for cat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.name) - } - } - - impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } - - } - - impl cat { - pub fn speak(&mut self) { self.meow(); } - - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } - } - - pub fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } - } -} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_trait.rs b/tests/ui/structs-enums/auxiliary/cci_class_trait.rs deleted file mode 100644 index 2d02b591c555..000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class_trait.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod animals { - pub trait noisy { - fn speak(&mut self); - } -} diff --git a/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs b/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs deleted file mode 100644 index d4caa19135e8..000000000000 --- a/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass -//@ aux-build:cci_class_cast.rs - -extern crate cci_class_cast; - -use cci_class_cast::kitty::cat; - -fn print_out(thing: Box, expected: String) { - let actual = (*thing).to_string(); - println!("{}", actual); - assert_eq!(actual.to_string(), expected); -} - -pub fn main() { - let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; - print_out(nyan, "nyan".to_string()); -} diff --git a/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs b/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs deleted file mode 100644 index 658e9d2117dc..000000000000 --- a/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs +++ /dev/null @@ -1,94 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] -#![allow(dead_code)] - -trait noisy { - fn speak(&mut self) -> isize; -} - -struct dog { - barks: usize, - - volume: isize, -} - -impl dog { - fn bark(&mut self) -> isize { - println!("Woof {} {}", self.barks, self.volume); - self.barks += 1_usize; - if self.barks % 3_usize == 0_usize { - self.volume += 1; - } - if self.barks % 10_usize == 0_usize { - self.volume -= 2; - } - println!("Grrr {} {}", self.barks, self.volume); - self.volume - } -} - -impl noisy for dog { - fn speak(&mut self) -> isize { - self.bark() - } -} - -fn dog() -> dog { - dog { - volume: 0, - barks: 0_usize - } -} - -#[derive(Clone)] -struct cat { - meows: usize, - - how_hungry: isize, - name: String, -} - -impl noisy for cat { - fn speak(&mut self) -> isize { - self.meow() as isize - } -} - -impl cat { - pub fn meow_count(&self) -> usize { - self.meows - } -} - -impl cat { - fn meow(&mut self) -> usize { - println!("Meow"); - self.meows += 1_usize; - if self.meows % 5_usize == 0_usize { - self.how_hungry += 1; - } - self.meows - } -} - -fn cat(in_x: usize, in_y: isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - - -fn annoy_neighbors(critter: &mut dyn noisy) { - for _i in 0_usize..10 { critter.speak(); } -} - -pub fn main() { - let mut nyan: cat = cat(0_usize, 2, "nyan".to_string()); - let mut whitefang: dog = dog(); - annoy_neighbors(&mut nyan); - annoy_neighbors(&mut whitefang); - assert_eq!(nyan.meow_count(), 10_usize); - assert_eq!(whitefang.volume, 1); -} diff --git a/tests/ui/structs-enums/class-cast-to-trait.rs b/tests/ui/structs-enums/class-cast-to-trait.rs deleted file mode 100644 index bbbde34ec096..000000000000 --- a/tests/ui/structs-enums/class-cast-to-trait.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(unused_mut)] -#![allow(non_camel_case_types)] - -//@ ignore-freebsd FIXME fails on BSD - - -trait noisy { - fn speak(&mut self); -} - -struct cat { - meows: usize, - how_hungry: isize, - name: String, -} - -impl noisy for cat { - fn speak(&mut self) { self.meow(); } -} - -impl cat { - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - - -pub fn main() { - let mut nyan = cat(0, 2, "nyan".to_string()); - let mut nyan: &mut dyn noisy = &mut nyan; - nyan.speak(); -} diff --git a/tests/ui/structs-enums/class-dtor.rs b/tests/ui/structs-enums/class-dtor.rs index a08f0f0b0a47..b7911823ef1b 100644 --- a/tests/ui/structs-enums/class-dtor.rs +++ b/tests/ui/structs-enums/class-dtor.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/class-exports.rs b/tests/ui/structs-enums/class-exports.rs deleted file mode 100644 index 53d0e3db6f5f..000000000000 --- a/tests/ui/structs-enums/class-exports.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -/* Test that exporting a class also exports its - public fields and methods */ - -use kitty::cat; - -mod kitty { - pub struct cat { - meows: usize, - name: String, - } - - impl cat { - pub fn get_name(&self) -> String { self.name.clone() } - } - - pub fn cat(in_name: String) -> cat { - cat { - name: in_name, - meows: 0 - } - } -} - -pub fn main() { - assert_eq!(cat("Spreckles".to_string()).get_name(), - "Spreckles".to_string()); -} diff --git a/tests/ui/structs-enums/class-implement-trait-cross-crate.rs b/tests/ui/structs-enums/class-implement-trait-cross-crate.rs deleted file mode 100644 index 781ac6ad10d2..000000000000 --- a/tests/ui/structs-enums/class-implement-trait-cross-crate.rs +++ /dev/null @@ -1,59 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -//@ aux-build:cci_class_trait.rs -extern crate cci_class_trait; -use cci_class_trait::animals::noisy; - -struct cat { - meows: usize, - - how_hungry : isize, - name : String, -} - -impl cat { - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } -} - -impl noisy for cat { - fn speak(&mut self) { self.meow(); } -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1_usize; - if self.meows % 5_usize == 0_usize { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - - -pub fn main() { - let mut nyan = cat(0_usize, 2, "nyan".to_string()); - nyan.eat(); - assert!(!nyan.eat()); - for _ in 1_usize..10_usize { nyan.speak(); }; - assert!(nyan.eat()); -} diff --git a/tests/ui/structs-enums/class-implement-traits.rs b/tests/ui/structs-enums/class-implement-traits.rs deleted file mode 100644 index 3a514ff9d758..000000000000 --- a/tests/ui/structs-enums/class-implement-traits.rs +++ /dev/null @@ -1,64 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] -#![allow(dead_code)] - -trait noisy { - fn speak(&mut self); -} - -#[derive(Clone)] -struct cat { - meows : usize, - - how_hungry : isize, - name : String, -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1_usize; - if self.meows % 5_usize == 0_usize { - self.how_hungry += 1; - } - } -} - -impl cat { - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } else { - println!("Not hungry!"); - return false; - } - } -} - -impl noisy for cat { - fn speak(&mut self) { self.meow(); } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name.clone() - } -} - - -fn make_speak(mut c: C) { - c.speak(); -} - -pub fn main() { - let mut nyan = cat(0_usize, 2, "nyan".to_string()); - nyan.eat(); - assert!(!nyan.eat()); - for _ in 1_usize..10_usize { - make_speak(nyan.clone()); - } -} diff --git a/tests/ui/structs-enums/class-method-cross-crate.rs b/tests/ui/structs-enums/class-method-cross-crate.rs deleted file mode 100644 index f73999a24501..000000000000 --- a/tests/ui/structs-enums/class-method-cross-crate.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass -//@ aux-build:cci_class_2.rs - -extern crate cci_class_2; -use cci_class_2::kitties::cat; - -pub fn main() { - let nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.speak(); -} diff --git a/tests/ui/structs-enums/class-methods-cross-crate.rs b/tests/ui/structs-enums/class-methods-cross-crate.rs deleted file mode 100644 index b2c48248a671..000000000000 --- a/tests/ui/structs-enums/class-methods-cross-crate.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass -//@ aux-build:cci_class_3.rs - -extern crate cci_class_3; -use cci_class_3::kitties::cat; - -pub fn main() { - let mut nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.speak(); - assert_eq!(nyan.meow_count(), 53); -} diff --git a/tests/ui/structs-enums/class-methods.rs b/tests/ui/structs-enums/class-methods.rs deleted file mode 100644 index b0dbbbec5224..000000000000 --- a/tests/ui/structs-enums/class-methods.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] - - -struct cat { - meows : usize, - - how_hungry : isize, -} - -impl cat { - pub fn speak(&mut self) { self.meows += 1; } - pub fn meow_count(&mut self) -> usize { self.meows } -} - -fn cat(in_x: usize, in_y: isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } -} - -pub fn main() { - let mut nyan: cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.speak(); - assert_eq!(nyan.meow_count(), 53); -} diff --git a/tests/ui/structs-enums/class-separate-impl.rs b/tests/ui/structs-enums/class-separate-impl.rs deleted file mode 100644 index 2768e284c173..000000000000 --- a/tests/ui/structs-enums/class-separate-impl.rs +++ /dev/null @@ -1,63 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -use std::fmt; - -struct cat { - meows : usize, - - how_hungry : isize, - name : String, -} - -impl cat { - pub fn speak(&mut self) { self.meow(); } - - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - -impl fmt::Display for cat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.name) - } -} - -fn print_out(thing: Box, expected: String) { - let actual = (*thing).to_string(); - println!("{}", actual); - assert_eq!(actual.to_string(), expected); -} - -pub fn main() { - let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; - print_out(nyan, "nyan".to_string()); -} diff --git a/tests/ui/structs-enums/class-str-field.rs b/tests/ui/structs-enums/class-str-field.rs deleted file mode 100644 index 24f648afc90b..000000000000 --- a/tests/ui/structs-enums/class-str-field.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - - -struct cat { - - name : String, - -} - -fn cat(in_name: String) -> cat { - cat { - name: in_name - } -} - -pub fn main() { - let _nyan = cat("nyan".to_string()); -} diff --git a/tests/ui/structs-enums/classes-cross-crate.rs b/tests/ui/structs-enums/classes-cross-crate.rs index 6fb5f2e3cc9d..85454bb15a7b 100644 --- a/tests/ui/structs-enums/classes-cross-crate.rs +++ b/tests/ui/structs-enums/classes-cross-crate.rs @@ -2,12 +2,118 @@ //@ aux-build:cci_class_4.rs extern crate cci_class_4; -use cci_class_4::kitties::cat; +use cci_class_4::*; -pub fn main() { +fn simple_cross_crate() { + let nyan: Cat = cat_unnamed(52, 99); + let kitty = cat_unnamed(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.noop(); +} + +fn cross_crate() { let mut nyan = cat(0_usize, 2, "nyan".to_string()); nyan.eat(); assert!(!nyan.eat()); - for _ in 1_usize..10_usize { nyan.speak(); }; + for _ in 1_usize..10_usize { + nyan.speak(); + } assert!(nyan.eat()); } + +fn print_out(thing: Box, expected: String) { + let actual = (*thing).to_string(); + println!("{}", actual); + assert_eq!(actual.to_string(), expected); +} + +fn separate_impl() { + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; + print_out(nyan, "nyan".to_string()); +} + +trait Noisy { + fn speak(&mut self) -> isize; +} + +impl Noisy for Cat { + fn speak(&mut self) -> isize { + self.meow(); + 0 + } +} + +fn make_speak(mut c: C) { + c.speak(); +} + +fn implement_traits() { + let mut nyan = cat(0_usize, 2, "nyan".to_string()); + nyan.eat(); + assert!(!nyan.eat()); + for _ in 1_usize..10_usize { + make_speak(nyan.clone()); + } +} + +struct Dog { + barks: usize, + + volume: isize, +} + +impl Dog { + fn bark(&mut self) -> isize { + println!("Woof {} {}", self.barks, self.volume); + self.barks += 1_usize; + if self.barks % 3_usize == 0_usize { + self.volume += 1; + } + if self.barks % 10_usize == 0_usize { + self.volume -= 2; + } + println!("Grrr {} {}", self.barks, self.volume); + self.volume + } +} + +impl Noisy for Dog { + fn speak(&mut self) -> isize { + self.bark() + } +} + +fn dog() -> Dog { + Dog { volume: 0, barks: 0_usize } +} + +fn annoy_neighbors(critter: &mut dyn Noisy) { + for _i in 0_usize..10 { + critter.speak(); + } +} + +fn multiple_types() { + let mut nyan: Cat = cat(0_usize, 2, "nyan".to_string()); + let mut whitefang: Dog = dog(); + annoy_neighbors(&mut nyan); + annoy_neighbors(&mut whitefang); + assert_eq!(nyan.meow_count(), 10_usize); + assert_eq!(whitefang.volume, 1); +} + +fn cast_to_trait() { + let mut nyan = cat(0, 2, "nyan".to_string()); + let nyan: &mut dyn Noisy = &mut nyan; + nyan.speak(); +} + +fn main() { + simple_cross_crate(); + cross_crate(); + separate_impl(); + implement_traits(); + multiple_types(); + cast_to_trait(); +} diff --git a/tests/ui/structs-enums/classes-self-referential.rs b/tests/ui/structs-enums/classes-self-referential.rs index f819e558aa2e..40c51a1573cd 100644 --- a/tests/ui/structs-enums/classes-self-referential.rs +++ b/tests/ui/structs-enums/classes-self-referential.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/classes-simple-cross-crate.rs b/tests/ui/structs-enums/classes-simple-cross-crate.rs deleted file mode 100644 index 1548f768b6f3..000000000000 --- a/tests/ui/structs-enums/classes-simple-cross-crate.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass -//@ aux-build:cci_class.rs - -extern crate cci_class; -use cci_class::kitties::cat; - -pub fn main() { - let nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); -} diff --git a/tests/ui/structs-enums/classes-simple-method.rs b/tests/ui/structs-enums/classes-simple-method.rs deleted file mode 100644 index 562fd5909815..000000000000 --- a/tests/ui/structs-enums/classes-simple-method.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -struct cat { - meows : usize, - - how_hungry : isize, -} - -impl cat { - pub fn speak(&mut self) {} -} - -fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } -} - -pub fn main() { - let mut nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.speak(); -} diff --git a/tests/ui/structs-enums/classes-simple.rs b/tests/ui/structs-enums/classes-simple.rs deleted file mode 100644 index d870a3101f1a..000000000000 --- a/tests/ui/structs-enums/classes-simple.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -struct cat { - meows : usize, - - how_hungry : isize, -} - -fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } -} - -pub fn main() { - let nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); -} diff --git a/tests/ui/structs-enums/classes.rs b/tests/ui/structs-enums/classes.rs deleted file mode 100644 index 05976f6a759a..000000000000 --- a/tests/ui/structs-enums/classes.rs +++ /dev/null @@ -1,51 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -struct cat { - meows : usize, - - how_hungry : isize, - name : String, -} - -impl cat { - pub fn speak(&mut self) { self.meow(); } - - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } else { - println!("Not hungry!"); - return false; - } - } -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1_usize; - if self.meows % 5_usize == 0_usize { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - -pub fn main() { - let mut nyan = cat(0_usize, 2, "nyan".to_string()); - nyan.eat(); - assert!(!nyan.eat()); - for _ in 1_usize..10_usize { nyan.speak(); }; - assert!(nyan.eat()); -} diff --git a/tests/ui/structs-enums/export-abstract-tag.rs b/tests/ui/structs-enums/export-abstract-tag.rs deleted file mode 100644 index e6d359803856..000000000000 --- a/tests/ui/structs-enums/export-abstract-tag.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] - -// We can export tags without exporting the variants to create a simple -// sort of ADT. - - -mod foo { - pub enum t { t1, } - - pub fn f() -> t { return t::t1; } -} - -pub fn main() { let _v: foo::t = foo::f(); } diff --git a/tests/ui/structs-enums/export-tag-variant.rs b/tests/ui/structs-enums/export-tag-variant.rs deleted file mode 100644 index c6216d1b567b..000000000000 --- a/tests/ui/structs-enums/export-tag-variant.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] - -mod foo { - pub enum t { t1, } -} - -pub fn main() { let _v = foo::t::t1; } diff --git a/tests/ui/structs-enums/foreign-struct.rs b/tests/ui/structs-enums/foreign-struct.rs index f339c191ae80..b710d83350ab 100644 --- a/tests/ui/structs-enums/foreign-struct.rs +++ b/tests/ui/structs-enums/foreign-struct.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/nested-enum-same-names.rs b/tests/ui/structs-enums/nested-enum-same-names.rs index 5ff730aff441..1d3fab4e722c 100644 --- a/tests/ui/structs-enums/nested-enum-same-names.rs +++ b/tests/ui/structs-enums/nested-enum-same-names.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] /* diff --git a/tests/ui/structs-enums/rec-auto.rs b/tests/ui/structs-enums/rec-auto.rs deleted file mode 100644 index bf2e37a189bc..000000000000 --- a/tests/ui/structs-enums/rec-auto.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass - - - - -// Issue #50. - -struct X { foo: String, bar: String } - -pub fn main() { - let x = X {foo: "hello".to_string(), bar: "world".to_string()}; - println!("{}", x.foo.clone()); - println!("{}", x.bar.clone()); -} diff --git a/tests/ui/structs-enums/simple-generic-tag.rs b/tests/ui/structs-enums/simple-generic-tag.rs index b78505edd1f2..dbb5d707b52f 100644 --- a/tests/ui/structs-enums/simple-generic-tag.rs +++ b/tests/ui/structs-enums/simple-generic-tag.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/tag-in-block.rs b/tests/ui/structs-enums/tag-in-block.rs index 27b48aae51f6..75691f02dd82 100644 --- a/tests/ui/structs-enums/tag-in-block.rs +++ b/tests/ui/structs-enums/tag-in-block.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs b/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs deleted file mode 100644 index f4c202d91a7c..000000000000 --- a/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - - -enum color { - red = 1, - blue = 2, -} - -pub fn main() {} diff --git a/tests/ui/structs-enums/tuple-struct-construct.rs b/tests/ui/structs-enums/tuple-struct-construct.rs deleted file mode 100644 index 4243bccb4eb7..000000000000 --- a/tests/ui/structs-enums/tuple-struct-construct.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass -#[allow(dead_code)] -#[derive(Debug)] -struct Foo(isize, isize); - -pub fn main() { - let x = Foo(1, 2); - println!("{:?}", x); -} diff --git a/tests/ui/structs-enums/tuple-struct-destructuring.rs b/tests/ui/structs-enums/tuple-struct-destructuring.rs index 5213052dd7a4..36a36605ba80 100644 --- a/tests/ui/structs-enums/tuple-struct-destructuring.rs +++ b/tests/ui/structs-enums/tuple-struct-destructuring.rs @@ -1,4 +1,5 @@ //@ run-pass +#[derive(Debug)] struct Foo(isize, isize); pub fn main() { @@ -7,4 +8,16 @@ pub fn main() { println!("{} {}", y, z); assert_eq!(y, 1); assert_eq!(z, 2); + + let x = Foo(1, 2); + match x { + Foo(a, b) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + println!("{} {}", a, b); + } + } + + let x = Foo(1, 2); + assert_eq!(format!("{x:?}"), "Foo(1, 2)"); } diff --git a/tests/ui/structs-enums/tuple-struct-matching.rs b/tests/ui/structs-enums/tuple-struct-matching.rs deleted file mode 100644 index a5436624c658..000000000000 --- a/tests/ui/structs-enums/tuple-struct-matching.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass -struct Foo(isize, isize); - -pub fn main() { - let x = Foo(1, 2); - match x { - Foo(a, b) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - println!("{} {}", a, b); - } - } -} diff --git a/tests/ui/structs-enums/tuple-struct-trivial.rs b/tests/ui/structs-enums/tuple-struct-trivial.rs deleted file mode 100644 index e2395036551e..000000000000 --- a/tests/ui/structs-enums/tuple-struct-trivial.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -struct Foo(isize, isize, isize); - -pub fn main() { -} diff --git a/tests/ui/structs-enums/auxiliary/newtype_struct_xc.rs b/tests/ui/structs/auxiliary/newtype_struct_xc.rs similarity index 100% rename from tests/ui/structs-enums/auxiliary/newtype_struct_xc.rs rename to tests/ui/structs/auxiliary/newtype_struct_xc.rs diff --git a/tests/ui/structs-enums/cross-crate-newtype-struct-pat.rs b/tests/ui/structs/cross-crate-newtype-struct-pat.rs similarity index 100% rename from tests/ui/structs-enums/cross-crate-newtype-struct-pat.rs rename to tests/ui/structs/cross-crate-newtype-struct-pat.rs diff --git a/tests/ui/structs/default-field-values/post-mono.rs b/tests/ui/structs/default-field-values/post-mono.rs index 68dfa391bb48..57092083ca10 100644 --- a/tests/ui/structs/default-field-values/post-mono.rs +++ b/tests/ui/structs/default-field-values/post-mono.rs @@ -1,6 +1,6 @@ //@ build-fail //@ revisions: direct indirect - +//@ ignore-parallel-frontend post-monomorphization errors #![feature(default_field_values)] struct Z { diff --git a/tests/ui/structs/default-field-values/struct-type-parameter-with-default.rs b/tests/ui/structs/default-field-values/struct-type-parameter-with-default.rs new file mode 100644 index 000000000000..c9e5aa9afb41 --- /dev/null +++ b/tests/ui/structs/default-field-values/struct-type-parameter-with-default.rs @@ -0,0 +1,11 @@ +// Test for #147748, providing additional clarification that default field values aren't compatible +// with type parameters unless going through the type parameter. +#![feature(default_field_values)] +struct Foo { //~ NOTE: expected this type parameter + x: T = String::new(), + //~^ ERROR: mismatched types + //~| NOTE: expected type parameter + //~| NOTE: expected type parameter + //~| NOTE: the type of default fields referencing type parameters can't be assumed inside the struct defining them +} +fn main() {} diff --git a/tests/ui/structs/default-field-values/struct-type-parameter-with-default.stderr b/tests/ui/structs/default-field-values/struct-type-parameter-with-default.stderr new file mode 100644 index 000000000000..553b49023835 --- /dev/null +++ b/tests/ui/structs/default-field-values/struct-type-parameter-with-default.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/struct-type-parameter-with-default.rs:5:12 + | +LL | struct Foo { + | ---------- expected this type parameter +LL | x: T = String::new(), + | ^^^^^^^^^^^^^ expected type parameter `T`, found `String` + | + = note: expected type parameter `T` + found struct `String` + = note: the type of default fields referencing type parameters can't be assumed inside the struct defining them + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/structs-enums/field-destruction-order.rs b/tests/ui/structs/field-destruction-order.rs similarity index 100% rename from tests/ui/structs-enums/field-destruction-order.rs rename to tests/ui/structs/field-destruction-order.rs diff --git a/tests/ui/structs-enums/module-qualified-struct-destructure.rs b/tests/ui/structs/module-qualified-struct-destructure.rs similarity index 100% rename from tests/ui/structs-enums/module-qualified-struct-destructure.rs rename to tests/ui/structs/module-qualified-struct-destructure.rs diff --git a/tests/ui/structs-enums/newtype-struct-drop-run.rs b/tests/ui/structs/newtype-struct-drop-run.rs similarity index 100% rename from tests/ui/structs-enums/newtype-struct-drop-run.rs rename to tests/ui/structs/newtype-struct-drop-run.rs diff --git a/tests/ui/structs-enums/newtype-struct-with-dtor.rs b/tests/ui/structs/newtype-struct-with-dtor.rs similarity index 94% rename from tests/ui/structs-enums/newtype-struct-with-dtor.rs rename to tests/ui/structs/newtype-struct-with-dtor.rs index 35476c5ed2d6..c0d04932c464 100644 --- a/tests/ui/structs-enums/newtype-struct-with-dtor.rs +++ b/tests/ui/structs/newtype-struct-with-dtor.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_unsafe)] #![allow(unused_variables)] diff --git a/tests/ui/structs-enums/newtype-struct-xc-2.rs b/tests/ui/structs/newtype-struct-xc-2.rs similarity index 100% rename from tests/ui/structs-enums/newtype-struct-xc-2.rs rename to tests/ui/structs/newtype-struct-xc-2.rs diff --git a/tests/ui/structs-enums/newtype-struct-xc.rs b/tests/ui/structs/newtype-struct-xc.rs similarity index 100% rename from tests/ui/structs-enums/newtype-struct-xc.rs rename to tests/ui/structs/newtype-struct-xc.rs diff --git a/tests/ui/structs-enums/rec-align-u32.rs b/tests/ui/structs/rec-align-u32.rs similarity index 100% rename from tests/ui/structs-enums/rec-align-u32.rs rename to tests/ui/structs/rec-align-u32.rs diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs/rec-align-u64.rs similarity index 100% rename from tests/ui/structs-enums/rec-align-u64.rs rename to tests/ui/structs/rec-align-u64.rs diff --git a/tests/ui/structs-enums/struct-lit-functional-no-fields.rs b/tests/ui/structs/struct-lit-functional-no-fields.rs similarity index 100% rename from tests/ui/structs-enums/struct-lit-functional-no-fields.rs rename to tests/ui/structs/struct-lit-functional-no-fields.rs diff --git a/tests/ui/structs-enums/struct-literal-dtor.rs b/tests/ui/structs/struct-literal-dtor.rs similarity index 100% rename from tests/ui/structs-enums/struct-literal-dtor.rs rename to tests/ui/structs/struct-literal-dtor.rs diff --git a/tests/ui/structs-enums/struct-new-as-field-name.rs b/tests/ui/structs/struct-new-as-field-name.rs similarity index 100% rename from tests/ui/structs-enums/struct-new-as-field-name.rs rename to tests/ui/structs/struct-new-as-field-name.rs diff --git a/tests/ui/structs-enums/struct-order-of-eval-1.rs b/tests/ui/structs/struct-order-of-eval-1.rs similarity index 100% rename from tests/ui/structs-enums/struct-order-of-eval-1.rs rename to tests/ui/structs/struct-order-of-eval-1.rs diff --git a/tests/ui/structs-enums/struct-order-of-eval-2.rs b/tests/ui/structs/struct-order-of-eval-2.rs similarity index 100% rename from tests/ui/structs-enums/struct-order-of-eval-2.rs rename to tests/ui/structs/struct-order-of-eval-2.rs diff --git a/tests/ui/structs-enums/struct-order-of-eval-3.rs b/tests/ui/structs/struct-order-of-eval-3.rs similarity index 100% rename from tests/ui/structs-enums/struct-order-of-eval-3.rs rename to tests/ui/structs/struct-order-of-eval-3.rs diff --git a/tests/ui/structs-enums/struct-order-of-eval-4.rs b/tests/ui/structs/struct-order-of-eval-4.rs similarity index 100% rename from tests/ui/structs-enums/struct-order-of-eval-4.rs rename to tests/ui/structs/struct-order-of-eval-4.rs diff --git a/tests/ui/structs-enums/struct-partial-move-1.rs b/tests/ui/structs/struct-partial-move-1.rs similarity index 100% rename from tests/ui/structs-enums/struct-partial-move-1.rs rename to tests/ui/structs/struct-partial-move-1.rs diff --git a/tests/ui/structs-enums/struct-partial-move-2.rs b/tests/ui/structs/struct-partial-move-2.rs similarity index 100% rename from tests/ui/structs-enums/struct-partial-move-2.rs rename to tests/ui/structs/struct-partial-move-2.rs diff --git a/tests/ui/structs-enums/struct-path-associated-type.rs b/tests/ui/structs/struct-path-associated-type-2.rs similarity index 100% rename from tests/ui/structs-enums/struct-path-associated-type.rs rename to tests/ui/structs/struct-path-associated-type-2.rs diff --git a/tests/ui/structs-enums/struct-path-self.rs b/tests/ui/structs/struct-path-self-2.rs similarity index 100% rename from tests/ui/structs-enums/struct-path-self.rs rename to tests/ui/structs/struct-path-self-2.rs diff --git a/tests/ui/structs-enums/struct-pattern-matching.rs b/tests/ui/structs/struct-pattern-matching.rs similarity index 100% rename from tests/ui/structs-enums/struct-pattern-matching.rs rename to tests/ui/structs/struct-pattern-matching.rs diff --git a/tests/ui/structs-enums/struct-variant-field-visibility.rs b/tests/ui/structs/struct-variant-field-visibility.rs similarity index 92% rename from tests/ui/structs-enums/struct-variant-field-visibility.rs rename to tests/ui/structs/struct-variant-field-visibility.rs index a6528f9a2b17..40acea956aea 100644 --- a/tests/ui/structs-enums/struct-variant-field-visibility.rs +++ b/tests/ui/structs/struct-variant-field-visibility.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] mod foo { diff --git a/tests/ui/structs-enums/uninstantiable-struct.rs b/tests/ui/structs/uninstantiable-struct.rs similarity index 81% rename from tests/ui/structs-enums/uninstantiable-struct.rs rename to tests/ui/structs/uninstantiable-struct.rs index 97bc7d8414e7..def0fa00e17c 100644 --- a/tests/ui/structs-enums/uninstantiable-struct.rs +++ b/tests/ui/structs/uninstantiable-struct.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass pub struct Z(#[allow(dead_code)] &'static Z); pub fn main() {} diff --git a/tests/ui/structs-enums/unit-like-struct-drop-run.rs b/tests/ui/structs/unit-like-struct-drop-run.rs similarity index 100% rename from tests/ui/structs-enums/unit-like-struct-drop-run.rs rename to tests/ui/structs/unit-like-struct-drop-run.rs diff --git a/tests/ui/structs-enums/unit-like-struct.rs b/tests/ui/structs/unit-like-struct.rs similarity index 100% rename from tests/ui/structs-enums/unit-like-struct.rs rename to tests/ui/structs/unit-like-struct.rs diff --git a/tests/ui/structs-enums/variant-structs-trivial.rs b/tests/ui/structs/variant-structs-trivial.rs similarity index 86% rename from tests/ui/structs-enums/variant-structs-trivial.rs rename to tests/ui/structs/variant-structs-trivial.rs index a7b057511843..c1403b79c8aa 100644 --- a/tests/ui/structs-enums/variant-structs-trivial.rs +++ b/tests/ui/structs/variant-structs-trivial.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] enum Foo { diff --git a/tests/ui/suggestions/as-ref-2.stderr b/tests/ui/suggestions/as-ref-2.stderr index 309285775374..b183c8b2faee 100644 --- a/tests/ui/suggestions/as-ref-2.stderr +++ b/tests/ui/suggestions/as-ref-2.stderr @@ -4,14 +4,20 @@ error[E0382]: use of moved value: `foo` LL | let foo = Some(Struct); | --- move occurs because `foo` has type `Option`, which does not implement the `Copy` trait LL | let _x: Option = foo.map(|s| bar(&s)); - | --- ---------------- `foo` moved due to this method call - | | - | help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents + | ---------------- `foo` moved due to this method call LL | let _y = foo; | ^^^ value used here after move | note: `Option::::map` takes ownership of the receiver `self`, which moves `foo` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider calling `.as_ref()` to borrow the value's contents + | +LL | let _x: Option = foo.as_ref().map(|s| bar(&s)); + | +++++++++ +help: consider calling `.as_mut()` to mutably borrow the value's contents + | +LL | let _x: Option = foo.as_mut().map(|s| bar(&s)); + | +++++++++ help: you could `clone` the value and consume it, if the `Struct: Clone` trait bound could be satisfied | LL | let _x: Option = foo.clone().map(|s| bar(&s)); diff --git a/tests/ui/suggestions/deref-path-method.rs b/tests/ui/suggestions/deref-path-method.rs index 0281cdb6b37c..d44b3bd70305 100644 --- a/tests/ui/suggestions/deref-path-method.rs +++ b/tests/ui/suggestions/deref-path-method.rs @@ -1,6 +1,6 @@ fn main() { let vec = Vec::new(); Vec::contains(&vec, &0); - //~^ ERROR no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope + //~^ ERROR no associated function or constant named `contains` found for struct `Vec<_, _>` in the current scope //~| HELP the function `contains` is implemented on `[_]` } diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr index 0dec424555ed..8cf8ec9146d7 100644 --- a/tests/ui/suggestions/deref-path-method.stderr +++ b/tests/ui/suggestions/deref-path-method.stderr @@ -1,8 +1,8 @@ -error[E0599]: no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope +error[E0599]: no associated function or constant named `contains` found for struct `Vec<_, _>` in the current scope --> $DIR/deref-path-method.rs:3:10 | LL | Vec::contains(&vec, &0); - | ^^^^^^^^ function or associated item not found in `Vec<_, _>` + | ^^^^^^^^ associated function or constant not found in `Vec<_, _>` | note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions: Vec::::new diff --git a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr index 5eb64c45f9d7..836d31f81541 100644 --- a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr +++ b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr @@ -4,13 +4,13 @@ error[E0277]: the trait bound `str: From<_>` is not satisfied LL | let _ = &str::from("value"); | ^^^ the trait `From<_>` is not implemented for `str` | - = help: the following other types implement trait `From`: - `String` implements `From<&String>` - `String` implements `From<&mut str>` - `String` implements `From<&str>` - `String` implements `From>` - `String` implements `From>` - `String` implements `From` + = help: `String` implements trait `From`: + From<&String> + From<&mut str> + From<&str> + From> + From> + From help: you likely meant to call the associated function `from` for type `&str`, but the code as written calls associated function `from` on type `str` | LL | let _ = <&str>::from("value"); diff --git a/tests/ui/suggestions/dont-suggest-private-trait-method.rs b/tests/ui/suggestions/dont-suggest-private-trait-method.rs index 6e2b1abd1370..6a220b01f195 100644 --- a/tests/ui/suggestions/dont-suggest-private-trait-method.rs +++ b/tests/ui/suggestions/dont-suggest-private-trait-method.rs @@ -2,5 +2,5 @@ fn main() { T::new(); - //~^ ERROR no function or associated item named `new` found + //~^ ERROR no associated function or constant named `new` found } diff --git a/tests/ui/suggestions/dont-suggest-private-trait-method.stderr b/tests/ui/suggestions/dont-suggest-private-trait-method.stderr index f251ad59a587..b53a8279dfea 100644 --- a/tests/ui/suggestions/dont-suggest-private-trait-method.stderr +++ b/tests/ui/suggestions/dont-suggest-private-trait-method.stderr @@ -1,11 +1,11 @@ -error[E0599]: no function or associated item named `new` found for struct `T` in the current scope +error[E0599]: no associated function or constant named `new` found for struct `T` in the current scope --> $DIR/dont-suggest-private-trait-method.rs:4:8 | LL | struct T; - | -------- function or associated item `new` not found for this struct + | -------- associated function or constant `new` not found for this struct ... LL | T::new(); - | ^^^ function or associated item not found in `T` + | ^^^ associated function or constant not found in `T` error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr index 99409dfd5c5e..03f02223165d 100644 --- a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr +++ b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr @@ -9,8 +9,7 @@ LL | consume_fn(|| { LL | let X(_t) = x; | -- ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -34,8 +33,7 @@ LL | consume_fn(|| { LL | if let Either::One(_t) = e { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -59,8 +57,7 @@ LL | consume_fn(|| { LL | while let Either::One(_t) = e { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -85,10 +82,7 @@ LL | match e { | ^ ... LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -113,10 +107,7 @@ LL | match e { | ^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -140,8 +131,7 @@ LL | consume_fn(|| { LL | let X(mut _t) = x; | ------ ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -165,8 +155,7 @@ LL | consume_fn(|| { LL | if let Either::One(mut _t) = em { } | ------ ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -190,8 +179,7 @@ LL | consume_fn(|| { LL | while let Either::One(mut _t) = em { } | ------ ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -216,10 +204,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -244,10 +229,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:14:18 @@ -270,8 +252,7 @@ LL | <() as T>::consume_fn(|| { LL | let X(_t) = x; | -- ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -295,8 +276,7 @@ LL | <() as T>::consume_fn(|| { LL | if let Either::One(_t) = e { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -320,8 +300,7 @@ LL | <() as T>::consume_fn(|| { LL | while let Either::One(_t) = e { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -346,10 +325,7 @@ LL | match e { | ^ ... LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -374,10 +350,7 @@ LL | match e { | ^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -401,8 +374,7 @@ LL | <() as T>::consume_fn(|| { LL | let X(mut _t) = x; | ------ ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -426,8 +398,7 @@ LL | <() as T>::consume_fn(|| { LL | if let Either::One(mut _t) = em { } | ------ ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -451,8 +422,7 @@ LL | <() as T>::consume_fn(|| { LL | while let Either::One(mut _t) = em { } | ------ ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -477,10 +447,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -505,10 +472,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:40:22 @@ -531,8 +495,7 @@ LL | ().method_consume_fn(|| { LL | let X(_t) = x; | -- ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -556,8 +519,7 @@ LL | ().method_consume_fn(|| { LL | if let Either::One(_t) = e { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -581,8 +543,7 @@ LL | ().method_consume_fn(|| { LL | while let Either::One(_t) = e { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -607,10 +568,7 @@ LL | match e { | ^ ... LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -635,10 +593,7 @@ LL | match e { | ^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -662,8 +617,7 @@ LL | ().method_consume_fn(|| { LL | let X(mut _t) = x; | ------ ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -687,8 +641,7 @@ LL | ().method_consume_fn(|| { LL | if let Either::One(mut _t) = em { } | ------ ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -712,8 +665,7 @@ LL | ().method_consume_fn(|| { LL | while let Either::One(mut _t) = em { } | ------ ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -738,10 +690,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -766,10 +715,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:51:29 @@ -792,8 +738,7 @@ LL | consume_fnmut(|| { LL | let X(_t) = x; | -- ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -817,8 +762,7 @@ LL | consume_fnmut(|| { LL | if let Either::One(_t) = e { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -842,8 +786,7 @@ LL | consume_fnmut(|| { LL | while let Either::One(_t) = e { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -868,10 +811,7 @@ LL | match e { | ^ ... LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -896,10 +836,7 @@ LL | match e { | ^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -923,8 +860,7 @@ LL | consume_fnmut(|| { LL | let X(mut _t) = x; | ------ ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -948,8 +884,7 @@ LL | consume_fnmut(|| { LL | if let Either::One(mut _t) = em { } | ------ ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -973,8 +908,7 @@ LL | consume_fnmut(|| { LL | while let Either::One(mut _t) = em { } | ------ ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -999,10 +933,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -1027,10 +958,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 @@ -1055,10 +983,7 @@ LL | match em { | ^^ ... LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | ------ data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:26:21 diff --git a/tests/ui/suggestions/dont-suggest-ref/simple.stderr b/tests/ui/suggestions/dont-suggest-ref/simple.stderr index 41571bf9b2ca..8e7582fbe588 100644 --- a/tests/ui/suggestions/dont-suggest-ref/simple.stderr +++ b/tests/ui/suggestions/dont-suggest-ref/simple.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of `s` which is behind a shared reference LL | let X(_t) = *s; | -- ^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -19,8 +18,7 @@ error[E0507]: cannot move out of `r` as enum variant `One` which is behind a sha LL | if let Either::One(_t) = *r { } | -- ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -34,8 +32,7 @@ error[E0507]: cannot move out of `r` as enum variant `One` which is behind a sha LL | while let Either::One(_t) = *r { } | -- ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -50,10 +47,7 @@ LL | match *r { | ^^ ... LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -68,10 +62,7 @@ LL | match *r { | ^^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -85,8 +76,7 @@ error[E0507]: cannot move out of `sm` which is behind a mutable reference LL | let X(_t) = *sm; | -- ^^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -100,8 +90,7 @@ error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mu LL | if let Either::One(_t) = *rm { } | -- ^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -115,8 +104,7 @@ error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mu LL | while let Either::One(_t) = *rm { } | -- ^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -131,10 +119,7 @@ LL | match *rm { | ^^^ ... LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -149,10 +134,7 @@ LL | match *rm { | ^^^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -167,10 +149,7 @@ LL | match *rm { | ^^^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -184,8 +163,7 @@ error[E0507]: cannot move out of index of `Vec` LL | let X(_t) = vs[0]; | -- ^^^^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -198,8 +176,7 @@ error[E0507]: cannot move out of index of `Vec` LL | if let Either::One(_t) = vr[0] { } | -- ^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -212,8 +189,7 @@ error[E0507]: cannot move out of index of `Vec` LL | while let Either::One(_t) = vr[0] { } | -- ^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -227,10 +203,7 @@ LL | match vr[0] { | ^^^^^ ... LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -244,10 +217,7 @@ LL | match vr[0] { | ^^^^^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -260,8 +230,7 @@ error[E0507]: cannot move out of index of `Vec` LL | let X(_t) = vsm[0]; | -- ^^^^^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -274,8 +243,7 @@ error[E0507]: cannot move out of index of `Vec` LL | if let Either::One(_t) = vrm[0] { } | -- ^^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -288,8 +256,7 @@ error[E0507]: cannot move out of index of `Vec` LL | while let Either::One(_t) = vrm[0] { } | -- ^^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -303,10 +270,7 @@ LL | match vrm[0] { | ^^^^^^ ... LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -320,10 +284,7 @@ LL | match vrm[0] { | ^^^^^^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -337,10 +298,7 @@ LL | match vrm[0] { | ^^^^^^ ... LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -353,8 +311,7 @@ error[E0507]: cannot move out of `s` which is behind a shared reference LL | let &X(_t) = s; | -- ^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -368,8 +325,7 @@ error[E0507]: cannot move out of `r` as enum variant `One` which is behind a sha LL | if let &Either::One(_t) = r { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -383,8 +339,7 @@ error[E0507]: cannot move out of `r` as enum variant `One` which is behind a sha LL | while let &Either::One(_t) = r { } | -- ^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -399,10 +354,7 @@ LL | match r { | ^ LL | LL | &Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -417,10 +369,7 @@ LL | match r { | ^ LL | LL | &Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -435,10 +384,7 @@ LL | match r { | ^ LL | LL | &Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -452,8 +398,7 @@ error[E0507]: cannot move out of `sm` which is behind a mutable reference LL | let &mut X(_t) = sm; | -- ^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -467,8 +412,7 @@ error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mu LL | if let &mut Either::One(_t) = rm { } | -- ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -482,8 +426,7 @@ error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mu LL | while let &mut Either::One(_t) = rm { } | -- ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -522,10 +465,7 @@ LL | match rm { | ^^ LL | LL | &mut Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -540,10 +480,7 @@ LL | match rm { | ^^ LL | LL | &mut Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -558,10 +495,7 @@ LL | match rm { | ^^ LL | LL | &mut Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -575,8 +509,7 @@ error[E0507]: cannot move out of a shared reference LL | let (&X(_t),) = (&x.clone(),); | -- ^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -590,8 +523,7 @@ error[E0507]: cannot move out of a shared reference LL | if let (&Either::One(_t),) = (&e.clone(),) { } | -- ^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -605,8 +537,7 @@ error[E0507]: cannot move out of a shared reference LL | while let (&Either::One(_t),) = (&e.clone(),) { } | -- ^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -621,10 +552,7 @@ LL | match (&e.clone(),) { | ^^^^^^^^^^^^^ LL | LL | (&Either::One(_t),) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -638,8 +566,7 @@ error[E0507]: cannot move out of a mutable reference LL | let (&mut X(_t),) = (&mut xm.clone(),); | -- ^^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -653,8 +580,7 @@ error[E0507]: cannot move out of a mutable reference LL | if let (&mut Either::One(_t),) = (&mut em.clone(),) { } | -- ^^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -668,8 +594,7 @@ error[E0507]: cannot move out of a mutable reference LL | while let (&mut Either::One(_t),) = (&mut em.clone(),) { } | -- ^^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -707,8 +632,7 @@ error[E0507]: cannot move out of a shared reference LL | let &X(_t) = &x; | -- ^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -722,8 +646,7 @@ error[E0507]: cannot move out of a shared reference LL | if let &Either::One(_t) = &e { } | -- ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -737,8 +660,7 @@ error[E0507]: cannot move out of a shared reference LL | while let &Either::One(_t) = &e { } | -- ^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -753,10 +675,7 @@ LL | match &e { | ^^ LL | LL | &Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -771,10 +690,7 @@ LL | match &e { | ^^ LL | LL | &Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -789,10 +705,7 @@ LL | match &e { | ^^ LL | LL | &Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -806,8 +719,7 @@ error[E0507]: cannot move out of a mutable reference LL | let &mut X(_t) = &mut xm; | -- ^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -821,8 +733,7 @@ error[E0507]: cannot move out of a mutable reference LL | if let &mut Either::One(_t) = &mut em { } | -- ^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -836,8 +747,7 @@ error[E0507]: cannot move out of a mutable reference LL | while let &mut Either::One(_t) = &mut em { } | -- ^^^^^^^ | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -852,10 +762,7 @@ LL | match &mut em { | ^^^^^^^ LL | LL | &mut Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -870,10 +777,7 @@ LL | match &mut em { | ^^^^^^^ LL | LL | &mut Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -888,10 +792,7 @@ LL | match &mut em { | ^^^^^^^ LL | LL | &mut Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -906,10 +807,7 @@ LL | match &mut em { | ^^^^^^^ LL | LL | &mut Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | -- data moved here because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -923,8 +821,7 @@ error[E0507]: cannot move out of a shared reference LL | fn f1(&X(_t): &X) { } | ^^^--^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -938,8 +835,7 @@ error[E0507]: cannot move out of a mutable reference LL | fn f2(&mut X(_t): &mut X) { } | ^^^^^^^--^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -953,8 +849,7 @@ error[E0507]: cannot move out of a shared reference LL | fn f3((&X(_t),): (&X,)) { } | ^^^^--^^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -968,8 +863,7 @@ error[E0507]: cannot move out of a mutable reference LL | fn f4((&mut X(_t),): (&mut X,)) { } | ^^^^^^^^--^^^ | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait + | data moved here because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the mutable borrow | @@ -983,8 +877,7 @@ error[E0507]: cannot move out of `a.a` as enum variant `Some` which is behind a LL | let Some(_s) = a.a else { | -- ^^^ | | - | data moved here - | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | data moved here because `_s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/suggestions/field-access.stderr b/tests/ui/suggestions/field-access.stderr index 362dae172c78..36e126176ee9 100644 --- a/tests/ui/suggestions/field-access.stderr +++ b/tests/ui/suggestions/field-access.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/field-access.rs:20:12 | -LL | Fst, - | --- unit variant defined here -... LL | if let B::Fst = a {}; | ^^^^^^ - this expression has type `A` | | @@ -17,9 +14,6 @@ LL | if let B::Fst = a.b {}; error[E0308]: mismatched types --> $DIR/field-access.rs:25:9 | -LL | Fst, - | --- unit variant defined here -... LL | match a { | - this expression has type `A` ... @@ -34,9 +28,6 @@ LL | match a.b { error[E0308]: mismatched types --> $DIR/field-access.rs:26:9 | -LL | Snd, - | --- unit variant defined here -... LL | match a { | - this expression has type `A` ... diff --git a/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.fixed b/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.fixed new file mode 100644 index 000000000000..50beced2940b --- /dev/null +++ b/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.fixed @@ -0,0 +1,11 @@ +//@ run-rustfix +#![allow(dead_code)] + +fn main() { + struct Error; + + const ERROR: Error = Error; + //~^ ERROR missing type for `const` item + //~| HELP provide a type for the constant + //~| SUGGESTION : Error +} diff --git a/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.rs b/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.rs new file mode 100644 index 000000000000..f3c4aed435da --- /dev/null +++ b/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.rs @@ -0,0 +1,11 @@ +//@ run-rustfix +#![allow(dead_code)] + +fn main() { + struct Error; + + const ERROR = Error; + //~^ ERROR missing type for `const` item + //~| HELP provide a type for the constant + //~| SUGGESTION : Error +} diff --git a/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.stderr b/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.stderr new file mode 100644 index 000000000000..4111f9d35306 --- /dev/null +++ b/tests/ui/suggestions/function-local-item-type-suggestion-issue-146786.stderr @@ -0,0 +1,8 @@ +error: missing type for `const` item + --> $DIR/function-local-item-type-suggestion-issue-146786.rs:7:16 + | +LL | const ERROR = Error; + | ^ help: provide a type for the constant: `: Error` + +error: aborting due to 1 previous error + diff --git a/tests/ui/suggestions/incorrect-variant-literal.svg b/tests/ui/suggestions/incorrect-variant-literal.svg index d2c1f6c95ca5..54eaee2a2e90 100644 --- a/tests/ui/suggestions/incorrect-variant-literal.svg +++ b/tests/ui/suggestions/incorrect-variant-literal.svg @@ -1,4 +1,4 @@ - + (I); - | ------------- function or associated item `f` not found for this struct + | ------------- associated function or constant `f` not found for this struct ... LL | Foo::<()>::f() - | ^ function or associated item cannot be called on `Foo<()>` due to unsatisfied trait bounds + | ^ associated function or constant cannot be called on `Foo<()>` due to unsatisfied trait bounds | note: trait bound `(): Iterator` was not satisfied --> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:5:23 diff --git a/tests/ui/traits/associated-item-unsatisfied-trait-bounds.stderr b/tests/ui/traits/associated-item-unsatisfied-trait-bounds.stderr index 42969de715eb..f26c321a2973 100644 --- a/tests/ui/traits/associated-item-unsatisfied-trait-bounds.stderr +++ b/tests/ui/traits/associated-item-unsatisfied-trait-bounds.stderr @@ -1,11 +1,11 @@ -error[E0599]: the function or associated item `bat` exists for struct `Foo`, but its trait bounds were not satisfied +error[E0599]: the associated function or constant `bat` exists for struct `Foo`, but its trait bounds were not satisfied --> $DIR/associated-item-unsatisfied-trait-bounds.rs:8:10 | LL | struct Foo; - | ---------- function or associated item `bat` not found for this struct because `Foo` doesn't implement `Bar` or `Baz` + | ---------- associated function or constant `bat` not found for this struct because `Foo` doesn't implement `Bar` or `Baz` ... LL | Foo::bat(()); - | ^^^ function or associated item cannot be called on `Foo` due to unsatisfied trait bounds + | ^^^ associated function or constant cannot be called on `Foo` due to unsatisfied trait bounds | note: for `bat` to be available, `Foo` must implement `Bar` and `Baz` --> $DIR/associated-item-unsatisfied-trait-bounds.rs:5:38 diff --git a/tests/ui/kindck/kindck-copy.rs b/tests/ui/traits/basic-copyable-types.rs similarity index 63% rename from tests/ui/kindck/kindck-copy.rs rename to tests/ui/traits/basic-copyable-types.rs index 36bf0d2b785f..c953b60260df 100644 --- a/tests/ui/kindck/kindck-copy.rs +++ b/tests/ui/traits/basic-copyable-types.rs @@ -2,9 +2,9 @@ use std::rc::Rc; -fn assert_copy() { } +fn assert_copy() {} -trait Dummy { } +trait Dummy {} #[derive(Copy, Clone)] struct MyStruct { @@ -16,8 +16,8 @@ struct MyNoncopyStruct { x: Box, } -fn test<'a,T,U:Copy>(_: &'a isize) { - // lifetime pointers are ok... +fn test<'a, T, U: Copy>(_: &'a isize) { + // references are ok... assert_copy::<&'static isize>(); assert_copy::<&'a isize>(); assert_copy::<&'a str>(); @@ -25,25 +25,25 @@ fn test<'a,T,U:Copy>(_: &'a isize) { // ...unless they are mutable assert_copy::<&'static mut isize>(); //~ ERROR : Copy` is not satisfied - assert_copy::<&'a mut isize>(); //~ ERROR : Copy` is not satisfied + assert_copy::<&'a mut isize>(); //~ ERROR : Copy` is not satisfied // boxes are not ok - assert_copy::>(); //~ ERROR : Copy` is not satisfied - assert_copy::(); //~ ERROR : Copy` is not satisfied - assert_copy:: >(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied + assert_copy::(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied assert_copy::>(); //~ ERROR : Copy` is not satisfied - // borrowed object types are generally ok + // borrowed trait objects are generally ok assert_copy::<&'a dyn Dummy>(); assert_copy::<&'a (dyn Dummy + Send)>(); assert_copy::<&'static (dyn Dummy + Send)>(); - // owned object types are not ok + // boxed trait objects are not ok assert_copy::>(); //~ ERROR : Copy` is not satisfied assert_copy::>(); //~ ERROR : Copy` is not satisfied - // mutable object types are not ok - assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : Copy` is not satisfied + // mutable references to trait objects are not ok + assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : Copy` is not satisfied // raw ptrs are ok assert_copy::<*const isize>(); @@ -55,7 +55,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::<()>(); // tuples are ok - assert_copy::<(isize,isize)>(); + assert_copy::<(isize, isize)>(); // structs of POD are ok assert_copy::(); @@ -64,8 +64,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::(); //~ ERROR : Copy` is not satisfied // ref counted types are not ok - assert_copy::>(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied } -pub fn main() { -} +pub fn main() {} diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/traits/basic-copyable-types.stderr similarity index 61% rename from tests/ui/kindck/kindck-copy.stderr rename to tests/ui/traits/basic-copyable-types.stderr index f5623ddd4f79..b4fa95753335 100644 --- a/tests/ui/kindck/kindck-copy.stderr +++ b/tests/ui/traits/basic-copyable-types.stderr @@ -1,14 +1,14 @@ error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied - --> $DIR/kindck-copy.rs:27:19 + --> $DIR/basic-copyable-types.rs:27:19 | LL | assert_copy::<&'static mut isize>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` help: consider removing the leading `&`-reference | LL - assert_copy::<&'static mut isize>(); @@ -16,16 +16,16 @@ LL + assert_copy::(); | error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied - --> $DIR/kindck-copy.rs:28:19 + --> $DIR/basic-copyable-types.rs:28:19 | LL | assert_copy::<&'a mut isize>(); | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` help: consider removing the leading `&`-reference | LL - assert_copy::<&'a mut isize>(); @@ -33,117 +33,117 @@ LL + assert_copy::(); | error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:31:19 + --> $DIR/basic-copyable-types.rs:31:19 | LL | assert_copy::>(); | ^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/kindck-copy.rs:32:19 + --> $DIR/basic-copyable-types.rs:32:19 | LL | assert_copy::(); | ^^^^^^ the trait `Copy` is not implemented for `String` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Vec: Copy` is not satisfied - --> $DIR/kindck-copy.rs:33:19 + --> $DIR/basic-copyable-types.rs:33:19 | -LL | assert_copy:: >(); +LL | assert_copy::>(); | ^^^^^^^^^^ the trait `Copy` is not implemented for `Vec` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box<&'a mut isize>: Copy` is not satisfied - --> $DIR/kindck-copy.rs:34:19 + --> $DIR/basic-copyable-types.rs:34:19 | LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<&'a mut isize>` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:42:19 + --> $DIR/basic-copyable-types.rs:42:19 | LL | assert_copy::>(); | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:43:19 + --> $DIR/basic-copyable-types.rs:43:19 | LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not satisfied - --> $DIR/kindck-copy.rs:46:19 + --> $DIR/basic-copyable-types.rs:46:19 | LL | assert_copy::<&'a mut (dyn Dummy + Send)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied - --> $DIR/kindck-copy.rs:64:19 + --> $DIR/basic-copyable-types.rs:64:19 | LL | assert_copy::(); | ^^^^^^^^^^^^^^^ unsatisfied trait bound | help: the trait `Copy` is not implemented for `MyNoncopyStruct` - --> $DIR/kindck-copy.rs:15:1 + --> $DIR/basic-copyable-types.rs:15:1 | LL | struct MyNoncopyStruct { | ^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Rc: Copy` is not satisfied - --> $DIR/kindck-copy.rs:67:19 + --> $DIR/basic-copyable-types.rs:67:19 | LL | assert_copy::>(); | ^^^^^^^^^ the trait `Copy` is not implemented for `Rc` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/basic-copyable-types.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error: aborting due to 11 previous errors diff --git a/tests/ui/kindck/kindck-nonsendable-1.rs b/tests/ui/traits/closure-rc-not-send.rs similarity index 70% rename from tests/ui/kindck/kindck-nonsendable-1.rs rename to tests/ui/traits/closure-rc-not-send.rs index b32fd78624b8..78ef834afabd 100644 --- a/tests/ui/kindck/kindck-nonsendable-1.rs +++ b/tests/ui/traits/closure-rc-not-send.rs @@ -2,10 +2,10 @@ fn foo(_x: Rc) {} -fn bar(_: F) { } +fn bar(_: F) {} fn main() { let x = Rc::new(3); - bar(move|| foo(x)); + bar(move || foo(x)); //~^ ERROR `Rc` cannot be sent between threads safely } diff --git a/tests/ui/traits/closure-rc-not-send.stderr b/tests/ui/traits/closure-rc-not-send.stderr new file mode 100644 index 000000000000..5e73f13648d5 --- /dev/null +++ b/tests/ui/traits/closure-rc-not-send.stderr @@ -0,0 +1,25 @@ +error[E0277]: `Rc` cannot be sent between threads safely + --> $DIR/closure-rc-not-send.rs:9:9 + | +LL | bar(move || foo(x)); + | --- -------^^^^^^^ + | | | + | | `Rc` cannot be sent between threads safely + | | within this `{closure@$DIR/closure-rc-not-send.rs:9:9: 9:16}` + | required by a bound introduced by this call + | + = help: within `{closure@$DIR/closure-rc-not-send.rs:9:9: 9:16}`, the trait `Send` is not implemented for `Rc` +note: required because it's used within this closure + --> $DIR/closure-rc-not-send.rs:9:9 + | +LL | bar(move || foo(x)); + | ^^^^^^^ +note: required by a bound in `bar` + --> $DIR/closure-rc-not-send.rs:5:22 + | +LL | fn bar(_: F) {} + | ^^^^ required by this bound in `bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/call-const-closure.stderr b/tests/ui/traits/const-traits/call-const-closure.next.stderr similarity index 82% rename from tests/ui/traits/const-traits/call-const-closure.stderr rename to tests/ui/traits/const-traits/call-const-closure.next.stderr index 9a851a97f186..16b936d58aaf 100644 --- a/tests/ui/traits/const-traits/call-const-closure.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.next.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `(): [const] Bar` is not satisfied +error[E0277]: the trait bound `(): const Bar` is not satisfied --> $DIR/call-const-closure.rs:16:18 | LL | (const || ().foo())(); diff --git a/tests/ui/traits/const-traits/call-const-closure.old.stderr b/tests/ui/traits/const-traits/call-const-closure.old.stderr new file mode 100644 index 000000000000..16b936d58aaf --- /dev/null +++ b/tests/ui/traits/const-traits/call-const-closure.old.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `(): const Bar` is not satisfied + --> $DIR/call-const-closure.rs:16:18 + | +LL | (const || ().foo())(); + | ^^^ + | +help: make the `impl` of trait `Bar` `const` + | +LL | impl const Bar for () { + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs index c4293579aea8..2cf561ae6db1 100644 --- a/tests/ui/traits/const-traits/call-const-closure.rs +++ b/tests/ui/traits/const-traits/call-const-closure.rs @@ -1,8 +1,8 @@ -//@ compile-flags: -Znext-solver +//@[next] compile-flags: -Znext-solver +//@ revisions: next old //@ edition:2021 #![feature(const_trait_impl, const_closures)] -#![allow(incomplete_features)] const trait Bar { fn foo(&self); @@ -14,8 +14,7 @@ fn foo(&self) {} const FOO: () = { (const || ().foo())(); - //~^ ERROR the trait bound `(): [const] Bar` is not satisfied - // FIXME(const_trait_impl): The constness environment for const closures is wrong. + //~^ ERROR the trait bound `(): const Bar` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index 360c08e1b7fe..71dea1ef4e04 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -1,11 +1,10 @@ -// FIXME(const_trait_impl) check-pass -//@ compile-flags: -Znext-solver +//@ check-pass +//@[next] compile-flags: -Znext-solver +//@revisions: next old #![feature(const_closures, const_trait_impl)] -#![allow(incomplete_features)] const _: () = { assert!((const || true)()); - //~^ ERROR }: [const] Fn()` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr deleted file mode 100644 index 8e32cab6dfcf..000000000000 --- a/tests/ui/traits/const-traits/call.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] Fn()` is not satisfied - --> $DIR/call.rs:7:13 - | -LL | assert!((const || true)()); - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs b/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs index 7a44920bb729..55fae27eb6dd 100644 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs @@ -1,4 +1,3 @@ -#![allow(incomplete_features)] #![feature(const_closures, const_trait_impl)] const fn create_array(mut f: impl FnMut(usize) -> u32 + Copy) -> [u32; N] { @@ -16,9 +15,9 @@ } fn main() { - let x = create_array(const |i| 2 * i as u32); + let x = const { create_array(const |i| 2 * i as u32) }; assert_eq!(x, [0, 2, 4, 6, 8]); - let y = create_array(const |i| 2 * i as u32 + 1); + let y = const { create_array(const |i| 2 * i as u32 + 1) }; assert_eq!(y, [1, 3, 5, 7, 9]); } diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr b/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr index 1eadd1d84269..448b343e2caa 100644 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `impl FnMut(usize) -> u32 + Copy: [const] FnMut(usize)` is not satisfied - --> $DIR/const-closure-issue-125866-error.rs:8:22 + --> $DIR/const-closure-issue-125866-error.rs:7:22 | LL | array[i] = f(i); | - ^ diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs b/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs deleted file mode 100644 index af7375172e67..000000000000 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ check-pass - -#![allow(incomplete_features)] -#![feature(const_closures, const_trait_impl)] - -const fn create_array(mut f: impl [const] FnMut(usize) -> u32 + Copy) -> [u32; N] { - let mut array = [0; N]; - let mut i = 0; - loop { - array[i] = f(i); - i += 1; - if i == N { - break; - } - } - array -} - -fn main() { - let x = create_array(const |i| 2 * i as u32); - assert_eq!(x, [0, 2, 4, 6, 8]); - - let y = create_array(const |i| 2 * i as u32 + 1); - assert_eq!(y, [1, 3, 5, 7, 9]); -} diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.rs b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs index 35127eda5c03..ce20b05a8133 100644 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.rs +++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs @@ -1,8 +1,6 @@ -//@ known-bug: #110395 -// FIXME check-pass +//@check-pass #![feature(const_trait_impl, const_closures)] -#![allow(incomplete_features)] const fn test() -> impl [const] Fn() { const move || {} diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr deleted file mode 100644 index 1d8d5ff1b4f2..000000000000 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `{closure@$DIR/const-closure-parse-not-item.rs:8:5: 8:18}: [const] Fn()` is not satisfied - --> $DIR/const-closure-parse-not-item.rs:7:20 - | -LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.next.stderr b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.next.stderr new file mode 100644 index 000000000000..8b5c4f59fbde --- /dev/null +++ b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.next.stderr @@ -0,0 +1,21 @@ +error[E0277]: the trait bound `Vec: const Destruct` is not satisfied + --> $DIR/const-closure-with-indestructible-indestructible.rs:10:16 + | +LL | i_need(const || { + | _________------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | let y = v; +LL | | }) + | |_________^ + | +note: required by a bound in `i_need` + --> $DIR/const-closure-with-indestructible-indestructible.rs:5:20 + | +LL | const fn i_need(x: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `i_need` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.old.stderr b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.old.stderr new file mode 100644 index 000000000000..8b5c4f59fbde --- /dev/null +++ b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.old.stderr @@ -0,0 +1,21 @@ +error[E0277]: the trait bound `Vec: const Destruct` is not satisfied + --> $DIR/const-closure-with-indestructible-indestructible.rs:10:16 + | +LL | i_need(const || { + | _________------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | let y = v; +LL | | }) + | |_________^ + | +note: required by a bound in `i_need` + --> $DIR/const-closure-with-indestructible-indestructible.rs:5:20 + | +LL | const fn i_need(x: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `i_need` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.rs b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.rs new file mode 100644 index 000000000000..d26260dd2d07 --- /dev/null +++ b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.rs @@ -0,0 +1,15 @@ +//@revisions: next old +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +#![feature(const_trait_impl, const_closures, const_destruct)] +const fn i_need(x: F) {} + +fn main() { + const { + let v = Vec::::new(); + i_need(const || { + //~^ ERROR the trait bound + let y = v; + }) + }; +} diff --git a/tests/ui/traits/const-traits/const-traits-core.rs b/tests/ui/traits/const-traits/const-traits-core.rs index 2cafde4f5bd0..ed244c230006 100644 --- a/tests/ui/traits/const-traits/const-traits-core.rs +++ b/tests/ui/traits/const-traits/const-traits-core.rs @@ -36,8 +36,8 @@ const OPT: Option = Default::default(); // core::iter::sources::empty const EMPTY: std::iter::Empty<()> = Default::default(); -// core::ptr::alignment -const ALIGNMENT: std::ptr::Alignment = Default::default(); +// core::mem::alignment +const ALIGNMENT: std::mem::Alignment = Default::default(); // core::slice const SLICE: &[()] = Default::default(); const MUT_SLICE: &mut [()] = Default::default(); diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs deleted file mode 100644 index e355ee724d1b..000000000000 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #110395 -//@ compile-flags: -Znext-solver -#![feature(const_closures, const_trait_impl)] -#![allow(incomplete_features)] - -trait Foo { - fn foo(&self); -} - -impl Foo for () { - fn foo(&self) {} -} - -fn main() { - (const || (()).foo())(); -} diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr deleted file mode 100644 index dab3f14161fa..000000000000 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] Fn()` is not satisfied - --> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5 - | -LL | (const || (()).foo())(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/gate.rs b/tests/ui/traits/const-traits/gate.rs index 3f348c841393..c9f56df35531 100644 --- a/tests/ui/traits/const-traits/gate.rs +++ b/tests/ui/traits/const-traits/gate.rs @@ -1,13 +1,14 @@ // gate-test-const_closures fn main() { - (const || {})(); + const { (const || {})() }; //~^ ERROR: const closures are experimental - //~| ERROR: the trait bound `{closure@$DIR/gate.rs:4:6: 4:14}: [const] Fn()` is not satisfied + //~| ERROR: cannot call conditionally-const closure in constants + //~| ERROR: `Fn` is not yet stable as a const trait } macro_rules! e { - ($e:expr) => {} + ($e:expr) => {}; } e!((const || {})); diff --git a/tests/ui/traits/const-traits/gate.stderr b/tests/ui/traits/const-traits/gate.stderr index 6bef2c511ce7..788878292b6f 100644 --- a/tests/ui/traits/const-traits/gate.stderr +++ b/tests/ui/traits/const-traits/gate.stderr @@ -1,15 +1,15 @@ error[E0658]: const closures are experimental - --> $DIR/gate.rs:4:6 + --> $DIR/gate.rs:4:14 | -LL | (const || {})(); - | ^^^^^ +LL | const { (const || {})() }; + | ^^^^^ | = note: see issue #106003 for more information = help: add `#![feature(const_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: const closures are experimental - --> $DIR/gate.rs:13:5 + --> $DIR/gate.rs:14:5 | LL | e!((const || {})); | ^^^^^ @@ -18,13 +18,29 @@ LL | e!((const || {})); = help: add `#![feature(const_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0277]: the trait bound `{closure@$DIR/gate.rs:4:6: 4:14}: [const] Fn()` is not satisfied - --> $DIR/gate.rs:4:5 +error[E0658]: cannot call conditionally-const closure in constants + --> $DIR/gate.rs:4:13 | -LL | (const || {})(); - | ^^^^^^^^^^^^^^^ +LL | const { (const || {})() }; + | ^^^^^^^^^^^^^^^ + | + = note: closures need an RFC before allowed to be called in constants + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: see issue #143874 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error: `Fn` is not yet stable as a const trait + --> $DIR/gate.rs:4:13 + | +LL | const { (const || {})() }; + | ^^^^^^^^^^^^^^^ + | +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | -Some errors have detailed explanations: E0277, E0658. -For more information about an error, try `rustc --explain E0277`. +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs index 8ee3db445d07..1f35abbb9d6a 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs @@ -1,14 +1,13 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_closures, const_cmp)] const fn test() -> impl [const] Fn() { - //~^ ERROR: }: [const] Fn()` is not satisfied - const move || { //~ ERROR const closures are experimental + const move || { let sl: &[u8] = b"foo"; match sl { [first, remainder @ ..] => { assert_eq!(first, &b'f'); - // FIXME(const_closures) ^ ERROR cannot call non-const function + //~^ ERROR cannot call non-const function } [] => panic!(), } diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr index abbe0a0070aa..73340f15cbb8 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr @@ -1,20 +1,13 @@ -error[E0658]: const closures are experimental - --> $DIR/ice-112822-expected-type-for-param.rs:5:5 +error[E0015]: cannot call non-const function `core::panicking::assert_failed::<&u8, &u8>` in constant functions + --> $DIR/ice-112822-expected-type-for-param.rs:9:17 | -LL | const move || { - | ^^^^^ +LL | assert_eq!(first, &b'f'); + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #106003 for more information - = help: add `#![feature(const_closures)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +note: function `assert_failed` is not const + --> $SRC_DIR/core/src/panicking.rs:LL:COL + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error[E0277]: the trait bound `{closure@$DIR/ice-112822-expected-type-for-param.rs:5:5: 5:18}: [const] Fn()` is not satisfied - --> $DIR/ice-112822-expected-type-for-param.rs:3:20 - | -LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^^^^^^^^^^^ +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0277, E0658. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/mismatched_generic_args.rs b/tests/ui/traits/const-traits/mismatched_generic_args.rs index 21e91c731b36..409a70445680 100644 --- a/tests/ui/traits/const-traits/mismatched_generic_args.rs +++ b/tests/ui/traits/const-traits/mismatched_generic_args.rs @@ -1,5 +1,4 @@ #![feature(generic_const_exprs)] -//~^ WARN: the feature `generic_const_exprs` is incomplete // Regression test for #125770 which would ICE under the old effects desugaring that // created a const generic parameter for constness on `Add`. diff --git a/tests/ui/traits/const-traits/mismatched_generic_args.stderr b/tests/ui/traits/const-traits/mismatched_generic_args.stderr index e8103313dc4f..3094cb501330 100644 --- a/tests/ui/traits/const-traits/mismatched_generic_args.stderr +++ b/tests/ui/traits/const-traits/mismatched_generic_args.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `y` in this scope - --> $DIR/mismatched_generic_args.rs:20:9 + --> $DIR/mismatched_generic_args.rs:19:9 | LL | pub fn add(x: Quantity) -> Quantity { | - similarly named const parameter `U` defined here @@ -13,17 +13,8 @@ LL - x + y LL + x + U | -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/mismatched_generic_args.rs:1:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `Dimension` is forbidden as the type of a const generic parameter - --> $DIR/mismatched_generic_args.rs:11:33 + --> $DIR/mismatched_generic_args.rs:10:33 | LL | pub struct Quantity(S); | ^^^^^^^^^ @@ -35,13 +26,13 @@ LL + #![feature(adt_const_params)] | error[E0107]: trait takes at most 1 generic argument but 2 generic arguments were supplied - --> $DIR/mismatched_generic_args.rs:14:36 + --> $DIR/mismatched_generic_args.rs:13:36 | LL | impl Add for Quantity {} | ^^^ expected at most 1 generic argument error: `Dimension` is forbidden as the type of a const generic parameter - --> $DIR/mismatched_generic_args.rs:14:15 + --> $DIR/mismatched_generic_args.rs:13:15 | LL | impl Add for Quantity {} | ^^^^^^^^^ @@ -53,7 +44,7 @@ LL + #![feature(adt_const_params)] | error: `Dimension` is forbidden as the type of a const generic parameter - --> $DIR/mismatched_generic_args.rs:18:21 + --> $DIR/mismatched_generic_args.rs:17:21 | LL | pub fn add(x: Quantity) -> Quantity { | ^^^^^^^^^ @@ -64,7 +55,7 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more LL + #![feature(adt_const_params)] | -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 5 previous errors Some errors have detailed explanations: E0107, E0425. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs index de5bedf0ace7..58402cbaec81 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs @@ -1,5 +1,4 @@ #![feature(const_closures, const_trait_impl)] -#![allow(incomplete_features)] trait Foo { fn foo(&self); @@ -13,5 +12,5 @@ fn main() { // #150052 deduplicate diagnostics for const trait supertraits // so we only get one error here (const || { (()).foo() })(); - //~^ ERROR: }: [const] Fn()` is not satisfied + //~^ ERROR: cannot use `const` closures outside of const contexts } diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr index efbedca1c7e7..f5521b90cc2d 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr @@ -1,9 +1,8 @@ -error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:15:6: 15:14}: [const] Fn()` is not satisfied - --> $DIR/non-const-op-const-closure-non-const-outer.rs:15:5 +error: cannot use `const` closures outside of const contexts + --> $DIR/non-const-op-const-closure-non-const-outer.rs:14:6 | LL | (const || { (()).foo() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr b/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr index a6bd8615d36d..57bb5569c8eb 100644 --- a/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr +++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Foo` for type `(_,)` - --> $DIR/overlap-const-with-nonconst.rs:21:1 + --> $DIR/overlap-const-with-nonconst.rs:20:1 | LL | / impl const Foo for T LL | | where diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs b/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs index 10dfb200c643..0e21d31a426a 100644 --- a/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs +++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs @@ -2,7 +2,6 @@ #![feature(const_trait_impl)] #![cfg_attr(spec, feature(specialization))] -//[spec]~^ WARN the feature `specialization` is incomplete #![cfg_attr(min_spec, feature(min_specialization))] const trait Bar {} diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr b/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr index 91628f65fdcd..57bb5569c8eb 100644 --- a/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr +++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr @@ -1,15 +1,5 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-const-with-nonconst.rs:4:27 - | -LL | #![cfg_attr(spec, feature(specialization))] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0119]: conflicting implementations of trait `Foo` for type `(_,)` - --> $DIR/overlap-const-with-nonconst.rs:21:1 + --> $DIR/overlap-const-with-nonconst.rs:20:1 | LL | / impl const Foo for T LL | | where @@ -19,6 +9,6 @@ LL | | T: [const] Bar, LL | impl Foo for (T,) { | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr index 520a6833f5a5..ad3c177862ae 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr +++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo` - --> $DIR/const-default-impl-non-const-specialized-impl.rs:21:1 + --> $DIR/const-default-impl-non-const-specialized-impl.rs:20:1 | LL | impl const Value for T { | ------------------------- first implementation here diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs index f7cd4599561c..b26e65590169 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs +++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs @@ -3,7 +3,6 @@ #![feature(const_trait_impl)] #![cfg_attr(spec, feature(specialization))] -//[spec]~^ WARN the feature `specialization` is incomplete #![cfg_attr(min_spec, feature(min_specialization))] const trait Value { diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr index 397d67855945..ad3c177862ae 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr +++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr @@ -1,15 +1,5 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-default-impl-non-const-specialized-impl.rs:5:27 - | -LL | #![cfg_attr(spec, feature(specialization))] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo` - --> $DIR/const-default-impl-non-const-specialized-impl.rs:21:1 + --> $DIR/const-default-impl-non-const-specialized-impl.rs:20:1 | LL | impl const Value for T { | ------------------------- first implementation here @@ -17,6 +7,6 @@ LL | impl const Value for T { LL | impl Value for FortyTwo { | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/kindck/kindck-impl-type-params.rs b/tests/ui/traits/copy-bounds-impl-type-params.rs similarity index 94% rename from tests/ui/kindck/kindck-impl-type-params.rs rename to tests/ui/traits/copy-bounds-impl-type-params.rs index 707c5dbaec30..ba54bc313c08 100644 --- a/tests/ui/kindck/kindck-impl-type-params.rs +++ b/tests/ui/traits/copy-bounds-impl-type-params.rs @@ -6,7 +6,9 @@ struct S(marker::PhantomData); trait Gettable { - fn get(&self) -> T { panic!() } + fn get(&self) -> T { + panic!() + } } impl Gettable for S {} @@ -45,4 +47,4 @@ fn foo3<'a>() { //~^ ERROR : Copy` is not satisfied } -fn main() { } +fn main() {} diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/traits/copy-bounds-impl-type-params.stderr similarity index 86% rename from tests/ui/kindck/kindck-impl-type-params.stderr rename to tests/ui/traits/copy-bounds-impl-type-params.stderr index 0c9ab13f4774..08fde8fb5df3 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/traits/copy-bounds-impl-type-params.stderr @@ -1,11 +1,11 @@ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/kindck-impl-type-params.rs:16:13 + --> $DIR/copy-bounds-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -18,13 +18,13 @@ LL | fn f(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:16:13 + --> $DIR/copy-bounds-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; | ^^ the trait `Copy` is not implemented for `T` | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -37,13 +37,13 @@ LL | fn f(val: T) { | +++++++++++++++++++ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/kindck-impl-type-params.rs:23:31 + --> $DIR/copy-bounds-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; | ^^ `T` cannot be sent between threads safely | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -56,13 +56,13 @@ LL | fn g(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:23:31 + --> $DIR/copy-bounds-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; | ^^ the trait `Copy` is not implemented for `T` | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -75,18 +75,18 @@ LL | fn g(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:36:13 + --> $DIR/copy-bounds-impl-type-params.rs:38:13 | LL | let a = t as Box>; | ^ the trait `Copy` is not implemented for `String` | help: the trait `Gettable` is implemented for `S` - --> $DIR/kindck-impl-type-params.rs:12:1 + --> $DIR/copy-bounds-impl-type-params.rs:14:1 | LL | impl Gettable for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -95,18 +95,18 @@ LL | impl Gettable for S {} = note: required for the cast from `Box>` to `Box>` error[E0277]: the trait bound `Foo: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:44:37 + --> $DIR/copy-bounds-impl-type-params.rs:46:37 | LL | let a: Box> = t; | ^ the trait `Copy` is not implemented for `Foo` | help: the trait `Gettable` is implemented for `S` - --> $DIR/kindck-impl-type-params.rs:12:1 + --> $DIR/copy-bounds-impl-type-params.rs:14:1 | LL | impl Gettable for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -120,7 +120,7 @@ LL | struct Foo; // does not impl Copy | error: lifetime may not live long enough - --> $DIR/kindck-impl-type-params.rs:30:13 + --> $DIR/copy-bounds-impl-type-params.rs:32:13 | LL | fn foo<'a>() { | -- lifetime `'a` defined here diff --git a/tests/ui/cross/cross-fn-cache-hole.rs b/tests/ui/traits/cross-fn-cache-hole.rs similarity index 100% rename from tests/ui/cross/cross-fn-cache-hole.rs rename to tests/ui/traits/cross-fn-cache-hole.rs diff --git a/tests/ui/cross/cross-fn-cache-hole.stderr b/tests/ui/traits/cross-fn-cache-hole.stderr similarity index 100% rename from tests/ui/cross/cross-fn-cache-hole.stderr rename to tests/ui/traits/cross-fn-cache-hole.stderr diff --git a/tests/ui/traits/explicit-reference-cast-unrelated-leaf.rs b/tests/ui/traits/explicit-reference-cast-unrelated-leaf.rs new file mode 100644 index 000000000000..83687f37f054 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-unrelated-leaf.rs @@ -0,0 +1,21 @@ +trait Output<'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper(self, _: F) + where + for<'a> F: Output<'a>, + for<'a> O: From<>::Type>, + { + } +} + +fn main() { + let wrapper = Wrapper; + wrapper.do_something_wrapper(|value| ()); + //~^ ERROR the trait bound `for<'a> {closure@ + //~| ERROR the trait bound `for<'a> _: From<<{closure@ +} diff --git a/tests/ui/traits/explicit-reference-cast-unrelated-leaf.stderr b/tests/ui/traits/explicit-reference-cast-unrelated-leaf.stderr new file mode 100644 index 000000000000..1e4cb7f1cd18 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-unrelated-leaf.stderr @@ -0,0 +1,47 @@ +error[E0277]: the trait bound `for<'a> {closure@$DIR/explicit-reference-cast-unrelated-leaf.rs:18:34: 18:41}: Output<'a>` is not satisfied + --> $DIR/explicit-reference-cast-unrelated-leaf.rs:18:34 + | +LL | wrapper.do_something_wrapper(|value| ()); + | -------------------- ^^^^^^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/explicit-reference-cast-unrelated-leaf.rs:18:34: 18:41}` +help: this trait has no implementations, consider adding one + --> $DIR/explicit-reference-cast-unrelated-leaf.rs:1:1 + | +LL | trait Output<'a> { + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Wrapper::do_something_wrapper` + --> $DIR/explicit-reference-cast-unrelated-leaf.rs:10:20 + | +LL | fn do_something_wrapper(self, _: F) + | -------------------- required by a bound in this associated function +LL | where +LL | for<'a> F: Output<'a>, + | ^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper` + +error[E0277]: the trait bound `for<'a> _: From<<{closure@$DIR/explicit-reference-cast-unrelated-leaf.rs:18:34: 18:41} as Output<'a>>::Type>` is not satisfied + --> $DIR/explicit-reference-cast-unrelated-leaf.rs:18:13 + | +LL | wrapper.do_something_wrapper(|value| ()); + | ^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | + = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/explicit-reference-cast-unrelated-leaf.rs:18:34: 18:41}` +help: this trait has no implementations, consider adding one + --> $DIR/explicit-reference-cast-unrelated-leaf.rs:1:1 + | +LL | trait Output<'a> { + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Wrapper::do_something_wrapper` + --> $DIR/explicit-reference-cast-unrelated-leaf.rs:11:20 + | +LL | fn do_something_wrapper(self, _: F) + | -------------------- required by a bound in this associated function +... +LL | for<'a> O: From<>::Type>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/explicit-reference-cast.rs b/tests/ui/traits/explicit-reference-cast.rs index efb4f10bea67..b9ccc1827a55 100644 --- a/tests/ui/traits/explicit-reference-cast.rs +++ b/tests/ui/traits/explicit-reference-cast.rs @@ -7,7 +7,7 @@ //~^ HELP the trait `From<&PathBuf>` is not implemented for `ToolA` impl From<&Path> for ToolA { - //~^ HELP the following other types implement trait `From` + //~^ HELP `ToolA` implements trait `From` fn from(p: &Path) -> ToolA { ToolA(p.to_path_buf()) } diff --git a/tests/ui/traits/explicit-reference-cast.stderr b/tests/ui/traits/explicit-reference-cast.stderr index 924de3d5bbe3..78eb25b0243d 100644 --- a/tests/ui/traits/explicit-reference-cast.stderr +++ b/tests/ui/traits/explicit-reference-cast.stderr @@ -10,14 +10,14 @@ help: the trait `From<&PathBuf>` is not implemented for `ToolA` | LL | pub struct ToolA(PathBuf); | ^^^^^^^^^^^^^^^^ -help: the following other types implement trait `From` +help: `ToolA` implements trait `From` --> $DIR/explicit-reference-cast.rs:9:1 | LL | impl From<&Path> for ToolA { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `ToolA` implements `From<&Path>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `From<&Path>` ... LL | impl From<&str> for ToolA { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ `ToolA` implements `From<&str>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `From<&str>` error[E0277]: the trait bound `ToolB: TryFrom<&PathBuf>` is not satisfied --> $DIR/explicit-reference-cast.rs:43:13 diff --git a/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr b/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr index e58f5c3fe90f..9b27491f5046 100644 --- a/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr +++ b/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr @@ -6,14 +6,14 @@ LL | c.same_as(22) | | | required by a bound introduced by this call | -help: the following other types implement trait `CompareTo` +help: `i64` implements trait `CompareTo` --> $DIR/repeated-supertrait-ambig.rs:15:1 | LL | impl CompareTo for i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `i64` implements `CompareTo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CompareTo` ... LL | impl CompareTo for i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `i64` implements `CompareTo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CompareTo` error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/repeated-supertrait-ambig.rs:30:15 @@ -34,14 +34,14 @@ error[E0277]: the trait bound `dyn CompareToInts: CompareTo` is not satisfi LL | ::same_as(c, 22) | ^^^^^^^^^^^^^^^^^ the trait `CompareTo` is not implemented for `dyn CompareToInts` | -help: the following other types implement trait `CompareTo` +help: `i64` implements trait `CompareTo` --> $DIR/repeated-supertrait-ambig.rs:15:1 | LL | impl CompareTo for i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `i64` implements `CompareTo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CompareTo` ... LL | impl CompareTo for i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `i64` implements `CompareTo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CompareTo` error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/repeated-supertrait-ambig.rs:38:24 @@ -64,14 +64,14 @@ LL | assert_eq!(22_i64.same_as(22), true); | | | required by a bound introduced by this call | -help: the following other types implement trait `CompareTo` +help: `i64` implements trait `CompareTo` --> $DIR/repeated-supertrait-ambig.rs:15:1 | LL | impl CompareTo for i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `i64` implements `CompareTo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CompareTo` ... LL | impl CompareTo for i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `i64` implements `CompareTo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CompareTo` error: aborting due to 5 previous errors diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/traits/inherited-copy-bound.rs similarity index 75% rename from tests/ui/kindck/kindck-inherited-copy-bound.rs rename to tests/ui/traits/inherited-copy-bound.rs index 92c2b273c2c1..dd9fea3dcde3 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.rs +++ b/tests/ui/traits/inherited-copy-bound.rs @@ -1,16 +1,14 @@ // Test that Copy bounds inherited by trait are checked. - use std::any::Any; -trait Foo : Copy { +trait Foo: Copy { fn foo(&self) {} } -impl Foo for T { -} +impl Foo for T {} -fn take_param(foo: &T) { } +fn take_param(foo: &T) {} fn a() { let x: Box<_> = Box::new(3); @@ -24,4 +22,4 @@ fn b() { //~^ ERROR E0038 } -fn main() { } +fn main() {} diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.stderr b/tests/ui/traits/inherited-copy-bound.stderr similarity index 62% rename from tests/ui/kindck/kindck-inherited-copy-bound.stderr rename to tests/ui/traits/inherited-copy-bound.stderr index c15aabacddd1..c251d5922446 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.stderr +++ b/tests/ui/traits/inherited-copy-bound.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied - --> $DIR/kindck-inherited-copy-bound.rs:17:16 + --> $DIR/inherited-copy-bound.rs:15:16 | LL | take_param(&x); | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` @@ -7,30 +7,30 @@ LL | take_param(&x); | required by a bound introduced by this call | note: required for `Box<{integer}>` to implement `Foo` - --> $DIR/kindck-inherited-copy-bound.rs:10:14 + --> $DIR/inherited-copy-bound.rs:9:15 | -LL | impl Foo for T { - | ---- ^^^ ^ - | | - | unsatisfied trait bound introduced here +LL | impl Foo for T {} + | ---- ^^^ ^ + | | + | unsatisfied trait bound introduced here note: required by a bound in `take_param` - --> $DIR/kindck-inherited-copy-bound.rs:13:17 + --> $DIR/inherited-copy-bound.rs:11:18 | -LL | fn take_param(foo: &T) { } - | ^^^ required by this bound in `take_param` +LL | fn take_param(foo: &T) {} + | ^^^ required by this bound in `take_param` error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/kindck-inherited-copy-bound.rs:23:24 + --> $DIR/inherited-copy-bound.rs:21:24 | LL | let z = &x as &dyn Foo; | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/kindck-inherited-copy-bound.rs:6:13 + --> $DIR/inherited-copy-bound.rs:5:12 | -LL | trait Foo : Copy { - | --- ^^^^ ...because it requires `Self: Sized` +LL | trait Foo: Copy { + | --- ^^^^ ...because it requires `Self: Sized` | | | this trait is not dyn compatible... diff --git a/tests/ui/traits/issue-3973.rs b/tests/ui/traits/issue-3973.rs index a5ed5b87051e..96e581c169f3 100644 --- a/tests/ui/traits/issue-3973.rs +++ b/tests/ui/traits/issue-3973.rs @@ -20,6 +20,6 @@ fn to_string(&self) -> String { fn main() { let p = Point::new(0.0, 0.0); - //~^ ERROR no function or associated item named `new` found for struct `Point` + //~^ ERROR no associated function or constant named `new` found for struct `Point` println!("{}", p.to_string()); } diff --git a/tests/ui/traits/issue-3973.stderr b/tests/ui/traits/issue-3973.stderr index 87ee08049300..9da3617c05b6 100644 --- a/tests/ui/traits/issue-3973.stderr +++ b/tests/ui/traits/issue-3973.stderr @@ -7,14 +7,14 @@ LL | | Point { x: x, y: y } LL | | } | |_____^ not a member of trait `ToString_` -error[E0599]: no function or associated item named `new` found for struct `Point` in the current scope +error[E0599]: no associated function or constant named `new` found for struct `Point` in the current scope --> $DIR/issue-3973.rs:22:20 | LL | struct Point { - | ------------ function or associated item `new` not found for this struct + | ------------ associated function or constant `new` not found for this struct ... LL | let p = Point::new(0.0, 0.0); - | ^^^ function or associated item not found in `Point` + | ^^^ associated function or constant not found in `Point` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/item-privacy.rs b/tests/ui/traits/item-privacy.rs index 44ba87642371..519a95c5c785 100644 --- a/tests/ui/traits/item-privacy.rs +++ b/tests/ui/traits/item-privacy.rs @@ -77,9 +77,9 @@ fn check_method() { // Methods, UFCS // a, b, c are resolved as trait items, their traits need to be in scope S::a(&S); - //~^ ERROR no function or associated item named `a` found + //~^ ERROR no associated function or constant named `a` found S::b(&S); - //~^ ERROR no function or associated item named `b` found + //~^ ERROR no associated function or constant named `b` found S::c(&S); // OK // a, b, c are resolved as inherent items, their traits don't need to be in scope ::a(&S); //~ ERROR method `a` is private @@ -95,8 +95,8 @@ fn check_assoc_const() { // Associated constants // A, B, C are resolved as trait items, their traits need to be in scope - S::A; //~ ERROR no associated item named `A` found - S::B; //~ ERROR no associated item named `B` found + S::A; //~ ERROR no associated function or constant named `A` found + S::B; //~ ERROR no associated function or constant named `B` found S::C; // OK // A, B, C are resolved as inherent items, their traits don't need to be in scope ::A; diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index 8c33bb6de200..7b199542c961 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -47,14 +47,14 @@ LL | fn a(&self) { } LL | c.a(); | ^ private method -error[E0599]: no function or associated item named `a` found for struct `S` in the current scope +error[E0599]: no associated function or constant named `a` found for struct `S` in the current scope --> $DIR/item-privacy.rs:79:8 | LL | struct S; - | -------- function or associated item `a` not found for this struct + | -------- associated function or constant `a` not found for this struct ... LL | S::a(&S); - | ^ function or associated item not found in `S` + | ^ associated function or constant not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope = help: trait `method::A` which provides `a` is implemented but not reachable @@ -64,14 +64,14 @@ help: there is an associated constant `B` with a similar name LL | const B: u8 = 0; | ^^^^^^^^^^^ -error[E0599]: no function or associated item named `b` found for struct `S` in the current scope +error[E0599]: no associated function or constant named `b` found for struct `S` in the current scope --> $DIR/item-privacy.rs:81:8 | LL | struct S; - | -------- function or associated item `b` not found for this struct + | -------- associated function or constant `b` not found for this struct ... LL | S::b(&S); - | ^ function or associated item not found in `S` + | ^ associated function or constant not found in `S` | = help: items from traits can only be used if the trait is in scope help: there is an associated constant `B` with a similar name @@ -93,14 +93,14 @@ LL | fn a(&self) { } LL | ::a(&S); | ^ private method -error[E0599]: no associated item named `A` found for struct `S` in the current scope +error[E0599]: no associated function or constant named `A` found for struct `S` in the current scope --> $DIR/item-privacy.rs:98:8 | LL | struct S; - | -------- associated item `A` not found for this struct + | -------- associated function or constant `A` not found for this struct ... LL | S::A; - | ^ associated item not found in `S` + | ^ associated function or constant not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope = help: trait `assoc_const::A` which provides `A` is implemented but not reachable @@ -110,14 +110,14 @@ LL - S::A; LL + S::B; | -error[E0599]: no associated item named `B` found for struct `S` in the current scope +error[E0599]: no associated function or constant named `B` found for struct `S` in the current scope --> $DIR/item-privacy.rs:99:8 | LL | struct S; - | -------- associated item `B` not found for this struct + | -------- associated function or constant `B` not found for this struct ... LL | S::B; - | ^ associated item not found in `S` + | ^ associated function or constant not found in `S` | = help: items from traits can only be used if the trait is in scope help: there is a method `b` with a similar name diff --git a/tests/ui/missing-trait-bounds/auxiliary/issue-69725.rs b/tests/ui/traits/missing-trait-bounds/auxiliary/struct-69725.rs similarity index 100% rename from tests/ui/missing-trait-bounds/auxiliary/issue-69725.rs rename to tests/ui/traits/missing-trait-bounds/auxiliary/struct-69725.rs diff --git a/tests/ui/missing-trait-bounds/issue-69725.fixed b/tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.fixed similarity index 64% rename from tests/ui/missing-trait-bounds/issue-69725.fixed rename to tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.fixed index f23468abcb0a..aea046b1e771 100644 --- a/tests/ui/missing-trait-bounds/issue-69725.fixed +++ b/tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.fixed @@ -1,9 +1,9 @@ //@ run-rustfix -//@ aux-build:issue-69725.rs +//@ aux-build:struct-69725.rs #![allow(dead_code)] -extern crate issue_69725; -use issue_69725::Struct; +extern crate struct_69725; +use struct_69725::Struct; fn crash() where A: Clone { let _ = Struct::::new().clone(); diff --git a/tests/ui/missing-trait-bounds/issue-69725.rs b/tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.rs similarity index 62% rename from tests/ui/missing-trait-bounds/issue-69725.rs rename to tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.rs index a51d2540b4cc..1ea88954e001 100644 --- a/tests/ui/missing-trait-bounds/issue-69725.rs +++ b/tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.rs @@ -1,9 +1,9 @@ //@ run-rustfix -//@ aux-build:issue-69725.rs +//@ aux-build:struct-69725.rs #![allow(dead_code)] -extern crate issue_69725; -use issue_69725::Struct; +extern crate struct_69725; +use struct_69725::Struct; fn crash() { let _ = Struct::::new().clone(); diff --git a/tests/ui/missing-trait-bounds/issue-69725.stderr b/tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.stderr similarity index 54% rename from tests/ui/missing-trait-bounds/issue-69725.stderr rename to tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.stderr index 20d2213f4f5f..bed40b83bc37 100644 --- a/tests/ui/missing-trait-bounds/issue-69725.stderr +++ b/tests/ui/traits/missing-trait-bounds/derive-clone-missing-bound-69725.stderr @@ -1,17 +1,17 @@ -error[E0599]: the method `clone` exists for struct `issue_69725::Struct`, but its trait bounds were not satisfied - --> $DIR/issue-69725.rs:9:32 +error[E0599]: the method `clone` exists for struct `struct_69725::Struct`, but its trait bounds were not satisfied + --> $DIR/derive-clone-missing-bound-69725.rs:9:32 | LL | let _ = Struct::::new().clone(); - | ^^^^^ method cannot be called on `issue_69725::Struct` due to unsatisfied trait bounds + | ^^^^^ method cannot be called on `struct_69725::Struct` due to unsatisfied trait bounds | - ::: $DIR/auxiliary/issue-69725.rs:2:1 + ::: $DIR/auxiliary/struct-69725.rs:2:1 | LL | pub struct Struct(A); - | -------------------- doesn't satisfy `issue_69725::Struct: Clone` + | -------------------- doesn't satisfy `struct_69725::Struct: Clone` | = note: the following trait bounds were not satisfied: `A: Clone` - which is required by `issue_69725::Struct: Clone` + which is required by `struct_69725::Struct: Clone` help: consider restricting the type parameter to satisfy the trait bound | LL | fn crash() where A: Clone { diff --git a/tests/ui/missing-trait-bounds/issue-35677.fixed b/tests/ui/traits/missing-trait-bounds/duplicate-bounds-diagnostic-35677.fixed similarity index 100% rename from tests/ui/missing-trait-bounds/issue-35677.fixed rename to tests/ui/traits/missing-trait-bounds/duplicate-bounds-diagnostic-35677.fixed diff --git a/tests/ui/missing-trait-bounds/issue-35677.rs b/tests/ui/traits/missing-trait-bounds/duplicate-bounds-diagnostic-35677.rs similarity index 100% rename from tests/ui/missing-trait-bounds/issue-35677.rs rename to tests/ui/traits/missing-trait-bounds/duplicate-bounds-diagnostic-35677.rs diff --git a/tests/ui/missing-trait-bounds/issue-35677.stderr b/tests/ui/traits/missing-trait-bounds/duplicate-bounds-diagnostic-35677.stderr similarity index 93% rename from tests/ui/missing-trait-bounds/issue-35677.stderr rename to tests/ui/traits/missing-trait-bounds/duplicate-bounds-diagnostic-35677.stderr index 3bfdd4da6dac..778a5664c0d7 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.stderr +++ b/tests/ui/traits/missing-trait-bounds/duplicate-bounds-diagnostic-35677.stderr @@ -1,5 +1,5 @@ error[E0599]: the method `is_subset` exists for reference `&HashSet`, but its trait bounds were not satisfied - --> $DIR/issue-35677.rs:7:10 + --> $DIR/duplicate-bounds-diagnostic-35677.rs:7:10 | LL | this.is_subset(other) | ^^^^^^^^^ method cannot be called on `&HashSet` due to unsatisfied trait bounds diff --git a/tests/ui/missing-trait-bounds/missing-trait-bound-for-op.fixed b/tests/ui/traits/missing-trait-bounds/missing-trait-bound-for-op.fixed similarity index 100% rename from tests/ui/missing-trait-bounds/missing-trait-bound-for-op.fixed rename to tests/ui/traits/missing-trait-bounds/missing-trait-bound-for-op.fixed diff --git a/tests/ui/missing-trait-bounds/missing-trait-bound-for-op.rs b/tests/ui/traits/missing-trait-bounds/missing-trait-bound-for-op.rs similarity index 100% rename from tests/ui/missing-trait-bounds/missing-trait-bound-for-op.rs rename to tests/ui/traits/missing-trait-bounds/missing-trait-bound-for-op.rs diff --git a/tests/ui/missing-trait-bounds/missing-trait-bound-for-op.stderr b/tests/ui/traits/missing-trait-bounds/missing-trait-bound-for-op.stderr similarity index 100% rename from tests/ui/missing-trait-bounds/missing-trait-bound-for-op.stderr rename to tests/ui/traits/missing-trait-bounds/missing-trait-bound-for-op.stderr diff --git a/tests/ui/missing-trait-bounds/missing-trait-bounds-for-method-call.rs b/tests/ui/traits/missing-trait-bounds/missing-trait-bounds-for-method-call.rs similarity index 100% rename from tests/ui/missing-trait-bounds/missing-trait-bounds-for-method-call.rs rename to tests/ui/traits/missing-trait-bounds/missing-trait-bounds-for-method-call.rs diff --git a/tests/ui/missing-trait-bounds/missing-trait-bounds-for-method-call.stderr b/tests/ui/traits/missing-trait-bounds/missing-trait-bounds-for-method-call.stderr similarity index 100% rename from tests/ui/missing-trait-bounds/missing-trait-bounds-for-method-call.stderr rename to tests/ui/traits/missing-trait-bounds/missing-trait-bounds-for-method-call.stderr diff --git a/tests/ui/traits/negative-impls/negative-default-impls.rs b/tests/ui/traits/negative-impls/negative-default-impls.rs index c68bca432fa8..2d50bc83ec30 100644 --- a/tests/ui/traits/negative-impls/negative-default-impls.rs +++ b/tests/ui/traits/negative-impls/negative-default-impls.rs @@ -1,6 +1,5 @@ #![feature(negative_impls)] #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait MyTrait { type Foo; diff --git a/tests/ui/traits/negative-impls/negative-default-impls.stderr b/tests/ui/traits/negative-impls/negative-default-impls.stderr index 328e744a1e39..b321898907d5 100644 --- a/tests/ui/traits/negative-impls/negative-default-impls.stderr +++ b/tests/ui/traits/negative-impls/negative-default-impls.stderr @@ -1,19 +1,9 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/negative-default-impls.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0750]: negative impls cannot be default impls - --> $DIR/negative-default-impls.rs:9:1 + --> $DIR/negative-default-impls.rs:8:1 | LL | default impl !MyTrait for u32 {} | ^^^^^^^ ^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0750`. diff --git a/tests/ui/traits/negative-impls/negative-specializes-negative.rs b/tests/ui/traits/negative-impls/negative-specializes-negative.rs index bb2856ae7e7c..fe5165a12d1b 100644 --- a/tests/ui/traits/negative-impls/negative-specializes-negative.rs +++ b/tests/ui/traits/negative-impls/negative-specializes-negative.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] #![feature(negative_impls)] // Test a negative impl that "specializes" another negative impl. diff --git a/tests/ui/traits/negative-impls/negative-specializes-negative.stderr b/tests/ui/traits/negative-impls/negative-specializes-negative.stderr deleted file mode 100644 index 751e29c3b236..000000000000 --- a/tests/ui/traits/negative-impls/negative-specializes-negative.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/negative-specializes-negative.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/negative-impls/negative-specializes-positive-item.rs b/tests/ui/traits/negative-impls/negative-specializes-positive-item.rs index 4281eedaf631..da22e43377f5 100644 --- a/tests/ui/traits/negative-impls/negative-specializes-positive-item.rs +++ b/tests/ui/traits/negative-impls/negative-specializes-positive-item.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] #![feature(negative_impls)] // Negative impl for u32 cannot "specialize" the base impl. diff --git a/tests/ui/traits/negative-impls/negative-specializes-positive-item.stderr b/tests/ui/traits/negative-impls/negative-specializes-positive-item.stderr index 97727da76f26..e281969ac2e0 100644 --- a/tests/ui/traits/negative-impls/negative-specializes-positive-item.stderr +++ b/tests/ui/traits/negative-impls/negative-specializes-positive-item.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/negative-specializes-positive-item.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/negative-specializes-positive-item.rs:11:1 | @@ -17,6 +7,6 @@ LL | impl MyTrait for T { LL | impl !MyTrait for u32 {} | ^^^^^^^^^^^^^^^^^^^^^ negative implementation here -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/traits/negative-impls/negative-specializes-positive.rs b/tests/ui/traits/negative-impls/negative-specializes-positive.rs index 0e227691e040..1939a098b50e 100644 --- a/tests/ui/traits/negative-impls/negative-specializes-positive.rs +++ b/tests/ui/traits/negative-impls/negative-specializes-positive.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] #![feature(negative_impls)] // Negative impl for u32 cannot "specialize" the base impl. diff --git a/tests/ui/traits/negative-impls/negative-specializes-positive.stderr b/tests/ui/traits/negative-impls/negative-specializes-positive.stderr index 100f97aba93c..6eab4aaf20a5 100644 --- a/tests/ui/traits/negative-impls/negative-specializes-positive.stderr +++ b/tests/ui/traits/negative-impls/negative-specializes-positive.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/negative-specializes-positive.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/negative-specializes-positive.rs:7:1 | @@ -16,6 +6,6 @@ LL | impl MyTrait for T {} LL | impl !MyTrait for u32 {} | ^^^^^^^^^^^^^^^^^^^^^ negative implementation here -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/traits/negative-impls/positive-specializes-negative.rs b/tests/ui/traits/negative-impls/positive-specializes-negative.rs index a06b35765406..f2c5f507a4eb 100644 --- a/tests/ui/traits/negative-impls/positive-specializes-negative.rs +++ b/tests/ui/traits/negative-impls/positive-specializes-negative.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] #![feature(negative_impls)] trait MyTrait {} diff --git a/tests/ui/traits/negative-impls/positive-specializes-negative.stderr b/tests/ui/traits/negative-impls/positive-specializes-negative.stderr index 1655cb05019c..7c3f5f6ef5c8 100644 --- a/tests/ui/traits/negative-impls/positive-specializes-negative.stderr +++ b/tests/ui/traits/negative-impls/positive-specializes-negative.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/positive-specializes-negative.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/positive-specializes-negative.rs:7:1 | @@ -16,6 +6,6 @@ LL | impl !MyTrait for T {} LL | impl MyTrait for u32 {} | ^^^^^^^^^^^^^^^^^^^^ positive implementation here -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.rs b/tests/ui/traits/next-solver/alias-bound-unsound.rs index 7b91078c639e..b2015b336b24 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/next-solver/alias-bound-unsound.rs @@ -26,8 +26,8 @@ impl Foo for () { fn main() { let x = String::from("hello, world"); let _ = identity(<() as Foo>::copy_me(&x)); - //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed` - //~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed` + //~^ ERROR overflow evaluating whether `<() as Foo>::Item` is well-formed + //~| ERROR overflow evaluating whether `&<() as Foo>::Item` is well-formed //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == String` //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _` //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _` diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.stderr b/tests/ui/traits/next-solver/alias-bound-unsound.stderr index 3509aea717ef..ebfaf469ddf8 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/next-solver/alias-bound-unsound.stderr @@ -32,13 +32,13 @@ LL | let _ = identity(<() as Foo>::copy_me(&x)); | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed` +error[E0275]: overflow evaluating whether `&<() as Foo>::Item` is well-formed --> $DIR/alias-bound-unsound.rs:28:43 | LL | let _ = identity(<() as Foo>::copy_me(&x)); | ^^ -error[E0275]: overflow evaluating the requirement `<() as Foo>::Item well-formed` +error[E0275]: overflow evaluating whether `<() as Foo>::Item` is well-formed --> $DIR/alias-bound-unsound.rs:28:22 | LL | let _ = identity(<() as Foo>::copy_me(&x)); diff --git a/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.stderr b/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.stderr index 4bd55ee80c6b..ac427c8f0cba 100644 --- a/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.stderr +++ b/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.stderr @@ -4,7 +4,7 @@ error[E0283]: type annotations needed LL | println!("{:?}", iter::<_>()); | ^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `iter` | - = note: cannot satisfy `_: Iterator` + = note: the type must implement `Iterator` note: required by a bound in `iter` --> $DIR/runaway-impl-candidate-selection.rs:8:12 | diff --git a/tests/ui/traits/next-solver/coherence/negative-coherence-bounds.rs b/tests/ui/traits/next-solver/coherence/negative-coherence-bounds.rs index d98cd1147efe..327f731d7e91 100644 --- a/tests/ui/traits/next-solver/coherence/negative-coherence-bounds.rs +++ b/tests/ui/traits/next-solver/coherence/negative-coherence-bounds.rs @@ -10,7 +10,6 @@ // which is provided by the first impl that it is specializing. #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete #![feature(with_negative_coherence)] trait BoxIter { diff --git a/tests/ui/traits/next-solver/coherence/negative-coherence-bounds.stderr b/tests/ui/traits/next-solver/coherence/negative-coherence-bounds.stderr deleted file mode 100644 index 4127f51f56da..000000000000 --- a/tests/ui/traits/next-solver/coherence/negative-coherence-bounds.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/negative-coherence-bounds.rs:12:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/next-solver/cycles/coinduction/item-bound-via-impl-where-clause.next.stderr b/tests/ui/traits/next-solver/cycles/coinduction/item-bound-via-impl-where-clause.next.stderr index 451c1442ed29..ed6e595d0afb 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/item-bound-via-impl-where-clause.next.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/item-bound-via-impl-where-clause.next.stderr @@ -30,7 +30,7 @@ LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]); | = note: the return type of a function must have a statically known size -error[E0275]: overflow evaluating the requirement `< as Trait>::Proof as Trait>::Proof well-formed` +error[E0275]: overflow evaluating whether `< as Trait>::Proof as Trait>::Proof` is well-formed --> $DIR/item-bound-via-impl-where-clause.rs:31:21 | LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]); diff --git a/tests/ui/traits/next-solver/cycles/coinduction/item-bound-via-impl-where-clause.rs b/tests/ui/traits/next-solver/cycles/coinduction/item-bound-via-impl-where-clause.rs index 39381d17f7af..6ac0c1481c79 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/item-bound-via-impl-where-clause.rs +++ b/tests/ui/traits/next-solver/cycles/coinduction/item-bound-via-impl-where-clause.rs @@ -33,7 +33,7 @@ fn main() { //[next]~| ERROR overflow evaluating the requirement `< as Trait>::Proof as Trait>::Proof == _` //[next]~| ERROR overflow evaluating the requirement `< as Trait>::Proof as Trait>::Proof == String` //[next]~| ERROR overflow evaluating the requirement `< as Trait>::Proof as Trait>::Proof: Sized` - //[next]~| ERROR overflow evaluating the requirement `< as Trait>::Proof as Trait>::Proof well-formed` + //[next]~| ERROR overflow evaluating whether `< as Trait>::Proof as Trait>::Proof` is well-formed //[next]~| ERROR overflow evaluating the requirement `< as Trait>::Proof as Trait>::Proof == _` println!("{}", s); // ABC } diff --git a/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr index 42b76a8f7ff6..04a4c70c6d7b 100644 --- a/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr +++ b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr @@ -5,7 +5,7 @@ LL | impls_trait::>() | ^^^^^^^ cannot infer type for struct `Head<_>` | = note: cannot satisfy `Head<_>: Trait` -help: the following types implement trait `Trait` +help: `Head` implements trait `Trait` --> $DIR/forced_ambiguity-use-head-maybe-cause.rs:23:1 | LL | / impl Trait for Head diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr index 8b24e682c769..cea95eb365e6 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr @@ -21,7 +21,7 @@ help: the trait `Trait` is not implemented for `MultipleCandidates` | LL | struct MultipleCandidates; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -help: the following other types implement trait `Trait` +help: `MultipleCandidates` implements trait `Trait` --> $DIR/inductive-cycle-but-err.rs:26:1 | LL | / impl Trait for MultipleCandidates diff --git a/tests/ui/traits/next-solver/find-param-recursion-issue-152716.rs b/tests/ui/traits/next-solver/find-param-recursion-issue-152716.rs new file mode 100644 index 000000000000..648796483815 --- /dev/null +++ b/tests/ui/traits/next-solver/find-param-recursion-issue-152716.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Znext-solver + +// Regression test for . +// +// This test checks that we hit the recursion limit for recursively defined projections. +// Normalization of `>::Assoc` could introduce the same projection again. +// Previously, we get into an infinite recursion. + +trait Trait {} +trait Proj<'a> { + type Assoc; +} +fn foo() +where + T: for<'a> Proj<'a, Assoc = for<'b> fn(>::Assoc)>, + (): Trait<>::Assoc> + //~^ ERROR overflow evaluating the requirement `(): Trait<>::Assoc>` [E0275] +{ +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/find-param-recursion-issue-152716.stderr b/tests/ui/traits/next-solver/find-param-recursion-issue-152716.stderr new file mode 100644 index 000000000000..e2ee83cfadbe --- /dev/null +++ b/tests/ui/traits/next-solver/find-param-recursion-issue-152716.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow evaluating the requirement `(): Trait<>::Assoc>` + --> $DIR/find-param-recursion-issue-152716.rs:16:9 + | +LL | (): Trait<>::Assoc> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`find_param_recursion_issue_152716`) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs b/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs new file mode 100644 index 000000000000..c3942b008ccb --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs @@ -0,0 +1,25 @@ +// revisions: next old +//[next] compile-flags: -Znext-solver +//@ check-pass +// Regression test for https://github.com/rust-lang/rust/issues/154173. +// The ICE there was caused by a (flawed) attempt to eagerly normalize during generalization. +// The normalize would constrain other inference variables, which we couldn't deal with. + +trait Trait { + type Assoc; +} + +impl Trait for () { + type Assoc = u32; +} + +trait Eq {} +impl, T> Eq for (C, T, >::Assoc) {} +fn foo() +where + ((), A, A): Eq +{} + +fn main() { + foo::<_>(); +} diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs index 84e2f4c94386..7a4cd2aaa1f1 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.rs +++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs @@ -3,7 +3,6 @@ // This is a gnarly test but I don't know how to minimize it, frankly. #![feature(lazy_type_alias)] -//~^ WARN the feature `lazy_type_alias` is incomplete trait ToUnit<'a> { type Unit; diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index 74cbb5be02b3..a4c8d259406b 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -1,32 +1,23 @@ error[E0425]: cannot find type `Missing` in this scope - --> $DIR/issue-118950-root-region.rs:19:55 + --> $DIR/issue-118950-root-region.rs:18:55 | LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} | ^^^^^^^ not found in this scope -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-118950-root-region.rs:5:12 - | -LL | #![feature(lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `*const T: ToUnit<'a>` is not satisfied - --> $DIR/issue-118950-root-region.rs:14:1 + --> $DIR/issue-118950-root-region.rs:13:1 | LL | type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit; | ^^^^^^^^^^^^^^^^^ the trait `ToUnit<'a>` is not implemented for `*const T` | help: this trait has no implementations, consider adding one - --> $DIR/issue-118950-root-region.rs:8:1 + --> $DIR/issue-118950-root-region.rs:7:1 | LL | trait ToUnit<'a> { | ^^^^^^^^^^^^^^^^ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a)), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } -error: aborting due to 2 previous errors; 1 warning emitted + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a)), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index 82a5f33628e6..cb1bbd4c6171 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -27,7 +27,7 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` LL | Self::Assoc: A, | ^^^^ -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc well-formed` +error[E0275]: overflow evaluating whether `<() as A>::Assoc` is well-formed --> $DIR/normalize-param-env-2.rs:24:22 | LL | Self::Assoc: A, diff --git a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.current.stderr b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.current.stderr deleted file mode 100644 index ef636811fd57..000000000000 --- a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.current.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalize-self-type-constrains-trait-args.rs:8:12 - | -LL | #![feature(lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.next.stderr deleted file mode 100644 index ef636811fd57..000000000000 --- a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.next.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalize-self-type-constrains-trait-args.rs:8:12 - | -LL | #![feature(lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs index c2a016713463..921d753fe2a1 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs +++ b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs @@ -6,7 +6,6 @@ // This goal is also possible w/ a GAT, but lazy_type_alias // makes the behavior a bit more readable. #![feature(lazy_type_alias)] -//~^ WARN the feature `lazy_type_alias` is incomplete struct Wr(T); trait Foo {} diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs index f1447cd6a9e2..ba8b49c9c4c2 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.rs +++ b/tests/ui/traits/next-solver/specialization-transmute.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Znext-solver #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait Default { type Id; diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index 8bd290ea1970..bdc03e5e1bf9 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -1,15 +1,5 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-transmute.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types - --> $DIR/specialization-transmute.rs:14:9 + --> $DIR/specialization-transmute.rs:13:9 | LL | fn intu(&self) -> &Self::Id { | --------- expected `&::Id` because of return type @@ -20,7 +10,7 @@ LL | self found reference `&T` error[E0271]: type mismatch resolving `::Id == Option>` - --> $DIR/specialization-transmute.rs:25:50 + --> $DIR/specialization-transmute.rs:24:50 | LL | let s = transmute::>>(0); | ------------------------------------ ^ types differ @@ -28,12 +18,12 @@ LL | let s = transmute::>>(0); | required by a bound introduced by this call | note: required by a bound in `transmute` - --> $DIR/specialization-transmute.rs:18:25 + --> $DIR/specialization-transmute.rs:17:25 | LL | fn transmute, U: Copy>(t: T) -> U { | ^^^^^^ required by this bound in `transmute` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0271, E0308. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.rs b/tests/ui/traits/next-solver/specialization-unconstrained.rs index 6835c0764d6c..27f6d00111a9 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.rs +++ b/tests/ui/traits/next-solver/specialization-unconstrained.rs @@ -1,7 +1,6 @@ //@ compile-flags: -Znext-solver #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete // Do not treat the RHS of a projection-goal as an unconstrained `Certainty::Yes` response // if the impl is still further specializable. diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.stderr b/tests/ui/traits/next-solver/specialization-unconstrained.stderr index 1bcf5eddb5bc..3e3638143873 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/next-solver/specialization-unconstrained.stderr @@ -1,25 +1,15 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-unconstrained.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0271]: type mismatch resolving `::Id == ()` - --> $DIR/specialization-unconstrained.rs:20:12 + --> $DIR/specialization-unconstrained.rs:19:12 | LL | test::(); | ^^^ types differ | note: required by a bound in `test` - --> $DIR/specialization-unconstrained.rs:17:20 + --> $DIR/specialization-unconstrained.rs:16:20 | LL | fn test, U>() {} | ^^^^^^ required by this bound in `test` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr index 8202b6ecb5d6..ce68c2f435fa 100644 --- a/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr +++ b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr @@ -4,13 +4,13 @@ error[E0277]: the trait bound `(): Trait<1>` is not satisfied LL | needs::<1>(); | ^ the trait `Trait<1>` is not implemented for `()` | -help: the following other types implement trait `Trait` +help: `()` implements trait `Trait` --> $DIR/unevaluated-const-impl-trait-ref.rs:7:1 | LL | impl Trait<{ 1 - 1 }> for () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` implements `Trait<0>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Trait<0>` LL | impl Trait<{ 1 + 1 }> for () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` implements `Trait<2>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Trait<2>` note: required by a bound in `needs` --> $DIR/unevaluated-const-impl-trait-ref.rs:10:38 | diff --git a/tests/ui/traits/non-lifetime-via-dyn-builtin.current.stderr b/tests/ui/traits/non-lifetime-via-dyn-builtin.current.stderr deleted file mode 100644 index 5393db6b1054..000000000000 --- a/tests/ui/traits/non-lifetime-via-dyn-builtin.current.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/non-lifetime-via-dyn-builtin.rs:6:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non-lifetime-via-dyn-builtin.next.stderr b/tests/ui/traits/non-lifetime-via-dyn-builtin.next.stderr deleted file mode 100644 index 5393db6b1054..000000000000 --- a/tests/ui/traits/non-lifetime-via-dyn-builtin.next.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/non-lifetime-via-dyn-builtin.rs:6:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non-lifetime-via-dyn-builtin.rs b/tests/ui/traits/non-lifetime-via-dyn-builtin.rs index ac61f8b614c4..00bf23725eb2 100644 --- a/tests/ui/traits/non-lifetime-via-dyn-builtin.rs +++ b/tests/ui/traits/non-lifetime-via-dyn-builtin.rs @@ -4,7 +4,6 @@ //@ check-pass #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete and may not be safe fn trivial() where diff --git a/tests/ui/traits/non_lifetime_binders/bad-bounds.rs b/tests/ui/traits/non_lifetime_binders/bad-bounds.rs new file mode 100644 index 000000000000..4fccaf1d84f3 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/bad-bounds.rs @@ -0,0 +1,13 @@ +//@ edition: 2024 + +#![feature(non_lifetime_binders)] +#![expect(incomplete_features)] + +fn produce() -> for; //~ ERROR the name `A` is defined multiple times +}>> Trait {} //~ ERROR cannot find trait `Trait` in this scope + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/bad-bounds.stderr b/tests/ui/traits/non_lifetime_binders/bad-bounds.stderr new file mode 100644 index 000000000000..ffc238c3f343 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/bad-bounds.stderr @@ -0,0 +1,46 @@ +error[E0428]: the name `A` is defined multiple times + --> $DIR/bad-bounds.rs:10:5 + | +LL | enum A {} + | ------ previous definition of the type `A` here +LL | struct A; + | ^^^^^^^^^^^^ `A` redefined here + | + = note: `A` must be defined only once in the type namespace of this block + +error[E0404]: expected trait, found type parameter `A` + --> $DIR/bad-bounds.rs:6:24 + | +LL | fn produce() -> for; +LL | | }>> Trait {} + | |__^ not a trait + +error[E0405]: cannot find trait `Trait` in this scope + --> $DIR/bad-bounds.rs:11:5 + | +LL | }>> Trait {} + | ^^^^^ not found in this scope + +error: bounds cannot be used in this context + --> $DIR/bad-bounds.rs:6:24 + | +LL | fn produce() -> for; +LL | | }>> Trait {} + | |__^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0404, E0405, E0428. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/traits/non_lifetime_binders/bad-copy-cond.rs b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.rs index 506cad25f630..9d792ad575e4 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-copy-cond.rs +++ b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.rs @@ -1,5 +1,4 @@ #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete fn foo() where for T: Copy {} diff --git a/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr index 4694e7da500f..f77d562dbcf2 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr +++ b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr @@ -1,24 +1,15 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-copy-cond.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/bad-copy-cond.rs:7:5 + --> $DIR/bad-copy-cond.rs:6:5 | LL | foo(); | ^^^^^ the trait `Copy` is not implemented for `T` | note: required by a bound in `foo` - --> $DIR/bad-copy-cond.rs:4:26 + --> $DIR/bad-copy-cond.rs:3:26 | LL | fn foo() where for T: Copy {} | ^^^^ required by this bound in `foo` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.rs b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.rs index dfc800c8e7e1..244ac2f9c005 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.rs +++ b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.rs @@ -1,5 +1,4 @@ #![feature(non_lifetime_binders)] -//~^ WARN is incomplete and may not be safe pub fn foo() where diff --git a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr index f4deb169516c..0b3aa5c904f9 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr +++ b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr @@ -1,21 +1,12 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-sized-cond.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the size for values of type `V` cannot be known at compilation time - --> $DIR/bad-sized-cond.rs:17:5 + --> $DIR/bad-sized-cond.rs:16:5 | LL | foo(); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `V` note: required by a bound in `foo` - --> $DIR/bad-sized-cond.rs:6:15 + --> $DIR/bad-sized-cond.rs:5:15 | LL | pub fn foo() | --- required by a bound in this function @@ -24,7 +15,7 @@ LL | for V: Sized, | ^^^^^ required by this bound in `foo` error[E0277]: `V` is not an iterator - --> $DIR/bad-sized-cond.rs:20:5 + --> $DIR/bad-sized-cond.rs:19:5 | LL | bar(); | ^^^^^ `V` is not an iterator @@ -32,7 +23,7 @@ LL | bar(); = help: the trait `Iterator` is not implemented for `V` = note: required for `V` to implement `IntoIterator` note: required by a bound in `bar` - --> $DIR/bad-sized-cond.rs:12:15 + --> $DIR/bad-sized-cond.rs:11:15 | LL | pub fn bar() | --- required by a bound in this function @@ -41,7 +32,7 @@ LL | for V: IntoIterator, | ^^^^^^^^^^^^ required by this bound in `bar` error[E0277]: the size for values of type `V` cannot be known at compilation time - --> $DIR/bad-sized-cond.rs:20:5 + --> $DIR/bad-sized-cond.rs:19:5 | LL | bar(); | ^^^^^ doesn't have a size known at compile-time @@ -49,7 +40,7 @@ LL | bar(); = help: the trait `Sized` is not implemented for `V` = note: required for `V` to implement `IntoIterator` note: required by a bound in `bar` - --> $DIR/bad-sized-cond.rs:12:15 + --> $DIR/bad-sized-cond.rs:11:15 | LL | pub fn bar() | --- required by a bound in this function @@ -57,6 +48,6 @@ LL | where LL | for V: IntoIterator, | ^^^^^^^^^^^^ required by this bound in `bar` -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs index b61a21eab419..8ad2ecf8271a 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs +++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs @@ -1,7 +1,5 @@ #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete // Test for , // which originally relied on associated_type_bounds, but was diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr index e891df3f0c09..0f0d2af50ba8 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr +++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr @@ -1,40 +1,23 @@ error: late-bound const parameters cannot be used currently - --> $DIR/bad-suggestion-on-missing-assoc.rs:20:15 + --> $DIR/bad-suggestion-on-missing-assoc.rs:18:15 | LL | for T: TraitA>, | ^ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-suggestion-on-missing-assoc.rs:1:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-suggestion-on-missing-assoc.rs:3:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - error: defaults for generic parameters are not allowed in `for<...>` binders - --> $DIR/bad-suggestion-on-missing-assoc.rs:20:9 + --> $DIR/bad-suggestion-on-missing-assoc.rs:18:9 | LL | for T: TraitA>, | ^^^^^^^^^^^^^^^^^^^^^^ error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/bad-suggestion-on-missing-assoc.rs:20:49 + --> $DIR/bad-suggestion-on-missing-assoc.rs:18:49 | LL | for T: TraitA>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error: aborting due to 3 previous errors; 2 warnings emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/traits/non_lifetime_binders/basic.rs b/tests/ui/traits/non_lifetime_binders/basic.rs index 09c0244ec954..893bfd87715f 100644 --- a/tests/ui/traits/non_lifetime_binders/basic.rs +++ b/tests/ui/traits/non_lifetime_binders/basic.rs @@ -3,7 +3,6 @@ #![feature(sized_hierarchy)] #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete use std::marker::PointeeSized; diff --git a/tests/ui/traits/non_lifetime_binders/basic.stderr b/tests/ui/traits/non_lifetime_binders/basic.stderr deleted file mode 100644 index 9f2df2238d15..000000000000 --- a/tests/ui/traits/non_lifetime_binders/basic.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/basic.rs:5:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs index 13f9f196970c..894f11ce5faf 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs @@ -1,5 +1,4 @@ #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete pub fn bar() where diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr index 608e8136d2a8..7383a554bcf3 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find type `V` in this scope - --> $DIR/binder-defaults-112547.rs:10:4 + --> $DIR/binder-defaults-112547.rs:9:4 | LL | }> V: IntoIterator | ^ not found in this scope @@ -10,22 +10,13 @@ LL | pub fn bar() | +++ error: late-bound const parameters cannot be used currently - --> $DIR/binder-defaults-112547.rs:6:15 + --> $DIR/binder-defaults-112547.rs:5:15 | LL | for $DIR/binder-defaults-112547.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error: defaults for generic parameters are not allowed in `for<...>` binders - --> $DIR/binder-defaults-112547.rs:6:9 + --> $DIR/binder-defaults-112547.rs:5:9 | LL | for V: IntoIterator | |_^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs index bdfe41ca11b0..509bdfc0821b 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs @@ -1,6 +1,4 @@ #![feature(non_lifetime_binders, generic_const_exprs)] -//~^ WARN the feature `non_lifetime_binders` is incomplete -//~| WARN the feature `generic_const_exprs` is incomplete fn fun() where diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr index 947dd3a73bf1..4fb7c26fc266 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr @@ -1,37 +1,20 @@ error: late-bound const parameters cannot be used currently - --> $DIR/binder-defaults-119489.rs:7:23 + --> $DIR/binder-defaults-119489.rs:5:23 | LL | for ():, | ^ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/binder-defaults-119489.rs:1:12 - | -LL | #![feature(non_lifetime_binders, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/binder-defaults-119489.rs:1:34 - | -LL | #![feature(non_lifetime_binders, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - error: defaults for generic parameters are not allowed in `for<...>` binders - --> $DIR/binder-defaults-119489.rs:7:9 + --> $DIR/binder-defaults-119489.rs:5:9 | LL | for ():, | ^^^^^^ error: defaults for generic parameters are not allowed in `for<...>` binders - --> $DIR/binder-defaults-119489.rs:7:17 + --> $DIR/binder-defaults-119489.rs:5:17 | LL | for ():, | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 2 warnings emitted +error: aborting due to 3 previous errors diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs index 22044c2e6627..a2a926e2c27d 100644 --- a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs +++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs @@ -3,7 +3,6 @@ #![feature(sized_hierarchy)] #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete use std::marker::PointeeSized; diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr index 8270fbeef0f6..0277abf52d35 100644 --- a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr +++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr @@ -1,31 +1,22 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/diagnostic-hir-wf-check.rs:5:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `(): B` is not satisfied - --> $DIR/diagnostic-hir-wf-check.rs:16:12 + --> $DIR/diagnostic-hir-wf-check.rs:15:12 | LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } | ^^^^^ the trait `B` is not implemented for `()` | help: this trait has no implementations, consider adding one - --> $DIR/diagnostic-hir-wf-check.rs:13:1 + --> $DIR/diagnostic-hir-wf-check.rs:12:1 | LL | trait B {} | ^^^^^^^ note: required by a bound in `W` - --> $DIR/diagnostic-hir-wf-check.rs:14:13 + --> $DIR/diagnostic-hir-wf-check.rs:13:13 | LL | struct W(T); | ^ required by this bound in `W` error[E0277]: the trait bound `(): B` is not satisfied - --> $DIR/diagnostic-hir-wf-check.rs:16:42 + --> $DIR/diagnostic-hir-wf-check.rs:15:42 | LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } | - ^^ the trait `B` is not implemented for `()` @@ -33,33 +24,33 @@ LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/diagnostic-hir-wf-check.rs:13:1 + --> $DIR/diagnostic-hir-wf-check.rs:12:1 | LL | trait B {} | ^^^^^^^ note: required by a bound in `W` - --> $DIR/diagnostic-hir-wf-check.rs:14:13 + --> $DIR/diagnostic-hir-wf-check.rs:13:13 | LL | struct W(T); | ^ required by this bound in `W` error[E0277]: the trait bound `(): B` is not satisfied - --> $DIR/diagnostic-hir-wf-check.rs:16:40 + --> $DIR/diagnostic-hir-wf-check.rs:15:40 | LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } | ^^^^^ the trait `B` is not implemented for `()` | help: this trait has no implementations, consider adding one - --> $DIR/diagnostic-hir-wf-check.rs:13:1 + --> $DIR/diagnostic-hir-wf-check.rs:12:1 | LL | trait B {} | ^^^^^^^ note: required by a bound in `W` - --> $DIR/diagnostic-hir-wf-check.rs:14:13 + --> $DIR/diagnostic-hir-wf-check.rs:13:13 | LL | struct W(T); | ^ required by this bound in `W` -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr index 1f13207e33ca..9a4d36a02f31 100644 --- a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr +++ b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr @@ -1,24 +1,15 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/drop-impl-pred.rs:6:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0367]: `Drop` impl requires `H: Foo` but the struct it is implemented for does not - --> $DIR/drop-impl-pred.rs:19:15 + --> $DIR/drop-impl-pred.rs:18:15 | LL | for H: Foo, | ^^^ | note: the implementor must specify the same requirement - --> $DIR/drop-impl-pred.rs:12:1 + --> $DIR/drop-impl-pred.rs:11:1 | LL | struct Bar(T) where T: Foo; | ^^^^^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0367`. diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs index db8f3de2149d..3444f1067283 100644 --- a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs +++ b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs @@ -4,7 +4,6 @@ // Issue 110557 #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete pub trait Foo {} diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr deleted file mode 100644 index 165cf2ee13da..000000000000 --- a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/drop-impl-pred.rs:6:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/fail.rs b/tests/ui/traits/non_lifetime_binders/fail.rs index 460f68907e88..7d916c422756 100644 --- a/tests/ui/traits/non_lifetime_binders/fail.rs +++ b/tests/ui/traits/non_lifetime_binders/fail.rs @@ -1,7 +1,6 @@ // Error reporting for where `for T: Trait` doesn't hold #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete trait Trait {} diff --git a/tests/ui/traits/non_lifetime_binders/fail.stderr b/tests/ui/traits/non_lifetime_binders/fail.stderr index 9a324c952931..38a0eabddd3b 100644 --- a/tests/ui/traits/non_lifetime_binders/fail.stderr +++ b/tests/ui/traits/non_lifetime_binders/fail.stderr @@ -1,25 +1,16 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/fail.rs:3:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/fail.rs:19:5 + --> $DIR/fail.rs:18:5 | LL | fail(); | ^^^^^^ the trait `Trait` is not implemented for `T` | help: this trait has no implementations, consider adding one - --> $DIR/fail.rs:6:1 + --> $DIR/fail.rs:5:1 | LL | trait Trait {} | ^^^^^^^^^^^ note: required by a bound in `fail` - --> $DIR/fail.rs:10:15 + --> $DIR/fail.rs:9:15 | LL | fn fail() | ---- required by a bound in this function @@ -28,14 +19,14 @@ LL | for T: Trait, | ^^^^^ required by this bound in `fail` error[E0277]: `T` cannot be sent between threads safely - --> $DIR/fail.rs:21:5 + --> $DIR/fail.rs:20:5 | LL | auto_trait(); | ^^^^^^^^^^^^ `T` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `T` note: required by a bound in `auto_trait` - --> $DIR/fail.rs:15:15 + --> $DIR/fail.rs:14:15 | LL | fn auto_trait() | ---------- required by a bound in this function @@ -43,6 +34,6 @@ LL | where LL | for T: Send, | ^^^^ required by this bound in `auto_trait` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs index 96a7424f0dc9..0c4347b2e4b3 100644 --- a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs @@ -1,5 +1,4 @@ #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete fn auto_trait() where diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr index abbdecf2fe1d..b621f5c612de 100644 --- a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr @@ -1,21 +1,12 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/foreach-partial-eq.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: can't compare `T` with `T` - --> $DIR/foreach-partial-eq.rs:10:5 + --> $DIR/foreach-partial-eq.rs:9:5 | LL | auto_trait(); | ^^^^^^^^^^^^ no implementation for `T < T` and `T > T` | = help: the trait `PartialOrd` is not implemented for `T` note: required by a bound in `auto_trait` - --> $DIR/foreach-partial-eq.rs:6:27 + --> $DIR/foreach-partial-eq.rs:5:27 | LL | fn auto_trait() | ---------- required by a bound in this function @@ -23,6 +14,6 @@ LL | where LL | for T: PartialEq + PartialOrd, | ^^^^^^^^^^ required by this bound in `auto_trait` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs index 94733f88c2da..e8b7139e82ea 100644 --- a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs +++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs @@ -1,6 +1,4 @@ #![feature(non_lifetime_binders, generic_const_exprs)] -//~^ WARN the feature `non_lifetime_binders` is incomplete -//~| WARN the feature `generic_const_exprs` is incomplete fn foo() -> usize where diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr index cc482887c814..cd8bc33ec313 100644 --- a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr +++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr @@ -1,27 +1,10 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/late-bound-in-anon-ct.rs:1:12 - | -LL | #![feature(non_lifetime_binders, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/late-bound-in-anon-ct.rs:1:34 - | -LL | #![feature(non_lifetime_binders, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - error: cannot capture late-bound type parameter in constant - --> $DIR/late-bound-in-anon-ct.rs:7:27 + --> $DIR/late-bound-in-anon-ct.rs:5:27 | LL | for [i32; { let _: T = todo!(); 0 }]:, | - ^ | | | parameter defined here -error: aborting due to 1 previous error; 2 warnings emitted +error: aborting due to 1 previous error diff --git a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs index 2d44388f875f..75117e10bc98 100644 --- a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs +++ b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs @@ -1,5 +1,4 @@ #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete fn b() where diff --git a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr index 136d533a03c4..98558dc74dc2 100644 --- a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr +++ b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr @@ -1,17 +1,8 @@ error: late-bound const parameters cannot be used currently - --> $DIR/late-const-param-wf.rs:6:15 + --> $DIR/late-const-param-wf.rs:5:15 | LL | for [(); C]: Copy, | ^ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/late-const-param-wf.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/traits/non_lifetime_binders/method-probe.rs b/tests/ui/traits/non_lifetime_binders/method-probe.rs index 5f8e31446f52..3d162524e950 100644 --- a/tests/ui/traits/non_lifetime_binders/method-probe.rs +++ b/tests/ui/traits/non_lifetime_binders/method-probe.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete trait Foo: for Bar {} diff --git a/tests/ui/traits/non_lifetime_binders/method-probe.stderr b/tests/ui/traits/non_lifetime_binders/method-probe.stderr deleted file mode 100644 index 8f61792e6ce7..000000000000 --- a/tests/ui/traits/non_lifetime_binders/method-probe.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/method-probe.rs:3:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs index 50f0152e904f..1e645f3e32d2 100644 --- a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs +++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs @@ -1,5 +1,4 @@ #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete fn f() where diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr index 02295307cb22..4de30e77d46b 100644 --- a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr +++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr @@ -1,14 +1,5 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/missing-assoc-item.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0223]: ambiguous associated type - --> $DIR/missing-assoc-item.rs:6:12 + --> $DIR/missing-assoc-item.rs:5:12 | LL | for B::Item: Send, | ^^^^^^^ @@ -19,6 +10,6 @@ LL - for B::Item: Send, LL + for ::Item: Send, | -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/traits/non_lifetime_binders/nested-apit-mentioning-outer-bound-var.rs b/tests/ui/traits/non_lifetime_binders/nested-apit-mentioning-outer-bound-var.rs index e9ae00df7a09..e5ab8d6bc638 100644 --- a/tests/ui/traits/non_lifetime_binders/nested-apit-mentioning-outer-bound-var.rs +++ b/tests/ui/traits/non_lifetime_binders/nested-apit-mentioning-outer-bound-var.rs @@ -1,5 +1,4 @@ #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete trait Trait { type Assoc; diff --git a/tests/ui/traits/non_lifetime_binders/nested-apit-mentioning-outer-bound-var.stderr b/tests/ui/traits/non_lifetime_binders/nested-apit-mentioning-outer-bound-var.stderr index 830446915091..12eb6c3406c3 100644 --- a/tests/ui/traits/non_lifetime_binders/nested-apit-mentioning-outer-bound-var.stderr +++ b/tests/ui/traits/non_lifetime_binders/nested-apit-mentioning-outer-bound-var.stderr @@ -1,17 +1,8 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/nested-apit-mentioning-outer-bound-var.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` can only mention type parameters from an fn or impl - --> $DIR/nested-apit-mentioning-outer-bound-var.rs:8:52 + --> $DIR/nested-apit-mentioning-outer-bound-var.rs:7:52 | LL | fn uwu(_: impl for Trait<(), Assoc = impl Trait>) {} | - type parameter declared here ^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs new file mode 100644 index 000000000000..52f83966c6bd --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs @@ -0,0 +1,22 @@ +//@ compile-flags: --crate-type=lib + +// Regression test for + +#![feature(rustc_attrs)] +#![feature(non_lifetime_binders)] +#![allow(incomplete_features)] +#![rustc_no_implicit_bounds] + +pub trait Foo { + type Bar; +} + +pub struct Bar {} //~ ERROR cannot find trait `AutoTrait` + +pub fn f() +where + T1: for Foo>, //~ ERROR missing generics for associated type `Foo::Bar` + //~| ERROR missing generics for associated type `Foo::Bar` + T2: for Foo = T1::Bar>, +{ +} diff --git a/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr new file mode 100644 index 000000000000..c95e6c68fc6a --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr @@ -0,0 +1,43 @@ +error[E0405]: cannot find trait `AutoTrait` in this scope + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:14:20 + | +LL | pub struct Bar {} + | ^^^^^^^^^ not found in this scope + +error[E0107]: missing generics for associated type `Foo::Bar` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:18:27 + | +LL | T1: for Foo>, + | ^^^ expected 1 generic argument + | +note: associated type defined here, with 1 generic parameter: `K` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:11:10 + | +LL | type Bar; + | ^^^ - +help: add missing generic argument + | +LL | T1: for Foo = Bar>, + | +++ + +error[E0107]: missing generics for associated type `Foo::Bar` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:18:27 + | +LL | T1: for Foo>, + | ^^^ expected 1 generic argument + | +note: associated type defined here, with 1 generic parameter: `K` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:11:10 + | +LL | type Bar; + | ^^^ - + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing generic argument + | +LL | T1: for Foo = Bar>, + | +++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0405. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs index e776d5f2f21a..4ccf4dbd20f8 100644 --- a/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs +++ b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs @@ -2,6 +2,5 @@ //@ compile-flags: --crate-type=lib #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete pub fn f() where for (T, U): Copy {} diff --git a/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr deleted file mode 100644 index 667575b72d4c..000000000000 --- a/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/object-lifetime-default-for-late.rs:4:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/on-dyn.rs b/tests/ui/traits/non_lifetime_binders/on-dyn.rs index 8fb7dd27605f..a081974ca8e6 100644 --- a/tests/ui/traits/non_lifetime_binders/on-dyn.rs +++ b/tests/ui/traits/non_lifetime_binders/on-dyn.rs @@ -1,7 +1,6 @@ // Tests to make sure that we reject polymorphic dyn trait. #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete trait Test {} diff --git a/tests/ui/traits/non_lifetime_binders/on-dyn.stderr b/tests/ui/traits/non_lifetime_binders/on-dyn.stderr index 2d330f6b1433..8d7cb51c034c 100644 --- a/tests/ui/traits/non_lifetime_binders/on-dyn.stderr +++ b/tests/ui/traits/non_lifetime_binders/on-dyn.stderr @@ -1,17 +1,8 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/on-dyn.rs:3:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error: late-bound type parameter not allowed on trait object types - --> $DIR/on-dyn.rs:8:30 + --> $DIR/on-dyn.rs:7:30 | LL | fn foo() -> &'static dyn for Test { | ^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/traits/non_lifetime_binders/on-ptr.rs b/tests/ui/traits/non_lifetime_binders/on-ptr.rs index 0aaff52b6d8c..96c155a13f3b 100644 --- a/tests/ui/traits/non_lifetime_binders/on-ptr.rs +++ b/tests/ui/traits/non_lifetime_binders/on-ptr.rs @@ -1,7 +1,6 @@ // Tests to make sure that we reject polymorphic fn ptrs. #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete fn foo() -> for fn(T) { //~^ ERROR late-bound type parameter not allowed on function pointer types diff --git a/tests/ui/traits/non_lifetime_binders/on-ptr.stderr b/tests/ui/traits/non_lifetime_binders/on-ptr.stderr index fbd723a1ba6b..680df6ddd0ae 100644 --- a/tests/ui/traits/non_lifetime_binders/on-ptr.stderr +++ b/tests/ui/traits/non_lifetime_binders/on-ptr.stderr @@ -1,17 +1,8 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/on-ptr.rs:3:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error: late-bound type parameter not allowed on function pointer types - --> $DIR/on-ptr.rs:6:17 + --> $DIR/on-ptr.rs:5:17 | LL | fn foo() -> for fn(T) { | ^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/traits/non_lifetime_binders/on-rpit.rs b/tests/ui/traits/non_lifetime_binders/on-rpit.rs index 1364f63a3733..092f838945ae 100644 --- a/tests/ui/traits/non_lifetime_binders/on-rpit.rs +++ b/tests/ui/traits/non_lifetime_binders/on-rpit.rs @@ -2,7 +2,6 @@ #![feature(sized_hierarchy)] #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete use std::marker::PointeeSized; diff --git a/tests/ui/traits/non_lifetime_binders/on-rpit.stderr b/tests/ui/traits/non_lifetime_binders/on-rpit.stderr deleted file mode 100644 index c8396c385484..000000000000 --- a/tests/ui/traits/non_lifetime_binders/on-rpit.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/on-rpit.rs:4:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.bad.stderr b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.bad.stderr index d51927aaa342..f8de7c7d9ebe 100644 --- a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.bad.stderr +++ b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.bad.stderr @@ -1,14 +1,5 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/placeholders-dont-outlive-static.rs:6:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0310]: the placeholder type `T` may not live long enough - --> $DIR/placeholders-dont-outlive-static.rs:13:5 + --> $DIR/placeholders-dont-outlive-static.rs:12:5 | LL | foo(); | ^^^^^ @@ -21,6 +12,6 @@ help: consider adding an explicit lifetime bound LL | fn bad() where T: 'static { | ++++++++++++++++ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.good.stderr b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.good.stderr index bc1a19923997..cc76a8ea0c5c 100644 --- a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.good.stderr +++ b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.good.stderr @@ -1,14 +1,5 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/placeholders-dont-outlive-static.rs:6:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0310]: the placeholder type `T` may not live long enough - --> $DIR/placeholders-dont-outlive-static.rs:19:5 + --> $DIR/placeholders-dont-outlive-static.rs:18:5 | LL | foo(); | ^^^^^ @@ -21,6 +12,6 @@ help: consider adding an explicit lifetime bound LL | fn good() where for T: 'static, T: 'static { | ++++++++++++ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.rs b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.rs index 3133d6aeedce..ca39eb66ed26 100644 --- a/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.rs +++ b/tests/ui/traits/non_lifetime_binders/placeholders-dont-outlive-static.rs @@ -4,7 +4,6 @@ // `for T: 'static` doesn't imply itself when processing outlives obligations #![feature(non_lifetime_binders)] -//[bad]~^ WARN the feature `non_lifetime_binders` is incomplete fn foo() where for T: 'static {} diff --git a/tests/ui/traits/non_lifetime_binders/shadowed.rs b/tests/ui/traits/non_lifetime_binders/shadowed.rs index 1c480e3940b8..ff8d3f7ebb2f 100644 --- a/tests/ui/traits/non_lifetime_binders/shadowed.rs +++ b/tests/ui/traits/non_lifetime_binders/shadowed.rs @@ -1,5 +1,4 @@ #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete fn function() where for (): Sized {} //~^ ERROR the name `T` is already used for a generic parameter diff --git a/tests/ui/traits/non_lifetime_binders/shadowed.stderr b/tests/ui/traits/non_lifetime_binders/shadowed.stderr index 59a073aefc96..982bd93f5cf1 100644 --- a/tests/ui/traits/non_lifetime_binders/shadowed.stderr +++ b/tests/ui/traits/non_lifetime_binders/shadowed.stderr @@ -1,5 +1,5 @@ error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowed.rs:4:28 + --> $DIR/shadowed.rs:3:28 | LL | fn function() where for (): Sized {} | - ^ already used @@ -7,7 +7,7 @@ LL | fn function() where for (): Sized {} | first use of `T` error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowed.rs:7:31 + --> $DIR/shadowed.rs:6:31 | LL | struct Struct(T) where for (): Sized; | - ^ already used @@ -15,7 +15,7 @@ LL | struct Struct(T) where for (): Sized; | first use of `T` error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowed.rs:11:27 + --> $DIR/shadowed.rs:10:27 | LL | impl Struct { | - first use of `T` @@ -23,22 +23,13 @@ LL | fn method() where for (): Sized {} | ^ already used error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowed.rs:15:28 + --> $DIR/shadowed.rs:14:28 | LL | fn repeated() where for (): Sized {} | - ^ already used | | | first use of `T` -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/shadowed.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0403`. diff --git a/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.rs b/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.rs index e4c3b4d2c788..981edc722ea5 100644 --- a/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.rs +++ b/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(non_lifetime_binders)] -//~^ WARN is incomplete and may not be safe pub fn foo() where diff --git a/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.stderr b/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.stderr deleted file mode 100644 index e75d81270529..000000000000 --- a/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/sized-late-bound-issue-114872.rs:3:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs index aab5479334e4..3ef1201b523f 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs @@ -1,6 +1,5 @@ #![feature(sized_hierarchy)] #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete use std::marker::PointeeSized; diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr index b32915ff549f..f1182788a6fd 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr @@ -1,21 +1,12 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/supertrait-dyn-compatibility.rs:2:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/supertrait-dyn-compatibility.rs:22:17 + --> $DIR/supertrait-dyn-compatibility.rs:21:17 | LL | let x: &dyn Foo = &(); | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/supertrait-dyn-compatibility.rs:7:12 + --> $DIR/supertrait-dyn-compatibility.rs:6:12 | LL | trait Foo: for Bar {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables @@ -23,6 +14,6 @@ LL | trait Foo: for Bar {} | this trait is not dyn compatible... = help: only type `()` implements `Foo`; consider using it directly instead. -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr index c325718b3033..e70ff4a89107 100644 --- a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr +++ b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr @@ -1,12 +1,3 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-match-with-late-bound.rs:6:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0309]: the placeholder type `F` may not live long enough --> $DIR/type-match-with-late-bound.rs:8:32 | @@ -54,6 +45,6 @@ help: consider adding an explicit lifetime bound LL | for F: 'a, F: 'a | +++++ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.current.stderr b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.current.stderr deleted file mode 100644 index 6551253d2e9e..000000000000 --- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.current.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unifying-placeholders-in-query-response-2.rs:7:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.next.stderr b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.next.stderr deleted file mode 100644 index 6551253d2e9e..000000000000 --- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.next.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unifying-placeholders-in-query-response-2.rs:7:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs index d900bd429e6e..2962a5b4f4ba 100644 --- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs +++ b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs @@ -5,7 +5,6 @@ #![feature(sized_hierarchy)] #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete use std::marker::PointeeSized; diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.current.stderr b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.current.stderr deleted file mode 100644 index fecdc860f8e7..000000000000 --- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.current.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unifying-placeholders-in-query-response.rs:7:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.next.stderr b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.next.stderr deleted file mode 100644 index fecdc860f8e7..000000000000 --- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.next.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unifying-placeholders-in-query-response.rs:7:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs index 04e34531f4d7..caad8bf65a90 100644 --- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs +++ b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs @@ -5,7 +5,6 @@ #![feature(sized_hierarchy)] #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete use std::marker::PointeeSized; diff --git a/tests/ui/traits/non_lifetime_binders/universe-error1.rs b/tests/ui/traits/non_lifetime_binders/universe-error1.rs index b4e8e3a8aada..1c99794b6a64 100644 --- a/tests/ui/traits/non_lifetime_binders/universe-error1.rs +++ b/tests/ui/traits/non_lifetime_binders/universe-error1.rs @@ -1,6 +1,5 @@ #![feature(sized_hierarchy)] #![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete use std::marker::PointeeSized; diff --git a/tests/ui/traits/non_lifetime_binders/universe-error1.stderr b/tests/ui/traits/non_lifetime_binders/universe-error1.stderr index b997e7379e25..899378b2bce4 100644 --- a/tests/ui/traits/non_lifetime_binders/universe-error1.stderr +++ b/tests/ui/traits/non_lifetime_binders/universe-error1.stderr @@ -1,20 +1,11 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/universe-error1.rs:2:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `T: Other<_>` is not satisfied - --> $DIR/universe-error1.rs:17:11 + --> $DIR/universe-error1.rs:16:11 | LL | foo::<_>(); | ^ the trait `Other<_>` is not implemented for `T` | note: required by a bound in `foo` - --> $DIR/universe-error1.rs:14:15 + --> $DIR/universe-error1.rs:13:15 | LL | fn foo() | --- required by a bound in this function @@ -22,6 +13,6 @@ LL | where LL | for T: Other {} | ^^^^^^^^ required by this bound in `foo` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/overflow-computing-ambiguity.stderr b/tests/ui/traits/overflow-computing-ambiguity.stderr index ab59f14cb6d0..f52f2e60757c 100644 --- a/tests/ui/traits/overflow-computing-ambiguity.stderr +++ b/tests/ui/traits/overflow-computing-ambiguity.stderr @@ -4,7 +4,7 @@ error[E0283]: type annotations needed LL | hello(); | ^^^^^ cannot infer type of the type parameter `T` declared on the function `hello` | - = note: cannot satisfy `_: Hello` + = note: the type must implement `Hello` help: the following types implement trait `Hello` --> $DIR/overflow-computing-ambiguity.rs:8:1 | diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs index dfea4b93f46d..f9ca6e0ab448 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.rs +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -35,7 +35,7 @@ fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE required for `Result<(), String>` to implement `FromResidual>` - //~| HELP the following other types implement trait `From`: + //~| HELP `String` implements trait `From`: Ok(one) } diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index be3f17cfc527..3739b508a868 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -30,13 +30,13 @@ LL | .map_err(|_| ())?; | this can't be annotated with `?` because it has type `Result<_, ()>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = help: the following other types implement trait `From`: - `String` implements `From<&String>` - `String` implements `From<&mut str>` - `String` implements `From<&str>` - `String` implements `From>` - `String` implements `From>` - `String` implements `From` + = help: `String` implements trait `From`: + From<&String> + From<&mut str> + From<&str> + From> + From> + From = note: required for `Result<(), String>` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` diff --git a/tests/ui/traits/question-mark-span-144304.stderr b/tests/ui/traits/question-mark-span-144304.stderr index a412da0d235d..37452cda8a6d 100644 --- a/tests/ui/traits/question-mark-span-144304.stderr +++ b/tests/ui/traits/question-mark-span-144304.stderr @@ -9,12 +9,12 @@ LL | Err("str").map_err(|e| e)?; | this has type `Result<_, &str>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = help: the following other types implement trait `From`: - `i32` implements `From` - `i32` implements `From` - `i32` implements `From` - `i32` implements `From` - `i32` implements `From` + = help: `i32` implements trait `From`: + From + From + From + From + From error[E0277]: `?` couldn't convert the error to `i32` --> $DIR/question-mark-span-144304.rs:4:42 @@ -29,12 +29,12 @@ LL | Err("str").map_err(|e| e.to_string())?; | this has type `Result<_, &str>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = help: the following other types implement trait `From`: - `i32` implements `From` - `i32` implements `From` - `i32` implements `From` - `i32` implements `From` - `i32` implements `From` + = help: `i32` implements trait `From`: + From + From + From + From + From error: aborting due to 2 previous errors diff --git a/tests/ui/traits/self-referential-param-env-normalization.rs b/tests/ui/traits/self-referential-param-env-normalization.rs new file mode 100644 index 000000000000..a40c8cc26bd9 --- /dev/null +++ b/tests/ui/traits/self-referential-param-env-normalization.rs @@ -0,0 +1,18 @@ +//~ ERROR overflow evaluating the requirement `Self: StreamingIterator<'_>` [E0275] +// Regression test for . + +trait StreamingIterator<'a> { + type Item: 'a; +} + +impl<'b, I, T> StreamingIterator<'b> for I +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates [E0207] +where + I: IntoIterator, + T: FnMut(Self::Item, I::Item), +{ + type Item = T; + //~^ ERROR overflow evaluating the requirement `I: IntoIterator` [E0275] +} + +fn main() {} diff --git a/tests/ui/traits/self-referential-param-env-normalization.stderr b/tests/ui/traits/self-referential-param-env-normalization.stderr new file mode 100644 index 000000000000..5e9c2c92eaac --- /dev/null +++ b/tests/ui/traits/self-referential-param-env-normalization.stderr @@ -0,0 +1,42 @@ +error[E0275]: overflow evaluating the requirement `Self: StreamingIterator<'_>` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`self_referential_param_env_normalization`) +note: required for `Self` to implement `StreamingIterator<'_>` + --> $DIR/self-referential-param-env-normalization.rs:8:16 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^^^^^^^^^^^^^^^^^^^^^ ^ +... +LL | T: FnMut(Self::Item, I::Item), + | -------------------------- unsatisfied trait bound introduced here + = note: 127 redundant requirements hidden + = note: required for `Self` to implement `StreamingIterator<'a>` + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/self-referential-param-env-normalization.rs:8:13 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^ unconstrained type parameter + +error[E0275]: overflow evaluating the requirement `I: IntoIterator` + --> $DIR/self-referential-param-env-normalization.rs:14:17 + | +LL | type Item = T; + | ^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`self_referential_param_env_normalization`) +note: required for `I` to implement `StreamingIterator<'_>` + --> $DIR/self-referential-param-env-normalization.rs:8:16 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^^^^^^^^^^^^^^^^^^^^^ ^ +... +LL | T: FnMut(Self::Item, I::Item), + | -------------------------- unsatisfied trait bound introduced here + = note: 127 redundant requirements hidden + = note: required for `I` to implement `StreamingIterator<'b>` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0207, E0275. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/traits/send-trait-objects-basic.rs b/tests/ui/traits/send-trait-objects-basic.rs new file mode 100644 index 000000000000..c999d4d0f695 --- /dev/null +++ b/tests/ui/traits/send-trait-objects-basic.rs @@ -0,0 +1,55 @@ +// Test which trait objects and basic types are considered sendable, considering lifetimes. + +fn assert_send_static() {} +fn assert_send() {} + +trait Dummy {} + +fn test1<'a>() { + assert_send_static::<&'a dyn Dummy>(); + //~^ ERROR `&'a (dyn Dummy + 'a)` cannot be sent between threads safely [E0277] +} + +fn test2<'a>() { + assert_send_static::<&'a (dyn Dummy + Sync)>(); + //~^ ERROR: lifetime may not live long enough +} + +fn test3<'a>() { + assert_send_static::>(); + //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely +} + +fn test4<'a>() { + assert_send::<*mut &'a isize>(); + //~^ ERROR `*mut &'a isize` cannot be sent between threads safely +} + +fn main() { + assert_send_static::<&'static (dyn Dummy + Sync)>(); + assert_send_static::>(); + + assert_send::<&'static dyn Dummy>(); + //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277] + assert_send::>(); + //~^ ERROR `dyn Dummy` cannot be sent between threads safely + assert_send::<&'static (dyn Dummy + Sync)>(); + assert_send::>(); + + // owned content is ok + assert_send::>(); + assert_send::(); + assert_send::>(); + + // but not if it owns a bad thing + assert_send::>(); + //~^ ERROR `*mut u8` cannot be sent between threads safely + + assert_send::<*mut isize>(); + //~^ ERROR `*mut isize` cannot be sent between threads safely +} + +fn object_ref_with_static_bound_not_ok() { + assert_send::<&'static (dyn Dummy + 'static)>(); + //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277] +} diff --git a/tests/ui/traits/send-trait-objects-basic.stderr b/tests/ui/traits/send-trait-objects-basic.stderr new file mode 100644 index 000000000000..0393f7bc19df --- /dev/null +++ b/tests/ui/traits/send-trait-objects-basic.stderr @@ -0,0 +1,127 @@ +error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:9:26 + | +LL | assert_send_static::<&'a dyn Dummy>(); + | ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely + | + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` + = note: required for `&'a (dyn Dummy + 'a)` to implement `Send` +note: required by a bound in `assert_send_static` + --> $DIR/send-trait-objects-basic.rs:3:26 + | +LL | fn assert_send_static() {} + | ^^^^ required by this bound in `assert_send_static` + +error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:19:26 + | +LL | assert_send_static::>(); + | ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` + = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send` +note: required because it appears within the type `Box<(dyn Dummy + 'a)>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +note: required by a bound in `assert_send_static` + --> $DIR/send-trait-objects-basic.rs:3:26 + | +LL | fn assert_send_static() {} + | ^^^^ required by this bound in `assert_send_static` + +error[E0277]: `*mut &'a isize` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:24:19 + | +LL | assert_send::<*mut &'a isize>(); + | ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `*mut &'a isize` +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:32:19 + | +LL | assert_send::<&'static dyn Dummy>(); + | ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely + | + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `dyn Dummy` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:34:19 + | +LL | assert_send::>(); + | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `dyn Dummy` + = note: required for `std::ptr::Unique` to implement `Send` +note: required because it appears within the type `Box` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `*mut u8` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:45:19 + | +LL | assert_send::>(); + | ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `*mut u8` + = note: required for `std::ptr::Unique<*mut u8>` to implement `Send` +note: required because it appears within the type `Box<*mut u8>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `*mut isize` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:48:19 + | +LL | assert_send::<*mut isize>(); + | ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `*mut isize` +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:53:19 + | +LL | assert_send::<&'static (dyn Dummy + 'static)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely + | + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error: lifetime may not live long enough + --> $DIR/send-trait-objects-basic.rs:14:5 + | +LL | fn test2<'a>() { + | -- lifetime `'a` defined here +LL | assert_send_static::<&'a (dyn Dummy + Sync)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/suggest-remove-reference-in-where-clause.rs b/tests/ui/traits/suggest-remove-reference-in-where-clause.rs new file mode 100644 index 000000000000..8e73e04e032f --- /dev/null +++ b/tests/ui/traits/suggest-remove-reference-in-where-clause.rs @@ -0,0 +1,4 @@ +use std::borrow::Borrow; +pub const F: for<'a> fn(&'a &'static String) -> &'a str = <&'static String as Borrow>::borrow; +//~^ ERROR E0277 +fn main() {} diff --git a/tests/ui/traits/suggest-remove-reference-in-where-clause.stderr b/tests/ui/traits/suggest-remove-reference-in-where-clause.stderr new file mode 100644 index 000000000000..e7e2da92ee02 --- /dev/null +++ b/tests/ui/traits/suggest-remove-reference-in-where-clause.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&'static String: Borrow` is not satisfied + --> $DIR/suggest-remove-reference-in-where-clause.rs:2:60 + | +LL | pub const F: for<'a> fn(&'a &'static String) -> &'a str = <&'static String as Borrow>::borrow; + | ^^^^^^^^^^^^^^^ the trait `Borrow` is not implemented for `&'static String` + | +help: consider removing the leading `&`-reference + | +LL - pub const F: for<'a> fn(&'a &'static String) -> &'a str = <&'static String as Borrow>::borrow; +LL + pub const F: for<'a> fn(&'a &'static String) -> &'a str = >::borrow; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/unspecified-self-in-trait-ref.rs b/tests/ui/traits/unspecified-self-in-trait-ref.rs index f175a8e6dbdf..fbc95e0443c5 100644 --- a/tests/ui/traits/unspecified-self-in-trait-ref.rs +++ b/tests/ui/traits/unspecified-self-in-trait-ref.rs @@ -9,19 +9,19 @@ pub trait Bar { fn main() { let a = Foo::lol(); - //~^ ERROR no function or associated item named + //~^ ERROR no associated function or constant named //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition let b = Foo::<_>::lol(); - //~^ ERROR no function or associated item named + //~^ ERROR no associated function or constant named //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition let c = Bar::lol(); - //~^ ERROR no function or associated item named + //~^ ERROR no associated function or constant named //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition let d = Bar::::lol(); - //~^ ERROR no function or associated item named + //~^ ERROR no associated function or constant named //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition let e = Bar::::lol(); diff --git a/tests/ui/traits/unspecified-self-in-trait-ref.stderr b/tests/ui/traits/unspecified-self-in-trait-ref.stderr index b7d78a3284e3..e76187de81f4 100644 --- a/tests/ui/traits/unspecified-self-in-trait-ref.stderr +++ b/tests/ui/traits/unspecified-self-in-trait-ref.stderr @@ -12,11 +12,11 @@ help: if this is a dyn-compatible trait, use `dyn` LL | let a = ::lol(); | ++++ + -error[E0599]: no function or associated item named `lol` found for trait object `dyn Foo<_>` in the current scope +error[E0599]: no associated function or constant named `lol` found for trait object `dyn Foo<_>` in the current scope --> $DIR/unspecified-self-in-trait-ref.rs:11:18 | LL | let a = Foo::lol(); - | ^^^ function or associated item not found in `dyn Foo<_>` + | ^^^ associated function or constant not found in `dyn Foo<_>` warning: trait objects without an explicit `dyn` are deprecated --> $DIR/unspecified-self-in-trait-ref.rs:15:13 @@ -31,11 +31,11 @@ help: if this is a dyn-compatible trait, use `dyn` LL | let b = >::lol(); | ++++ + -error[E0599]: no function or associated item named `lol` found for trait object `dyn Foo<_>` in the current scope +error[E0599]: no associated function or constant named `lol` found for trait object `dyn Foo<_>` in the current scope --> $DIR/unspecified-self-in-trait-ref.rs:15:23 | LL | let b = Foo::<_>::lol(); - | ^^^ function or associated item not found in `dyn Foo<_>` + | ^^^ associated function or constant not found in `dyn Foo<_>` warning: trait objects without an explicit `dyn` are deprecated --> $DIR/unspecified-self-in-trait-ref.rs:19:13 @@ -50,11 +50,11 @@ help: if this is a dyn-compatible trait, use `dyn` LL | let c = ::lol(); | ++++ + -error[E0599]: no function or associated item named `lol` found for trait object `dyn Bar<_, _>` in the current scope +error[E0599]: no associated function or constant named `lol` found for trait object `dyn Bar<_, _>` in the current scope --> $DIR/unspecified-self-in-trait-ref.rs:19:18 | LL | let c = Bar::lol(); - | ^^^ function or associated item not found in `dyn Bar<_, _>` + | ^^^ associated function or constant not found in `dyn Bar<_, _>` warning: trait objects without an explicit `dyn` are deprecated --> $DIR/unspecified-self-in-trait-ref.rs:23:13 @@ -69,11 +69,11 @@ help: if this is a dyn-compatible trait, use `dyn` LL | let d = >::lol(); | ++++ + -error[E0599]: no function or associated item named `lol` found for trait object `dyn Bar` in the current scope +error[E0599]: no associated function or constant named `lol` found for trait object `dyn Bar` in the current scope --> $DIR/unspecified-self-in-trait-ref.rs:23:30 | LL | let d = Bar::::lol(); - | ^^^ function or associated item not found in `dyn Bar` + | ^^^ associated function or constant not found in `dyn Bar` warning: trait objects without an explicit `dyn` are deprecated --> $DIR/unspecified-self-in-trait-ref.rs:27:13 diff --git a/tests/ui/transmutability/arrays/issue-103783-array-length.stderr b/tests/ui/transmutability/arrays/issue-103783-array-length.stderr index 02ac40741cb7..18f6e9b4ed10 100644 --- a/tests/ui/transmutability/arrays/issue-103783-array-length.stderr +++ b/tests/ui/transmutability/arrays/issue-103783-array-length.stderr @@ -3,6 +3,8 @@ error[E0308]: mismatched types | LL | type NaughtyLenArray = [u32; 3.14159]; | ^^^^^^^ expected `usize`, found floating-point number + | + = note: array length can only be `usize` error: aborting due to 1 previous error diff --git a/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.rs b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.rs index eeb0777c8566..67e5760fb242 100644 --- a/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.rs +++ b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.rs @@ -1,6 +1,5 @@ #![feature(transmutability)] #![feature(generic_const_exprs)] -//~^ WARN the feature `generic_const_exprs` is incomplete use std::mem::{Assume, TransmuteFrom}; diff --git a/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr index 6f7e9e1bfa33..5c59fb9e175e 100644 --- a/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr +++ b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr @@ -1,26 +1,17 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/dont-assume-err-is-yes-issue-126377.rs:2:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types - --> $DIR/dont-assume-err-is-yes-issue-126377.rs:14:23 + --> $DIR/dont-assume-err-is-yes-issue-126377.rs:13:23 | LL | is_transmutable::<{}>(); | ^^ expected `bool`, found `()` error[E0277]: the trait bound `(): TransmuteFrom<(), { Assume::SAFETY }>` is not satisfied - --> $DIR/dont-assume-err-is-yes-issue-126377.rs:14:23 + --> $DIR/dont-assume-err-is-yes-issue-126377.rs:13:23 | LL | is_transmutable::<{}>(); | ^^ the nightly-only, unstable trait `TransmuteFrom<(), { Assume::SAFETY }>` is not implemented for `()` | note: required by a bound in `is_transmutable` - --> $DIR/dont-assume-err-is-yes-issue-126377.rs:9:9 + --> $DIR/dont-assume-err-is-yes-issue-126377.rs:8:9 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -28,7 +19,7 @@ LL | where LL | (): TransmuteFrom<(), { Assume::SAFETY }>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/generic-transmute-from-regression.rs b/tests/ui/transmutability/generic-transmute-from-regression.rs new file mode 100644 index 000000000000..38568243ed9d --- /dev/null +++ b/tests/ui/transmutability/generic-transmute-from-regression.rs @@ -0,0 +1,11 @@ +//! Regression test for: +#![feature(transmutability)] + +fn foo(x: T) -> U { + unsafe { + std::mem::TransmuteFrom::transmute(x) + //~^ ERROR: the trait bound `U: TransmuteFrom` is not satisfied [E0277] + } +} + +fn main() {} diff --git a/tests/ui/transmutability/generic-transmute-from-regression.stderr b/tests/ui/transmutability/generic-transmute-from-regression.stderr new file mode 100644 index 000000000000..3912aec0a9c8 --- /dev/null +++ b/tests/ui/transmutability/generic-transmute-from-regression.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `U: TransmuteFrom` is not satisfied + --> $DIR/generic-transmute-from-regression.rs:6:44 + | +LL | std::mem::TransmuteFrom::transmute(x) + | ---------------------------------- ^ the nightly-only, unstable trait `TransmuteFrom` is not implemented for `U` + | | + | required by a bound introduced by this call + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/non_scalar_alignment_value.rs b/tests/ui/transmutability/non_scalar_alignment_value.rs index 45c9e61fcfe2..3b21cdd1c84c 100644 --- a/tests/ui/transmutability/non_scalar_alignment_value.rs +++ b/tests/ui/transmutability/non_scalar_alignment_value.rs @@ -1,5 +1,4 @@ #![feature(min_generic_const_args)] -//~^ WARN the feature `min_generic_const_args` is incomplete #![feature(transmutability)] diff --git a/tests/ui/transmutability/non_scalar_alignment_value.stderr b/tests/ui/transmutability/non_scalar_alignment_value.stderr index d22c6d0b27e8..99d1852b7790 100644 --- a/tests/ui/transmutability/non_scalar_alignment_value.stderr +++ b/tests/ui/transmutability/non_scalar_alignment_value.stderr @@ -1,35 +1,26 @@ -warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/non_scalar_alignment_value.rs:1:12 - | -LL | #![feature(min_generic_const_args)] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #132980 for more information - = note: `#[warn(incomplete_features)]` on by default - error: struct expression with missing field initialiser for `alignment` - --> $DIR/non_scalar_alignment_value.rs:15:32 + --> $DIR/non_scalar_alignment_value.rs:14:32 | LL | alignment: Assume {}, | ^^^^^^^^^ error: struct expression with missing field initialiser for `lifetimes` - --> $DIR/non_scalar_alignment_value.rs:15:32 + --> $DIR/non_scalar_alignment_value.rs:14:32 | LL | alignment: Assume {}, | ^^^^^^^^^ error: struct expression with missing field initialiser for `safety` - --> $DIR/non_scalar_alignment_value.rs:15:32 + --> $DIR/non_scalar_alignment_value.rs:14:32 | LL | alignment: Assume {}, | ^^^^^^^^^ error: struct expression with missing field initialiser for `validity` - --> $DIR/non_scalar_alignment_value.rs:15:32 + --> $DIR/non_scalar_alignment_value.rs:14:32 | LL | alignment: Assume {}, | ^^^^^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors diff --git a/tests/ui/transmutability/transmute-from-const-args-ice-150457.rs b/tests/ui/transmutability/transmute-from-const-args-ice-150457.rs new file mode 100644 index 000000000000..8c1b709127b0 --- /dev/null +++ b/tests/ui/transmutability/transmute-from-const-args-ice-150457.rs @@ -0,0 +1,31 @@ +//! Ensure `TransmuteFrom` with `min_generic_const_args` doesn't ICE +//! during well-formedness checking. +//! +//! Regression test for . + +//@ check-pass + +#![feature(transmutability)] +#![feature(min_generic_const_args)] + +use std::mem::{Assume, TransmuteFrom}; + +struct W<'a>(&'a ()); + +fn test<'a>() +where + W<'a>: TransmuteFrom< + (), + { + Assume { + alignment: const { true }, + lifetimes: const { true }, + safety: const { true }, + validity: true, + } + }, + >, +{ +} + +fn main() {} diff --git a/tests/ui/try-block/try-block-homogeneous-pre-expansion.rs b/tests/ui/try-block/try-block-homogeneous-pre-expansion.rs deleted file mode 100644 index 980f97ca0672..000000000000 --- a/tests/ui/try-block/try-block-homogeneous-pre-expansion.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ check-pass -//@ edition: 2018 - -// For historical reasons this is only a warning, not an error. -// See - -fn main() { - #[cfg(false)] - try {} - //~^ warn `try` blocks are unstable - //~| warn unstable syntax can change at any point -} diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index a566800da53e..e1cc7a45e5de 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -9,16 +9,16 @@ LL | Ok(Err(123_i32)?) | this can't be annotated with `?` because it has type `Result<_, i32>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait -help: the following other types implement trait `From` +help: `u8` implements trait `From` --> $SRC_DIR/core/src/convert/num.rs:LL:COL | - = note: `u8` implements `From` + = note: `From` ::: $SRC_DIR/core/src/convert/num.rs:LL:COL | = note: in this macro invocation --> $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL | - = note: `u8` implements `From` + = note: `From` ::: $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL | = note: in this macro invocation diff --git a/tests/ui/tuple/array-diagnostics.rs b/tests/ui/tuple/array-diagnostics.rs index 1929dab07316..0a88e9cc3a51 100644 --- a/tests/ui/tuple/array-diagnostics.rs +++ b/tests/ui/tuple/array-diagnostics.rs @@ -1,7 +1,7 @@ fn main() { let _tmp = [ ("C200B40A82", 3), - ("C200B40A83", 4) //~ ERROR: expected function, found `(&'static str, {integer})` [E0618] + ("C200B40A83", 4) //~ ERROR: expected function, found `(&str, {integer})` [E0618] ("C200B40A8537", 5), ]; } diff --git a/tests/ui/tuple/array-diagnostics.stderr b/tests/ui/tuple/array-diagnostics.stderr index 629ca2b37fa5..b8f7840ea4b6 100644 --- a/tests/ui/tuple/array-diagnostics.stderr +++ b/tests/ui/tuple/array-diagnostics.stderr @@ -1,4 +1,4 @@ -error[E0618]: expected function, found `(&'static str, {integer})` +error[E0618]: expected function, found `(&str, {integer})` --> $DIR/array-diagnostics.rs:4:9 | LL | ("C200B40A83", 4) diff --git a/tests/ui/tuple/coercion-never.rs b/tests/ui/tuple/coercion-never.rs new file mode 100644 index 000000000000..3e4c4480c6f1 --- /dev/null +++ b/tests/ui/tuple/coercion-never.rs @@ -0,0 +1,16 @@ +// This test checks if tuple elements are a coercion site or not. +// Note that the code here is a degenerate case, but you can get similar effects in real code, when +// unifying match arms, for example. +// +// See also coercion-slice.rs +// +//@ check-pass + +fn main() { + let _: ((),) = (loop {},); + + ((),) = (loop {},); + + let x = (loop {},); + let _: ((),) = x; +} diff --git a/tests/ui/tuple/coercion-slice.rs b/tests/ui/tuple/coercion-slice.rs new file mode 100644 index 000000000000..250265f28ff0 --- /dev/null +++ b/tests/ui/tuple/coercion-slice.rs @@ -0,0 +1,12 @@ +// This test checks if tuple elements are a coercion site or not. +// Note that the code here is a degenerate case, but you can get similar effects in real code, when +// unifying match arms, for example. +// +// See also: coercion-never.rs + +fn main() { + let _: (&[u8],) = (&[],); + + let y = (&[],); + let _: (&[u8],) = y; //~ error: mismatched types +} diff --git a/tests/ui/tuple/coercion-slice.stderr b/tests/ui/tuple/coercion-slice.stderr new file mode 100644 index 000000000000..a8ae7db4490c --- /dev/null +++ b/tests/ui/tuple/coercion-slice.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/coercion-slice.rs:11:23 + | +LL | let _: (&[u8],) = y; + | -------- ^ expected `(&[u8],)`, found `(&[_; 0],)` + | | + | expected due to this + | + = note: expected tuple `(&[u8],)` + found tuple `(&[_; 0],)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr index d17a82194353..fc6bf3f18902 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr @@ -9,14 +9,14 @@ help: the trait `Trait` is not implemented for `Foo` | LL | struct Foo; | ^^^^^^^^^^ -help: the following other types implement trait `Trait` +help: `Foo` implements trait `Trait` --> $DIR/constrain_in_projection2.rs:18:1 | LL | impl Trait<()> for Foo { - | ^^^^^^^^^^^^^^^^^^^^^^ `Foo` implements `Trait<()>` + | ^^^^^^^^^^^^^^^^^^^^^^ `Trait<()>` ... LL | impl Trait for Foo { - | ^^^^^^^^^^^^^^^^^^^^^^^ `Foo` implements `Trait` + | ^^^^^^^^^^^^^^^^^^^^^^^ `Trait` error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/constrain_in_projection2.rs:28:13 @@ -29,14 +29,14 @@ help: the trait `Trait` is not implemented for `Foo` | LL | struct Foo; | ^^^^^^^^^^ -help: the following other types implement trait `Trait` +help: `Foo` implements trait `Trait` --> $DIR/constrain_in_projection2.rs:18:1 | LL | impl Trait<()> for Foo { - | ^^^^^^^^^^^^^^^^^^^^^^ `Foo` implements `Trait<()>` + | ^^^^^^^^^^^^^^^^^^^^^^ `Trait<()>` ... LL | impl Trait for Foo { - | ^^^^^^^^^^^^^^^^^^^^^^^ `Foo` implements `Trait` + | ^^^^^^^^^^^^^^^^^^^^^^^ `Trait` error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr index 956ce3e5936b..c5e347e59de7 100644 --- a/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr +++ b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr @@ -16,8 +16,7 @@ error[E0507]: cannot move out of a shared reference LL | with_positive(|&n| ()); | ^- | | - | data moved here - | move occurs because `n` has type `S`, which does not implement the `Copy` trait + | data moved here because `n` has type `S`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.rs b/tests/ui/type-alias-impl-trait/in-where-clause.rs index 8d5bfc48a66e..f4b788b5b680 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.rs +++ b/tests/ui/type-alias-impl-trait/in-where-clause.rs @@ -11,7 +11,6 @@ fn foo() -> Bar Bar: Send, { [0; 1 + 2] - //~^ ERROR: type annotations needed: cannot satisfy `Bar: Send` } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr index 81be8c8362e3..fcb590a961c1 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -1,19 +1,3 @@ -error[E0283]: type annotations needed: cannot satisfy `Bar: Send` - --> $DIR/in-where-clause.rs:13:9 - | -LL | [0; 1 + 2] - | ^^^^^ - | - = note: cannot satisfy `Bar: Send` -note: required by a bound in `foo` - --> $DIR/in-where-clause.rs:11:10 - | -LL | fn foo() -> Bar - | --- required by a bound in this function -LL | where -LL | Bar: Send, - | ^^^^ required by this bound in `foo` - error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}` --> $DIR/in-where-clause.rs:5:12 | @@ -77,7 +61,6 @@ LL | type Bar = impl Sized; = note: cycle used when evaluating trait selection obligation `Bar: core::marker::Send` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0283, E0391. -For more information about an error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution.current.stderr index 07e7126f8a05..660e4351d0ca 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution.current.stderr +++ b/tests/ui/type-alias-impl-trait/method_resolution.current.stderr @@ -7,8 +7,7 @@ LL | struct Bar(T); LL | self.bar() | ^^^ method not found in `Bar` | - = note: the method was found for - - `Bar` + = note: the method was found for `Bar` error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr b/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr index 4cc69daffe62..674442784ae7 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr @@ -7,13 +7,13 @@ LL | LL | () | -- return type was inferred to be `()` here | -help: the following other types implement trait `Foo` +help: `()` implements trait `Foo` --> $DIR/nested-tait-inference2.rs:14:1 | LL | impl Foo<()> for () {} - | ^^^^^^^^^^^^^^^^^^^ `()` implements `Foo<()>` + | ^^^^^^^^^^^^^^^^^^^ `Foo<()>` LL | impl Foo for () {} - | ^^^^^^^^^^^^^^^^^^^^ `()` implements `Foo` + | ^^^^^^^^^^^^^^^^^^^^ `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr index e1fdd222ee14..94cd9a312ca1 100644 --- a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr +++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr @@ -16,8 +16,7 @@ error[E0507]: cannot move out of a shared reference LL | with_positive(|&n| ()); | ^- | | - | data moved here - | move occurs because `n` has type `S`, which does not implement the `Copy` trait + | data moved here because `n` has type `S`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr index 8b5dc950afdd..dc282f30b45b 100644 --- a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr +++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr @@ -16,8 +16,7 @@ error[E0507]: cannot move out of a shared reference LL | with_positive(|&n| ()); | ^- | | - | data moved here - | move occurs because `n` has type `S`, which does not implement the `Copy` trait + | data moved here because `n` has type `S`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -31,8 +30,7 @@ error[E0507]: cannot move out of a shared reference LL | with_positive(|&a| ()); | ^- | | - | data moved here - | move occurs because `a` has type `S`, which does not implement the `Copy` trait + | data moved here because `a` has type `S`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/type-alias/lack-of-wfcheck.rs b/tests/ui/type-alias/lack-of-wfcheck.rs new file mode 100644 index 000000000000..91fbee8d3f19 --- /dev/null +++ b/tests/ui/type-alias/lack-of-wfcheck.rs @@ -0,0 +1,27 @@ +// Demonstrate that we don't check the definition site of (eager) type aliases for well-formedness. +// +// Listed below are ill-formed type system entities which we don't reject since they appear inside +// the definition of (eager) type aliases. These type aliases are intentionally not referenced from +// anywhere to prevent the eagerly expanded / instantiated aliased types from getting wfchecked +// since that's not what we're testing here. + +//@ check-pass + +type UnsatTraitBound0 = [str]; // `str: Sized` unsatisfied +type UnsatTraitBound1> = T; // `str: Sized` unsatisfied +type UnsatOutlivesBound<'a> = &'static &'a (); // `'a: 'static` unsatisfied + +type Diverging = [(); panic!()]; // `panic!()` diverging + +type DynIncompat0 = dyn Sized; // `Sized` axiomatically dyn incompatible +// issue: +type DynIncompat1 = dyn HasAssocConst; // dyn incompatible due to (non-type-level) assoc const + +// * dyn incompatible due to GAT +// * `'a: 'static`, `String: Copy` and `[u8]: Sized` unsatisfied, `loop {}` diverging +type Several<'a> = dyn HasGenericAssocType = [u8]>; + +trait HasAssocConst { const N: usize; } +trait HasGenericAssocType { type Type<'a: 'static, T: Copy, const N: usize>; } + +fn main() {} diff --git a/tests/ui/type-alias/recursive-lazy-type-alias-ice-152633.rs b/tests/ui/type-alias/recursive-lazy-type-alias-ice-152633.rs new file mode 100644 index 000000000000..4b3633653133 --- /dev/null +++ b/tests/ui/type-alias/recursive-lazy-type-alias-ice-152633.rs @@ -0,0 +1,14 @@ +//! Ensure a self-referencing lazy type alias with `min_generic_const_args` +//! doesn't ICE during normalization. +//! +//! Regression test for . + +#![feature(lazy_type_alias)] +#![feature(min_generic_const_args)] + +trait Trait { + type const ASSOC: (); +} +type Arr2 = [usize; ::ASSOC]; //~ ERROR E0275 + +fn main() {} diff --git a/tests/ui/type-alias/recursive-lazy-type-alias-ice-152633.stderr b/tests/ui/type-alias/recursive-lazy-type-alias-ice-152633.stderr new file mode 100644 index 000000000000..a8e68a05253b --- /dev/null +++ b/tests/ui/type-alias/recursive-lazy-type-alias-ice-152633.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow normalizing the type alias `Arr2` + --> $DIR/recursive-lazy-type-alias-ice-152633.rs:12:1 + | +LL | type Arr2 = [usize; ::ASSOC]; + | ^^^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-inference/panic-with-unspecified-type.stderr b/tests/ui/type-inference/panic-with-unspecified-type.stderr index cd8485f392bc..99c6e83ef322 100644 --- a/tests/ui/type-inference/panic-with-unspecified-type.stderr +++ b/tests/ui/type-inference/panic-with-unspecified-type.stderr @@ -7,7 +7,7 @@ LL | panic!(std::default::Default::default()); | | cannot infer type | required by a bound introduced by this call | - = note: cannot satisfy `_: Any` + = note: the type must implement `Any` note: required by a bound in `std::rt::begin_panic` --> $SRC_DIR/std/src/panicking.rs:LL:COL diff --git a/tests/ui/type-inference/sort_by_key.stderr b/tests/ui/type-inference/sort_by_key.stderr index 3d2e0250dd21..74d89b2459f9 100644 --- a/tests/ui/type-inference/sort_by_key.stderr +++ b/tests/ui/type-inference/sort_by_key.stderr @@ -6,7 +6,7 @@ LL | lst.sort_by_key(|&(v, _)| v.iter().sum()); | | | type must be known at this point | - = note: cannot satisfy `_: Ord` + = note: the type must implement `Ord` note: required by a bound in `slice::::sort_by_key` --> $SRC_DIR/alloc/src/slice.rs:LL:COL help: consider specifying the generic argument diff --git a/tests/ui/type/issue-103271.rs b/tests/ui/type/issue-103271.rs index 98cfaaf5cff7..e949bb10ece2 100644 --- a/tests/ui/type/issue-103271.rs +++ b/tests/ui/type/issue-103271.rs @@ -1,15 +1,15 @@ fn main() { let iter_fun = <&[u32]>::iter; - //~^ ERROR no function or associated item named `iter` found for reference `&[u32]` in the current scope [E0599] - //~| NOTE function or associated item not found in `&[u32]` + //~^ ERROR no associated function or constant named `iter` found for reference `&[u32]` in the current scope [E0599] + //~| NOTE associated function or constant not found in `&[u32]` //~| HELP the function `iter` is implemented on `[u32]` for item in iter_fun(&[1,1]) { let x: &u32 = item; assert_eq!(x, &1); } let iter_fun2 = <(&[u32])>::iter; - //~^ ERROR no function or associated item named `iter` found for reference `&[u32]` in the current scope [E0599] - //~| NOTE function or associated item not found in `&[u32]` + //~^ ERROR no associated function or constant named `iter` found for reference `&[u32]` in the current scope [E0599] + //~| NOTE associated function or constant not found in `&[u32]` //~| HELP the function `iter` is implemented on `[u32]` for item2 in iter_fun2(&[1,1]) { let x: &u32 = item2; diff --git a/tests/ui/type/issue-103271.stderr b/tests/ui/type/issue-103271.stderr index 1b84033291a5..a83b782bec52 100644 --- a/tests/ui/type/issue-103271.stderr +++ b/tests/ui/type/issue-103271.stderr @@ -1,8 +1,8 @@ -error[E0599]: no function or associated item named `iter` found for reference `&[u32]` in the current scope +error[E0599]: no associated function or constant named `iter` found for reference `&[u32]` in the current scope --> $DIR/issue-103271.rs:2:30 | LL | let iter_fun = <&[u32]>::iter; - | ^^^^ function or associated item not found in `&[u32]` + | ^^^^ associated function or constant not found in `&[u32]` | help: the function `iter` is implemented on `[u32]` | @@ -10,11 +10,11 @@ LL - let iter_fun = <&[u32]>::iter; LL + let iter_fun = <[u32]>::iter; | -error[E0599]: no function or associated item named `iter` found for reference `&[u32]` in the current scope +error[E0599]: no associated function or constant named `iter` found for reference `&[u32]` in the current scope --> $DIR/issue-103271.rs:10:33 | LL | let iter_fun2 = <(&[u32])>::iter; - | ^^^^ function or associated item not found in `&[u32]` + | ^^^^ associated function or constant not found in `&[u32]` | help: the function `iter` is implemented on `[u32]` | diff --git a/tests/ui/type/pattern_types/matching_fail.stderr b/tests/ui/type/pattern_types/matching_fail.stderr index 446180d80f24..495d73907878 100644 --- a/tests/ui/type/pattern_types/matching_fail.stderr +++ b/tests/ui/type/pattern_types/matching_fail.stderr @@ -33,10 +33,14 @@ LL | THREE => {} | | | expected integer, found `(u32) is 1..` | `THREE` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_three` | = note: expected type `{integer}` found pattern type `(u32) is 1..` +help: introduce a new binding instead + | +LL - THREE => {} +LL + other_three => {} + | error: aborting due to 3 previous errors diff --git a/tests/ui/type/pattern_types/nested.stderr b/tests/ui/type/pattern_types/nested.stderr index 7893cc849248..cb491a78945c 100644 --- a/tests/ui/type/pattern_types/nested.stderr +++ b/tests/ui/type/pattern_types/nested.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/nested.rs:10:63 | LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!(); - | ^ expected `(u32) is 1..`, found integer + | ------------------------- ^ expected `(u32) is 1..`, found integer + | | + | the pattern must match the type | = note: expected pattern type `(u32) is 1..` found type `{integer}` diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.stderr b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr index 4af92a89c445..129e4b5cdc7b 100644 --- a/tests/ui/type/pattern_types/pattern_type_mismatch.stderr +++ b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/pattern_type_mismatch.rs:8:41 | LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); - | ^^^ expected `u8`, found `char` + | -- ^^^ expected `u8`, found `char` + | | + | the pattern must match the type | help: if you meant to write a byte literal, prefix with `b` | @@ -13,7 +15,9 @@ error[E0308]: mismatched types --> $DIR/pattern_type_mismatch.rs:8:47 | LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); - | ^^^ expected `u8`, found `char` + | -- ^^^ expected `u8`, found `char` + | | + | the pattern must match the type | help: if you meant to write a byte literal, prefix with `b` | @@ -24,13 +28,17 @@ error[E0308]: mismatched types --> $DIR/pattern_type_mismatch.rs:12:43 | LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!(); - | ^ expected `char`, found `u8` + | ---- ^ expected `char`, found `u8` + | | + | the pattern must match the type error[E0308]: mismatched types --> $DIR/pattern_type_mismatch.rs:12:47 | LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!(); - | ^ expected `char`, found `u8` + | ---- ^ expected `char`, found `u8` + | | + | the pattern must match the type error: aborting due to 4 previous errors diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs index 432aacb9be3f..6c630fc2633b 100644 --- a/tests/ui/type/pattern_types/validity.rs +++ b/tests/ui/type/pattern_types/validity.rs @@ -1,14 +1,14 @@ //! Check that pattern types have their validity checked // Strip out raw byte dumps to make tests platform-independent: //@ normalize-stderr: "([[:xdigit:]]{2}\s){4,8}\s+│\s.{4,8}" -> "HEX_DUMP" - +//@ ignore-parallel-frontend different alloc ids #![feature(pattern_types, const_trait_impl, pattern_type_range_trait)] #![feature(pattern_type_macro)] use std::pat::pattern_type; const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; -//~^ ERROR: constructing invalid value: encountered 0 +//~^ ERROR: encountered 0 const BAD_UNINIT: pattern_type!(u32 is 1..) = //~^ ERROR: this operation requires initialized memory @@ -18,22 +18,22 @@ //~^ ERROR: unable to turn pointer into integer const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); -//~^ ERROR: constructing invalid value at .0: encountered 0 +//~^ ERROR: at .0, encountered 0 struct Foo(Bar); struct Bar(pattern_type!(u32 is 1..)); const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); -//~^ ERROR: constructing invalid value at .0.0: encountered 0 +//~^ ERROR: at .0.0, encountered 0 const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = //~^ ERROR: this operation requires initialized memory unsafe { std::mem::transmute(std::mem::MaybeUninit::::uninit()) }; const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; -//~^ ERROR: constructing invalid value: encountered 97, but expected something in the range 65..=89 +//~^ ERROR: encountered 97, but expected something in the range 65..=89 const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; -//~^ ERROR: constructing invalid value: encountered 0xffffffff +//~^ ERROR: encountered 0xffffffff fn main() {} diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index e19915a58a32..a4fb46cf3ed0 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type (u32) is 1..: encountered 0, but expected something greater or equal to 1 --> $DIR/validity.rs:10:1 | LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; @@ -28,7 +28,7 @@ LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(& = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type ((u32) is 1.., u32): at .0, encountered 0, but expected something greater or equal to 1 --> $DIR/validity.rs:20:1 | LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); @@ -39,7 +39,7 @@ LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem: HEX_DUMP } -error[E0080]: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 +error[E0080]: constructing invalid value of type Foo: at .0.0, encountered 0, but expected something greater or equal to 1 --> $DIR/validity.rs:26:1 | LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); @@ -60,7 +60,7 @@ LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = __ __ __ __ │ ░░░░ } -error[E0080]: constructing invalid value: encountered 97, but expected something in the range 65..=89 +error[E0080]: constructing invalid value of type (char) is 'A'..='Y': encountered 97, but expected something in the range 65..=89 --> $DIR/validity.rs:33:1 | LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; @@ -71,7 +71,7 @@ LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::tr HEX_DUMP } -error[E0080]: constructing invalid value: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) +error[E0080]: constructing invalid value of type (char) is 'A'..='Y': encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) --> $DIR/validity.rs:36:1 | LL | const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; diff --git a/tests/ui/type/type-annotation-needed.rs b/tests/ui/type/type-annotation-needed.rs index 347887f4bcfd..a063ad77742a 100644 --- a/tests/ui/type/type-annotation-needed.rs +++ b/tests/ui/type/type-annotation-needed.rs @@ -6,5 +6,5 @@ fn main() { foo(42); //~^ ERROR type annotations needed //~| NOTE cannot infer type - //~| NOTE cannot satisfy + //~| NOTE the type must implement } diff --git a/tests/ui/type/type-annotation-needed.stderr b/tests/ui/type/type-annotation-needed.stderr index 521d25537f3b..78726643a3ab 100644 --- a/tests/ui/type/type-annotation-needed.stderr +++ b/tests/ui/type/type-annotation-needed.stderr @@ -4,7 +4,7 @@ error[E0283]: type annotations needed LL | foo(42); | ^^^ cannot infer type of the type parameter `T` declared on the function `foo` | - = note: cannot satisfy `_: Into` + = note: the type must implement `Into` note: required by a bound in `foo` --> $DIR/type-annotation-needed.rs:1:11 | diff --git a/tests/ui/type/type-ascription-instead-of-initializer.stderr b/tests/ui/type/type-ascription-instead-of-initializer.stderr index 630e82d254ee..edc38b0ca7b9 100644 --- a/tests/ui/type/type-ascription-instead-of-initializer.stderr +++ b/tests/ui/type/type-ascription-instead-of-initializer.stderr @@ -5,7 +5,12 @@ LL | let x: Vec::with_capacity(10, 20); | - ^^ expected type | | | while parsing the type for `x` - | help: use `=` if you meant to assign + | +help: use `=` if you meant to assign + | +LL - let x: Vec::with_capacity(10, 20); +LL + let x = Vec::with_capacity(10, 20); + | error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/type-ascription-instead-of-initializer.rs:2:12 diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr index 53920bc9e02e..fd07d5b09aeb 100644 --- a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr @@ -112,6 +112,9 @@ LL + let x: u16 = (S {}).method(0u16); error[E0308]: arguments to this function are incorrect --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5 | +LL | fn main() { + | - this implicit `()` return type influences the call expression's return type +... LL | function(0u32, 8u8) | ^^^^^^^^ ---- --- expected `bool`, found `u8` | | diff --git a/tests/ui/typeck/auxiliary/empty-struct.rs b/tests/ui/typeck/auxiliary/empty-struct.rs new file mode 100644 index 000000000000..b9ce9de82142 --- /dev/null +++ b/tests/ui/typeck/auxiliary/empty-struct.rs @@ -0,0 +1,2 @@ +pub struct XEmpty1; +pub struct XEmpty2(); diff --git a/tests/ui/typeck/derive-sugg-arg-arity.rs b/tests/ui/typeck/derive-sugg-arg-arity.rs index 094c93a8535d..1a233e68639d 100644 --- a/tests/ui/typeck/derive-sugg-arg-arity.rs +++ b/tests/ui/typeck/derive-sugg-arg-arity.rs @@ -3,6 +3,6 @@ fn main() { match () { _ => match A::partial_cmp() {}, - //~^ ERROR the function or associated item `partial_cmp` exists for struct `A`, but its trait bounds were not satisfied + //~^ ERROR the associated function or constant `partial_cmp` exists for struct `A`, but its trait bounds were not satisfied } } diff --git a/tests/ui/typeck/derive-sugg-arg-arity.stderr b/tests/ui/typeck/derive-sugg-arg-arity.stderr index 382b324c4cc5..029d8dfdfc79 100644 --- a/tests/ui/typeck/derive-sugg-arg-arity.stderr +++ b/tests/ui/typeck/derive-sugg-arg-arity.stderr @@ -1,11 +1,11 @@ -error[E0599]: the function or associated item `partial_cmp` exists for struct `A`, but its trait bounds were not satisfied +error[E0599]: the associated function or constant `partial_cmp` exists for struct `A`, but its trait bounds were not satisfied --> $DIR/derive-sugg-arg-arity.rs:5:23 | LL | pub struct A; - | ------------ function or associated item `partial_cmp` not found for this struct because it doesn't satisfy `A: Iterator` or `A: PartialOrd<_>` + | ------------ associated function or constant `partial_cmp` not found for this struct because it doesn't satisfy `A: Iterator` or `A: PartialOrd<_>` ... LL | _ => match A::partial_cmp() {}, - | ^^^^^^^^^^^ function or associated item cannot be called on `A` due to unsatisfied trait bounds + | ^^^^^^^^^^^ associated function or constant cannot be called on `A` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `A: PartialOrd<_>` diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.rs b/tests/ui/typeck/dont-suggest-private-dependencies.rs index ee5224e2d821..23debbf4e342 100644 --- a/tests/ui/typeck/dont-suggest-private-dependencies.rs +++ b/tests/ui/typeck/dont-suggest-private-dependencies.rs @@ -31,7 +31,7 @@ fn read(&mut self, buf: &mut [u8]) -> std::io::Result { fn main() { let _ = u8::cast_from_lossy(9); - //~^ ERROR no function or associated item named `cast_from_lossy` found for type `u8` + //~^ ERROR no associated function or constant named `cast_from_lossy` found for type `u8` let _ = B::foo(); - //~^ ERROR no function or associated item named `foo` found for struct `B` + //~^ ERROR no associated function or constant named `foo` found for struct `B` } diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.stderr b/tests/ui/typeck/dont-suggest-private-dependencies.stderr index b7b14ee6b9bb..d17964cc933a 100644 --- a/tests/ui/typeck/dont-suggest-private-dependencies.stderr +++ b/tests/ui/typeck/dont-suggest-private-dependencies.stderr @@ -10,17 +10,17 @@ help: there is a method `read1` with a similar name, but with different argument LL | fn read1(&self) {} | ^^^^^^^^^^^^^^^ -error[E0599]: no function or associated item named `cast_from_lossy` found for type `u8` in the current scope +error[E0599]: no associated function or constant named `cast_from_lossy` found for type `u8` in the current scope --> $DIR/dont-suggest-private-dependencies.rs:33:17 | LL | let _ = u8::cast_from_lossy(9); - | ^^^^^^^^^^^^^^^ function or associated item not found in `u8` + | ^^^^^^^^^^^^^^^ associated function or constant not found in `u8` -error[E0599]: no function or associated item named `foo` found for struct `B` in the current scope +error[E0599]: no associated function or constant named `foo` found for struct `B` in the current scope --> $DIR/dont-suggest-private-dependencies.rs:35:16 | LL | let _ = B::foo(); - | ^^^ function or associated item not found in `B` + | ^^^ associated function or constant not found in `B` error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr index 2e140461c1d9..fe9af5a5f4f5 100644 --- a/tests/ui/typeck/issue-90101.stderr +++ b/tests/ui/typeck/issue-90101.stderr @@ -6,12 +6,12 @@ LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world") | | | required by a bound introduced by this call | - = help: the following other types implement trait `From`: - `PathBuf` implements `From<&T>` - `PathBuf` implements `From>` - `PathBuf` implements `From>` - `PathBuf` implements `From` - `PathBuf` implements `From` + = help: `PathBuf` implements trait `From`: + From<&T> + From> + From> + From + From = note: required for `Cow<'_, str>` to implement `Into` note: required by a bound in `func` --> $DIR/issue-90101.rs:3:20 diff --git a/tests/ui/typeck/struct-pattern-mismatch-37026.rs b/tests/ui/typeck/struct-pattern-mismatch-37026.rs new file mode 100644 index 000000000000..f879ef4edeaf --- /dev/null +++ b/tests/ui/typeck/struct-pattern-mismatch-37026.rs @@ -0,0 +1,8 @@ +//@ aux-build:empty-struct.rs + +extern crate empty_struct; + +fn main() { + let empty_struct::XEmpty1 = (); //~ ERROR mismatched types + let empty_struct::XEmpty2(..) = (); //~ ERROR mismatched types +} diff --git a/tests/ui/empty/issue-37026.stderr b/tests/ui/typeck/struct-pattern-mismatch-37026.stderr similarity index 64% rename from tests/ui/empty/issue-37026.stderr rename to tests/ui/typeck/struct-pattern-mismatch-37026.stderr index 75c3ab13cacc..b1b40d348210 100644 --- a/tests/ui/empty/issue-37026.stderr +++ b/tests/ui/typeck/struct-pattern-mismatch-37026.stderr @@ -1,18 +1,18 @@ error[E0308]: mismatched types - --> $DIR/issue-37026.rs:6:9 + --> $DIR/struct-pattern-mismatch-37026.rs:6:9 | -LL | let empty_struct::XEmpty2 = (); +LL | let empty_struct::XEmpty1 = (); | ^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()` | | - | expected `()`, found `XEmpty2` + | expected `()`, found `XEmpty1` error[E0308]: mismatched types - --> $DIR/issue-37026.rs:7:9 + --> $DIR/struct-pattern-mismatch-37026.rs:7:9 | -LL | let empty_struct::XEmpty6(..) = (); +LL | let empty_struct::XEmpty2(..) = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()` | | - | expected `()`, found `XEmpty6` + | expected `()`, found `XEmpty2` error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.rs b/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.rs index 3cb775e85ac6..56d46fda9842 100644 --- a/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.rs +++ b/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.rs @@ -7,5 +7,5 @@ fn main() { Bar::foo(); - //~^ ERROR: no function or associated item named `foo` found for struct `Bar` in the current scope [E0599] + //~^ ERROR: no associated function or constant named `foo` found for struct `Bar` in the current scope [E0599] } diff --git a/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.stderr b/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.stderr index 9128ee684446..7f78d2aef617 100644 --- a/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.stderr +++ b/tests/ui/typeck/suggest-trait-reexported-as-not-doc-visible.stderr @@ -1,8 +1,8 @@ -error[E0599]: no function or associated item named `foo` found for struct `Bar` in the current scope +error[E0599]: no associated function or constant named `foo` found for struct `Bar` in the current scope --> $DIR/suggest-trait-reexported-as-not-doc-visible.rs:9:10 | LL | Bar::foo(); - | ^^^ function or associated item not found in `Bar` + | ^^^ associated function or constant not found in `Bar` | = help: items from traits can only be used if the trait is in scope help: trait `Foo` which provides `foo` is implemented but not in scope; perhaps you want to import it diff --git a/tests/ui/typeck/unit-type-add-error-11771.stderr b/tests/ui/typeck/unit-type-add-error-11771.stderr index 155cc0935245..4b8f59e543fa 100644 --- a/tests/ui/typeck/unit-type-add-error-11771.stderr +++ b/tests/ui/typeck/unit-type-add-error-11771.stderr @@ -2,7 +2,9 @@ error[E0277]: cannot add `()` to `{integer}` --> $DIR/unit-type-add-error-11771.rs:5:7 | LL | 1 + - | ^ no implementation for `{integer} + ()` + | - ^ no implementation for `{integer} + ()` +LL | x + | - | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: @@ -20,7 +22,9 @@ error[E0277]: cannot add `()` to `{integer}` --> $DIR/unit-type-add-error-11771.rs:10:7 | LL | 1 + - | ^ no implementation for `{integer} + ()` + | - ^ no implementation for `{integer} + ()` +LL | x + | - | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: diff --git a/tests/ui/ufcs/bad-builder.rs b/tests/ui/ufcs/bad-builder.rs index 350c96acca08..53d174b7eaf2 100644 --- a/tests/ui/ufcs/bad-builder.rs +++ b/tests/ui/ufcs/bad-builder.rs @@ -1,6 +1,6 @@ fn hello() -> Vec { Vec::::mew() - //~^ ERROR no function or associated item named `mew` found for struct `Vec` in the current scope + //~^ ERROR no associated function or constant named `mew` found for struct `Vec` in the current scope } fn main() {} diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr index 2504a3d09253..5fae6268af47 100644 --- a/tests/ui/ufcs/bad-builder.stderr +++ b/tests/ui/ufcs/bad-builder.stderr @@ -1,8 +1,8 @@ -error[E0599]: no function or associated item named `mew` found for struct `Vec` in the current scope +error[E0599]: no associated function or constant named `mew` found for struct `Vec` in the current scope --> $DIR/bad-builder.rs:2:15 | LL | Vec::::mew() - | ^^^ function or associated item not found in `Vec` + | ^^^ associated function or constant not found in `Vec` | note: if you're trying to build a new `Vec` consider using one of the following associated functions: Vec::::new diff --git a/tests/ui/ufcs/ufcs-partially-resolved.rs b/tests/ui/ufcs/ufcs-partially-resolved.rs index 712668728c9e..ac98aef4e1de 100644 --- a/tests/ui/ufcs/ufcs-partially-resolved.rs +++ b/tests/ui/ufcs/ufcs-partially-resolved.rs @@ -35,7 +35,7 @@ fn main() { ::N::NN; //~ ERROR expected trait, found type alias `A` let _: ::Y::NN; //~ ERROR ambiguous associated type let _: ::Y::NN; //~ ERROR expected trait, found enum `E` - ::Y::NN; //~ ERROR no associated item named `NN` found for type `u16` + ::Y::NN; //~ ERROR no associated function or constant named `NN` found for type `u16` ::Y::NN; //~ ERROR expected trait, found enum `E` let _: ::NN; //~ ERROR cannot find trait `N` in trait `Tr` @@ -52,5 +52,5 @@ fn main() { let _: ::Z; //~ ERROR expected associated type, found associated function `Dr::Z` ::X; //~ ERROR expected method or associated constant, found associated type `Dr::X` let _: ::Z::N; //~ ERROR expected associated type, found associated function `Dr::Z` - ::X::N; //~ ERROR no associated item named `N` found for type `u16` + ::X::N; //~ ERROR no associated function or constant named `N` found for type `u16` } diff --git a/tests/ui/ufcs/ufcs-partially-resolved.stderr b/tests/ui/ufcs/ufcs-partially-resolved.stderr index e1df200feccf..9efadec872b3 100644 --- a/tests/ui/ufcs/ufcs-partially-resolved.stderr +++ b/tests/ui/ufcs/ufcs-partially-resolved.stderr @@ -335,17 +335,17 @@ LL - let _: ::Y::NN; LL + let _: <::Y as Example>::NN; | -error[E0599]: no associated item named `NN` found for type `u16` in the current scope +error[E0599]: no associated function or constant named `NN` found for type `u16` in the current scope --> $DIR/ufcs-partially-resolved.rs:38:20 | LL | ::Y::NN; - | ^^ associated item not found in `u16` + | ^^ associated function or constant not found in `u16` -error[E0599]: no associated item named `N` found for type `u16` in the current scope +error[E0599]: no associated function or constant named `N` found for type `u16` in the current scope --> $DIR/ufcs-partially-resolved.rs:55:20 | LL | ::X::N; - | ^ associated item not found in `u16` + | ^ associated function or constant not found in `u16` error: aborting due to 32 previous errors diff --git a/tests/ui/unsafe/access_union_field.rs b/tests/ui/union/access_union_field.rs similarity index 100% rename from tests/ui/unsafe/access_union_field.rs rename to tests/ui/union/access_union_field.rs diff --git a/tests/ui/unsafe/access_union_field.stderr b/tests/ui/union/access_union_field.stderr similarity index 100% rename from tests/ui/unsafe/access_union_field.stderr rename to tests/ui/union/access_union_field.stderr diff --git a/tests/ui/unsafe/union-assignop.rs b/tests/ui/union/union-assignop.rs similarity index 100% rename from tests/ui/unsafe/union-assignop.rs rename to tests/ui/union/union-assignop.rs diff --git a/tests/ui/unsafe/union-assignop.stderr b/tests/ui/union/union-assignop.stderr similarity index 100% rename from tests/ui/unsafe/union-assignop.stderr rename to tests/ui/union/union-assignop.stderr diff --git a/tests/ui/unsafe/union-modification.rs b/tests/ui/union/union-modification.rs similarity index 100% rename from tests/ui/unsafe/union-modification.rs rename to tests/ui/union/union-modification.rs diff --git a/tests/ui/union/union-no-derive-suggestion.rs b/tests/ui/union/union-no-derive-suggestion.rs new file mode 100644 index 000000000000..0ccbac3167f2 --- /dev/null +++ b/tests/ui/union/union-no-derive-suggestion.rs @@ -0,0 +1,37 @@ +//! Check that we do not suggest using `#[derive(...)]` for unions, +//! as some traits cannot be autoderived for them. +//@ dont-require-annotations: NOTE + +union U { //~ HELP consider annotating `U` with `#[derive(Clone)]` + //~| HELP consider annotating `U` with `#[derive(Copy)]` + //~| HELP the trait `Debug` is not implemented for `U` + //~| HELP the trait `Default` is not implemented for `U` + //~| HELP the trait `Hash` is not implemented for `U` + a: u8, +} + +fn x() {} +fn y() {} + +fn main() { + let u = U { a: 0 }; + // Debug + println!("{u:?}"); //~ ERROR `U` doesn't implement `Debug` + //~| NOTE manually `impl Debug for U` + // PartialEq + let _ = u == U { a: 0 }; //~ ERROR binary operation `==` cannot be applied to type `U` + //~| NOTE the trait `PartialEq` must be implemented + // PartialOrd + let _ = u < U { a: 1 }; //~ ERROR binary operation `<` cannot be applied to type `U` + //~| NOTE the trait `PartialOrd` must be implemented + // Default + let _: U = Default::default(); //~ ERROR the trait bound `U: Default` is not satisfied + // Hash + let mut h = std::collections::hash_map::DefaultHasher::new(); + std::hash::Hash::hash(&u, &mut h); //~ ERROR the trait bound `U: Hash` is not satisfied + + // Clone + x::(); //~ ERROR the trait bound `U: Clone` is not satisfied + // Copy + y::(); //~ ERROR the trait bound `U: Copy` is not satisfied +} diff --git a/tests/ui/union/union-no-derive-suggestion.stderr b/tests/ui/union/union-no-derive-suggestion.stderr new file mode 100644 index 000000000000..7a42b871b80d --- /dev/null +++ b/tests/ui/union/union-no-derive-suggestion.stderr @@ -0,0 +1,109 @@ +error[E0277]: `U` doesn't implement `Debug` + --> $DIR/union-no-derive-suggestion.rs:19:15 + | +LL | println!("{u:?}"); + | ^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +help: the trait `Debug` is not implemented for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ + = note: manually `impl Debug for U` + +error[E0369]: binary operation `==` cannot be applied to type `U` + --> $DIR/union-no-derive-suggestion.rs:22:15 + | +LL | let _ = u == U { a: 0 }; + | - ^^ ---------- U + | | + | U + | +note: an implementation of `PartialEq` might be missing for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ must implement `PartialEq` +note: the trait `PartialEq` must be implemented + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error[E0369]: binary operation `<` cannot be applied to type `U` + --> $DIR/union-no-derive-suggestion.rs:25:15 + | +LL | let _ = u < U { a: 1 }; + | - ^ ---------- U + | | + | U + | +note: an implementation of `PartialOrd` might be missing for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ must implement `PartialOrd` +note: the trait `PartialOrd` must be implemented + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error[E0277]: the trait bound `U: Default` is not satisfied + --> $DIR/union-no-derive-suggestion.rs:28:16 + | +LL | let _: U = Default::default(); + | ^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `Default` is not implemented for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ + +error[E0277]: the trait bound `U: Hash` is not satisfied + --> $DIR/union-no-derive-suggestion.rs:31:27 + | +LL | std::hash::Hash::hash(&u, &mut h); + | --------------------- ^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `Hash` is not implemented for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ + +error[E0277]: the trait bound `U: Clone` is not satisfied + --> $DIR/union-no-derive-suggestion.rs:34:9 + | +LL | x::(); + | ^ the trait `Clone` is not implemented for `U` + | +note: required by a bound in `x` + --> $DIR/union-no-derive-suggestion.rs:13:9 + | +LL | fn x() {} + | ^^^^^ required by this bound in `x` +help: consider annotating `U` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | union U { + | + +error[E0277]: the trait bound `U: Copy` is not satisfied + --> $DIR/union-no-derive-suggestion.rs:36:9 + | +LL | y::(); + | ^ the trait `Copy` is not implemented for `U` + | +note: required by a bound in `y` + --> $DIR/union-no-derive-suggestion.rs:14:9 + | +LL | fn y() {} + | ^^^^ required by this bound in `y` +help: consider annotating `U` with `#[derive(Copy)]` + | +LL + #[derive(Copy)] +LL | union U { + | + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/unsafe/union-pat-in-param.rs b/tests/ui/union/union-pat-in-param.rs similarity index 100% rename from tests/ui/unsafe/union-pat-in-param.rs rename to tests/ui/union/union-pat-in-param.rs diff --git a/tests/ui/unsafe/union-pat-in-param.stderr b/tests/ui/union/union-pat-in-param.stderr similarity index 100% rename from tests/ui/unsafe/union-pat-in-param.stderr rename to tests/ui/union/union-pat-in-param.stderr diff --git a/tests/ui/unsafe/union.rs b/tests/ui/union/union.rs similarity index 100% rename from tests/ui/unsafe/union.rs rename to tests/ui/union/union.rs diff --git a/tests/ui/unsafe/union.stderr b/tests/ui/union/union.stderr similarity index 100% rename from tests/ui/unsafe/union.stderr rename to tests/ui/union/union.stderr diff --git a/tests/ui/unsafe/union_access_through_block.rs b/tests/ui/union/union_access_through_block.rs similarity index 100% rename from tests/ui/unsafe/union_access_through_block.rs rename to tests/ui/union/union_access_through_block.rs diff --git a/tests/ui/unsafe/union_destructure.rs b/tests/ui/union/union_destructure.rs similarity index 100% rename from tests/ui/unsafe/union_destructure.rs rename to tests/ui/union/union_destructure.rs diff --git a/tests/ui/unsafe/union_wild_or_wild.rs b/tests/ui/union/union_wild_or_wild.rs similarity index 100% rename from tests/ui/unsafe/union_wild_or_wild.rs rename to tests/ui/union/union_wild_or_wild.rs diff --git a/tests/ui/unsafe-binders/binder-sized-crit.rs b/tests/ui/unsafe-binders/binder-sized-crit.rs index 37677c0ef69b..cda807119ef9 100644 --- a/tests/ui/unsafe-binders/binder-sized-crit.rs +++ b/tests/ui/unsafe-binders/binder-sized-crit.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(unsafe_binders)] -//~^ WARN the feature `unsafe_binders` is incomplete use std::unsafe_binder::wrap_binder; diff --git a/tests/ui/unsafe-binders/binder-sized-crit.stderr b/tests/ui/unsafe-binders/binder-sized-crit.stderr deleted file mode 100644 index 3ba6cf2ef8c1..000000000000 --- a/tests/ui/unsafe-binders/binder-sized-crit.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/binder-sized-crit.rs:3:12 - | -LL | #![feature(unsafe_binders)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130516 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/unsafe-binders/expr.rs b/tests/ui/unsafe-binders/expr.rs index d437d8f8ac07..9feb29439187 100644 --- a/tests/ui/unsafe-binders/expr.rs +++ b/tests/ui/unsafe-binders/expr.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(unsafe_binders)] -//~^ WARN the feature `unsafe_binders` is incomplete use std::unsafe_binder::{wrap_binder, unwrap_binder}; diff --git a/tests/ui/unsafe-binders/expr.stderr b/tests/ui/unsafe-binders/expr.stderr deleted file mode 100644 index 07026e18e125..000000000000 --- a/tests/ui/unsafe-binders/expr.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/expr.rs:3:12 - | -LL | #![feature(unsafe_binders)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130516 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/unsafe-binders/lifetime-resolution.rs b/tests/ui/unsafe-binders/lifetime-resolution.rs index d24315401194..9935edffaa53 100644 --- a/tests/ui/unsafe-binders/lifetime-resolution.rs +++ b/tests/ui/unsafe-binders/lifetime-resolution.rs @@ -1,5 +1,4 @@ #![feature(unsafe_binders)] -//~^ WARN the feature `unsafe_binders` is incomplete fn foo<'a>() { let good: unsafe<'b> &'a &'b (); diff --git a/tests/ui/unsafe-binders/lifetime-resolution.stderr b/tests/ui/unsafe-binders/lifetime-resolution.stderr index 69660c271bfc..2f445e9a02b4 100644 --- a/tests/ui/unsafe-binders/lifetime-resolution.stderr +++ b/tests/ui/unsafe-binders/lifetime-resolution.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'missing` - --> $DIR/lifetime-resolution.rs:7:28 + --> $DIR/lifetime-resolution.rs:6:28 | LL | let missing: unsafe<> &'missing (); | ^^^^^^^^ undeclared lifetime @@ -15,7 +15,7 @@ LL | fn foo<'missing, 'a>() { | +++++++++ error[E0401]: can't use generic parameters from outer item - --> $DIR/lifetime-resolution.rs:11:30 + --> $DIR/lifetime-resolution.rs:10:30 | LL | fn foo<'a>() { | -- lifetime parameter from outer item @@ -32,16 +32,7 @@ help: consider introducing lifetime `'a` here LL | fn inner<'a, 'b>() { | +++ -warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/lifetime-resolution.rs:1:12 - | -LL | #![feature(unsafe_binders)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130516 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0261, E0401. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/unsafe-binders/mismatch.rs b/tests/ui/unsafe-binders/mismatch.rs index 840d938cbe98..8da94ccebb73 100644 --- a/tests/ui/unsafe-binders/mismatch.rs +++ b/tests/ui/unsafe-binders/mismatch.rs @@ -1,5 +1,4 @@ #![feature(unsafe_binders)] -//~^ WARN the feature `unsafe_binders` is incomplete use std::unsafe_binder::{wrap_binder, unwrap_binder}; diff --git a/tests/ui/unsafe-binders/mismatch.stderr b/tests/ui/unsafe-binders/mismatch.stderr index f64db92eb655..5e0720feddf0 100644 --- a/tests/ui/unsafe-binders/mismatch.stderr +++ b/tests/ui/unsafe-binders/mismatch.stderr @@ -1,14 +1,5 @@ -warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/mismatch.rs:1:12 - | -LL | #![feature(unsafe_binders)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130516 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types - --> $DIR/mismatch.rs:7:46 + --> $DIR/mismatch.rs:6:46 | LL | let _: unsafe<'a> &'a i32 = wrap_binder!(&()); | ^^^ expected `&i32`, found `&()` @@ -17,7 +8,7 @@ LL | let _: unsafe<'a> &'a i32 = wrap_binder!(&()); found reference `&()` error: `wrap_binder!()` can only wrap into unsafe binder, not `i32` - --> $DIR/mismatch.rs:12:18 + --> $DIR/mismatch.rs:11:18 | LL | let _: i32 = wrap_binder!(&()); | ^^^^^^^^^^^^^^^^^ @@ -26,7 +17,7 @@ LL | let _: i32 = wrap_binder!(&()); = note: this error originates in the macro `wrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info) error: expected unsafe binder, found integer as input of `unwrap_binder!()` - --> $DIR/mismatch.rs:18:20 + --> $DIR/mismatch.rs:17:20 | LL | unwrap_binder!(y); | ^ @@ -34,7 +25,7 @@ LL | unwrap_binder!(y); = note: only an unsafe binder type can be unwrapped error[E0282]: type annotations needed - --> $DIR/mismatch.rs:23:9 + --> $DIR/mismatch.rs:22:9 | LL | let unknown = Default::default(); | ^^^^^^^ @@ -48,12 +39,12 @@ LL | let unknown: /* Type */ = Default::default(); | ++++++++++++ error[E0282]: type annotations needed - --> $DIR/mismatch.rs:29:26 + --> $DIR/mismatch.rs:28:26 | LL | let x = wrap_binder!(&42); | ^^^ cannot infer type -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 5 previous errors Some errors have detailed explanations: E0282, E0308. For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/unsafe/move-out-of-non-copy.rs b/tests/ui/unsafe-binders/move-out-of-non-copy.rs similarity index 100% rename from tests/ui/unsafe/move-out-of-non-copy.rs rename to tests/ui/unsafe-binders/move-out-of-non-copy.rs diff --git a/tests/ui/unsafe/move-out-of-non-copy.stderr b/tests/ui/unsafe-binders/move-out-of-non-copy.stderr similarity index 100% rename from tests/ui/unsafe/move-out-of-non-copy.stderr rename to tests/ui/unsafe-binders/move-out-of-non-copy.stderr diff --git a/tests/ui/unsafe-binders/moves.rs b/tests/ui/unsafe-binders/moves.rs index 9397c2bc20f9..df2cb2265e66 100644 --- a/tests/ui/unsafe-binders/moves.rs +++ b/tests/ui/unsafe-binders/moves.rs @@ -1,5 +1,4 @@ #![feature(unsafe_binders)] -//~^ WARN the feature `unsafe_binders` is incomplete use std::mem::{ManuallyDrop, drop}; use std::unsafe_binder::{unwrap_binder, wrap_binder}; diff --git a/tests/ui/unsafe-binders/moves.stderr b/tests/ui/unsafe-binders/moves.stderr index bd4801570778..a6d6380a0c52 100644 --- a/tests/ui/unsafe-binders/moves.stderr +++ b/tests/ui/unsafe-binders/moves.stderr @@ -1,14 +1,5 @@ -warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/moves.rs:1:12 - | -LL | #![feature(unsafe_binders)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130516 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0382]: use of moved value: `base` - --> $DIR/moves.rs:15:14 + --> $DIR/moves.rs:14:14 | LL | let base = NotCopy::default(); | ---- move occurs because `base` has type `ManuallyDrop`, which does not implement the `Copy` trait @@ -18,7 +9,7 @@ LL | drop(base); | ^^^^ value used here after move | note: if `NotCopyInner` implemented `Clone`, you could clone the value - --> $DIR/moves.rs:8:1 + --> $DIR/moves.rs:7:1 | LL | struct NotCopyInner; | ^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type @@ -27,7 +18,7 @@ LL | let binder: unsafe<> NotCopy = wrap_binder!(base); | ---- you could clone this value error[E0382]: use of moved value: `binder` - --> $DIR/moves.rs:24:14 + --> $DIR/moves.rs:23:14 | LL | drop(unwrap_binder!(binder)); | ---------------------- value moved here @@ -38,7 +29,7 @@ LL | drop(unwrap_binder!(binder)); = note: this error originates in the macro `unwrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0382]: use of moved value: `binder.0` - --> $DIR/moves.rs:36:14 + --> $DIR/moves.rs:35:14 | LL | drop(unwrap_binder!(binder).0); | ------------------------ value moved here @@ -48,6 +39,6 @@ LL | drop(unwrap_binder!(binder).0); | = note: move occurs because `binder.0` has type `ManuallyDrop`, which does not implement the `Copy` trait -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/unsafe-binders/simple.rs b/tests/ui/unsafe-binders/simple.rs index 6172a9e1e7bb..99f20d6b2ec9 100644 --- a/tests/ui/unsafe-binders/simple.rs +++ b/tests/ui/unsafe-binders/simple.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(unsafe_binders)] -//~^ WARN the feature `unsafe_binders` is incomplete fn main() { let x: unsafe<'a> &'a (); diff --git a/tests/ui/unsafe-binders/simple.stderr b/tests/ui/unsafe-binders/simple.stderr deleted file mode 100644 index e4b82c12b066..000000000000 --- a/tests/ui/unsafe-binders/simple.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/simple.rs:3:12 - | -LL | #![feature(unsafe_binders)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130516 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/unsafe-binders/type-mismatch.rs b/tests/ui/unsafe-binders/type-mismatch.rs index 9ac4e817c28b..22937bb09e82 100644 --- a/tests/ui/unsafe-binders/type-mismatch.rs +++ b/tests/ui/unsafe-binders/type-mismatch.rs @@ -1,5 +1,4 @@ #![feature(unsafe_binders)] -//~^ WARN the feature `unsafe_binders` is incomplete fn main() { let x: unsafe<> i32 = 0; diff --git a/tests/ui/unsafe-binders/type-mismatch.stderr b/tests/ui/unsafe-binders/type-mismatch.stderr index e694b5d464d8..6262620ff6b0 100644 --- a/tests/ui/unsafe-binders/type-mismatch.stderr +++ b/tests/ui/unsafe-binders/type-mismatch.stderr @@ -1,14 +1,5 @@ -warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-mismatch.rs:1:12 - | -LL | #![feature(unsafe_binders)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130516 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types - --> $DIR/type-mismatch.rs:5:27 + --> $DIR/type-mismatch.rs:4:27 | LL | let x: unsafe<> i32 = 0; | ------------ ^ expected `unsafe<> i32`, found integer @@ -19,7 +10,7 @@ LL | let x: unsafe<> i32 = 0; found type `{integer}` error[E0308]: mismatched types - --> $DIR/type-mismatch.rs:7:33 + --> $DIR/type-mismatch.rs:6:33 | LL | let x: unsafe<'a> &'a i32 = &0; | ------------------ ^^ expected `unsafe<'a> &i32`, found `&{integer}` @@ -29,6 +20,6 @@ LL | let x: unsafe<'a> &'a i32 = &0; = note: expected unsafe binder `unsafe<'a> &'a i32` found reference `&{integer}` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs index 15245d9ba4f2..21f8fe7fdf8f 100644 --- a/tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs +++ b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs @@ -3,7 +3,6 @@ //@ compile-flags: -Cdebuginfo=2 //@ ignore-backends: gcc #![feature(unsafe_binders)] -//~^ WARN the feature `unsafe_binders` is incomplete use std::unsafe_binder::wrap_binder; fn main() { diff --git a/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr deleted file mode 100644 index 283b8b9c04f6..000000000000 --- a/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unsafe-binders-debuginfo.rs:5:12 - | -LL | #![feature(unsafe_binders)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130516 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/unsafe/initializing-ranged-via-ctor.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/initializing-ranged-via-ctor.rs similarity index 100% rename from tests/ui/unsafe/initializing-ranged-via-ctor.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/initializing-ranged-via-ctor.rs diff --git a/tests/ui/unsafe/initializing-ranged-via-ctor.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/initializing-ranged-via-ctor.stderr similarity index 100% rename from tests/ui/unsafe/initializing-ranged-via-ctor.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/initializing-ranged-via-ctor.stderr diff --git a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged-ctor-as-fn-ptr.rs similarity index 100% rename from tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged-ctor-as-fn-ptr.rs diff --git a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged-ctor-as-fn-ptr.stderr similarity index 100% rename from tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged-ctor-as-fn-ptr.stderr diff --git a/tests/ui/unsafe/ranged_ints.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints.rs diff --git a/tests/ui/unsafe/ranged_ints.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints.stderr diff --git a/tests/ui/unsafe/ranged_ints2.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints2.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints2.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints2.rs diff --git a/tests/ui/unsafe/ranged_ints2.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints2.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints2.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints2.stderr diff --git a/tests/ui/unsafe/ranged_ints2_const.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints2_const.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints2_const.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints2_const.rs diff --git a/tests/ui/unsafe/ranged_ints2_const.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints2_const.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints2_const.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints2_const.stderr diff --git a/tests/ui/unsafe/ranged_ints3.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints3.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3.rs diff --git a/tests/ui/unsafe/ranged_ints3.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints3.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3.stderr diff --git a/tests/ui/unsafe/ranged_ints3_const.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3_const.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints3_const.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3_const.rs diff --git a/tests/ui/unsafe/ranged_ints3_const.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3_const.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints3_const.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3_const.stderr diff --git a/tests/ui/unsafe/ranged_ints3_match.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3_match.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints3_match.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3_match.rs diff --git a/tests/ui/unsafe/ranged_ints3_match.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3_match.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints3_match.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints3_match.stderr diff --git a/tests/ui/unsafe/ranged_ints4.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints4.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints4.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints4.rs diff --git a/tests/ui/unsafe/ranged_ints4.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints4.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints4.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints4.stderr diff --git a/tests/ui/unsafe/ranged_ints4_const.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints4_const.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints4_const.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints4_const.rs diff --git a/tests/ui/unsafe/ranged_ints4_const.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints4_const.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints4_const.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints4_const.stderr diff --git a/tests/ui/unsafe/ranged_ints_const.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints_const.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints_const.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints_const.rs diff --git a/tests/ui/unsafe/ranged_ints_const.stderr b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints_const.stderr similarity index 100% rename from tests/ui/unsafe/ranged_ints_const.stderr rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints_const.stderr diff --git a/tests/ui/unsafe/ranged_ints_macro.rs b/tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints_macro.rs similarity index 100% rename from tests/ui/unsafe/ranged_ints_macro.rs rename to tests/ui/unsafe/rustc_layout_scalar_valid_range/ranged_ints_macro.rs diff --git a/tests/ui/use/pub-use-self-super-crate.rs b/tests/ui/use/pub-use-self-super-crate.rs new file mode 100644 index 000000000000..1a799acb50fb --- /dev/null +++ b/tests/ui/use/pub-use-self-super-crate.rs @@ -0,0 +1,24 @@ +mod foo { + pub use self as this; + //~^ ERROR `self` is only public within the crate, and cannot be re-exported outside + + pub mod bar { + pub use super as parent; + //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside + pub use self::super as parent2; + //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside + pub use super::{self as parent3}; + //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside + pub use self::{super as parent4}; + //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside + + pub use crate as root; + pub use crate::{self as root2}; + pub use super::super as root3; + } +} + +pub use foo::*; +pub use foo::bar::*; + +pub fn main() {} diff --git a/tests/ui/use/pub-use-self-super-crate.stderr b/tests/ui/use/pub-use-self-super-crate.stderr new file mode 100644 index 000000000000..3b336800a180 --- /dev/null +++ b/tests/ui/use/pub-use-self-super-crate.stderr @@ -0,0 +1,43 @@ +error[E0365]: `self` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:2:13 + | +LL | pub use self as this; + | ^^^^^^^^^^^^ re-export of crate public `self` + | + = note: consider declaring type or module `self` with `pub` + +error[E0365]: `super` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:6:17 + | +LL | pub use super as parent; + | ^^^^^^^^^^^^^^^ re-export of crate public `super` + | + = note: consider declaring type or module `super` with `pub` + +error[E0365]: `super` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:8:17 + | +LL | pub use self::super as parent2; + | ^^^^^^^^^^^^^^^^^^^^^^ re-export of crate public `super` + | + = note: consider declaring type or module `super` with `pub` + +error[E0365]: `super` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:10:25 + | +LL | pub use super::{self as parent3}; + | ^^^^^^^^^^^^^^^ re-export of crate public `super` + | + = note: consider declaring type or module `super` with `pub` + +error[E0365]: `super` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:12:24 + | +LL | pub use self::{super as parent4}; + | ^^^^^^^^^^^^^^^^ re-export of crate public `super` + | + = note: consider declaring type or module `super` with `pub` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0365`. diff --git a/tests/ui/use/use-path-segment-kw.rs b/tests/ui/use/use-path-segment-kw.rs index be64f239b9fc..164f645dc5c5 100644 --- a/tests/ui/use/use-path-segment-kw.rs +++ b/tests/ui/use/use-path-segment-kw.rs @@ -70,7 +70,7 @@ macro_rules! macro_dollar_crate { fn outer() {} -mod foo { +pub mod foo { pub mod bar { pub mod foobar { pub mod qux { diff --git a/tests/ui/issues/issue-17546.rs b/tests/ui/variants/variant-result-noresult-used-as-type.rs similarity index 94% rename from tests/ui/issues/issue-17546.rs rename to tests/ui/variants/variant-result-noresult-used-as-type.rs index 1f0afc368a2e..14433c1460eb 100644 --- a/tests/ui/issues/issue-17546.rs +++ b/tests/ui/variants/variant-result-noresult-used-as-type.rs @@ -1,5 +1,6 @@ //@ edition:2015 //@ ignore-sgx std::os::fortanix_sgx::usercalls::raw::Result changes compiler suggestions +// https://github.com/rust-lang/rust/issues/17546 use foo::MyEnum::Result; use foo::NoResult; // Through a re-export diff --git a/tests/ui/issues/issue-17546.stderr b/tests/ui/variants/variant-result-noresult-used-as-type.stderr similarity index 89% rename from tests/ui/issues/issue-17546.stderr rename to tests/ui/variants/variant-result-noresult-used-as-type.stderr index d4aa354491fe..511cb3562f94 100644 --- a/tests/ui/issues/issue-17546.stderr +++ b/tests/ui/variants/variant-result-noresult-used-as-type.stderr @@ -1,5 +1,5 @@ error[E0573]: expected type, found variant `NoResult` - --> $DIR/issue-17546.rs:15:17 + --> $DIR/variant-result-noresult-used-as-type.rs:16:17 | LL | fn new() -> NoResult { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL + fn new() -> Result { | error[E0573]: expected type, found variant `Result` - --> $DIR/issue-17546.rs:25:17 + --> $DIR/variant-result-noresult-used-as-type.rs:26:17 | LL | fn new() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type @@ -36,7 +36,7 @@ LL + use std::thread::Result; | error[E0573]: expected type, found variant `Result` - --> $DIR/issue-17546.rs:31:13 + --> $DIR/variant-result-noresult-used-as-type.rs:32:13 | LL | fn new() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type @@ -53,7 +53,7 @@ LL + use std::thread::Result; | error[E0573]: expected type, found variant `NoResult` - --> $DIR/issue-17546.rs:36:15 + --> $DIR/variant-result-noresult-used-as-type.rs:37:15 | LL | fn newer() -> NoResult { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs index 072a699a6b5b..732a5c334e50 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs @@ -4,7 +4,6 @@ trait Trait { fn fnc(&self) -> dyn Trait { //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters //~| ERROR expected value, found builtin type `u32` - //~| ERROR defaults for generic parameters are not allowed here bar //~^ ERROR cannot find value `bar` in this scope } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index 47f3e83fae21..ce567b9043f0 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -20,7 +20,7 @@ LL | fn fnc(&self) -> dyn Trait { | ^^^ not a value error[E0425]: cannot find value `bar` in this scope - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:8:9 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:7:9 | LL | bar | ^^^ not found in this scope @@ -39,13 +39,7 @@ LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: defaults for generic parameters are not allowed here - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:12 - | -LL | fn fnc(&self) -> dyn Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0391, E0403, E0423, E0425. For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs index 13d7a800c51f..1948e76af7ec 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs @@ -4,13 +4,11 @@ trait Foo> { //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| ERROR cycle detected when computing type of `Foo::N` - //~| ERROR `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter fn func() {} } - +//@ ignore-parallel-frontend query cycle trait Bar> {} //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! -//~| ERROR `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index f9a855d3b93b..4024f57af4ff 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -13,7 +13,7 @@ LL | trait Foo> { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:20 | LL | trait Bar> {} | ^^^^^^ @@ -32,7 +32,7 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^ | note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:11 | LL | trait Bar> {} | ^^^^^^^^^^^^^^^ @@ -44,22 +44,6 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:3:20 - | -LL | trait Foo> { - | ^^^^^^ - | - = note: the only supported types are integers, `bool`, and `char` - -error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 - | -LL | trait Bar> {} - | ^^^^^^ - | - = note: the only supported types are integers, `bool`, and `char` - -error: aborting due to 3 previous errors; 2 warnings emitted +error: aborting due to 1 previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index 49651e8d6c05..42e3e2608d73 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `T` is not dyn compatible - --> $DIR/issue-87495.rs:4:29 + --> $DIR/issue-87495.rs:4:25 | LL | const CONST: (bool, dyn T); - | ^ `T` is not dyn compatible + | ^^^^^ `T` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -13,6 +13,11 @@ LL | trait T { LL | const CONST: (bool, dyn T); | ^^^^^ ...because it contains associated const `CONST` = help: consider moving `CONST` to another trait +help: you might have meant to use `Self` to refer to the implementing type + | +LL - const CONST: (bool, dyn T); +LL + const CONST: (bool, Self); + | error: aborting due to 1 previous error diff --git a/tests/ui/wf/range-expr-root-of-constant-issue-40749.rs b/tests/ui/wf/range-expr-root-of-constant-issue-40749.rs index bec92448d1c8..07e4b9addaa1 100644 --- a/tests/ui/wf/range-expr-root-of-constant-issue-40749.rs +++ b/tests/ui/wf/range-expr-root-of-constant-issue-40749.rs @@ -1,9 +1,11 @@ fn main() { [0; ..10]; - //~^ ERROR mismatched types - //~| NOTE expected type `usize` - //~| NOTE found struct `RangeTo<{integer}>` - //~| NOTE expected `usize`, found `RangeTo<{integer}> - //~| NOTE in this expansion of desugaring of range expression - //~| NOTE in this expansion of desugaring of range expression + //~^ ERROR: mismatched types + //~| NOTE: expected type `usize` + //~| NOTE: found struct `RangeTo<{integer}>` + //~| NOTE: expected `usize`, found `RangeTo<{integer}> + //~| NOTE: array length can only be `usize` + //~| NOTE: in this expansion of desugaring of range expression + //~| NOTE: in this expansion of desugaring of range expression + //~| NOTE: in this expansion of desugaring of range expression } diff --git a/tests/ui/wf/range-expr-root-of-constant-issue-40749.stderr b/tests/ui/wf/range-expr-root-of-constant-issue-40749.stderr index 482773a39440..daddbe9fa469 100644 --- a/tests/ui/wf/range-expr-root-of-constant-issue-40749.stderr +++ b/tests/ui/wf/range-expr-root-of-constant-issue-40749.stderr @@ -6,6 +6,7 @@ LL | [0; ..10]; | = note: expected type `usize` found struct `RangeTo<{integer}>` + = note: array length can only be `usize` error: aborting due to 1 previous error diff --git a/tests/ui/where-clauses/cfg_attribute.a.stderr b/tests/ui/where-clauses/cfg_attribute.a.stderr index 0ede890eb44f..5bfa65df6032 100644 --- a/tests/ui/where-clauses/cfg_attribute.a.stderr +++ b/tests/ui/where-clauses/cfg_attribute.a.stderr @@ -1,83 +1,83 @@ error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:32:7 + --> $DIR/cfg_attribute.rs:31:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:43:11 + --> $DIR/cfg_attribute.rs:42:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:54:11 + --> $DIR/cfg_attribute.rs:53:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:66:7 + --> $DIR/cfg_attribute.rs:65:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:76:11 + --> $DIR/cfg_attribute.rs:75:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:87:11 + --> $DIR/cfg_attribute.rs:86:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:100:7 + --> $DIR/cfg_attribute.rs:99:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:114:7 + --> $DIR/cfg_attribute.rs:113:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:129:7 + --> $DIR/cfg_attribute.rs:128:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:144:7 + --> $DIR/cfg_attribute.rs:143:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:155:7 + --> $DIR/cfg_attribute.rs:154:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:165:11 + --> $DIR/cfg_attribute.rs:164:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:178:7 + --> $DIR/cfg_attribute.rs:177:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:32:5 + --> $DIR/cfg_attribute.rs:31:5 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:35:5 + --> $DIR/cfg_attribute.rs:34:5 | LL | #[rustfmt::skip] ():, | ^^^^^^^^^^^^^^^^ @@ -93,119 +93,7 @@ LL | #[rustfmt::skip] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:66:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:69:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:100:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:103:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:114:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:117:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:129:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:132:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:144:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:147:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:155:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:158:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:178:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:181:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:43:9 + --> $DIR/cfg_attribute.rs:42:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -213,7 +101,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:46:9 + --> $DIR/cfg_attribute.rs:45:9 | LL | #[rustfmt::skip] ():; | ^^^^^^^^^^^^^^^^ @@ -221,7 +109,7 @@ LL | #[rustfmt::skip] ():; = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:54:9 + --> $DIR/cfg_attribute.rs:53:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -229,7 +117,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:57:9 + --> $DIR/cfg_attribute.rs:56:9 | LL | #[rustfmt::skip] ():; | ^^^^^^^^^^^^^^^^ @@ -237,7 +125,23 @@ LL | #[rustfmt::skip] ():; = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:76:9 + --> $DIR/cfg_attribute.rs:65:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:68:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:75:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -245,7 +149,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:79:9 + --> $DIR/cfg_attribute.rs:78:9 | LL | #[rustfmt::skip] ():; | ^^^^^^^^^^^^^^^^ @@ -253,7 +157,7 @@ LL | #[rustfmt::skip] ():; = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:87:9 + --> $DIR/cfg_attribute.rs:86:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -261,7 +165,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:90:9 + --> $DIR/cfg_attribute.rs:89:9 | LL | #[rustfmt::skip] ():, | ^^^^^^^^^^^^^^^^ @@ -269,7 +173,87 @@ LL | #[rustfmt::skip] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:165:9 + --> $DIR/cfg_attribute.rs:99:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:102:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:113:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:116:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:128:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:131:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:143:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:146:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:154:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:157:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:164:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -277,12 +261,28 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:168:9 + --> $DIR/cfg_attribute.rs:167:9 | LL | #[rustfmt::skip] ():, | ^^^^^^^^^^^^^^^^ | = help: only `#[cfg]` and `#[cfg_attr]` are supported +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:177:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:180:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + error: aborting due to 39 previous errors diff --git a/tests/ui/where-clauses/cfg_attribute.b.stderr b/tests/ui/where-clauses/cfg_attribute.b.stderr index 0ede890eb44f..5bfa65df6032 100644 --- a/tests/ui/where-clauses/cfg_attribute.b.stderr +++ b/tests/ui/where-clauses/cfg_attribute.b.stderr @@ -1,83 +1,83 @@ error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:32:7 + --> $DIR/cfg_attribute.rs:31:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:43:11 + --> $DIR/cfg_attribute.rs:42:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:54:11 + --> $DIR/cfg_attribute.rs:53:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:66:7 + --> $DIR/cfg_attribute.rs:65:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:76:11 + --> $DIR/cfg_attribute.rs:75:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:87:11 + --> $DIR/cfg_attribute.rs:86:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:100:7 + --> $DIR/cfg_attribute.rs:99:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:114:7 + --> $DIR/cfg_attribute.rs:113:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:129:7 + --> $DIR/cfg_attribute.rs:128:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:144:7 + --> $DIR/cfg_attribute.rs:143:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:155:7 + --> $DIR/cfg_attribute.rs:154:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:165:11 + --> $DIR/cfg_attribute.rs:164:11 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/cfg_attribute.rs:178:7 + --> $DIR/cfg_attribute.rs:177:7 | LL | #[derive(Clone)] ():, | ^^^^^^ not a non-macro attribute error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:32:5 + --> $DIR/cfg_attribute.rs:31:5 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:35:5 + --> $DIR/cfg_attribute.rs:34:5 | LL | #[rustfmt::skip] ():, | ^^^^^^^^^^^^^^^^ @@ -93,119 +93,7 @@ LL | #[rustfmt::skip] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:66:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:69:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:100:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:103:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:114:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:117:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:129:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:132:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:144:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:147:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:155:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:158:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:178:5 - | -LL | #[derive(Clone)] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:181:5 - | -LL | #[rustfmt::skip] ():, - | ^^^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:43:9 + --> $DIR/cfg_attribute.rs:42:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -213,7 +101,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:46:9 + --> $DIR/cfg_attribute.rs:45:9 | LL | #[rustfmt::skip] ():; | ^^^^^^^^^^^^^^^^ @@ -221,7 +109,7 @@ LL | #[rustfmt::skip] ():; = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:54:9 + --> $DIR/cfg_attribute.rs:53:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -229,7 +117,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:57:9 + --> $DIR/cfg_attribute.rs:56:9 | LL | #[rustfmt::skip] ():; | ^^^^^^^^^^^^^^^^ @@ -237,7 +125,23 @@ LL | #[rustfmt::skip] ():; = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:76:9 + --> $DIR/cfg_attribute.rs:65:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:68:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:75:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -245,7 +149,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:79:9 + --> $DIR/cfg_attribute.rs:78:9 | LL | #[rustfmt::skip] ():; | ^^^^^^^^^^^^^^^^ @@ -253,7 +157,7 @@ LL | #[rustfmt::skip] ():; = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:87:9 + --> $DIR/cfg_attribute.rs:86:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -261,7 +165,7 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:90:9 + --> $DIR/cfg_attribute.rs:89:9 | LL | #[rustfmt::skip] ():, | ^^^^^^^^^^^^^^^^ @@ -269,7 +173,87 @@ LL | #[rustfmt::skip] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:165:9 + --> $DIR/cfg_attribute.rs:99:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:102:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:113:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:116:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:128:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:131:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:143:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:146:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:154:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:157:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:164:9 | LL | #[derive(Clone)] ():, | ^^^^^^^^^^^^^^^^ @@ -277,12 +261,28 @@ LL | #[derive(Clone)] ():, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/cfg_attribute.rs:168:9 + --> $DIR/cfg_attribute.rs:167:9 | LL | #[rustfmt::skip] ():, | ^^^^^^^^^^^^^^^^ | = help: only `#[cfg]` and `#[cfg_attr]` are supported +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:177:5 + | +LL | #[derive(Clone)] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + +error: most attributes are not supported in `where` clauses + --> $DIR/cfg_attribute.rs:180:5 + | +LL | #[rustfmt::skip] ():, + | ^^^^^^^^^^^^^^^^ + | + = help: only `#[cfg]` and `#[cfg_attr]` are supported + error: aborting due to 39 previous errors diff --git a/tests/ui/where-clauses/cfg_attribute.rs b/tests/ui/where-clauses/cfg_attribute.rs index 8cbca0bee75d..13ba070990b7 100644 --- a/tests/ui/where-clauses/cfg_attribute.rs +++ b/tests/ui/where-clauses/cfg_attribute.rs @@ -7,7 +7,6 @@ #![feature(custom_test_frameworks)] #![feature(derive_const)] #![feature(where_clause_attrs)] -#![allow(soft_unstable)] use std::marker::PhantomData; diff --git a/tests/ui/where-clauses/unsupported_attribute.rs b/tests/ui/where-clauses/unsupported_attribute.rs index 75213e176610..e86274f3ed5e 100644 --- a/tests/ui/where-clauses/unsupported_attribute.rs +++ b/tests/ui/where-clauses/unsupported_attribute.rs @@ -5,7 +5,6 @@ #![feature(custom_test_frameworks)] #![feature(derive_const)] #![feature(where_clause_attrs)] -#![allow(soft_unstable)] trait Trait {} diff --git a/tests/ui/where-clauses/unsupported_attribute.stderr b/tests/ui/where-clauses/unsupported_attribute.stderr index e69eff976c3f..11f13ffa4d00 100644 --- a/tests/ui/where-clauses/unsupported_attribute.stderr +++ b/tests/ui/where-clauses/unsupported_attribute.stderr @@ -1,97 +1,17 @@ error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/unsupported_attribute.rs:28:7 + --> $DIR/unsupported_attribute.rs:27:7 | LL | #[derive(Clone)] T: Trait, | ^^^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `derive` - --> $DIR/unsupported_attribute.rs:31:7 + --> $DIR/unsupported_attribute.rs:30:7 | LL | #[derive(Clone)] 'a: 'static, | ^^^^^^ not a non-macro attribute -error: `#[ignore]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:16:5 - | -LL | #[ignore] T: Trait, - | ^^^^^^^^^ - | - = help: `#[ignore]` can only be applied to functions - -error: `#[ignore]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:17:5 - | -LL | #[ignore] 'a: 'static, - | ^^^^^^^^^ - | - = help: `#[ignore]` can only be applied to functions - -error: `#[should_panic]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:18:5 - | -LL | #[should_panic] T: Trait, - | ^^^^^^^^^^^^^^^ - | - = help: `#[should_panic]` can only be applied to functions - -error: `#[should_panic]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:19:5 - | -LL | #[should_panic] 'a: 'static, - | ^^^^^^^^^^^^^^^ - | - = help: `#[should_panic]` can only be applied to functions - -error: `#[macro_use]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:20:5 - | -LL | #[macro_use] T: Trait, - | ^^^^^^^^^^^^ - | - = help: `#[macro_use]` can be applied to crates, extern crates, and modules - -error: `#[macro_use]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:21:5 - | -LL | #[macro_use] 'a: 'static, - | ^^^^^^^^^^^^ - | - = help: `#[macro_use]` can be applied to crates, extern crates, and modules - -error: `#[deprecated]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:24:5 - | -LL | #[deprecated] T: Trait, - | ^^^^^^^^^^^^^ - | - = help: `#[deprecated]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, foreign statics, functions, inherent impl blocks, macro defs, modules, statics, struct fields, traits, type aliases, and use statements - -error: `#[deprecated]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:25:5 - | -LL | #[deprecated] 'a: 'static, - | ^^^^^^^^^^^^^ - | - = help: `#[deprecated]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, foreign statics, functions, inherent impl blocks, macro defs, modules, statics, struct fields, traits, type aliases, and use statements - -error: `#[automatically_derived]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:26:5 - | -LL | #[automatically_derived] T: Trait, - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `#[automatically_derived]` can only be applied to trait impl blocks - -error: `#[automatically_derived]` attribute cannot be used on where predicates - --> $DIR/unsupported_attribute.rs:27:5 - | -LL | #[automatically_derived] 'a: 'static, - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `#[automatically_derived]` can only be applied to trait impl blocks - error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:14:5 + --> $DIR/unsupported_attribute.rs:13:5 | LL | #[doc = "doc"] T: Trait, | ^^^^^^^^^^^^^^ @@ -99,15 +19,63 @@ LL | #[doc = "doc"] T: Trait, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:15:5 + --> $DIR/unsupported_attribute.rs:14:5 | LL | #[doc = "doc"] 'a: 'static, | ^^^^^^^^^^^^^^ | = help: only `#[cfg]` and `#[cfg_attr]` are supported +error: `#[ignore]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:15:5 + | +LL | #[ignore] T: Trait, + | ^^^^^^^^^ + | + = help: `#[ignore]` can only be applied to functions + +error: `#[ignore]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:16:5 + | +LL | #[ignore] 'a: 'static, + | ^^^^^^^^^ + | + = help: `#[ignore]` can only be applied to functions + +error: `#[should_panic]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:17:5 + | +LL | #[should_panic] T: Trait, + | ^^^^^^^^^^^^^^^ + | + = help: `#[should_panic]` can only be applied to functions + +error: `#[should_panic]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:18:5 + | +LL | #[should_panic] 'a: 'static, + | ^^^^^^^^^^^^^^^ + | + = help: `#[should_panic]` can only be applied to functions + +error: `#[macro_use]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:19:5 + | +LL | #[macro_use] T: Trait, + | ^^^^^^^^^^^^ + | + = help: `#[macro_use]` can be applied to crates, extern crates, and modules + +error: `#[macro_use]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:20:5 + | +LL | #[macro_use] 'a: 'static, + | ^^^^^^^^^^^^ + | + = help: `#[macro_use]` can be applied to crates, extern crates, and modules + error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:22:5 + --> $DIR/unsupported_attribute.rs:21:5 | LL | #[allow(unused)] T: Trait, | ^^^^^^^^^^^^^^^^ @@ -115,15 +83,47 @@ LL | #[allow(unused)] T: Trait, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:23:5 + --> $DIR/unsupported_attribute.rs:22:5 | LL | #[allow(unused)] 'a: 'static, | ^^^^^^^^^^^^^^^^ | = help: only `#[cfg]` and `#[cfg_attr]` are supported +error: `#[deprecated]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:23:5 + | +LL | #[deprecated] T: Trait, + | ^^^^^^^^^^^^^ + | + = help: `#[deprecated]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, foreign statics, functions, inherent impl blocks, macro defs, modules, statics, struct fields, traits, type aliases, and use statements + +error: `#[deprecated]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:24:5 + | +LL | #[deprecated] 'a: 'static, + | ^^^^^^^^^^^^^ + | + = help: `#[deprecated]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, foreign statics, functions, inherent impl blocks, macro defs, modules, statics, struct fields, traits, type aliases, and use statements + +error: `#[automatically_derived]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:25:5 + | +LL | #[automatically_derived] T: Trait, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[automatically_derived]` can only be applied to trait impl blocks + +error: `#[automatically_derived]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:26:5 + | +LL | #[automatically_derived] 'a: 'static, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[automatically_derived]` can only be applied to trait impl blocks + error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:28:5 + --> $DIR/unsupported_attribute.rs:27:5 | LL | #[derive(Clone)] T: Trait, | ^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | #[derive(Clone)] T: Trait, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:31:5 + --> $DIR/unsupported_attribute.rs:30:5 | LL | #[derive(Clone)] 'a: 'static, | ^^^^^^^^^^^^^^^^ @@ -139,7 +139,7 @@ LL | #[derive(Clone)] 'a: 'static, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:34:5 + --> $DIR/unsupported_attribute.rs:33:5 | LL | #[rustfmt::skip] T: Trait, | ^^^^^^^^^^^^^^^^ @@ -147,7 +147,7 @@ LL | #[rustfmt::skip] T: Trait, = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:35:5 + --> $DIR/unsupported_attribute.rs:34:5 | LL | #[rustfmt::skip] 'a: 'static, | ^^^^^^^^^^^^^^^^ diff --git a/triagebot.toml b/triagebot.toml index f2bfa0084d87..f99d700310df 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -194,6 +194,11 @@ Hi relnotes-interest-group, this issue/PR could use some help in reviewing / adjusting release notes. Could you take a look if available? Thanks <3 """ +[ping.gpu-target] +message = """\ +Hi GPU experts, this issue/PR could use some guidance on how this should be +resolved/implemented. Could you take a look if available? Thanks <3 +""" # ------------------------------------------------------------------------------ # Autolabels @@ -1012,6 +1017,13 @@ cc = ["@lcnr"] message = "HIR ty lowering was modified" cc = ["@fmease"] +[mentions."compiler/rustc_parse"] +message = """ +The parser was modified, potentially altering the grammar of (stable) Rust +which would be a breaking change. +""" +cc = ["@fmease"] + [mentions."library/core/src/mem/type_info.rs"] message = """ The reflection data structures are tied exactly to the implementation @@ -1061,6 +1073,10 @@ instead. """ cc = ["@Amanieu", "@folkertdev", "@sayantn"] +[mentions."library/std_detect"] +message = "Some changes occurred in `std_detect`" +cc = ["@Amanieu", "@folkertdev", "@sayantn"] + [mentions."library/core/src/intrinsics/simd.rs"] message = """ Some changes occurred to the platform-builtins intrinsics. Make sure the @@ -1170,7 +1186,7 @@ cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@vakaras"] [mentions."compiler/rustc_error_messages"] message = "`rustc_error_messages` was changed" -cc = ["@davidtwco", "@TaKO8Ki"] +cc = ["@TaKO8Ki"] [mentions."compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs"] message = "`rustc_errors::annotate_snippet_emitter_writer` was changed" @@ -1182,11 +1198,11 @@ cc = ["@Muscraft"] [mentions."compiler/rustc_errors/src/formatting.rs"] message = "`rustc_errors::formatting` was changed" -cc = ["@davidtwco", "@TaKO8Ki", "@JonathanBrouwer"] +cc = ["@TaKO8Ki", "@JonathanBrouwer"] [mentions."compiler/rustc_macros/src/diagnostics"] message = "`rustc_macros::diagnostics` was changed" -cc = ["@davidtwco", "@TaKO8Ki", "@JonathanBrouwer"] +cc = ["@TaKO8Ki", "@JonathanBrouwer"] [mentions."compiler/rustc_public"] message = "This PR changes rustc_public" @@ -1400,6 +1416,15 @@ cc = ["@m-ou-se"] [mentions."compiler/rustc_ast_lowering/src/format.rs"] cc = ["@m-ou-se"] +[mentions."src/ci/github-actions/jobs.yml"] +message = """ +> [!WARNING] +> +> If you are changing how CI LLVM is built or linked, make sure to bump +> `src/bootstrap/download-ci-llvm-stamp`. +""" +cc = ["@jieyouxu"] + # Content-based mentions [mentions."#[miri::intrinsic_fallback_is_spec]"] @@ -1580,6 +1605,7 @@ dep-bumps = [ "/library/std" = ["libs", "@ChrisDenton"] "/library/std/src/sys/pal/windows" = ["@ChrisDenton"] "/library/stdarch" = ["libs"] +"/library/std_detect" = ["libs"] "/library/test" = ["libs"] "/src/bootstrap" = ["bootstrap"] "/src/ci" = ["infra-ci"] diff --git a/typos.toml b/typos.toml index 3c95a45d572d..8e14ce58dcb4 100644 --- a/typos.toml +++ b/typos.toml @@ -20,6 +20,7 @@ extend-exclude = [ # right now. Entries should look like `mipsel = "mipsel"`. # # tidy-alphabetical-start +anser = "anser" # an ANSI parsing package used by rust-analyzer arange = "arange" # short for A-range childs = "childs" clonable = "clonable" @@ -29,10 +30,12 @@ makro = "makro" # deliberate misspelling to avoid `macro` keyword misformed = "misformed" moreso = "moreso" numer = "numer" # short for numerator, not a typo for "number" +old-skool = "old-skool" # variant spelling of "old-school" optin = "optin" # short for opt-in publically = "publically" rplace = "rplace" # short for R-place splitted = "splitted" +sythetic = "sythetic" # typo in vendored LLVM sources taits = "taits" # lowercase for TAITs (type alias impl trait) targetting = "targetting" unparseable = "unparseable" @@ -45,6 +48,7 @@ unstalled = "unstalled" # short for un-stalled # the non-empty form can be automatically fixed by `--bless`. # # tidy-alphabetical-start +atomicaly = "atomically" definitinon = "definition" dependy = "" similarlty = "similarity" diff --git a/x b/x index a8acbd4d5ac6..768ed1674641 100755 --- a/x +++ b/x @@ -46,7 +46,7 @@ for SEARCH_PYTHON in $SEARCH; do fi done -python=$(bash -c "compgen -c python" | grep '^python[2-3]\.[0-9]+$' | head -n1) +python=$(bash -c "compgen -c python" | grep -E '^python[2-3](\.[0-9]+)?$' | head -n1) if ! [ "$python" = "" ]; then exec "$python" "$xpy" "$@" fi

= self.child.get(); - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/issues/issue-42880.rs b/tests/ui/issues/issue-42880.rs index b61ba80e27ab..36d15fc35b48 100644 --- a/tests/ui/issues/issue-42880.rs +++ b/tests/ui/issues/issue-42880.rs @@ -1,7 +1,7 @@ type Value = String; fn main() { - let f = |&Value::String(_)| (); //~ ERROR no associated item named + let f = |&Value::String(_)| (); //~ ERROR no associated function or constant named let vec: Vec = Vec::new(); vec.last().map(f); diff --git a/tests/ui/issues/issue-42880.stderr b/tests/ui/issues/issue-42880.stderr index f174f42b2398..8743b1cfdef7 100644 --- a/tests/ui/issues/issue-42880.stderr +++ b/tests/ui/issues/issue-42880.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `String` found for struct `String` in the current scope +error[E0599]: no associated function or constant named `String` found for struct `String` in the current scope --> $DIR/issue-42880.rs:4:22 | LL | let f = |&Value::String(_)| (); - | ^^^^^^ associated item not found in `String` + | ^^^^^^ associated function or constant not found in `String` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-4830.rs b/tests/ui/issues/issue-4830.rs deleted file mode 100644 index d48c13fd10b1..000000000000 --- a/tests/ui/issues/issue-4830.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ check-pass -#![allow(dead_code)] - - -pub struct Scheduler { - /// The event loop used to drive the scheduler and perform I/O - event_loop: Box -} - -pub fn main() { } diff --git a/tests/ui/issues/issue-5100.stderr b/tests/ui/issues/issue-5100.stderr index 24d41a1a8afa..c545f70415c1 100644 --- a/tests/ui/issues/issue-5100.stderr +++ b/tests/ui/issues/issue-5100.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/issue-5100.rs:9:9 | -LL | enum A { B, C } - | - unit variant defined here -... LL | match (true, false) { | ------------- this expression has type `(bool, bool)` LL | A::B => (), diff --git a/tests/ui/issues/issue-5192.rs b/tests/ui/issues/issue-5192.rs deleted file mode 100644 index be5d70f09b3c..000000000000 --- a/tests/ui/issues/issue-5192.rs +++ /dev/null @@ -1,38 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -pub trait EventLoop { - fn dummy(&self) { } -} - -pub struct UvEventLoop { - uvio: isize -} - -impl UvEventLoop { - pub fn new() -> UvEventLoop { - UvEventLoop { - uvio: 0 - } - } -} - -impl EventLoop for UvEventLoop { -} - -pub struct Scheduler { - event_loop: Box, -} - -impl Scheduler { - - pub fn new(event_loop: Box) -> Scheduler { - Scheduler { - event_loop: event_loop, - } - } -} - -pub fn main() { - let _sched = Scheduler::new(Box::new(UvEventLoop::new()) as Box); -} diff --git a/tests/ui/iterators/auxiliary/rangefrom-overflow-2crates-ocno.rs b/tests/ui/iterators/auxiliary/rangefrom-overflow-2crates-ocno.rs new file mode 100644 index 000000000000..e2aa817699a0 --- /dev/null +++ b/tests/ui/iterators/auxiliary/rangefrom-overflow-2crates-ocno.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -C overflow-checks=no + +#![crate_type = "lib"] + +use std::range::RangeFromIter; + +pub fn next(iter: &mut RangeFromIter) -> u8 { + iter.next().unwrap() +} diff --git a/tests/ui/iterators/auxiliary/rangefrom-overflow-2crates-ocyes.rs b/tests/ui/iterators/auxiliary/rangefrom-overflow-2crates-ocyes.rs new file mode 100644 index 000000000000..b37f6985a0ea --- /dev/null +++ b/tests/ui/iterators/auxiliary/rangefrom-overflow-2crates-ocyes.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -C overflow-checks=yes + +#![crate_type = "lib"] + +use std::range::RangeFromIter; + +pub fn next(iter: &mut RangeFromIter) -> u8 { + iter.next().unwrap() +} diff --git a/tests/ui/iterators/fromrangeiter.rs b/tests/ui/iterators/fromrangeiter.rs index 54d8f522a2c8..c672f1348437 100644 --- a/tests/ui/iterators/fromrangeiter.rs +++ b/tests/ui/iterators/fromrangeiter.rs @@ -1,8 +1,6 @@ //@ run-pass //@ compile-flags: -C overflow-checks=yes -#![feature(new_range_api)] - use std::{iter, range}; fn main() { diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr index 99bff6b450b5..f22fc2143edf 100644 --- a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr @@ -33,13 +33,13 @@ LL | println!("{}", scores.sum::()); | required by a bound introduced by this call | = help: the trait `Sum<()>` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation @@ -74,13 +74,13 @@ LL | .sum::(), | required by a bound introduced by this call | = help: the trait `Sum<()>` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation @@ -115,13 +115,13 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | required by a bound introduced by this call | = help: the trait `Sum<()>` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr index c94b716e3131..82269f6253a3 100644 --- a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -7,13 +7,13 @@ LL | let x = Some(()).iter().map(|()| 1).sum::(); | required by a bound introduced by this call | = help: the trait `Sum<{integer}>` is not implemented for `f32` -help: the following other types implement trait `Sum` +help: `f32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `f32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `f32` implements `Sum<&f32>` + = note: `Sum<&f32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index 7f0c154e255a..d58fe438a627 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -33,13 +33,13 @@ LL | println!("{}", scores.sum::()); | required by a bound introduced by this call | = help: the trait `Sum<()>` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation @@ -73,13 +73,13 @@ LL | .sum::(), | required by a bound introduced by this call | = help: the trait `Sum<()>` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation @@ -120,13 +120,13 @@ LL | .sum::(), | required by a bound introduced by this call | = help: the trait `Sum` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation @@ -158,13 +158,13 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | required by a bound introduced by this call | = help: the trait `Sum<()>` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation @@ -194,13 +194,13 @@ LL | println!("{}", vec![(), ()].iter().sum::()); | required by a bound introduced by this call | = help: the trait `Sum<&()>` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation diff --git a/tests/ui/iterators/rangefrom-overflow-2crates.rs b/tests/ui/iterators/rangefrom-overflow-2crates.rs new file mode 100644 index 000000000000..56b642b2c548 --- /dev/null +++ b/tests/ui/iterators/rangefrom-overflow-2crates.rs @@ -0,0 +1,38 @@ +//@ run-pass +//@ needs-unwind +//@ aux-build:rangefrom-overflow-2crates-ocno.rs +//@ aux-build:rangefrom-overflow-2crates-ocyes.rs + +// For #154124 +// Test that two crates with different overflow-checks have the same results, +// even when the iterator is passed between them. + +extern crate rangefrom_overflow_2crates_ocno; +extern crate rangefrom_overflow_2crates_ocyes; + +use rangefrom_overflow_2crates_ocno::next as next_ocno; +use rangefrom_overflow_2crates_ocyes::next as next_ocyes; + +fn main() { + let mut iter_ocyes = std::range::RangeFrom::from(0_u8..).into_iter(); + let mut iter_ocno = iter_ocyes.clone(); + + for n in 0_u8..=255 { + assert_eq!(n, next_ocno(&mut iter_ocyes.clone())); + assert_eq!(n, next_ocyes(&mut iter_ocyes)); + assert_eq!(n, next_ocyes(&mut iter_ocno.clone())); + assert_eq!(n, next_ocno(&mut iter_ocno)); + } + + // `iter_ocno` should have wrapped + assert_eq!(0, next_ocyes(&mut iter_ocno.clone())); + assert_eq!(0, next_ocno(&mut iter_ocno)); + // `iter_ocyes` should be exhausted, + // which will wrap when called without overflow-checks + assert_eq!(0, next_ocno(&mut iter_ocyes.clone())); + // and panic when called with overflow-checks + let r = std::panic::catch_unwind(move || { + let _ = next_ocyes(&mut iter_ocyes); + }); + assert!(r.is_err()); +} diff --git a/tests/ui/iterators/rangefrom-overflow-debug.rs b/tests/ui/iterators/rangefrom-overflow-debug.rs index 9a1bc6910a04..7eafbadc62fb 100644 --- a/tests/ui/iterators/rangefrom-overflow-debug.rs +++ b/tests/ui/iterators/rangefrom-overflow-debug.rs @@ -2,7 +2,7 @@ //@ needs-unwind //@ compile-flags: -O -C debug_assertions=yes -#![feature(new_range_api)] +#![feature(new_range_remainder)] use std::panic; diff --git a/tests/ui/iterators/rangefrom-overflow-ndebug.rs b/tests/ui/iterators/rangefrom-overflow-ndebug.rs index 4ce9b0636383..f1a6301c50d9 100644 --- a/tests/ui/iterators/rangefrom-overflow-ndebug.rs +++ b/tests/ui/iterators/rangefrom-overflow-ndebug.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -O -C debug_assertions=no -#![feature(new_range_api)] +#![feature(new_range_remainder)] fn main() { let mut it = core::range::RangeFrom::from(u8::MAX..).into_iter(); diff --git a/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs b/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs index 7e3b0fc30840..af432afacabb 100644 --- a/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs +++ b/tests/ui/iterators/rangefrom-overflow-overflow-checks.rs @@ -2,7 +2,7 @@ //@ needs-unwind //@ compile-flags: -O -C overflow-checks=yes -#![feature(new_range_api)] +#![feature(new_range_remainder)] use std::panic; diff --git a/tests/ui/kindck/kindck-impl-type-params-2.rs b/tests/ui/kindck/kindck-impl-type-params-2.rs deleted file mode 100644 index 8b0771985dc3..000000000000 --- a/tests/ui/kindck/kindck-impl-type-params-2.rs +++ /dev/null @@ -1,15 +0,0 @@ -trait Foo { -} - - - -impl Foo for T { -} - -fn take_param(foo: &T) { } - -fn main() { - let x: Box<_> = Box::new(3); - take_param(&x); - //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied -} diff --git a/tests/ui/kindck/kindck-impl-type-params-2.stderr b/tests/ui/kindck/kindck-impl-type-params-2.stderr deleted file mode 100644 index 38dc94f9104d..000000000000 --- a/tests/ui/kindck/kindck-impl-type-params-2.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied - --> $DIR/kindck-impl-type-params-2.rs:13:16 - | -LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` - | | - | required by a bound introduced by this call - | -note: required for `Box<{integer}>` to implement `Foo` - --> $DIR/kindck-impl-type-params-2.rs:6:14 - | -LL | impl Foo for T { - | ---- ^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required by a bound in `take_param` - --> $DIR/kindck-impl-type-params-2.rs:9:17 - | -LL | fn take_param(foo: &T) { } - | ^^^ required by this bound in `take_param` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr deleted file mode 100644 index 95048c4454b3..000000000000 --- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied - --> $DIR/kindck-inherited-copy-bound.rs:21:16 - | -LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` - | | - | required by a bound introduced by this call - | -note: required for `Box<{integer}>` to implement `Foo` - --> $DIR/kindck-inherited-copy-bound.rs:14:14 - | -LL | impl Foo for T { - | ---- ^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required by a bound in `take_param` - --> $DIR/kindck-inherited-copy-bound.rs:17:17 - | -LL | fn take_param(foo: &T) { } - | ^^^ required by this bound in `take_param` - -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/kindck-inherited-copy-bound.rs:28:19 - | -LL | let z = &x as &dyn Foo; - | ^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/kindck-inherited-copy-bound.rs:10:13 - | -LL | trait Foo : Copy { - | --- ^^^^ ...because it requires `Self: Sized` - | | - | this trait is not dyn compatible... - -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/kindck-inherited-copy-bound.rs:28:13 - | -LL | let z = &x as &dyn Foo; - | ^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/kindck-inherited-copy-bound.rs:10:13 - | -LL | trait Foo : Copy { - | --- ^^^^ ...because it requires `Self: Sized` - | | - | this trait is not dyn compatible... - = note: required for the cast from `&Box<{integer}>` to `&dyn Foo` - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0038, E0277. -For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/kindck/kindck-nonsendable-1.stderr deleted file mode 100644 index 8bb784d1d496..000000000000 --- a/tests/ui/kindck/kindck-nonsendable-1.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0277]: `Rc` cannot be sent between threads safely - --> $DIR/kindck-nonsendable-1.rs:9:9 - | -LL | bar(move|| foo(x)); - | --- ------^^^^^^^ - | | | - | | `Rc` cannot be sent between threads safely - | | within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}` - | required by a bound introduced by this call - | - = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc` -note: required because it's used within this closure - --> $DIR/kindck-nonsendable-1.rs:9:9 - | -LL | bar(move|| foo(x)); - | ^^^^^^ -note: required by a bound in `bar` - --> $DIR/kindck-nonsendable-1.rs:5:21 - | -LL | fn bar(_: F) { } - | ^^^^ required by this bound in `bar` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-object.rs b/tests/ui/kindck/kindck-send-object.rs deleted file mode 100644 index f5d44246efe5..000000000000 --- a/tests/ui/kindck/kindck-send-object.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Test which of the builtin types are considered sendable. The tests -// in this file all test the "kind" violates detected during kindck. -// See all `regions-bounded-by-send.rs` - -fn assert_send() { } -trait Dummy { } -trait Message : Send { } - -// careful with object types, who knows what they close over... - -fn object_ref_with_static_bound_not_ok() { - assert_send::<&'static (dyn Dummy + 'static)>(); - //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277] -} - -fn box_object_with_no_bound_not_ok<'a>() { - assert_send::>(); - //~^ ERROR `dyn Dummy` cannot be sent between threads safely -} - -fn object_with_send_bound_ok() { - assert_send::<&'static (dyn Dummy + Sync)>(); - assert_send::>(); -} - -fn main() { } diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr deleted file mode 100644 index b71d4029350e..000000000000 --- a/tests/ui/kindck/kindck-send-object.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely - --> $DIR/kindck-send-object.rs:12:19 - | -LL | assert_send::<&'static (dyn Dummy + 'static)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely - | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` - = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object.rs:5:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error[E0277]: `dyn Dummy` cannot be sent between threads safely - --> $DIR/kindck-send-object.rs:17:19 - | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `dyn Dummy` - = note: required for `std::ptr::Unique` to implement `Send` -note: required because it appears within the type `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object.rs:5:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-object1.rs b/tests/ui/kindck/kindck-send-object1.rs deleted file mode 100644 index 76a9fc6019ab..000000000000 --- a/tests/ui/kindck/kindck-send-object1.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Test which object types are considered sendable. This test -// is broken into two parts because some errors occur in distinct -// phases in the compiler. See kindck-send-object2.rs as well! - -fn assert_send() { } -trait Dummy { } - -// careful with object types, who knows what they close over... -fn test51<'a>() { - assert_send::<&'a dyn Dummy>(); - //~^ ERROR `&'a (dyn Dummy + 'a)` cannot be sent between threads safely [E0277] -} -fn test52<'a>() { - assert_send::<&'a (dyn Dummy + Sync)>(); - //~^ ERROR: lifetime may not live long enough -} - -// ...unless they are properly bounded -fn test60() { - assert_send::<&'static (dyn Dummy + Sync)>(); -} -fn test61() { - assert_send::>(); -} - -// closure and object types can have lifetime bounds which make -// them not ok -fn test_71<'a>() { - assert_send::>(); - //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely -} - -fn main() { } diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr deleted file mode 100644 index 2184ae704673..000000000000 --- a/tests/ui/kindck/kindck-send-object1.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely - --> $DIR/kindck-send-object1.rs:10:19 - | -LL | assert_send::<&'a dyn Dummy>(); - | ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely - | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` - = note: required for `&'a (dyn Dummy + 'a)` to implement `Send` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object1.rs:5:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely - --> $DIR/kindck-send-object1.rs:29:19 - | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` - = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send` -note: required because it appears within the type `Box<(dyn Dummy + 'a)>` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object1.rs:5:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error: lifetime may not live long enough - --> $DIR/kindck-send-object1.rs:14:5 - | -LL | fn test52<'a>() { - | -- lifetime `'a` defined here -LL | assert_send::<&'a (dyn Dummy + Sync)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-object2.rs b/tests/ui/kindck/kindck-send-object2.rs deleted file mode 100644 index d37074e65746..000000000000 --- a/tests/ui/kindck/kindck-send-object2.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Continue kindck-send-object1.rs. - -fn assert_send() { } -trait Dummy { } - -fn test50() { - assert_send::<&'static dyn Dummy>(); - //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277] -} - -fn test53() { - assert_send::>(); - //~^ ERROR `dyn Dummy` cannot be sent between threads safely -} - -// ...unless they are properly bounded -fn test60() { - assert_send::<&'static (dyn Dummy + Sync)>(); -} -fn test61() { - assert_send::>(); -} - -fn main() { } diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr deleted file mode 100644 index 52a7055b4229..000000000000 --- a/tests/ui/kindck/kindck-send-object2.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely - --> $DIR/kindck-send-object2.rs:7:19 - | -LL | assert_send::<&'static dyn Dummy>(); - | ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely - | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` - = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object2.rs:3:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error[E0277]: `dyn Dummy` cannot be sent between threads safely - --> $DIR/kindck-send-object2.rs:12:19 - | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `dyn Dummy` - = note: required for `std::ptr::Unique` to implement `Send` -note: required because it appears within the type `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object2.rs:3:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-owned.rs b/tests/ui/kindck/kindck-send-owned.rs deleted file mode 100644 index 65efb69041d5..000000000000 --- a/tests/ui/kindck/kindck-send-owned.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Test which of the builtin types are considered sendable. - -fn assert_send() { } - -// owned content are ok -fn test30() { assert_send::>(); } -fn test31() { assert_send::(); } -fn test32() { assert_send:: >(); } - -// but not if they own a bad thing -fn test40() { - assert_send::>(); - //~^ ERROR `*mut u8` cannot be sent between threads safely -} - -fn main() { } diff --git a/tests/ui/kindck/kindck-send-owned.stderr b/tests/ui/kindck/kindck-send-owned.stderr deleted file mode 100644 index c433d80cf140..000000000000 --- a/tests/ui/kindck/kindck-send-owned.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: `*mut u8` cannot be sent between threads safely - --> $DIR/kindck-send-owned.rs:12:19 - | -LL | assert_send::>(); - | ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `*mut u8` - = note: required for `std::ptr::Unique<*mut u8>` to implement `Send` -note: required because it appears within the type `Box<*mut u8>` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: required by a bound in `assert_send` - --> $DIR/kindck-send-owned.rs:3:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-unsafe.rs b/tests/ui/kindck/kindck-send-unsafe.rs deleted file mode 100644 index eb1f2a549b16..000000000000 --- a/tests/ui/kindck/kindck-send-unsafe.rs +++ /dev/null @@ -1,15 +0,0 @@ -extern crate core; - -fn assert_send() {} - -fn test70() { - assert_send::<*mut isize>(); - //~^ ERROR `*mut isize` cannot be sent between threads safely -} - -fn test71<'a>() { - assert_send::<*mut &'a isize>(); - //~^ ERROR `*mut &'a isize` cannot be sent between threads safely -} - -fn main() {} diff --git a/tests/ui/kindck/kindck-send-unsafe.stderr b/tests/ui/kindck/kindck-send-unsafe.stderr deleted file mode 100644 index f1a5054abbc4..000000000000 --- a/tests/ui/kindck/kindck-send-unsafe.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0277]: `*mut isize` cannot be sent between threads safely - --> $DIR/kindck-send-unsafe.rs:6:19 - | -LL | assert_send::<*mut isize>(); - | ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `*mut isize` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-unsafe.rs:3:19 - | -LL | fn assert_send() {} - | ^^^^ required by this bound in `assert_send` - -error[E0277]: `*mut &'a isize` cannot be sent between threads safely - --> $DIR/kindck-send-unsafe.rs:11:19 - | -LL | assert_send::<*mut &'a isize>(); - | ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `*mut &'a isize` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-unsafe.rs:3:19 - | -LL | fn assert_send() {} - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/gce-rigid-const-in-array-len.rs b/tests/ui/layout/gce-rigid-const-in-array-len.rs index 8e57907a2c5e..d8cc415ba1c2 100644 --- a/tests/ui/layout/gce-rigid-const-in-array-len.rs +++ b/tests/ui/layout/gce-rigid-const-in-array-len.rs @@ -12,7 +12,7 @@ //! constant. #![feature(rustc_attrs)] -#![feature(generic_const_exprs)] //~ WARNING: the feature `generic_const_exprs` is incomplete +#![feature(generic_const_exprs)] #![feature(trivial_bounds)] #![crate_type = "lib"] diff --git a/tests/ui/layout/gce-rigid-const-in-array-len.stderr b/tests/ui/layout/gce-rigid-const-in-array-len.stderr index 6149debdfe88..903856315978 100644 --- a/tests/ui/layout/gce-rigid-const-in-array-len.stderr +++ b/tests/ui/layout/gce-rigid-const-in-array-len.stderr @@ -1,17 +1,8 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/gce-rigid-const-in-array-len.rs:15:12 - | -LL | #![feature(generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error: the type `[u8; ::B]` has an unknown layout --> $DIR/gce-rigid-const-in-array-len.rs:25:1 | LL | struct S([u8; ::B]) | ^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/invalid/issue-114435-layout-type-err.rs b/tests/ui/layout/layout-type-err-nested-structs-114435.rs similarity index 100% rename from tests/ui/invalid/issue-114435-layout-type-err.rs rename to tests/ui/layout/layout-type-err-nested-structs-114435.rs diff --git a/tests/ui/invalid/issue-114435-layout-type-err.stderr b/tests/ui/layout/layout-type-err-nested-structs-114435.stderr similarity index 100% rename from tests/ui/invalid/issue-114435-layout-type-err.stderr rename to tests/ui/layout/layout-type-err-nested-structs-114435.stderr diff --git a/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs b/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs index 6ded9118700c..e9e7de84a7a4 100644 --- a/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs +++ b/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs @@ -1,7 +1,6 @@ // regression test for #127351 #![feature(lazy_type_alias)] -//~^ WARN the feature `lazy_type_alias` is incomplete type ExplicitTypeOutlives = T; diff --git a/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr b/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr index 3a5ded60241b..7aa34a22f736 100644 --- a/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr +++ b/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr @@ -1,20 +1,11 @@ -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-lazy-type-alias.rs:3:12 - | -LL | #![feature(lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0107]: missing generics for type alias `ExplicitTypeOutlives` - --> $DIR/bad-lazy-type-alias.rs:9:24 + --> $DIR/bad-lazy-type-alias.rs:8:24 | LL | _significant_drop: ExplicitTypeOutlives, | ^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: type alias defined here, with 1 generic parameter: `T` - --> $DIR/bad-lazy-type-alias.rs:6:6 + --> $DIR/bad-lazy-type-alias.rs:5:6 | LL | type ExplicitTypeOutlives = T; | ^^^^^^^^^^^^^^^^^^^^ - @@ -23,6 +14,6 @@ help: add missing generic argument LL | _significant_drop: ExplicitTypeOutlives, | +++ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr b/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr deleted file mode 100644 index 78dd05b78af1..000000000000 --- a/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/coerce-behind-lazy.rs:6:12 - | -LL | #![feature(lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr b/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr deleted file mode 100644 index 78dd05b78af1..000000000000 --- a/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/coerce-behind-lazy.rs:6:12 - | -LL | #![feature(lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.rs b/tests/ui/lazy-type-alias/coerce-behind-lazy.rs index 7873ff46b66f..a69e39b02b32 100644 --- a/tests/ui/lazy-type-alias/coerce-behind-lazy.rs +++ b/tests/ui/lazy-type-alias/coerce-behind-lazy.rs @@ -4,7 +4,6 @@ //@[next] compile-flags: -Znext-solver #![feature(lazy_type_alias)] -//~^ WARN the feature `lazy_type_alias` is incomplete use std::any::Any; diff --git a/tests/ui/lazy-type-alias/enum-variant.rs b/tests/ui/lazy-type-alias/enum-variant.rs index d9b7dff26647..236e1933a8a9 100644 --- a/tests/ui/lazy-type-alias/enum-variant.rs +++ b/tests/ui/lazy-type-alias/enum-variant.rs @@ -2,7 +2,6 @@ //@ check-pass #![feature(lazy_type_alias)] -//~^ WARN the feature `lazy_type_alias` is incomplete and may not be safe to use enum Enum { Unit, diff --git a/tests/ui/lazy-type-alias/enum-variant.stderr b/tests/ui/lazy-type-alias/enum-variant.stderr deleted file mode 100644 index 4360db917783..000000000000 --- a/tests/ui/lazy-type-alias/enum-variant.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/enum-variant.rs:4:12 - | -LL | #![feature(lazy_type_alias)] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #112792 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/lazy-type-alias/trailing-where-clause.stderr b/tests/ui/lazy-type-alias/trailing-where-clause.stderr index 93cd3145928b..170bc3bca78d 100644 --- a/tests/ui/lazy-type-alias/trailing-where-clause.stderr +++ b/tests/ui/lazy-type-alias/trailing-where-clause.stderr @@ -4,13 +4,13 @@ error[E0277]: the trait bound `String: From<()>` is not satisfied LL | let _: Alias<()>; | ^^ the trait `From<()>` is not implemented for `String` | - = help: the following other types implement trait `From`: - `String` implements `From<&String>` - `String` implements `From<&mut str>` - `String` implements `From<&str>` - `String` implements `From>` - `String` implements `From>` - `String` implements `From` + = help: `String` implements trait `From`: + From<&String> + From<&mut str> + From<&str> + From> + From> + From note: required by a bound in `Alias` --> $DIR/trailing-where-clause.rs:8:13 | diff --git a/tests/ui/let-else/let-else-deref-coercion.stderr b/tests/ui/let-else/let-else-deref-coercion.stderr index 543737868c9f..ed4e32cbd659 100644 --- a/tests/ui/let-else/let-else-deref-coercion.stderr +++ b/tests/ui/let-else/let-else-deref-coercion.stderr @@ -6,7 +6,7 @@ LL | let Bar::Present(z) = self else { | | | expected `Foo`, found `Bar` | -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let Bar::Present(z) = &**self else { | +++ @@ -19,7 +19,7 @@ LL | let Bar(z) = x; | | | expected `Foo`, found `Bar` | -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let Bar(z) = &**x; | +++ diff --git a/tests/ui/let-else/let-else-no-double-error.rs b/tests/ui/let-else/let-else-no-double-error.rs index 91fcc5d7e91e..7b695595483f 100644 --- a/tests/ui/let-else/let-else-no-double-error.rs +++ b/tests/ui/let-else/let-else-no-double-error.rs @@ -8,5 +8,5 @@ fn main() { let foo = 22; - let u32::XXX = foo else { return }; //~ ERROR: no associated item named `XXX` found for type `u32` in the current scope [E0599] + let u32::XXX = foo else { return }; //~ ERROR: no associated function or constant named `XXX` found for type `u32` in the current scope [E0599] } diff --git a/tests/ui/let-else/let-else-no-double-error.stderr b/tests/ui/let-else/let-else-no-double-error.stderr index 05668a23138e..4fd6a14ca911 100644 --- a/tests/ui/let-else/let-else-no-double-error.stderr +++ b/tests/ui/let-else/let-else-no-double-error.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `XXX` found for type `u32` in the current scope +error[E0599]: no associated function or constant named `XXX` found for type `u32` in the current scope --> $DIR/let-else-no-double-error.rs:11:14 | LL | let u32::XXX = foo else { return }; - | ^^^ associated item not found in `u32` + | ^^^ associated function or constant not found in `u32` error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 7f44ab2ed6b4..1ce50903ff10 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -37,6 +37,8 @@ error[E0308]: mismatched types | LL | fn a() -> [u8; foo()] { | ^^^^^ expected `usize`, found `()` + | + = note: array length can only be `usize` error: aborting due to 6 previous errors diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.rs index f5fb1649cdc4..d9251f6950df 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.rs @@ -1,11 +1,11 @@ //@ only-windows #[link(name = "foo", kind = "raw-dylib")] extern "C" { - #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes - #[link_ordinal(2)] + #[link_ordinal(1)] + #[link_ordinal(2)] //~ ERROR multiple `link_ordinal` attributes fn foo(); - #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes - #[link_ordinal(2)] + #[link_ordinal(1)] + #[link_ordinal(2)] //~ ERROR multiple `link_ordinal` attributes static mut imported_variable: i32; } diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.stderr index 2e6cf3761c2f..26d735154fcc 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.stderr @@ -1,25 +1,25 @@ error: multiple `link_ordinal` attributes - --> $DIR/link-ordinal-multiple.rs:4:5 - | -LL | #[link_ordinal(1)] - | ^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here --> $DIR/link-ordinal-multiple.rs:5:5 | LL | #[link_ordinal(2)] - | ^^^^^^^^^^^^^^^^^^ - -error: multiple `link_ordinal` attributes - --> $DIR/link-ordinal-multiple.rs:7:5 - | -LL | #[link_ordinal(1)] | ^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here + --> $DIR/link-ordinal-multiple.rs:4:5 + | +LL | #[link_ordinal(1)] + | ^^^^^^^^^^^^^^^^^^ + +error: multiple `link_ordinal` attributes --> $DIR/link-ordinal-multiple.rs:8:5 | LL | #[link_ordinal(2)] + | ^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/link-ordinal-multiple.rs:7:5 + | +LL | #[link_ordinal(1)] | ^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dead-code/const-underscore-issue-101532.rs b/tests/ui/lint/dead-code/const-underscore-issue-101532.rs new file mode 100644 index 000000000000..4dc25fbbecea --- /dev/null +++ b/tests/ui/lint/dead-code/const-underscore-issue-101532.rs @@ -0,0 +1,14 @@ +//@ check-pass +// Test for issue #101532 - dead code warnings should work inside const _ + +#![warn(dead_code)] + +const _: () = { + let a: (); + struct B {} //~ WARN struct `B` is never constructed + enum C {} //~ WARN enum `C` is never used + fn d() {} //~ WARN function `d` is never used + const E: () = {}; //~ WARN constant `E` is never used +}; + +fn main() {} diff --git a/tests/ui/lint/dead-code/const-underscore-issue-101532.stderr b/tests/ui/lint/dead-code/const-underscore-issue-101532.stderr new file mode 100644 index 000000000000..d330b9e9f40a --- /dev/null +++ b/tests/ui/lint/dead-code/const-underscore-issue-101532.stderr @@ -0,0 +1,32 @@ +warning: struct `B` is never constructed + --> $DIR/const-underscore-issue-101532.rs:8:12 + | +LL | struct B {} + | ^ + | +note: the lint level is defined here + --> $DIR/const-underscore-issue-101532.rs:4:9 + | +LL | #![warn(dead_code)] + | ^^^^^^^^^ + +warning: enum `C` is never used + --> $DIR/const-underscore-issue-101532.rs:9:10 + | +LL | enum C {} + | ^ + +warning: function `d` is never used + --> $DIR/const-underscore-issue-101532.rs:10:8 + | +LL | fn d() {} + | ^ + +warning: constant `E` is never used + --> $DIR/const-underscore-issue-101532.rs:11:11 + | +LL | const E: () = {}; + | ^ + +warning: 4 warnings emitted + diff --git a/tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs new file mode 100644 index 000000000000..68eff33cb3f1 --- /dev/null +++ b/tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs @@ -0,0 +1,13 @@ +#[macro_export] +macro_rules! identity { + ($x:ident) => { + $x + }; +} + +#[macro_export] +macro_rules! do_loop { + ($x:ident) => { + for $crate::identity!($x) in $x {} + }; +} diff --git a/tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs new file mode 100644 index 000000000000..ca3ac3b9a864 --- /dev/null +++ b/tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ aux-build:external-macro-issue-148114.rs + +// This test ensures we do not trigger the lint on external macros +// ref. + +#![deny(for_loops_over_fallibles)] + +extern crate external_macro_issue_148114 as dep; + +fn main() { + let _name = Some(1); + dep::do_loop!(_name); +} diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs b/tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.rs similarity index 100% rename from tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs rename to tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.rs diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr b/tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.stderr similarity index 100% rename from tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr rename to tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.stderr diff --git a/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs new file mode 100644 index 000000000000..0fe88734099c --- /dev/null +++ b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs @@ -0,0 +1,21 @@ +// This test ensures that the `for-loops-over-fallibles` lint doesn't suggest +// removing `next`. +// ref. + +#![forbid(for_loops_over_fallibles)] +//~^ NOTE: the lint level is defined here + +fn main() { + macro_rules! mac { + (next $e:expr) => { + $e.iter().next() + }; + } + + for _ in mac!(next [1, 2]) {} + //~^ ERROR: for loop over an `Option`. This is more readably written as an `if let` statement + //~| NOTE: in this expansion of desugaring of `for` loop + //~| NOTE: in this expansion of desugaring of `for` loop + //~| HELP: to check pattern in a loop use `while let` + //~| HELP: consider using `if let` to clear intent +} diff --git a/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr new file mode 100644 index 000000000000..36848fffa439 --- /dev/null +++ b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr @@ -0,0 +1,24 @@ +error: for loop over an `Option`. This is more readably written as an `if let` statement + --> $DIR/macro-iterator-next.rs:15:14 + | +LL | for _ in mac!(next [1, 2]) {} + | ^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/macro-iterator-next.rs:5:11 + | +LL | #![forbid(for_loops_over_fallibles)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: to check pattern in a loop use `while let` + | +LL - for _ in mac!(next [1, 2]) {} +LL + while let Some(_) = mac!(next [1, 2]) {} + | +help: consider using `if let` to clear intent + | +LL - for _ in mac!(next [1, 2]) {} +LL + if let Some(_) = mac!(next [1, 2]) {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/inline-trait-and-foreign-items.stderr b/tests/ui/lint/inline-trait-and-foreign-items.stderr index 4bde4bc590aa..b12fa4d9c47f 100644 --- a/tests/ui/lint/inline-trait-and-foreign-items.stderr +++ b/tests/ui/lint/inline-trait-and-foreign-items.stderr @@ -38,14 +38,6 @@ LL | #[inline] | = help: `#[inline]` can only be applied to functions -error: unconstrained opaque type - --> $DIR/inline-trait-and-foreign-items.rs:26:14 - | -LL | type U = impl Trait; - | ^^^^^^^^^^ - | - = note: `U` must be used in combination with a concrete type within the same impl - warning: `#[inline]` attribute cannot be used on associated consts --> $DIR/inline-trait-and-foreign-items.rs:7:5 | @@ -69,5 +61,13 @@ LL | #[inline] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[inline]` can only be applied to functions +error: unconstrained opaque type + --> $DIR/inline-trait-and-foreign-items.rs:26:14 + | +LL | type U = impl Trait; + | ^^^^^^^^^^ + | + = note: `U` must be used in combination with a concrete type within the same impl + error: aborting due to 6 previous errors; 2 warnings emitted diff --git a/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs index dfa0b8015d03..a8e23c0246ee 100644 --- a/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs +++ b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs @@ -3,7 +3,7 @@ #![move_size_limit = "1000"] //@ build-fail //@ only-64bit - +//@ ignore-parallel-frontend post-monomorphization errors //@ edition:2018 //@ compile-flags: -Zmir-opt-level=1 diff --git a/tests/ui/lint/large_assignments/copy_into_fn.rs b/tests/ui/lint/large_assignments/copy_into_fn.rs index 5222e833bcc8..8f8e7f0822bb 100644 --- a/tests/ui/lint/large_assignments/copy_into_fn.rs +++ b/tests/ui/lint/large_assignments/copy_into_fn.rs @@ -1,5 +1,5 @@ //@ build-fail - +//@ ignore-parallel-frontend post-monomorphization errors #![feature(large_assignments)] #![move_size_limit = "1000"] #![deny(large_assignments)] diff --git a/tests/ui/lint/large_assignments/inline_mir.rs b/tests/ui/lint/large_assignments/inline_mir.rs index d16aae6ab145..68c5de4902f3 100644 --- a/tests/ui/lint/large_assignments/inline_mir.rs +++ b/tests/ui/lint/large_assignments/inline_mir.rs @@ -13,7 +13,7 @@ //! ``` //! //! We want the diagnostics to point to the relevant user code. - +//@ ignore-parallel-frontend post-monomorphization errors //@ build-fail //@ compile-flags: -Zmir-opt-level=1 -Zinline-mir diff --git a/tests/ui/lint/large_assignments/large_future.rs b/tests/ui/lint/large_assignments/large_future.rs index 28c358bdbf08..1be66f16313b 100644 --- a/tests/ui/lint/large_assignments/large_future.rs +++ b/tests/ui/lint/large_assignments/large_future.rs @@ -5,7 +5,7 @@ //@ only-64bit //@ revisions: attribute option //@ [option]compile-flags: -Zmove-size-limit=1000 - +//@ ignore-parallel-frontend post-monomorphization errors //@ edition:2018 //@ compile-flags: -Zmir-opt-level=0 diff --git a/tests/ui/lint/large_assignments/move_into_fn.rs b/tests/ui/lint/large_assignments/move_into_fn.rs index b3b2160ca36e..1e793a082e3e 100644 --- a/tests/ui/lint/large_assignments/move_into_fn.rs +++ b/tests/ui/lint/large_assignments/move_into_fn.rs @@ -1,5 +1,5 @@ //@ build-fail - +//@ ignore-parallel-frontend post-monomorphization errors #![feature(large_assignments)] #![move_size_limit = "1000"] #![deny(large_assignments)] diff --git a/tests/ui/lint/must_not_suspend/issue-89562.rs b/tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs similarity index 67% rename from tests/ui/lint/must_not_suspend/issue-89562.rs rename to tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs index 99a548130720..d1c48c3c5145 100644 --- a/tests/ui/lint/must_not_suspend/issue-89562.rs +++ b/tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs @@ -1,9 +1,13 @@ +//! Regression test for + //@ edition:2018 //@ run-pass +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + use std::sync::Mutex; -// Copied from the issue. Allow-by-default for now, so run-pass pub async fn foo() { let foo = Mutex::new(1); let lock = foo.lock().unwrap(); diff --git a/tests/ui/lint/non-snake-case/lint-uppercase-variables.rs b/tests/ui/lint/non-snake-case/lint-uppercase-variables.rs index aefbe63606a1..be3450494aaf 100644 --- a/tests/ui/lint/non-snake-case/lint-uppercase-variables.rs +++ b/tests/ui/lint/non-snake-case/lint-uppercase-variables.rs @@ -1,7 +1,7 @@ #![warn(unused)] #![allow(dead_code)] #![deny(non_snake_case)] - +//@ ignore-parallel-frontend `note`s on different source lines mod foo { pub enum Foo { Foo } } diff --git a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs index ad85a777ef9a..3b8cbe99a65e 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs @@ -2,7 +2,7 @@ //@ compile-flags: --force-warn unused_variables //@ compile-flags: --force-warn unused_mut //@ check-pass - +//@ ignore-parallel-frontend `note`s on different source lines fn expect_early_pass_lint() { #[expect(while_true)] while true { diff --git a/tests/ui/lint/unused-features/stable-features.rs b/tests/ui/lint/unused-features/stable-features.rs new file mode 100644 index 000000000000..d27be14b86d5 --- /dev/null +++ b/tests/ui/lint/unused-features/stable-features.rs @@ -0,0 +1,17 @@ +//@ check-pass + +#![deny(warnings)] +#![allow(stable_features)] + +// Lang feature +#![feature(lint_reasons)] + +// Lib feature +#![feature(euclidean_division)] + +#[allow(unused_variables, reason = "my reason")] +fn main() { + let x = (); + + let _ = 42.0_f32.div_euclid(3.0); +} diff --git a/tests/ui/lint/unused-features/unused-library-features.rs b/tests/ui/lint/unused-features/unused-library-features.rs index 75afd32e56cb..2f53ab66b160 100644 --- a/tests/ui/lint/unused-features/unused-library-features.rs +++ b/tests/ui/lint/unused-features/unused-library-features.rs @@ -5,8 +5,7 @@ #![feature(step_trait)] //~^ ERROR feature `step_trait` is declared but not used #![feature(is_sorted)] -//~^ ERROR feature `is_sorted` is declared but not used -//~^^ WARN the feature `is_sorted` has been stable since 1.82.0 and no longer requires an attribute to enable +//~^ WARN the feature `is_sorted` has been stable since 1.82.0 and no longer requires an attribute to enable // Enabled via cfg_attr, unused #![cfg_attr(all(), feature(slice_ptr_get))] diff --git a/tests/ui/lint/unused-features/unused-library-features.stderr b/tests/ui/lint/unused-features/unused-library-features.stderr index e259058d6c33..bf71e269e2f0 100644 --- a/tests/ui/lint/unused-features/unused-library-features.stderr +++ b/tests/ui/lint/unused-features/unused-library-features.stderr @@ -18,17 +18,11 @@ note: the lint level is defined here LL | #![deny(unused_features)] | ^^^^^^^^^^^^^^^ -error: feature `is_sorted` is declared but not used - --> $DIR/unused-library-features.rs:7:12 - | -LL | #![feature(is_sorted)] - | ^^^^^^^^^ - error: feature `slice_ptr_get` is declared but not used - --> $DIR/unused-library-features.rs:12:28 + --> $DIR/unused-library-features.rs:11:28 | LL | #![cfg_attr(all(), feature(slice_ptr_get))] | ^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/empty/empty-attributes.rs b/tests/ui/lint/unused/empty-attributes.rs similarity index 100% rename from tests/ui/empty/empty-attributes.rs rename to tests/ui/lint/unused/empty-attributes.rs diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/lint/unused/empty-attributes.stderr similarity index 100% rename from tests/ui/empty/empty-attributes.stderr rename to tests/ui/lint/unused/empty-attributes.stderr diff --git a/tests/ui/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs index a334c49788cb..2b29fde128e4 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.rs +++ b/tests/ui/lint/unused/unused-attr-duplicate.rs @@ -61,7 +61,7 @@ macro_rules! foo { fn t1() {} #[must_use] -#[must_use = "some message"] //~ ERROR unused attribute +#[must_use = "some message"] //~ ERROR unused attribute //~^ WARN this was previously accepted // No warnings for #[repr], would require more logic. #[repr(C)] @@ -89,15 +89,15 @@ pub fn xyz() {} #[link(name = "rust_test_helpers", kind = "static")] #[link(name = "rust_test_helpers", kind = "static")] extern "C" { - #[link_name = "this_does_not_exist"] //~ ERROR unused attribute + #[link_name = "this_does_not_exist"] + #[link_name = "rust_dbg_extern_identity_u32"] //~ ERROR unused attribute //~^ WARN this was previously accepted - #[link_name = "rust_dbg_extern_identity_u32"] pub fn name_in_rust(v: u32) -> u32; } -#[export_name = "exported_symbol_name"] //~ ERROR unused attribute +#[export_name = "exported_symbol_name"] +#[export_name = "exported_symbol_name2"] //~ ERROR unused attribute //~^ WARN this was previously accepted -#[export_name = "exported_symbol_name2"] pub fn export_test() {} #[no_mangle] @@ -109,9 +109,9 @@ pub fn no_mangle_test() {} static FOO: u32 = 0; #[link_section = ".text"] +#[link_section = ".bss"] //~^ ERROR unused attribute //~| WARN this was previously accepted -#[link_section = ".bss"] pub extern "C" fn example() {} fn main() {} diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 351645f4a783..1942249d1f8e 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -165,29 +165,29 @@ LL | #[track_caller] | ^^^^^^^^^^^^^^^ error: unused attribute + --> $DIR/unused-attr-duplicate.rs:93:5 + | +LL | #[link_name = "rust_dbg_extern_identity_u32"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here --> $DIR/unused-attr-duplicate.rs:92:5 | LL | #[link_name = "this_does_not_exist"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:94:5 - | -LL | #[link_name = "rust_dbg_extern_identity_u32"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute + --> $DIR/unused-attr-duplicate.rs:99:1 + | +LL | #[export_name = "exported_symbol_name2"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here --> $DIR/unused-attr-duplicate.rs:98:1 | LL | #[export_name = "exported_symbol_name"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:100:1 - | -LL | #[export_name = "exported_symbol_name2"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute @@ -215,16 +215,16 @@ LL | #[used] | ^^^^^^^ error: unused attribute + --> $DIR/unused-attr-duplicate.rs:112:1 + | +LL | #[link_section = ".bss"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here --> $DIR/unused-attr-duplicate.rs:111:1 | LL | #[link_section = ".text"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:114:1 - | -LL | #[link_section = ".bss"] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute diff --git a/tests/ui/liveness/liveness-unused.rs b/tests/ui/liveness/liveness-unused.rs index a291d2489695..95345c22b041 100644 --- a/tests/ui/liveness/liveness-unused.rs +++ b/tests/ui/liveness/liveness-unused.rs @@ -3,7 +3,7 @@ #![deny(unused_assignments)] #![allow(dead_code, non_camel_case_types, trivial_numeric_casts, dropping_copy_types)] #![feature(intrinsics)] - +//@ ignore-parallel-frontend `note`s on different source lines use std::ops::AddAssign; fn f1(x: isize) { diff --git a/tests/ui/liveness/liveness-upvars.rs b/tests/ui/liveness/liveness-upvars.rs index be58b48a4057..0e198f1dea10 100644 --- a/tests/ui/liveness/liveness-upvars.rs +++ b/tests/ui/liveness/liveness-upvars.rs @@ -98,7 +98,7 @@ pub fn g(mut v: T) { } pub fn h() { - let mut z = T::default(); + let mut z = T::default(); //~ WARN unused variable: `z` let _ = move |b| { loop { if b { diff --git a/tests/ui/liveness/liveness-upvars.stderr b/tests/ui/liveness/liveness-upvars.stderr index cfed2830164a..0bb5786ab3e2 100644 --- a/tests/ui/liveness/liveness-upvars.stderr +++ b/tests/ui/liveness/liveness-upvars.stderr @@ -156,6 +156,14 @@ LL | z = T::default(); | = help: maybe it is overwritten before being read? +warning: unused variable: `z` + --> $DIR/liveness-upvars.rs:101:9 + | +LL | let mut z = T::default(); + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_z` + | + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + warning: value captured by `state` is never read --> $DIR/liveness-upvars.rs:131:9 | @@ -196,5 +204,5 @@ LL | s = yield (); | = help: maybe it is overwritten before being read? -warning: 24 warnings emitted +warning: 25 warnings emitted diff --git a/tests/ui/loops/loop-break-value.stderr b/tests/ui/loops/loop-break-value.stderr index 3b9735510bd7..8810d16ca598 100644 --- a/tests/ui/loops/loop-break-value.stderr +++ b/tests/ui/loops/loop-break-value.stderr @@ -232,10 +232,10 @@ LL | break (break, break); | || | | || expected because of this `break` | |expected because of this `break` - | expected `()`, found `(!, !)` + | expected `()`, found `(_, _)` | = note: expected unit type `()` - found tuple `(!, !)` + found tuple `(_, _)` error[E0308]: mismatched types --> $DIR/loop-break-value.rs:89:15 diff --git a/tests/ui/lowering/issue-121108.stderr b/tests/ui/lowering/issue-121108.stderr index f68655a70021..e1aa153eede6 100644 --- a/tests/ui/lowering/issue-121108.stderr +++ b/tests/ui/lowering/issue-121108.stderr @@ -5,7 +5,7 @@ LL | #![derive(Clone, Copy)] | ^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | use std::ptr::addr_of; - | ------- the inner attribute doesn't annotate this import + | ---------------------- the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | diff --git a/tests/ui/issues/issue-44056.rs b/tests/ui/lto/lto-avx-target-feature.rs similarity index 72% rename from tests/ui/issues/issue-44056.rs rename to tests/ui/lto/lto-avx-target-feature.rs index 37d7b00cf7f0..37a8ce67dcfc 100644 --- a/tests/ui/issues/issue-44056.rs +++ b/tests/ui/lto/lto-avx-target-feature.rs @@ -1,3 +1,4 @@ +//! regression test for //@ build-pass (FIXME(55996): should be run on targets supporting avx) //@ only-x86_64 //@ no-prefer-dynamic diff --git a/tests/ui/issues/issue-51947.rs b/tests/ui/lto/lto-weak-merge-functions.rs similarity index 82% rename from tests/ui/issues/issue-51947.rs rename to tests/ui/lto/lto-weak-merge-functions.rs index eda48aa5cf47..bf16fbc83435 100644 --- a/tests/ui/issues/issue-51947.rs +++ b/tests/ui/lto/lto-weak-merge-functions.rs @@ -1,3 +1,4 @@ +//! regression test for //@ build-pass #![crate_type = "lib"] diff --git a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs new file mode 100644 index 000000000000..5a6ef0421e2f --- /dev/null +++ b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs @@ -0,0 +1,23 @@ +macro_rules! local_assert_ne { + ($left:expr, $right:expr $(,)?) => { + match (&$left, &$right) { + (left_val, right_val) => { + if *left_val == *right_val { + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + panic!(); + } + } + } + }; +} + +fn main() { + let buf = [0_u8; 4]; + assert_ne!(buf, b"----"); + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + + assert_eq!(buf, b"----"); + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + + local_assert_ne!(buf, b"----"); +} diff --git a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr new file mode 100644 index 000000000000..359deee7bee4 --- /dev/null +++ b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr @@ -0,0 +1,55 @@ +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:16:5 + | +LL | assert_ne!(buf, b"----"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `[u8; 4] == &[u8; 4]` + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq<[U; N]>` + `&[u8; N]` implements `PartialEq` + `&[u8; N]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&mut [T]` implements `PartialEq>` + `&mut [T]` implements `PartialEq<[U; N]>` + and 11 others + +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:19:5 + | +LL | assert_eq!(buf, b"----"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `[u8; 4] == &[u8; 4]` + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq<[U; N]>` + `&[u8; N]` implements `PartialEq` + `&[u8; N]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&mut [T]` implements `PartialEq>` + `&mut [T]` implements `PartialEq<[U; N]>` + and 11 others + +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:5:30 + | +LL | if *left_val == *right_val { + | ^^ no implementation for `[u8; 4] == &[u8; 4]` +... +LL | local_assert_ne!(buf, b"----"); + | ------------------------------ in this macro invocation + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = note: this error originates in the macro `local_assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider dereferencing here + | +LL | if *left_val == **right_val { + | + + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/macros/attr-expr.rs b/tests/ui/macros/attr-expr.rs new file mode 100644 index 000000000000..a2bee8728ac5 --- /dev/null +++ b/tests/ui/macros/attr-expr.rs @@ -0,0 +1,19 @@ +macro_rules! foo { + ($e:expr) => { + #[$e] + //~^ ERROR expected identifier, found metavariable + fn foo() {} + }; +} +foo!(inline); + +macro_rules! bar { + ($e:expr) => { + #[inline($e)] + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable + fn bar() {} + }; +} +bar!(always); + +fn main() {} diff --git a/tests/ui/macros/attr-expr.stderr b/tests/ui/macros/attr-expr.stderr new file mode 100644 index 000000000000..eaad41c44fb9 --- /dev/null +++ b/tests/ui/macros/attr-expr.stderr @@ -0,0 +1,24 @@ +error: expected identifier, found metavariable + --> $DIR/attr-expr.rs:3:11 + | +LL | #[$e] + | ^^ expected identifier, found metavariable +... +LL | foo!(inline); + | ------------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable + --> $DIR/attr-expr.rs:12:18 + | +LL | #[inline($e)] + | ^^ +... +LL | bar!(always); + | ------------ in this macro invocation + | + = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/cfg-expr.rs b/tests/ui/macros/cfg-expr.rs new file mode 100644 index 000000000000..e9ca6e3d7b10 --- /dev/null +++ b/tests/ui/macros/cfg-expr.rs @@ -0,0 +1,44 @@ +//@ run-pass +macro_rules! foo { + ($e:expr, $n:ident) => { + #[cfg($e)] + macro_rules! $n { + () => {} + } + + #[cfg_attr($e, allow(non_snake_case))] + #[cfg($e)] + fn $n() { + #[cfg($e)] + $n!(); + } + + #[cfg_attr(not($e), allow(unused))] + #[cfg(not($e))] + fn $n() { + panic!() + } + } +} +foo!(true, BAR); +foo!(any(true, unix, target_pointer_width = "64"), baz); +foo!(target_pointer_width = "64", quux); +foo!(false, haha); + +fn main() { + BAR(); + BAR!(); + baz(); + baz!(); + #[cfg(target_pointer_width = "64")] + quux(); + #[cfg(target_pointer_width = "64")] + quux!(); + #[cfg(panic = "unwind")] + { + let result = std::panic::catch_unwind(|| { + haha(); + }); + assert!(result.is_err()); + } +} diff --git a/tests/ui/macros/cfg_attr-expr.rs b/tests/ui/macros/cfg_attr-expr.rs new file mode 100644 index 000000000000..1dab2cae59fa --- /dev/null +++ b/tests/ui/macros/cfg_attr-expr.rs @@ -0,0 +1,9 @@ +macro_rules! foo { + ($e:expr) => { + #[cfg_attr(true, $e)] + //~^ ERROR expected identifier, found metavariable + fn foo() {} + } +} +foo!(inline); +fn main() {} diff --git a/tests/ui/macros/cfg_attr-expr.stderr b/tests/ui/macros/cfg_attr-expr.stderr new file mode 100644 index 000000000000..a46ea104b939 --- /dev/null +++ b/tests/ui/macros/cfg_attr-expr.stderr @@ -0,0 +1,17 @@ +error: expected identifier, found metavariable + --> $DIR/cfg_attr-expr.rs:3:26 + | +LL | #[cfg_attr(true, $e)] + | -----------------^^-- + | | | + | | expected identifier, found metavariable + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` +... +LL | foo!(inline); + | ------------ in this macro invocation + | + = note: for more information, visit + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/cfg_select-expr.rs b/tests/ui/macros/cfg_select-expr.rs new file mode 100644 index 000000000000..90e894562a16 --- /dev/null +++ b/tests/ui/macros/cfg_select-expr.rs @@ -0,0 +1,57 @@ +//@ run-pass +#![allow(unreachable_cfg_select_predicates)] + +macro_rules! foo { + ($e:expr, $n:ident) => { + cfg_select! { + $e => { + macro_rules! $n { + () => {} + } + } + _ => {} + } + + cfg_select! { + $e => { + #[cfg_attr($e, allow(non_snake_case))] + fn $n() { + cfg_select! { + $e => { + $n!(); + } + _ => {} + } + } + } + not($e) => { + #[cfg_attr(not($e), allow(unused))] + fn $n() { + panic!() + } + } + } + } +} +foo!(true, BAR); +foo!(any(true, unix, target_pointer_width = "64"), baz); +foo!(target_pointer_width = "64", quux); +foo!(false, haha); + +fn main() { + BAR(); + BAR!(); + baz(); + baz!(); + #[cfg(target_pointer_width = "64")] + quux(); + #[cfg(target_pointer_width = "64")] + quux!(); + #[cfg(panic = "unwind")] + { + let result = std::panic::catch_unwind(|| { + haha(); + }); + assert!(result.is_err()); + } +} diff --git a/tests/ui/cross/cross-file-errors/main.rs b/tests/ui/macros/cross-file-errors.rs similarity index 100% rename from tests/ui/cross/cross-file-errors/main.rs rename to tests/ui/macros/cross-file-errors.rs diff --git a/tests/ui/cross/cross-file-errors/main.stderr b/tests/ui/macros/cross-file-errors.stderr similarity index 92% rename from tests/ui/cross/cross-file-errors/main.stderr rename to tests/ui/macros/cross-file-errors.stderr index db7b3a84fc8b..70db7d5185ea 100644 --- a/tests/ui/cross/cross-file-errors/main.stderr +++ b/tests/ui/macros/cross-file-errors.stderr @@ -4,7 +4,7 @@ error: in expressions, `_` can only be used on the left-hand side of an assignme LL | _ | ^ `_` not allowed here | - ::: $DIR/main.rs:5:5 + ::: $DIR/cross-file-errors.rs:5:5 | LL | underscore!(); | ------------- in this macro invocation diff --git a/tests/ui/macros/die-macro-2.rs b/tests/ui/macros/die-macro-2.rs deleted file mode 100644 index d802f189ce1a..000000000000 --- a/tests/ui/macros/die-macro-2.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-fail -//@ error-pattern:test -//@ needs-subprocess - -fn main() { - panic!("test"); -} diff --git a/tests/ui/macros/die-macro-pure.rs b/tests/ui/macros/die-macro-pure.rs deleted file mode 100644 index d84787705a1a..000000000000 --- a/tests/ui/macros/die-macro-pure.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-fail -//@ error-pattern:test -//@ needs-subprocess - -fn f() { - panic!("test"); -} - -fn main() { - f(); -} diff --git a/tests/ui/macros/die-macro.rs b/tests/ui/macros/die-macro.rs deleted file mode 100644 index b717eed3fb43..000000000000 --- a/tests/ui/macros/die-macro.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -// Just testing that panic!() type checks in statement or expr - - -#![allow(unreachable_code)] - -fn f() { - panic!(); - - let _x: isize = panic!(); -} - -pub fn main() { - -} diff --git a/tests/ui/empty/empty-comment.rs b/tests/ui/macros/empty-comment.rs similarity index 100% rename from tests/ui/empty/empty-comment.rs rename to tests/ui/macros/empty-comment.rs diff --git a/tests/ui/empty/empty-comment.stderr b/tests/ui/macros/empty-comment.stderr similarity index 100% rename from tests/ui/empty/empty-comment.stderr rename to tests/ui/macros/empty-comment.stderr diff --git a/tests/ui/invalid/invalid-macro-matcher.rs b/tests/ui/macros/invalid-macro-matcher.rs similarity index 100% rename from tests/ui/invalid/invalid-macro-matcher.rs rename to tests/ui/macros/invalid-macro-matcher.rs diff --git a/tests/ui/invalid/invalid-macro-matcher.stderr b/tests/ui/macros/invalid-macro-matcher.stderr similarity index 100% rename from tests/ui/invalid/invalid-macro-matcher.stderr rename to tests/ui/macros/invalid-macro-matcher.stderr diff --git a/tests/ui/macros/issue-2804.rs b/tests/ui/macros/issue-2804.rs index 0b6f9487ece2..9f45df4a3178 100644 --- a/tests/ui/macros/issue-2804.rs +++ b/tests/ui/macros/issue-2804.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(non_camel_case_types)] #![allow(dead_code)] diff --git a/tests/ui/macros/issue-33185.rs b/tests/ui/macros/issue-33185.rs index 8d7e305f1e35..5771b40809dc 100644 --- a/tests/ui/macros/issue-33185.rs +++ b/tests/ui/macros/issue-33185.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #[macro_export] diff --git a/tests/ui/macros/issue-40469.rs b/tests/ui/macros/issue-40469.rs index faa4c6581af7..4529e44e267d 100644 --- a/tests/ui/macros/issue-40469.rs +++ b/tests/ui/macros/issue-40469.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] diff --git a/tests/ui/macros/issue-40770.rs b/tests/ui/macros/issue-40770.rs index d90294acd251..028bd48b1be7 100644 --- a/tests/ui/macros/issue-40770.rs +++ b/tests/ui/macros/issue-40770.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_macros)] macro_rules! m { ($e:expr) => { diff --git a/tests/ui/macros/issue-6596-1.stderr b/tests/ui/macros/issue-6596-1.stderr index f20d67329dbe..cb66dcc6ea89 100644 --- a/tests/ui/macros/issue-6596-1.stderr +++ b/tests/ui/macros/issue-6596-1.stderr @@ -2,11 +2,15 @@ error: expected expression, found `$` --> $DIR/issue-6596-1.rs:3:9 | LL | $nonexistent - | ^^^^^^^^^^^^ expected expression + | ^----------- + | || + | |macro metavariable not found + | expected expression ... LL | e!(foo); | ------- in this macro invocation | + = note: available metavariable names are: $inp = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-attribute-expansion.rs b/tests/ui/macros/macro-attribute-expansion.rs index be682b38865d..255400e2679e 100644 --- a/tests/ui/macros/macro-attribute-expansion.rs +++ b/tests/ui/macros/macro-attribute-expansion.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! descriptions { ($name:ident is $desc:expr) => { // Check that we will correctly expand attributes diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs index 976d2cbcccdb..a25ed2ba7ef6 100644 --- a/tests/ui/macros/macro-attributes.rs +++ b/tests/ui/macros/macro-attributes.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! compiles_fine { (#[$at:meta]) => { diff --git a/tests/ui/macros/macro-delimiter-significance.rs b/tests/ui/macros/macro-delimiter-significance.rs index 8b532e19196b..1947ecf9b22e 100644 --- a/tests/ui/macros/macro-delimiter-significance.rs +++ b/tests/ui/macros/macro-delimiter-significance.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass fn main() { vec![1_usize, 2, 3].len(); } diff --git a/tests/ui/macros/macro-doc-comments.rs b/tests/ui/macros/macro-doc-comments.rs index 47740e26fb6f..4622c3710e93 100644 --- a/tests/ui/macros/macro-doc-comments.rs +++ b/tests/ui/macros/macro-doc-comments.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(non_snake_case)] macro_rules! doc { diff --git a/tests/ui/macros/macro-doc-escapes.rs b/tests/ui/macros/macro-doc-escapes.rs index 81c8d3383b57..77d9a5c048fa 100644 --- a/tests/ui/macros/macro-doc-escapes.rs +++ b/tests/ui/macros/macro-doc-escapes.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass // When expanding a macro, documentation attributes (including documentation comments) must be // passed "as is" without being parsed. Otherwise, some text will be incorrectly interpreted as // escape sequences, leading to an ICE. diff --git a/tests/ui/macros/macro-follow-rpass.rs b/tests/ui/macros/macro-follow-rpass.rs index 8551b1887708..3103e86539a6 100644 --- a/tests/ui/macros/macro-follow-rpass.rs +++ b/tests/ui/macros/macro-follow-rpass.rs @@ -1,15 +1,16 @@ //@ edition:2015..2021 -//@ run-pass +//@ check-pass #![allow(unused_macros)] // Check the macro follow sets (see corresponding cfail test). -// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} +// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), MetaVarDecl(Guard), Ident(in)} macro_rules! follow_pat { ($p:pat =>) => {}; ($p:pat ,) => {}; ($p:pat =) => {}; ($p:pat |) => {}; ($p:pat if) => {}; + ($p:pat if let) => {}; ($p:pat in) => {}; } // FOLLOW(expr) = {FatArrow, Comma, Semicolon} diff --git a/tests/ui/macros/macro-follow.rs b/tests/ui/macros/macro-follow.rs index 923c9bd6cedc..874bad6a7431 100644 --- a/tests/ui/macros/macro-follow.rs +++ b/tests/ui/macros/macro-follow.rs @@ -2,9 +2,10 @@ // // Check the macro follow sets (see corresponding rpass test). +#![feature(macro_guard_matcher)] #![allow(unused_macros)] -// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} +// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), MetaVarDecl(Guard), Ident(in)} macro_rules! follow_pat { ($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(` ($p:pat []) => {}; //~ERROR `$p:pat` is followed by `[` @@ -47,6 +48,7 @@ macro_rules! follow_expr { ($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt` ($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item` ($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta` + ($e:expr $g:guard) => {}; //~ERROR `$e:expr` is followed by `$g:guard` } // FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or, // Ident(as), Ident(where), OpenDelim(Bracket), Nonterminal(Block)} @@ -66,6 +68,7 @@ macro_rules! follow_ty { ($t:ty $r:tt) => {}; //~ERROR `$t:ty` is followed by `$r:tt` ($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item` ($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta` + ($t:ty $g:guard) => {}; //~ERROR `$t:ty` is followed by `$g:guard` } // FOLLOW(stmt) = FOLLOW(expr) macro_rules! follow_stmt { @@ -90,6 +93,7 @@ macro_rules! follow_stmt { ($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt` ($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item` ($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta` + ($s:stmt $g:guard) => {}; //~ERROR `$s:stmt` is followed by `$g:guard` } // FOLLOW(path) = FOLLOW(ty) macro_rules! follow_path { @@ -108,6 +112,7 @@ macro_rules! follow_path { ($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt` ($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item` ($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta` + ($p:path $g:guard) => {}; //~ERROR `$p:path` is followed by `$g:guard` } // FOLLOW(block) = any token // FOLLOW(ident) = any token diff --git a/tests/ui/macros/macro-follow.stderr b/tests/ui/macros/macro-follow.stderr index 92491dc26d12..78d167added7 100644 --- a/tests/ui/macros/macro-follow.stderr +++ b/tests/ui/macros/macro-follow.stderr @@ -1,141 +1,141 @@ error: `$p:pat` is followed by `(`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:9:13 + --> $DIR/macro-follow.rs:10:13 | LL | ($p:pat ()) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:10:13 + --> $DIR/macro-follow.rs:11:13 | LL | ($p:pat []) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:11:13 + --> $DIR/macro-follow.rs:12:13 | LL | ($p:pat {}) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:12:13 + --> $DIR/macro-follow.rs:13:13 | LL | ($p:pat :) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:13:13 + --> $DIR/macro-follow.rs:14:13 | LL | ($p:pat >) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:14:13 + --> $DIR/macro-follow.rs:15:13 | LL | ($p:pat +) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:15:13 + --> $DIR/macro-follow.rs:16:13 | LL | ($p:pat ident) => {}; | ^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$q:pat`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:16:13 + --> $DIR/macro-follow.rs:17:13 | LL | ($p:pat $q:pat) => {}; | ^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:17:13 + --> $DIR/macro-follow.rs:18:13 | LL | ($p:pat $e:expr) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:18:13 + --> $DIR/macro-follow.rs:19:13 | LL | ($p:pat $t:ty) => {}; | ^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:19:13 + --> $DIR/macro-follow.rs:20:13 | LL | ($p:pat $s:stmt) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$q:path`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:20:13 + --> $DIR/macro-follow.rs:21:13 | LL | ($p:pat $q:path) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:21:13 + --> $DIR/macro-follow.rs:22:13 | LL | ($p:pat $b:block) => {}; | ^^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:22:13 + --> $DIR/macro-follow.rs:23:13 | LL | ($p:pat $i:ident) => {}; | ^^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:23:13 + --> $DIR/macro-follow.rs:24:13 | LL | ($p:pat $t:tt) => {}; | ^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:24:13 + --> $DIR/macro-follow.rs:25:13 | LL | ($p:pat $i:item) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:25:13 + --> $DIR/macro-follow.rs:26:13 | LL | ($p:pat $m:meta) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:29:14 + --> $DIR/macro-follow.rs:30:14 | LL | ($e:expr ()) => {}; | ^ not allowed after `expr` fragments @@ -143,7 +143,7 @@ LL | ($e:expr ()) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:30:14 + --> $DIR/macro-follow.rs:31:14 | LL | ($e:expr []) => {}; | ^ not allowed after `expr` fragments @@ -151,7 +151,7 @@ LL | ($e:expr []) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:31:14 + --> $DIR/macro-follow.rs:32:14 | LL | ($e:expr {}) => {}; | ^ not allowed after `expr` fragments @@ -159,7 +159,7 @@ LL | ($e:expr {}) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:32:14 + --> $DIR/macro-follow.rs:33:14 | LL | ($e:expr =) => {}; | ^ not allowed after `expr` fragments @@ -167,7 +167,7 @@ LL | ($e:expr =) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:33:14 + --> $DIR/macro-follow.rs:34:14 | LL | ($e:expr |) => {}; | ^ not allowed after `expr` fragments @@ -175,7 +175,7 @@ LL | ($e:expr |) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:34:14 + --> $DIR/macro-follow.rs:35:14 | LL | ($e:expr :) => {}; | ^ not allowed after `expr` fragments @@ -183,7 +183,7 @@ LL | ($e:expr :) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:35:14 + --> $DIR/macro-follow.rs:36:14 | LL | ($e:expr >) => {}; | ^ not allowed after `expr` fragments @@ -191,7 +191,7 @@ LL | ($e:expr >) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:36:14 + --> $DIR/macro-follow.rs:37:14 | LL | ($e:expr +) => {}; | ^ not allowed after `expr` fragments @@ -199,7 +199,7 @@ LL | ($e:expr +) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:37:14 + --> $DIR/macro-follow.rs:38:14 | LL | ($e:expr ident) => {}; | ^^^^^ not allowed after `expr` fragments @@ -207,7 +207,7 @@ LL | ($e:expr ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:38:14 + --> $DIR/macro-follow.rs:39:14 | LL | ($e:expr if) => {}; | ^^ not allowed after `expr` fragments @@ -215,7 +215,7 @@ LL | ($e:expr if) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:39:14 + --> $DIR/macro-follow.rs:40:14 | LL | ($e:expr in) => {}; | ^^ not allowed after `expr` fragments @@ -223,7 +223,7 @@ LL | ($e:expr in) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:40:14 + --> $DIR/macro-follow.rs:41:14 | LL | ($e:expr $p:pat) => {}; | ^^^^^^ not allowed after `expr` fragments @@ -231,7 +231,7 @@ LL | ($e:expr $p:pat) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$f:expr`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:41:14 + --> $DIR/macro-follow.rs:42:14 | LL | ($e:expr $f:expr) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -239,7 +239,7 @@ LL | ($e:expr $f:expr) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:42:14 + --> $DIR/macro-follow.rs:43:14 | LL | ($e:expr $t:ty) => {}; | ^^^^^ not allowed after `expr` fragments @@ -247,7 +247,7 @@ LL | ($e:expr $t:ty) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:43:14 + --> $DIR/macro-follow.rs:44:14 | LL | ($e:expr $s:stmt) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -255,7 +255,7 @@ LL | ($e:expr $s:stmt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:44:14 + --> $DIR/macro-follow.rs:45:14 | LL | ($e:expr $p:path) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -263,7 +263,7 @@ LL | ($e:expr $p:path) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:45:14 + --> $DIR/macro-follow.rs:46:14 | LL | ($e:expr $b:block) => {}; | ^^^^^^^^ not allowed after `expr` fragments @@ -271,7 +271,7 @@ LL | ($e:expr $b:block) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:46:14 + --> $DIR/macro-follow.rs:47:14 | LL | ($e:expr $i:ident) => {}; | ^^^^^^^^ not allowed after `expr` fragments @@ -279,7 +279,7 @@ LL | ($e:expr $i:ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:47:14 + --> $DIR/macro-follow.rs:48:14 | LL | ($e:expr $t:tt) => {}; | ^^^^^ not allowed after `expr` fragments @@ -287,7 +287,7 @@ LL | ($e:expr $t:tt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:48:14 + --> $DIR/macro-follow.rs:49:14 | LL | ($e:expr $i:item) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -295,15 +295,23 @@ LL | ($e:expr $i:item) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:49:14 + --> $DIR/macro-follow.rs:50:14 | LL | ($e:expr $m:meta) => {}; | ^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` +error: `$e:expr` is followed by `$g:guard`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:51:14 + | +LL | ($e:expr $g:guard) => {}; + | ^^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:54:12 + --> $DIR/macro-follow.rs:56:12 | LL | ($t:ty ()) => {}; | ^ not allowed after `ty` fragments @@ -311,7 +319,7 @@ LL | ($t:ty ()) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:56:12 + --> $DIR/macro-follow.rs:58:12 | LL | ($t:ty +) => {}; | ^ not allowed after `ty` fragments @@ -319,7 +327,7 @@ LL | ($t:ty +) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:57:12 + --> $DIR/macro-follow.rs:59:12 | LL | ($t:ty ident) => {}; | ^^^^^ not allowed after `ty` fragments @@ -327,7 +335,7 @@ LL | ($t:ty ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:58:12 + --> $DIR/macro-follow.rs:60:12 | LL | ($t:ty if) => {}; | ^^ not allowed after `ty` fragments @@ -335,7 +343,7 @@ LL | ($t:ty if) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:59:12 + --> $DIR/macro-follow.rs:61:12 | LL | ($t:ty $p:pat) => {}; | ^^^^^^ not allowed after `ty` fragments @@ -343,7 +351,7 @@ LL | ($t:ty $p:pat) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:60:12 + --> $DIR/macro-follow.rs:62:12 | LL | ($t:ty $e:expr) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -351,7 +359,7 @@ LL | ($t:ty $e:expr) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$r:ty`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:61:12 + --> $DIR/macro-follow.rs:63:12 | LL | ($t:ty $r:ty) => {}; | ^^^^^ not allowed after `ty` fragments @@ -359,7 +367,7 @@ LL | ($t:ty $r:ty) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:62:12 + --> $DIR/macro-follow.rs:64:12 | LL | ($t:ty $s:stmt) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -367,7 +375,7 @@ LL | ($t:ty $s:stmt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:63:12 + --> $DIR/macro-follow.rs:65:12 | LL | ($t:ty $p:path) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -375,7 +383,7 @@ LL | ($t:ty $p:path) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:65:12 + --> $DIR/macro-follow.rs:67:12 | LL | ($t:ty $i:ident) => {}; | ^^^^^^^^ not allowed after `ty` fragments @@ -383,7 +391,7 @@ LL | ($t:ty $i:ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$r:tt`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:66:12 + --> $DIR/macro-follow.rs:68:12 | LL | ($t:ty $r:tt) => {}; | ^^^^^ not allowed after `ty` fragments @@ -391,7 +399,7 @@ LL | ($t:ty $r:tt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:67:12 + --> $DIR/macro-follow.rs:69:12 | LL | ($t:ty $i:item) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -399,15 +407,23 @@ LL | ($t:ty $i:item) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:68:12 + --> $DIR/macro-follow.rs:70:12 | LL | ($t:ty $m:meta) => {}; | ^^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` +error: `$t:ty` is followed by `$g:guard`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:71:12 + | +LL | ($t:ty $g:guard) => {}; + | ^^^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:72:14 + --> $DIR/macro-follow.rs:75:14 | LL | ($s:stmt ()) => {}; | ^ not allowed after `stmt` fragments @@ -415,7 +431,7 @@ LL | ($s:stmt ()) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:73:14 + --> $DIR/macro-follow.rs:76:14 | LL | ($s:stmt []) => {}; | ^ not allowed after `stmt` fragments @@ -423,7 +439,7 @@ LL | ($s:stmt []) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:74:14 + --> $DIR/macro-follow.rs:77:14 | LL | ($s:stmt {}) => {}; | ^ not allowed after `stmt` fragments @@ -431,7 +447,7 @@ LL | ($s:stmt {}) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:75:14 + --> $DIR/macro-follow.rs:78:14 | LL | ($s:stmt =) => {}; | ^ not allowed after `stmt` fragments @@ -439,7 +455,7 @@ LL | ($s:stmt =) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:76:14 + --> $DIR/macro-follow.rs:79:14 | LL | ($s:stmt |) => {}; | ^ not allowed after `stmt` fragments @@ -447,7 +463,7 @@ LL | ($s:stmt |) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:77:14 + --> $DIR/macro-follow.rs:80:14 | LL | ($s:stmt :) => {}; | ^ not allowed after `stmt` fragments @@ -455,7 +471,7 @@ LL | ($s:stmt :) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:78:14 + --> $DIR/macro-follow.rs:81:14 | LL | ($s:stmt >) => {}; | ^ not allowed after `stmt` fragments @@ -463,7 +479,7 @@ LL | ($s:stmt >) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:79:14 + --> $DIR/macro-follow.rs:82:14 | LL | ($s:stmt +) => {}; | ^ not allowed after `stmt` fragments @@ -471,7 +487,7 @@ LL | ($s:stmt +) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:80:14 + --> $DIR/macro-follow.rs:83:14 | LL | ($s:stmt ident) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -479,7 +495,7 @@ LL | ($s:stmt ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:81:14 + --> $DIR/macro-follow.rs:84:14 | LL | ($s:stmt if) => {}; | ^^ not allowed after `stmt` fragments @@ -487,7 +503,7 @@ LL | ($s:stmt if) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:82:14 + --> $DIR/macro-follow.rs:85:14 | LL | ($s:stmt in) => {}; | ^^ not allowed after `stmt` fragments @@ -495,7 +511,7 @@ LL | ($s:stmt in) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:83:14 + --> $DIR/macro-follow.rs:86:14 | LL | ($s:stmt $p:pat) => {}; | ^^^^^^ not allowed after `stmt` fragments @@ -503,7 +519,7 @@ LL | ($s:stmt $p:pat) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:84:14 + --> $DIR/macro-follow.rs:87:14 | LL | ($s:stmt $e:expr) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -511,7 +527,7 @@ LL | ($s:stmt $e:expr) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:85:14 + --> $DIR/macro-follow.rs:88:14 | LL | ($s:stmt $t:ty) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -519,7 +535,7 @@ LL | ($s:stmt $t:ty) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:stmt`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:86:14 + --> $DIR/macro-follow.rs:89:14 | LL | ($s:stmt $t:stmt) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -527,7 +543,7 @@ LL | ($s:stmt $t:stmt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:87:14 + --> $DIR/macro-follow.rs:90:14 | LL | ($s:stmt $p:path) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -535,7 +551,7 @@ LL | ($s:stmt $p:path) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:88:14 + --> $DIR/macro-follow.rs:91:14 | LL | ($s:stmt $b:block) => {}; | ^^^^^^^^ not allowed after `stmt` fragments @@ -543,7 +559,7 @@ LL | ($s:stmt $b:block) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:89:14 + --> $DIR/macro-follow.rs:92:14 | LL | ($s:stmt $i:ident) => {}; | ^^^^^^^^ not allowed after `stmt` fragments @@ -551,7 +567,7 @@ LL | ($s:stmt $i:ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:90:14 + --> $DIR/macro-follow.rs:93:14 | LL | ($s:stmt $t:tt) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -559,7 +575,7 @@ LL | ($s:stmt $t:tt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:91:14 + --> $DIR/macro-follow.rs:94:14 | LL | ($s:stmt $i:item) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -567,23 +583,31 @@ LL | ($s:stmt $i:item) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:92:14 + --> $DIR/macro-follow.rs:95:14 | LL | ($s:stmt $m:meta) => {}; | ^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` -error: `$p:path` is followed by `(`, which is not allowed for `path` fragments +error: `$s:stmt` is followed by `$g:guard`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:96:14 | +LL | ($s:stmt $g:guard) => {}; + | ^^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$p:path` is followed by `(`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:100:14 + | LL | ($p:path ()) => {}; | ^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `+`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:98:14 + --> $DIR/macro-follow.rs:102:14 | LL | ($p:path +) => {}; | ^ not allowed after `path` fragments @@ -591,7 +615,7 @@ LL | ($p:path +) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:99:14 + --> $DIR/macro-follow.rs:103:14 | LL | ($p:path ident) => {}; | ^^^^^ not allowed after `path` fragments @@ -599,7 +623,7 @@ LL | ($p:path ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `if`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:100:14 + --> $DIR/macro-follow.rs:104:14 | LL | ($p:path if) => {}; | ^^ not allowed after `path` fragments @@ -607,7 +631,7 @@ LL | ($p:path if) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$q:pat`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:101:14 + --> $DIR/macro-follow.rs:105:14 | LL | ($p:path $q:pat) => {}; | ^^^^^^ not allowed after `path` fragments @@ -615,7 +639,7 @@ LL | ($p:path $q:pat) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:102:14 + --> $DIR/macro-follow.rs:106:14 | LL | ($p:path $e:expr) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -623,7 +647,7 @@ LL | ($p:path $e:expr) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:103:14 + --> $DIR/macro-follow.rs:107:14 | LL | ($p:path $t:ty) => {}; | ^^^^^ not allowed after `path` fragments @@ -631,7 +655,7 @@ LL | ($p:path $t:ty) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:104:14 + --> $DIR/macro-follow.rs:108:14 | LL | ($p:path $s:stmt) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -639,7 +663,7 @@ LL | ($p:path $s:stmt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$q:path`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:105:14 + --> $DIR/macro-follow.rs:109:14 | LL | ($p:path $q:path) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -647,7 +671,7 @@ LL | ($p:path $q:path) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:107:14 + --> $DIR/macro-follow.rs:111:14 | LL | ($p:path $i:ident) => {}; | ^^^^^^^^ not allowed after `path` fragments @@ -655,7 +679,7 @@ LL | ($p:path $i:ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:108:14 + --> $DIR/macro-follow.rs:112:14 | LL | ($p:path $t:tt) => {}; | ^^^^^ not allowed after `path` fragments @@ -663,7 +687,7 @@ LL | ($p:path $t:tt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:109:14 + --> $DIR/macro-follow.rs:113:14 | LL | ($p:path $i:item) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -671,12 +695,20 @@ LL | ($p:path $i:item) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:110:14 + --> $DIR/macro-follow.rs:114:14 | LL | ($p:path $m:meta) => {}; | ^^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` -error: aborting due to 85 previous errors +error: `$p:path` is followed by `$g:guard`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:115:14 + | +LL | ($p:path $g:guard) => {}; + | ^^^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: aborting due to 89 previous errors diff --git a/tests/ui/macros/macro-followed-by-seq.rs b/tests/ui/macros/macro-followed-by-seq.rs index f4756d42088a..3643836fa031 100644 --- a/tests/ui/macros/macro-followed-by-seq.rs +++ b/tests/ui/macros/macro-followed-by-seq.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_macros)] // Regression test for issue #25436: check that things which can be // followed by any token also permit X* to come afterwards. diff --git a/tests/ui/macros/macro-guard-matcher.rs b/tests/ui/macros/macro-guard-matcher.rs new file mode 100644 index 000000000000..81a4412686de --- /dev/null +++ b/tests/ui/macros/macro-guard-matcher.rs @@ -0,0 +1,17 @@ +#![feature(macro_guard_matcher)] + +fn main() { + macro_rules! m { + ($x:guard) => {}; + } + + // Accepts + m!(if true); + m!(if let Some(x) = Some(1)); + m!(if let Some(x) = Some(1) && x == 1); + m!(if let Some(x) = Some(Some(1)) && let Some(1) = x); + m!(if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1); + + // Rejects + m!(let Some(x) = Some(1)); //~ERROR no rules expected keyword `let` +} diff --git a/tests/ui/macros/macro-guard-matcher.stderr b/tests/ui/macros/macro-guard-matcher.stderr new file mode 100644 index 000000000000..eddb0de9c4c5 --- /dev/null +++ b/tests/ui/macros/macro-guard-matcher.stderr @@ -0,0 +1,17 @@ +error: no rules expected keyword `let` + --> $DIR/macro-guard-matcher.rs:16:8 + | +LL | macro_rules! m { + | -------------- when calling this macro +... +LL | m!(let Some(x) = Some(1)); + | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$x:guard` + --> $DIR/macro-guard-matcher.rs:5:10 + | +LL | ($x:guard) => {}; + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/macro-in-fn.rs b/tests/ui/macros/macro-in-fn.rs index 2ffa6b2e4572..48085b8b221b 100644 --- a/tests/ui/macros/macro-in-fn.rs +++ b/tests/ui/macros/macro-in-fn.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![feature(decl_macro)] pub fn moo() { diff --git a/tests/ui/issues/issue-23891.rs b/tests/ui/macros/macro-in-or-pattern.rs similarity index 56% rename from tests/ui/issues/issue-23891.rs rename to tests/ui/macros/macro-in-or-pattern.rs index 131139470f9f..c1dcd6efeaa4 100644 --- a/tests/ui/issues/issue-23891.rs +++ b/tests/ui/macros/macro-in-or-pattern.rs @@ -1,3 +1,6 @@ +// Regression test for https://github.com/rust-lang/rust/issues/23891 +// Tests that a macro expanding to a pattern works correctly inside of or patterns + //@ run-pass macro_rules! id { ($s: pat) => ($s); diff --git a/tests/ui/macros/macro-input-future-proofing.stderr b/tests/ui/macros/macro-input-future-proofing.stderr index 11960db98743..a12cc9f9b416 100644 --- a/tests/ui/macros/macro-input-future-proofing.stderr +++ b/tests/ui/macros/macro-input-future-proofing.stderr @@ -20,7 +20,7 @@ error: `$pa:pat` is followed by `>`, which is not allowed for `pat` fragments LL | ($pa:pat >) => (); | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragments --> $DIR/macro-input-future-proofing.rs:14:14 @@ -28,7 +28,7 @@ error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragme LL | ($pa:pat $pb:pat $ty:ty ,) => (); | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragments --> $DIR/macro-input-future-proofing.rs:14:22 @@ -36,7 +36,7 @@ error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragmen LL | ($pa:pat $pb:pat $ty:ty ,) => (); | ^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments --> $DIR/macro-input-future-proofing.rs:17:17 diff --git a/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs b/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs index e80c712b03dc..ed8974c23e71 100644 --- a/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs +++ b/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! four { () => (4) diff --git a/tests/ui/macros/macro-multiple-items.rs b/tests/ui/macros/macro-multiple-items.rs index c746d1bc5188..46b561af4467 100644 --- a/tests/ui/macros/macro-multiple-items.rs +++ b/tests/ui/macros/macro-multiple-items.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! make_foo { () => ( struct Foo; diff --git a/tests/ui/macros/macro-named-default.rs b/tests/ui/macros/macro-named-default.rs index bca0e005083d..c7eac831cffb 100644 --- a/tests/ui/macros/macro-named-default.rs +++ b/tests/ui/macros/macro-named-default.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! default { ($($x:tt)*) => { $($x)* } } diff --git a/tests/ui/macros/macro-nt-list.rs b/tests/ui/macros/macro-nt-list.rs index b7b260c5398c..56ea917c3be9 100644 --- a/tests/ui/macros/macro-nt-list.rs +++ b/tests/ui/macros/macro-nt-list.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! list { ( ($($id:ident),*) ) => (()); diff --git a/tests/ui/macros/macro-pat-follow-2018.rs b/tests/ui/macros/macro-pat-follow-2018.rs index 6dcb841fec15..b2a556fce6f9 100644 --- a/tests/ui/macros/macro-pat-follow-2018.rs +++ b/tests/ui/macros/macro-pat-follow-2018.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ edition:2018 macro_rules! pat_bar { diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr index a06487be3d60..9179fbc31961 100644 --- a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr @@ -6,7 +6,7 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} } | | | help: try a `pat_param` fragment specifier instead: `$x:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32 @@ -16,7 +16,7 @@ LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } | | | help: try a `pat_param` fragment specifier instead: `$x:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36 @@ -26,7 +26,7 @@ LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { | | | help: try a `pat_param` fragment specifier instead: `$pat:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: aborting due to 3 previous errors diff --git a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr index c3754dde080a..af76e3f095f1 100644 --- a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr +++ b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr @@ -6,7 +6,7 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} } | | | help: try a `pat_param` fragment specifier instead: `$x:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28 @@ -16,7 +16,7 @@ LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } | | | help: try a `pat_param` fragment specifier instead: `$x:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35 @@ -26,7 +26,7 @@ LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { | | | help: try a `pat_param` fragment specifier instead: `$pat:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: aborting due to 3 previous errors diff --git a/tests/ui/macros/macro-pub-matcher.rs b/tests/ui/macros/macro-pub-matcher.rs index e0b03dbbeb1b..20cacab390d5 100644 --- a/tests/ui/macros/macro-pub-matcher.rs +++ b/tests/ui/macros/macro-pub-matcher.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code, unused_imports, unused_macro_rules)] /** diff --git a/tests/ui/macros/macro-seq-followed-by-seq.rs b/tests/ui/macros/macro-seq-followed-by-seq.rs index 3661744284ee..cf5a1c117031 100644 --- a/tests/ui/macros/macro-seq-followed-by-seq.rs +++ b/tests/ui/macros/macro-seq-followed-by-seq.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass // Test of allowing two sequences repetitions in a row, // functionality added as byproduct of RFC amendment #1384 // https://github.com/rust-lang/rfcs/pull/1384 diff --git a/tests/ui/macros/macro-use-all-and-none.rs b/tests/ui/macros/macro-use-all-and-none.rs index f1acff484038..53d450ed8d58 100644 --- a/tests/ui/macros/macro-use-all-and-none.rs +++ b/tests/ui/macros/macro-use-all-and-none.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros-rpass.rs #![warn(unused_attributes)] diff --git a/tests/ui/macros/macro-use-all.rs b/tests/ui/macros/macro-use-all.rs index a7fd3dfa5ce6..06b96da7f8b1 100644 --- a/tests/ui/macros/macro-use-all.rs +++ b/tests/ui/macros/macro-use-all.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros.rs #[macro_use] diff --git a/tests/ui/macros/macro-use-both.rs b/tests/ui/macros/macro-use-both.rs index e49f346c8e3e..c41797513f6a 100644 --- a/tests/ui/macros/macro-use-both.rs +++ b/tests/ui/macros/macro-use-both.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros.rs #[macro_use(macro_one, macro_two)] diff --git a/tests/ui/empty/empty-macro-use.rs b/tests/ui/macros/macro-use-empty.rs similarity index 100% rename from tests/ui/empty/empty-macro-use.rs rename to tests/ui/macros/macro-use-empty.rs diff --git a/tests/ui/empty/empty-macro-use.stderr b/tests/ui/macros/macro-use-empty.stderr similarity index 88% rename from tests/ui/empty/empty-macro-use.stderr rename to tests/ui/macros/macro-use-empty.stderr index 0b23dd4e1721..f3997ad3c27f 100644 --- a/tests/ui/empty/empty-macro-use.stderr +++ b/tests/ui/macros/macro-use-empty.stderr @@ -1,5 +1,5 @@ error: cannot find macro `macro_two` in this scope - --> $DIR/empty-macro-use.rs:8:5 + --> $DIR/macro-use-empty.rs:8:5 | LL | macro_two!(); | ^^^^^^^^^ @@ -10,7 +10,7 @@ LL + use two_macros::macro_two; | warning: unused attribute - --> $DIR/empty-macro-use.rs:3:12 + --> $DIR/macro-use-empty.rs:3:12 | LL | #[macro_use()] | ^^ help: remove these parentheses diff --git a/tests/ui/macros/macro-use-one.rs b/tests/ui/macros/macro-use-one.rs index 2b048651cccc..93f7c212e001 100644 --- a/tests/ui/macros/macro-use-one.rs +++ b/tests/ui/macros/macro-use-one.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros.rs #[macro_use(macro_two)] diff --git a/tests/ui/macros/die-macro-expr.rs b/tests/ui/macros/panic-macro-basic.rs similarity index 53% rename from tests/ui/macros/die-macro-expr.rs rename to tests/ui/macros/panic-macro-basic.rs index f4fefb0ca37d..96ed4265ef6e 100644 --- a/tests/ui/macros/die-macro-expr.rs +++ b/tests/ui/macros/panic-macro-basic.rs @@ -1,7 +1,14 @@ //@ run-fail //@ error-pattern:test //@ needs-subprocess +// Just testing that panic!() type checks in statement or expr + +fn f() { + let __isize: isize = panic!("test"); + + panic!(); +} fn main() { - let __isize: isize = panic!("test"); + f(); } diff --git a/tests/ui/macros/parse-complex-macro-invoc-op.rs b/tests/ui/macros/parse-complex-macro-invoc-op.rs index 2c384bdb42ef..bbb01facc624 100644 --- a/tests/ui/macros/parse-complex-macro-invoc-op.rs +++ b/tests/ui/macros/parse-complex-macro-invoc-op.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_must_use)] #![allow(dead_code)] #![allow(unused_assignments)] diff --git a/tests/ui/macros/pub-item-inside-macro.rs b/tests/ui/macros/pub-item-inside-macro.rs index c37945a2d672..679987ac1f4a 100644 --- a/tests/ui/macros/pub-item-inside-macro.rs +++ b/tests/ui/macros/pub-item-inside-macro.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass // Issue #14660 diff --git a/tests/ui/macros/pub-method-inside-macro.rs b/tests/ui/macros/pub-method-inside-macro.rs index dd4e6fda8be9..23d8c454d697 100644 --- a/tests/ui/macros/pub-method-inside-macro.rs +++ b/tests/ui/macros/pub-method-inside-macro.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass // Issue #17436 diff --git a/tests/ui/macros/semi-after-macro-ty.rs b/tests/ui/macros/semi-after-macro-ty.rs index 60afc3b44506..ff026c53b1d7 100644 --- a/tests/ui/macros/semi-after-macro-ty.rs +++ b/tests/ui/macros/semi-after-macro-ty.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! foo { ($t:ty; $p:path;) => {} } diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 3f331b0dd5f1..af2ba7a809ad 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -14,6 +14,7 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![feature(macro_guard_matcher)] #![deny(unused_macros)] // These macros force the use of AST pretty-printing by converting the input to @@ -27,6 +28,7 @@ macro_rules! stmt { ($stmt:stmt) => { stringify!($stmt) }; } macro_rules! ty { ($ty:ty) => { stringify!($ty) }; } macro_rules! vis { ($vis:vis) => { stringify!($vis) }; } +macro_rules! guard { ($guard:guard) => { stringify!($guard) }; } macro_rules! c1 { ($frag:ident, [$($tt:tt)*], $s:literal) => { @@ -792,6 +794,21 @@ fn test_vis() { // Attributes are not allowed on visibilities. } +#[test] +fn test_guard() { + c1!(guard, [ if true ], "if true"); + c1!(guard, [ if let Some(x) = Some(1) ], "if let Some(x) = Some(1)"); + c1!(guard, [ if let Some(x) = Some(1) && x == 1 ], "if let Some(x) = Some(1) && x == 1"); + c1!(guard, + [ if let Some(x) = Some(Some(1)) && let Some(1) = x ], + "if let Some(x) = Some(Some(1)) && let Some(1) = x" + ); + c1!(guard, + [ if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1 ], + "if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1" + ); +} + macro_rules! p { ([$($tt:tt)*], $s:literal) => { assert_eq!(stringify!($($tt)*), $s); diff --git a/tests/ui/macros/two-macro-use.rs b/tests/ui/macros/two-macro-use.rs index 8bb3c9da3051..733853f8d234 100644 --- a/tests/ui/macros/two-macro-use.rs +++ b/tests/ui/macros/two-macro-use.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros.rs #[macro_use(macro_one)] diff --git a/tests/ui/macros/type-macros-simple.rs b/tests/ui/macros/type-macros-simple.rs index d189b881f7dd..800a796491be 100644 --- a/tests/ui/macros/type-macros-simple.rs +++ b/tests/ui/macros/type-macros-simple.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(unused_variables)] #![allow(non_local_definitions)] diff --git a/tests/ui/macros/typo-in-norepeat-expr-2.rs b/tests/ui/macros/typo-in-norepeat-expr-2.rs new file mode 100644 index 000000000000..48b64c248d63 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr-2.rs @@ -0,0 +1,42 @@ +macro_rules! err { + (begin $follow:ident end $arg:expr) => { + [$arg] + }; + (begin1 $arg1:ident end $agr2:expr) => { + [$follow] //~ ERROR: expected expression, found `$` + //~^ NOTE: there is an macro metavariable with this name in another macro matcher + //~| NOTE: expected expression + }; +} + +macro_rules! err1 { + (begin $follow:ident end $arg:expr) => { + [$arg] + }; + (begin1 $arg1:ident end) => { + [$follo] //~ ERROR: expected expression, found `$` + //~| NOTE: expected expression + //~| HELP: there is a macro metavariable with a similar name in another macro matcher + }; +} + +macro_rules! err2 { + (begin $follow:ident end $arg:expr) => { + [$arg] + }; + (begin1 $arg1:ident end) => { + [$xyz] //~ ERROR: expected expression, found `$` + //~^ NOTE: expected expression + //~| NOTE available metavariable names are: $arg1 + //~| NOTE: macro metavariable not found + }; +} + +fn main () { + let _ = err![begin1 x end ig]; //~ NOTE: in this expansion of err! + let _ = err1![begin1 x end]; //~ NOTE: in this expansion of err1! + //~| NOTE: in this expansion of err1! + + let _ = err2![begin1 x end]; //~ NOTE: in this expansion of err2! + //~| NOTE in this expansion of err2! +} diff --git a/tests/ui/macros/typo-in-norepeat-expr-2.stderr b/tests/ui/macros/typo-in-norepeat-expr-2.stderr new file mode 100644 index 000000000000..20390cccc9a7 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr-2.stderr @@ -0,0 +1,46 @@ +error: expected expression, found `$` + --> $DIR/typo-in-norepeat-expr-2.rs:6:10 + | +LL | [$follow] + | ^------ + | || + | |there is an macro metavariable with this name in another macro matcher + | expected expression +... +LL | let _ = err![begin1 x end ig]; + | ---------------------- in this macro invocation + | + = note: this error originates in the macro `err` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `$` + --> $DIR/typo-in-norepeat-expr-2.rs:17:10 + | +LL | [$follo] + | ^^^^^^ expected expression +... +LL | let _ = err1![begin1 x end]; + | -------------------- in this macro invocation + | + = note: this error originates in the macro `err1` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a macro metavariable with a similar name in another macro matcher + | +LL | [$follow] + | + + +error: expected expression, found `$` + --> $DIR/typo-in-norepeat-expr-2.rs:28:10 + | +LL | [$xyz] + | ^--- + | || + | |macro metavariable not found + | expected expression +... +LL | let _ = err2![begin1 x end]; + | -------------------- in this macro invocation + | + = note: available metavariable names are: $arg1 + = note: this error originates in the macro `err2` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/typo-in-norepeat-expr.fixed b/tests/ui/macros/typo-in-norepeat-expr.fixed new file mode 100644 index 000000000000..a59f461e6312 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr.fixed @@ -0,0 +1,12 @@ +//@ run-rustfix +macro_rules! m { + (begin $ard:ident end) => { + [$ard] //~ ERROR: expected expression, found `$` + //~^ HELP: there is a macro metavariable with similar name + }; +} + +fn main() { + let x = 1; + let _ = m![begin x end]; +} diff --git a/tests/ui/macros/typo-in-norepeat-expr.rs b/tests/ui/macros/typo-in-norepeat-expr.rs new file mode 100644 index 000000000000..fe554f07e755 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr.rs @@ -0,0 +1,12 @@ +//@ run-rustfix +macro_rules! m { + (begin $ard:ident end) => { + [$arg] //~ ERROR: expected expression, found `$` + //~^ HELP: there is a macro metavariable with similar name + }; +} + +fn main() { + let x = 1; + let _ = m![begin x end]; +} diff --git a/tests/ui/macros/typo-in-norepeat-expr.stderr b/tests/ui/macros/typo-in-norepeat-expr.stderr new file mode 100644 index 000000000000..8f37957ea98e --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr.stderr @@ -0,0 +1,18 @@ +error: expected expression, found `$` + --> $DIR/typo-in-norepeat-expr.rs:4:10 + | +LL | [$arg] + | ^^^^ expected expression +... +LL | let _ = m![begin x end]; + | --------------- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a macro metavariable with similar name + | +LL - [$arg] +LL + [$ard] + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/cross/cross-file-errors/underscore.rs b/tests/ui/macros/underscore.rs similarity index 100% rename from tests/ui/cross/cross-file-errors/underscore.rs rename to tests/ui/macros/underscore.rs diff --git a/tests/ui/macros/unreachable.rs b/tests/ui/macros/unreachable.rs deleted file mode 100644 index c5cea5551cfc..000000000000 --- a/tests/ui/macros/unreachable.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-fail -//@ error-pattern:internal error: entered unreachable code -//@ needs-subprocess - -fn main() { - unreachable!() -} diff --git a/tests/ui/macros/use-macro-self.rs b/tests/ui/macros/use-macro-self.rs index 1d15b8386af9..cf5a410c6edf 100644 --- a/tests/ui/macros/use-macro-self.rs +++ b/tests/ui/macros/use-macro-self.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_imports)] //@ aux-build:use-macro-self.rs diff --git a/tests/ui/marker_trait_attr/overlap-doesnt-conflict-with-specialization.rs b/tests/ui/marker_trait_attr/overlap-doesnt-conflict-with-specialization.rs index a9f0cdae1f6c..cd2eaa5337e8 100644 --- a/tests/ui/marker_trait_attr/overlap-doesnt-conflict-with-specialization.rs +++ b/tests/ui/marker_trait_attr/overlap-doesnt-conflict-with-specialization.rs @@ -1,7 +1,7 @@ //@ run-pass #![feature(marker_trait_attr)] -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] #[marker] trait MyMarker {} diff --git a/tests/ui/marker_trait_attr/overlap-doesnt-conflict-with-specialization.stderr b/tests/ui/marker_trait_attr/overlap-doesnt-conflict-with-specialization.stderr deleted file mode 100644 index 649e58915d0a..000000000000 --- a/tests/ui/marker_trait_attr/overlap-doesnt-conflict-with-specialization.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-doesnt-conflict-with-specialization.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/match/match-const-tuple-type-mismatch.stderr b/tests/ui/match/match-const-tuple-type-mismatch.stderr index e7dd97c4e9a6..06f65b257069 100644 --- a/tests/ui/match/match-const-tuple-type-mismatch.stderr +++ b/tests/ui/match/match-const-tuple-type-mismatch.stderr @@ -11,10 +11,14 @@ LL | A => (), | | | expected integer, found `(isize, isize)` | `A` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_a` | = note: expected type `{integer}` found tuple `(isize, isize)` +help: introduce a new binding instead + | +LL - A => (), +LL + other_a => (), + | error: aborting due to 1 previous error diff --git a/tests/ui/match/match-tag-nullary.stderr b/tests/ui/match/match-tag-nullary.stderr index c9446d164337..2822d715ab31 100644 --- a/tests/ui/match/match-tag-nullary.stderr +++ b/tests/ui/match/match-tag-nullary.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/match-tag-nullary.rs:4:40 | -LL | enum B { B } - | - unit variant defined here -LL | LL | fn main() { let x: A = A::A; match x { B::B => { } } } | - ^^^^ expected `A`, found `B` | | diff --git a/tests/ui/match/mismatched-types-in-match-7867.stderr b/tests/ui/match/mismatched-types-in-match-7867.stderr index e41a61e42f4b..6f25175209dc 100644 --- a/tests/ui/match/mismatched-types-in-match-7867.stderr +++ b/tests/ui/match/mismatched-types-in-match-7867.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/mismatched-types-in-match-7867.rs:10:9 | -LL | enum A { B, C } - | - unit variant defined here -... LL | match (true, false) { | ------------- this expression has type `(bool, bool)` LL | A::B => (), diff --git a/tests/ui/methods/ident-from-macro-expansion.rs b/tests/ui/methods/ident-from-macro-expansion.rs index 38d2fee0e53c..2bdf5fc17b14 100644 --- a/tests/ui/methods/ident-from-macro-expansion.rs +++ b/tests/ui/methods/ident-from-macro-expansion.rs @@ -14,5 +14,5 @@ fn main() { dot!(hello); //~^ ERROR no method named `hello` found for unit type `()` in the current scope dispatch!(hello); - //~^ ERROR no function or associated item named `hello` found for unit type `()` in the current scope + //~^ ERROR no associated function or constant named `hello` found for unit type `()` in the current scope } diff --git a/tests/ui/methods/ident-from-macro-expansion.stderr b/tests/ui/methods/ident-from-macro-expansion.stderr index b596ce29f6fe..5fc8be865c4a 100644 --- a/tests/ui/methods/ident-from-macro-expansion.stderr +++ b/tests/ui/methods/ident-from-macro-expansion.stderr @@ -7,14 +7,14 @@ LL | ().$id(); LL | dot!(hello); | ^^^^^ method not found in `()` -error[E0599]: no function or associated item named `hello` found for unit type `()` in the current scope +error[E0599]: no associated function or constant named `hello` found for unit type `()` in the current scope --> $DIR/ident-from-macro-expansion.rs:16:15 | LL | <()>::$id(); | --- due to this macro variable ... LL | dispatch!(hello); - | ^^^^^ function or associated item not found in `()` + | ^^^^^ associated function or constant not found in `()` error: aborting due to 2 previous errors diff --git a/tests/ui/methods/issue-7950.rs b/tests/ui/methods/issue-7950.rs index d3dcb3380bbc..d87618a15ef3 100644 --- a/tests/ui/methods/issue-7950.rs +++ b/tests/ui/methods/issue-7950.rs @@ -4,5 +4,5 @@ fn main() { Foo::bar(); - //~^ ERROR no function or associated item named `bar` found for struct `Foo` + //~^ ERROR no associated function or constant named `bar` found for struct `Foo` } diff --git a/tests/ui/methods/issue-7950.stderr b/tests/ui/methods/issue-7950.stderr index 80504c070a3c..84e6dfee7757 100644 --- a/tests/ui/methods/issue-7950.stderr +++ b/tests/ui/methods/issue-7950.stderr @@ -1,11 +1,11 @@ -error[E0599]: no function or associated item named `bar` found for struct `Foo` in the current scope +error[E0599]: no associated function or constant named `bar` found for struct `Foo` in the current scope --> $DIR/issue-7950.rs:6:10 | LL | struct Foo; - | ---------- function or associated item `bar` not found for this struct + | ---------- associated function or constant `bar` not found for this struct ... LL | Foo::bar(); - | ^^^ function or associated item not found in `Foo` + | ^^^ associated function or constant not found in `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.stderr b/tests/ui/methods/method-not-found-generic-arg-elision.stderr index 75fabc27b0f7..3b4c761741b9 100644 --- a/tests/ui/methods/method-not-found-generic-arg-elision.stderr +++ b/tests/ui/methods/method-not-found-generic-arg-elision.stderr @@ -7,8 +7,7 @@ LL | struct Point { LL | let d = point_i32.distance(); | ^^^^^^^^ method not found in `Point` | - = note: the method was found for - - `Point` + = note: the method was found for `Point` error[E0599]: no method named `other` found for struct `Point` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:84:23 diff --git a/tests/ui/methods/missing-method-on-type-parameter.stderr b/tests/ui/methods/missing-method-on-type-parameter.stderr index 0b58fbfa4af1..0289904effa3 100644 --- a/tests/ui/methods/missing-method-on-type-parameter.stderr +++ b/tests/ui/methods/missing-method-on-type-parameter.stderr @@ -1,10 +1,10 @@ -error[E0599]: no function or associated item named `try_from` found for type parameter `T` in the current scope +error[E0599]: no associated function or constant named `try_from` found for type parameter `T` in the current scope --> $DIR/missing-method-on-type-parameter.rs:4:8 | LL | fn x() { - | - function or associated item `try_from` not found for this type parameter + | - associated function or constant `try_from` not found for this type parameter LL | T::try_from(); - | ^^^^^^^^ function or associated item not found in `T` + | ^^^^^^^^ associated function or constant not found in `T` | = help: items from traits can only be used if the trait is in scope help: there is an associated function `from` with a similar name diff --git a/tests/ui/methods/receiver-equality.rs b/tests/ui/methods/receiver-equality.rs index 891435a425eb..d409edc864af 100644 --- a/tests/ui/methods/receiver-equality.rs +++ b/tests/ui/methods/receiver-equality.rs @@ -10,7 +10,7 @@ fn method(self) { fn foo(y: B) { B:: fn(&'a ())>::method(y); - //~^ ERROR no function or associated item named `method` found + //~^ ERROR no associated function or constant named `method` found } fn main() {} diff --git a/tests/ui/methods/receiver-equality.stderr b/tests/ui/methods/receiver-equality.stderr index bf149cc2eb4d..9dd4d71c367b 100644 --- a/tests/ui/methods/receiver-equality.stderr +++ b/tests/ui/methods/receiver-equality.stderr @@ -1,11 +1,11 @@ -error[E0599]: no function or associated item named `method` found for struct `B fn(&'a ())>` in the current scope +error[E0599]: no associated function or constant named `method` found for struct `B fn(&'a ())>` in the current scope --> $DIR/receiver-equality.rs:12:30 | LL | struct B(T); - | ----------- function or associated item `method` not found for this struct + | ----------- associated function or constant `method` not found for this struct ... LL | B:: fn(&'a ())>::method(y); - | ^^^^^^ function or associated item not found in `B fn(&'a ())>` + | ^^^^^^ associated function or constant not found in `B fn(&'a ())>` error: aborting due to 1 previous error diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.fixed b/tests/ui/methods/shadowed-intrinsic-method-deref.fixed new file mode 100644 index 000000000000..927c168af568 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.fixed @@ -0,0 +1,21 @@ +//@ run-rustfix +#![allow(unused_imports)] +use std::rc::Rc; +use std::cell::RefCell; +use std::borrow::Borrow; // Without this import, the code would compile. + +pub struct S { + flag: bool, +} + +type SCell = Rc>; + +fn main() { + // Type annotations just for clarity + let s : SCell = Rc::new(RefCell::new(S {flag: false})); + let sb : &S = &RefCell::borrow(&s); + //~^ ERROR: the trait bound `Rc>: Borrow` is not satisfied [E0277] + //~| NOTE: the trait `Borrow` is not implemented for `Rc>` + //~| NOTE: there's an inherent method on `RefCell` of the same name + println!("{:?}", sb.flag); +} diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.rs b/tests/ui/methods/shadowed-intrinsic-method-deref.rs new file mode 100644 index 000000000000..1e8ddb152d87 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.rs @@ -0,0 +1,21 @@ +//@ run-rustfix +#![allow(unused_imports)] +use std::rc::Rc; +use std::cell::RefCell; +use std::borrow::Borrow; // Without this import, the code would compile. + +pub struct S { + flag: bool, +} + +type SCell = Rc>; + +fn main() { + // Type annotations just for clarity + let s : SCell = Rc::new(RefCell::new(S {flag: false})); + let sb : &S = &s.borrow(); + //~^ ERROR: the trait bound `Rc>: Borrow` is not satisfied [E0277] + //~| NOTE: the trait `Borrow` is not implemented for `Rc>` + //~| NOTE: there's an inherent method on `RefCell` of the same name + println!("{:?}", sb.flag); +} diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.stderr b/tests/ui/methods/shadowed-intrinsic-method-deref.stderr new file mode 100644 index 000000000000..4e0c5dfc55f0 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `Rc>: Borrow` is not satisfied + --> $DIR/shadowed-intrinsic-method-deref.rs:16:22 + | +LL | let sb : &S = &s.borrow(); + | ^^^^^^ the trait `Borrow` is not implemented for `Rc>` + | +help: the trait `Borrow` is not implemented for `Rc>` + but trait `Borrow>` is implemented for it + --> $SRC_DIR/alloc/src/rc.rs:LL:COL + = help: for that trait implementation, expected `RefCell`, found `S` + = note: there's an inherent method on `RefCell` of the same name, which can be auto-dereferenced from `&RefCell` +help: to access the inherent method on `RefCell`, use the fully-qualified path + | +LL - let sb : &S = &s.borrow(); +LL + let sb : &S = &RefCell::borrow(&s); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-50411.rs b/tests/ui/mir/inliner-double-elaborate.rs similarity index 73% rename from tests/ui/issues/issue-50411.rs rename to tests/ui/mir/inliner-double-elaborate.rs index 7fbbadac1e2b..c6af573a5869 100644 --- a/tests/ui/issues/issue-50411.rs +++ b/tests/ui/mir/inliner-double-elaborate.rs @@ -1,4 +1,4 @@ -// Regression test for #50411: the MIR inliner was causing problems +// Regression test for https://github.com/rust-lang/rust/issues/50411: the MIR inliner was causing problems // here because it would inline promoted code (which had already had // elaborate-drops invoked on it) and then try to elaboate drops a // second time. Uncool. diff --git a/tests/ui/mismatched_types/array-len-is-closure.stderr b/tests/ui/mismatched_types/array-len-is-closure.stderr index db5d801871bc..a6f9518c3e63 100644 --- a/tests/ui/mismatched_types/array-len-is-closure.stderr +++ b/tests/ui/mismatched_types/array-len-is-closure.stderr @@ -6,6 +6,7 @@ LL | [1; || {}]; | = note: expected type `usize` found closure `{closure@$DIR/array-len-is-closure.rs:4:9: 4:11}` + = note: array length can only be `usize` error: aborting due to 1 previous error diff --git a/tests/ui/mismatched_types/array-repeat-unit-struct.rs b/tests/ui/mismatched_types/array-repeat-unit-struct.rs index db05e1daedbd..f92f97ed587b 100644 --- a/tests/ui/mismatched_types/array-repeat-unit-struct.rs +++ b/tests/ui/mismatched_types/array-repeat-unit-struct.rs @@ -4,6 +4,7 @@ fn main() { let b = [0; S]; - //~^ ERROR mismatched types - //~| NOTE expected `usize`, found `S` + //~^ ERROR: mismatched types + //~| NOTE: expected `usize`, found `S` + //~| NOTE: array length } diff --git a/tests/ui/mismatched_types/array-repeat-unit-struct.stderr b/tests/ui/mismatched_types/array-repeat-unit-struct.stderr index 9a9cc946f82a..155adb5363a2 100644 --- a/tests/ui/mismatched_types/array-repeat-unit-struct.stderr +++ b/tests/ui/mismatched_types/array-repeat-unit-struct.stderr @@ -3,6 +3,8 @@ error[E0308]: mismatched types | LL | let b = [0; S]; | ^ expected `usize`, found `S` + | + = note: array length can only be `usize` error: aborting due to 1 previous error diff --git a/tests/ui/mismatched_types/expectation-from-return-type.rs b/tests/ui/mismatched_types/expectation-from-return-type.rs new file mode 100644 index 000000000000..ffe3d929984d --- /dev/null +++ b/tests/ui/mismatched_types/expectation-from-return-type.rs @@ -0,0 +1,21 @@ +use std::ptr; + +fn main() { //~ NOTE: this implicit `()` return type influences the call expression's return type + let a = 0; + ptr::read(&a) + //~^ ERROR: mismatched types + //~| NOTE: expected `*const ()`, found `&{integer}` + //~| NOTE: arguments to this function are incorrect + //~| NOTE: expected raw pointer + //~| NOTE: function defined here +} + +fn foo() { //~ NOTE: this implicit `()` return type influences the call expression's return type + let a = 0; + return ptr::read(&a); + //~^ ERROR: mismatched types + //~| NOTE: expected `*const ()`, found `&{integer}` + //~| NOTE: arguments to this function are incorrect + //~| NOTE: expected raw pointer + //~| NOTE: function defined here +} diff --git a/tests/ui/mismatched_types/expectation-from-return-type.stderr b/tests/ui/mismatched_types/expectation-from-return-type.stderr new file mode 100644 index 000000000000..3bd7a21f987f --- /dev/null +++ b/tests/ui/mismatched_types/expectation-from-return-type.stderr @@ -0,0 +1,35 @@ +error[E0308]: mismatched types + --> $DIR/expectation-from-return-type.rs:5:15 + | +LL | fn main() { + | - this implicit `()` return type influences the call expression's return type +LL | let a = 0; +LL | ptr::read(&a) + | --------- ^^ expected `*const ()`, found `&{integer}` + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*const ()` + found reference `&{integer}` +note: function defined here + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + +error[E0308]: mismatched types + --> $DIR/expectation-from-return-type.rs:15:22 + | +LL | fn foo() { + | - this implicit `()` return type influences the call expression's return type +LL | let a = 0; +LL | return ptr::read(&a); + | --------- ^^ expected `*const ()`, found `&{integer}` + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*const ()` + found reference `&{integer}` +note: function defined here + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 9a18798db213..6243a9a729a2 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -16,6 +16,8 @@ LL | arg.map(|v| &**v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:9:19 | +LL | pub fn bar(arg: Option<&Vec>) -> &[i32] { + | ------ this return type influences the call expression's return type LL | arg.unwrap_or(&[]) | --------- ^^^ expected `&Vec`, found `&[_; 0]` | | @@ -41,6 +43,8 @@ LL + arg.map_or(&[], |v| v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:13:19 | +LL | pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { + | --------- this return type influences the call expression's return type LL | arg.unwrap_or(v) | --------- ^ expected `&Vec`, found `&[i32]` | | @@ -66,6 +70,8 @@ LL + arg.map_or(v, |v| v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:17:19 | +LL | pub fn convert_result(arg: Result<&Vec, ()>) -> &[i32] { + | ------ this return type influences the call expression's return type LL | arg.unwrap_or(&[]) | --------- ^^^ expected `&Vec`, found `&[_; 0]` | | diff --git a/tests/ui/missing/missing-items/missing-type-parameter2.rs b/tests/ui/missing/missing-items/missing-type-parameter2.rs index 772e60b1376c..c52f3157454a 100644 --- a/tests/ui/missing/missing-items/missing-type-parameter2.rs +++ b/tests/ui/missing/missing-items/missing-type-parameter2.rs @@ -1,10 +1,10 @@ struct X(); impl X {} -//~^ ERROR cannot find type `N` in this scope +//~^ ERROR cannot find const `N` in this scope //~| ERROR unresolved item provided when a constant was expected impl X {} -//~^ ERROR cannot find type `N` in this scope +//~^ ERROR cannot find const `N` in this scope //~| ERROR defaults for generic parameters are not allowed here //~| ERROR unresolved item provided when a constant was expected @@ -15,5 +15,4 @@ fn foo(_: T) where T: Send {} fn bar(_: A) {} //~^ ERROR cannot find type `A` in this scope -fn main() { -} +fn main() {} diff --git a/tests/ui/missing/missing-items/missing-type-parameter2.stderr b/tests/ui/missing/missing-items/missing-type-parameter2.stderr index c361ed79cc79..7c85d39ba78a 100644 --- a/tests/ui/missing/missing-items/missing-type-parameter2.stderr +++ b/tests/ui/missing/missing-items/missing-type-parameter2.stderr @@ -1,39 +1,30 @@ -error[E0425]: cannot find type `N` in this scope +error[E0425]: cannot find const `N` in this scope --> $DIR/missing-type-parameter2.rs:3:8 | LL | struct X(); - | ------------------------ similarly named struct `X` defined here + | ----------- corresponding const parameter on the type defined here LL | LL | impl X {} - | ^ + | ^ not found in this scope | -help: a struct with a similar name exists +help: you might have meant to introduce a const parameter `N` on the impl | -LL - impl X {} -LL + impl X {} - | -help: you might be missing a type parameter - | -LL | impl X {} - | +++ +LL | impl X {} + | +++++++++++++ -error[E0425]: cannot find type `N` in this scope +error[E0425]: cannot find const `N` in this scope --> $DIR/missing-type-parameter2.rs:6:28 | +LL | struct X(); + | ----------- corresponding const parameter on the type defined here +... LL | impl X {} - | - ^ - | | - | similarly named type parameter `T` defined here + | ^ not found in this scope | -help: a type parameter with a similar name exists +help: you might have meant to introduce a const parameter `N` on the impl | -LL - impl X {} -LL + impl X {} - | -help: you might be missing a type parameter - | -LL | impl X {} - | +++ +LL | impl X {} + | +++++++++++++ error[E0425]: cannot find type `T` in this scope --> $DIR/missing-type-parameter2.rs:11:20 diff --git a/tests/ui/missing/undeclared-generic-parameter.rs b/tests/ui/missing/undeclared-generic-parameter.rs new file mode 100644 index 000000000000..eebae215c881 --- /dev/null +++ b/tests/ui/missing/undeclared-generic-parameter.rs @@ -0,0 +1,5 @@ +struct A; +impl A {} +//~^ ERROR cannot find type `B` in this scope +//~| ERROR struct takes 0 generic arguments but 1 generic argument was supplied +fn main() {} diff --git a/tests/ui/missing/undeclared-generic-parameter.stderr b/tests/ui/missing/undeclared-generic-parameter.stderr new file mode 100644 index 000000000000..101a5790ed4e --- /dev/null +++ b/tests/ui/missing/undeclared-generic-parameter.stderr @@ -0,0 +1,36 @@ +error[E0425]: cannot find type `B` in this scope + --> $DIR/undeclared-generic-parameter.rs:2:8 + | +LL | struct A; + | --------- similarly named struct `A` defined here +LL | impl A {} + | ^ + | +help: a struct with a similar name exists + | +LL - impl A {} +LL + impl A {} + | +help: you might be missing a type parameter + | +LL | impl A {} + | +++ + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/undeclared-generic-parameter.rs:2:6 + | +LL | impl A {} + | ^--- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: struct defined here, with 0 generic parameters + --> $DIR/undeclared-generic-parameter.rs:1:8 + | +LL | struct A; + | ^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0425. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/moves/array-copy-move.rs b/tests/ui/moves/array-copy-move.rs deleted file mode 100644 index ea95bc06a369..000000000000 --- a/tests/ui/moves/array-copy-move.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! regression test for issue https://github.com/rust-lang/rust/issues/16783 -//@ run-pass -#![allow(unused_variables)] - -pub fn main() { - let x = [1, 2, 3]; - let y = x; -} diff --git a/tests/ui/moves/do-not-suggest-removing-wrong-ref-pattern-issue-132806.stderr b/tests/ui/moves/do-not-suggest-removing-wrong-ref-pattern-issue-132806.stderr index ff579f934137..5f66c2eb6787 100644 --- a/tests/ui/moves/do-not-suggest-removing-wrong-ref-pattern-issue-132806.stderr +++ b/tests/ui/moves/do-not-suggest-removing-wrong-ref-pattern-issue-132806.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | let _ = HashMap::::new().iter().filter(|&(&_k, &_v)| { true }); | ^^^--^^^^^^ | | - | data moved here - | move occurs because `_k` has type `String`, which does not implement the `Copy` trait + | data moved here because `_k` has type `String`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr index c2bc85ee6bee..21f51907b5e7 100644 --- a/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr +++ b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr @@ -4,8 +4,7 @@ error[E0509]: cannot move out of type `Thing`, which implements the `Drop` trait LL | Thing(*&mut String::new()) = Thing(String::new()); | ------------------- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here | | - | data moved here - | move occurs because the place has type `String`, which does not implement the `Copy` trait + | data moved here because the place has type `String`, which does not implement the `Copy` trait error: aborting due to 1 previous error diff --git a/tests/ui/moves/issue-99470-move-out-of-some.stderr b/tests/ui/moves/issue-99470-move-out-of-some.stderr index 71ec5adfdeac..59e4e7d073d9 100644 --- a/tests/ui/moves/issue-99470-move-out-of-some.stderr +++ b/tests/ui/moves/issue-99470-move-out-of-some.stderr @@ -5,10 +5,7 @@ LL | match x { | ^ LL | LL | &Some(_y) => (), - | -- - | | - | data moved here - | move occurs because `_y` has type `Box`, which does not implement the `Copy` trait + | -- data moved here because `_y` has type `Box`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/moves/move-1-unique.rs b/tests/ui/moves/move-1-unique.rs deleted file mode 100644 index c97bfaaaf1a5..000000000000 --- a/tests/ui/moves/move-1-unique.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] -#![allow(dead_code)] - -#[derive(Clone)] -struct Triple { - x: isize, - y: isize, - z: isize, -} - -fn test(x: bool, foo: Box) -> isize { - let bar = foo; - let mut y: Box; - if x { y = bar; } else { y = Box::new(Triple{x: 4, y: 5, z: 6}); } - return y.y; -} - -pub fn main() { - let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3}); - assert_eq!(test(true, x.clone()), 2); - assert_eq!(test(true, x.clone()), 2); - assert_eq!(test(true, x.clone()), 2); - assert_eq!(test(false, x), 5); -} diff --git a/tests/ui/moves/move-2-unique.rs b/tests/ui/moves/move-2-unique.rs deleted file mode 100644 index 2204ea95741d..000000000000 --- a/tests/ui/moves/move-2-unique.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -struct X { x: isize, y: isize, z: isize } - -pub fn main() { - let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); - let y = x; - assert_eq!(y.y, 2); -} diff --git a/tests/ui/moves/move-4-unique.rs b/tests/ui/moves/move-4-unique.rs deleted file mode 100644 index 09e0f11a8b44..000000000000 --- a/tests/ui/moves/move-4-unique.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -struct Triple {a: isize, b: isize, c: isize} - -fn test(foo: Box) -> Box { - let foo = foo; - let bar = foo; - let baz = bar; - let quux = baz; - return quux; -} - -pub fn main() { - let x = Box::new(Triple{a: 1, b: 2, c: 3}); - let y = test(x); - assert_eq!(y.c, 3); -} diff --git a/tests/ui/moves/move-arg-2-unique.rs b/tests/ui/moves/move-arg-2-unique.rs deleted file mode 100644 index d9a03be0ed2d..000000000000 --- a/tests/ui/moves/move-arg-2-unique.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass - -fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } - -pub fn main() { - let x = Box::new(vec![10]); - // Test forgetting a local by move-in - test(x); - - // Test forgetting a temporary by move-in. - test(Box::new(vec![10])); -} diff --git a/tests/ui/moves/move-out-of-array-ref.stderr b/tests/ui/moves/move-out-of-array-ref.stderr index 26d4996d6cb1..5c3e0ad5872c 100644 --- a/tests/ui/moves/move-out-of-array-ref.stderr +++ b/tests/ui/moves/move-out-of-array-ref.stderr @@ -4,8 +4,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array LL | let [_, e, _, _] = *a; | - ^^ cannot move out of here | | - | data moved here - | move occurs because `e` has type `D`, which does not implement the `Copy` trait + | data moved here because `e` has type `D`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -19,8 +18,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array LL | let [_, s @ .. , _] = *a; | - ^^ cannot move out of here | | - | data moved here - | move occurs because `s` has type `[D; 2]`, which does not implement the `Copy` trait + | data moved here because `s` has type `[D; 2]`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -34,8 +32,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array LL | let [_, e, _, _] = *a; | - ^^ cannot move out of here | | - | data moved here - | move occurs because `e` has type `D`, which does not implement the `Copy` trait + | data moved here because `e` has type `D`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -49,8 +46,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array LL | let [_, s @ .. , _] = *a; | - ^^ cannot move out of here | | - | data moved here - | move occurs because `s` has type `[D; 2]`, which does not implement the `Copy` trait + | data moved here because `s` has type `[D; 2]`, which does not implement the `Copy` trait | help: consider removing the dereference here | diff --git a/tests/ui/moves/move-out-of-slice-1.stderr b/tests/ui/moves/move-out-of-slice-1.stderr index 86533714474b..4b917554057c 100644 --- a/tests/ui/moves/move-out-of-slice-1.stderr +++ b/tests/ui/moves/move-out-of-slice-1.stderr @@ -4,10 +4,7 @@ error[E0508]: cannot move out of type `[A]`, a non-copy slice LL | match a { | ^ cannot move out of here LL | box [a] => {}, - | - - | | - | data moved here - | move occurs because `a` has type `A`, which does not implement the `Copy` trait + | - data moved here because `a` has type `A`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/moves/move-scalar.rs b/tests/ui/moves/move-scalar.rs deleted file mode 100644 index e8cf5632b322..000000000000 --- a/tests/ui/moves/move-scalar.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] - -pub fn main() { - - let y: isize = 42; - let mut x: isize; - x = y; - assert_eq!(x, 42); -} diff --git a/tests/ui/moves/moves-based-on-type-block-bad.stderr b/tests/ui/moves/moves-based-on-type-block-bad.stderr index 431ee1c0bb1b..31417b59f099 100644 --- a/tests/ui/moves/moves-based-on-type-block-bad.stderr +++ b/tests/ui/moves/moves-based-on-type-block-bad.stderr @@ -5,10 +5,7 @@ LL | match hellothere.x { | ^^^^^^^^^^^^ LL | box E::Foo(_) => {} LL | box E::Bar(x) => println!("{}", x.to_string()), - | - - | | - | data moved here - | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | - data moved here because `x` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here | diff --git a/tests/ui/empty/empty-never-array.rs b/tests/ui/never_type/empty-never-array.rs similarity index 100% rename from tests/ui/empty/empty-never-array.rs rename to tests/ui/never_type/empty-never-array.rs diff --git a/tests/ui/empty/empty-never-array.stderr b/tests/ui/never_type/empty-never-array.stderr similarity index 100% rename from tests/ui/empty/empty-never-array.stderr rename to tests/ui/never_type/empty-never-array.stderr diff --git a/tests/ui/never_type/regress/divergent-block-with-tail.stderr b/tests/ui/never_type/regress/divergent-block-with-tail.stderr index 1f205e896788..94cf5e5fa915 100644 --- a/tests/ui/never_type/regress/divergent-block-with-tail.stderr +++ b/tests/ui/never_type/regress/divergent-block-with-tail.stderr @@ -22,10 +22,10 @@ error[E0308]: mismatched types LL | fn f() -> isize { | ----- expected `isize` because of return type LL | (return 1, return 2) - | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `(!, !)` + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `(_, _)` | = note: expected type `isize` - found tuple `(!, !)` + found tuple `(_, _)` error: aborting due to 2 previous errors diff --git a/tests/ui/never_type/regress/loop-in-array-length.stderr b/tests/ui/never_type/regress/loop-in-array-length.stderr index a51eb46fb244..fc0a670d08dc 100644 --- a/tests/ui/never_type/regress/loop-in-array-length.stderr +++ b/tests/ui/never_type/regress/loop-in-array-length.stderr @@ -14,6 +14,7 @@ LL | [(); & { loop { continue } } ]; | = note: expected type `usize` found reference `&_` + = note: array length can only be `usize` help: consider removing the borrow | LL - [(); & { loop { continue } } ]; diff --git a/tests/ui/nll/issue-57362-2.rs b/tests/ui/nll/issue-57362-2.rs index 664cdf89a388..1f723be6794b 100644 --- a/tests/ui/nll/issue-57362-2.rs +++ b/tests/ui/nll/issue-57362-2.rs @@ -21,7 +21,7 @@ fn make_g() -> Self::G { // FIXME(@compiler-errors): This error message is less than helpful. fn g() { let x = ::make_g(); - //~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope + //~^ ERROR no associated function or constant named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope } fn main() {} diff --git a/tests/ui/nll/issue-57362-2.stderr b/tests/ui/nll/issue-57362-2.stderr index 8a1a4d6b22c1..1b962b16bdc8 100644 --- a/tests/ui/nll/issue-57362-2.stderr +++ b/tests/ui/nll/issue-57362-2.stderr @@ -1,8 +1,8 @@ -error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope +error[E0599]: no associated function or constant named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope --> $DIR/issue-57362-2.rs:23:25 | LL | let x = ::make_g(); - | ^^^^^^ function or associated item not found in `for<'a> fn(&'a ())` + | ^^^^^^ associated function or constant not found in `for<'a> fn(&'a ())` | = help: items from traits can only be used if the trait is implemented and in scope note: `X` defines an item `make_g`, perhaps you need to implement it diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.rs b/tests/ui/nll/issue-57642-higher-ranked-subtype.rs index 69187cab3422..059a2beb92f4 100644 --- a/tests/ui/nll/issue-57642-higher-ranked-subtype.rs +++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.rs @@ -29,11 +29,12 @@ fn make_f() -> Self::F { fn higher_ranked_region_has_lost_its_binder() { let x = ::make_g(); - //~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope + //~^ ERROR no associated function or constant named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope } fn magical() { - let x = ::make_f(); //~ ERROR no function + let x = ::make_f(); + //~^ ERROR no associated function or constant named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope } fn main() {} diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr index 27a887e86004..0a56d1bc7203 100644 --- a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr +++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr @@ -1,8 +1,8 @@ -error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope +error[E0599]: no associated function or constant named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope --> $DIR/issue-57642-higher-ranked-subtype.rs:31:25 | LL | let x = ::make_g(); - | ^^^^^^ function or associated item not found in `for<'a> fn(&'a ())` + | ^^^^^^ associated function or constant not found in `for<'a> fn(&'a ())` | = help: items from traits can only be used if the trait is implemented and in scope note: `X` defines an item `make_g`, perhaps you need to implement it @@ -11,11 +11,11 @@ note: `X` defines an item `make_g`, perhaps you need to implement it LL | trait X { | ^^^^^^^ -error[E0599]: no function or associated item named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope +error[E0599]: no associated function or constant named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope --> $DIR/issue-57642-higher-ranked-subtype.rs:36:25 | LL | let x = ::make_f(); - | ^^^^^^ function or associated item not found in `for<'a> fn(&'a ())` + | ^^^^^^ associated function or constant not found in `for<'a> fn(&'a ())` | = help: items from traits can only be used if the trait is implemented and in scope note: `Y` defines an item `make_f`, perhaps you need to implement it diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr index bcb2ab84a239..c1ec357cab06 100644 --- a/tests/ui/nll/move-errors.stderr +++ b/tests/ui/nll/move-errors.stderr @@ -108,8 +108,7 @@ error[E0507]: cannot move out of `a` which is behind a shared reference LL | let A(s) = *a; | - ^^ | | - | data moved here - | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | data moved here because `s` has type `String`, which does not implement the `Copy` trait | help: consider removing the dereference here | @@ -123,8 +122,7 @@ error[E0509]: cannot move out of type `D`, which implements the `Drop` trait LL | let C(D(s)) = c; | - ^ cannot move out of here | | - | data moved here - | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | data moved here because `s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -170,10 +168,7 @@ LL | match x { | ^ cannot move out of here ... LL | B::U(D(s)) => (), - | - - | | - | data moved here - | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | - data moved here because `s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -187,10 +182,7 @@ LL | match x { | ^ cannot move out of here ... LL | (D(s), &t) => (), - | - - | | - | data moved here - | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | - data moved here because `s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -204,10 +196,7 @@ LL | match x { | ^ ... LL | (D(s), &t) => (), - | - - | | - | data moved here - | move occurs because `t` has type `String`, which does not implement the `Copy` trait + | - data moved here because `t` has type `String`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -243,10 +232,7 @@ LL | match *x { | ^^ LL | LL | Ok(s) | Err(s) => (), - | - - | | - | data moved here - | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | - data moved here because `s` has type `String`, which does not implement the `Copy` trait | help: consider removing the dereference here | diff --git a/tests/ui/numeric/const-scope.stderr b/tests/ui/numeric/const-scope.stderr index 2c8d4da9d218..4851a20fcf0e 100644 --- a/tests/ui/numeric/const-scope.stderr +++ b/tests/ui/numeric/const-scope.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/const-scope.rs:1:16 | LL | const C: i32 = 1i8; - | ^^^ expected `i32`, found `i8` + | --- ^^^ expected `i32`, found `i8` + | | + | expected because of the type of the constant | help: change the type of the numeric literal from `i8` to `i32` | @@ -14,7 +16,9 @@ error[E0308]: mismatched types --> $DIR/const-scope.rs:2:15 | LL | const D: i8 = C; - | ^ expected `i8`, found `i32` + | -- ^ expected `i8`, found `i32` + | | + | expected because of the type of the constant error[E0308]: mismatched types --> $DIR/const-scope.rs:5:18 diff --git a/tests/ui/on-unimplemented/self-types.rs b/tests/ui/on-unimplemented/self-types.rs new file mode 100644 index 000000000000..736d3baf60c7 --- /dev/null +++ b/tests/ui/on-unimplemented/self-types.rs @@ -0,0 +1,30 @@ +#![feature(rustc_attrs)] + +#[rustc_on_unimplemented( + on(Self = "{union}", message = "union self type"), + on(Self = "{enum}", message = "enum self type"), + on(Self = "{struct}", message = "struct self type"), + message = "fallback self type `{Self}`" +)] +trait Trait {} + +union Union { + value: u8, +} + +enum Enum { + Variant, +} + +struct Struct; + +fn needs_trait() {} + +fn main() { + needs_trait::(); + //~^ ERROR union self type + needs_trait::(); + //~^ ERROR enum self type + needs_trait::(); + //~^ ERROR struct self type +} diff --git a/tests/ui/on-unimplemented/self-types.stderr b/tests/ui/on-unimplemented/self-types.stderr new file mode 100644 index 000000000000..ea40ac566bb9 --- /dev/null +++ b/tests/ui/on-unimplemented/self-types.stderr @@ -0,0 +1,69 @@ +error[E0277]: union self type + --> $DIR/self-types.rs:24:19 + | +LL | needs_trait::(); + | ^^^^^ unsatisfied trait bound + | +help: the trait `Trait` is not implemented for `Union` + --> $DIR/self-types.rs:11:1 + | +LL | union Union { + | ^^^^^^^^^^^ +help: this trait has no implementations, consider adding one + --> $DIR/self-types.rs:9:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/self-types.rs:21:19 + | +LL | fn needs_trait() {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: enum self type + --> $DIR/self-types.rs:26:19 + | +LL | needs_trait::(); + | ^^^^ unsatisfied trait bound + | +help: the trait `Trait` is not implemented for `Enum` + --> $DIR/self-types.rs:15:1 + | +LL | enum Enum { + | ^^^^^^^^^ +help: this trait has no implementations, consider adding one + --> $DIR/self-types.rs:9:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/self-types.rs:21:19 + | +LL | fn needs_trait() {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: struct self type + --> $DIR/self-types.rs:28:19 + | +LL | needs_trait::(); + | ^^^^^^ unsatisfied trait bound + | +help: the trait `Trait` is not implemented for `Struct` + --> $DIR/self-types.rs:19:1 + | +LL | struct Struct; + | ^^^^^^^^^^^^^ +help: this trait has no implementations, consider adding one + --> $DIR/self-types.rs:9:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/self-types.rs:21:19 + | +LL | fn needs_trait() {} + | ^^^^^ required by this bound in `needs_trait` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index 67b72bd038d8..61d4866f5618 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -5,13 +5,13 @@ LL | x[1i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[i32]>` is not implemented for `i32` -help: the following other types implement trait `SliceIndex` +help: `usize` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `usize` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `usize` implements `SliceIndex` + = note: `SliceIndex` = note: required for `[i32]` to implement `Index` error[E0277]: the type `[i32]` cannot be indexed by `RangeTo` @@ -21,19 +21,19 @@ LL | x[..1i32]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo` -help: the following other types implement trait `SliceIndex` +help: `RangeTo` implements trait `SliceIndex` --> $SRC_DIR/core/src/slice/index.rs:LL:COL | - = note: `RangeTo` implements `SliceIndex<[T]>` + = note: `SliceIndex<[T]>` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | - = note: `RangeTo` implements `SliceIndex` + = note: `SliceIndex` ::: $SRC_DIR/core/src/bstr/traits.rs:LL:COL | = note: in this macro invocation --> $SRC_DIR/core/src/str/traits.rs:LL:COL | - = note: `RangeTo` implements `SliceIndex` + = note: `SliceIndex` = note: required for `[i32]` to implement `Index>` = note: this error originates in the macro `impl_slice_index` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.rs b/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.rs index aaaf4d3b2e11..2c898633b5e4 100644 --- a/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.rs +++ b/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.rs @@ -5,7 +5,7 @@ fn from(_: (u8,)) -> Self { todo!() } } -impl From<(u8, u8)> for Tuple { //~ HELP the following other types implement trait `From` +impl From<(u8, u8)> for Tuple { //~ HELP `Tuple` implements trait `From` fn from(_: (u8, u8)) -> Self { todo!() } diff --git a/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.stderr b/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.stderr index cf15ac1f279b..f07db05abad6 100644 --- a/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.stderr +++ b/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.stderr @@ -11,17 +11,17 @@ help: the trait `From` is not implemented for `Tuple` | LL | struct Tuple; | ^^^^^^^^^^^^ -help: the following other types implement trait `From` +help: `Tuple` implements trait `From` --> $DIR/suggest_tuple_wrap_root_obligation.rs:3:1 | LL | impl From<(u8,)> for Tuple { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `Tuple` implements `From<(u8,)>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `From<(u8,)>` ... LL | impl From<(u8, u8)> for Tuple { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Tuple` implements `From<(u8, u8)>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `From<(u8, u8)>` ... LL | impl From<(u8, u8, u8)> for Tuple { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Tuple` implements `From<(u8, u8, u8)>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `From<(u8, u8, u8)>` = note: required for `u8` to implement `Into` note: required by a bound in `convert_into_tuple` --> $DIR/suggest_tuple_wrap_root_obligation.rs:19:32 diff --git a/tests/ui/on-unimplemented/sum.stderr b/tests/ui/on-unimplemented/sum.stderr index 5e82948352f7..56257079bd31 100644 --- a/tests/ui/on-unimplemented/sum.stderr +++ b/tests/ui/on-unimplemented/sum.stderr @@ -7,13 +7,13 @@ LL | vec![(), ()].iter().sum::(); | required by a bound introduced by this call | = help: the trait `Sum<&()>` is not implemented for `i32` -help: the following other types implement trait `Sum` +help: `i32` implements trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum` + = note: `Sum` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Sum<&i32>` + = note: `Sum<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation @@ -37,13 +37,13 @@ LL | vec![(), ()].iter().product::(); | required by a bound introduced by this call | = help: the trait `Product<&()>` is not implemented for `i32` -help: the following other types implement trait `Product` +help: `i32` implements trait `Product` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Product` + = note: `Product` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | - = note: `i32` implements `Product<&i32>` + = note: `Product<&i32>` ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation diff --git a/tests/ui/parallel-rustc/assert-found_cycle-issue-115223.rs b/tests/ui/parallel-rustc/assert-found_cycle-issue-115223.rs new file mode 100644 index 000000000000..96a11720abdf --- /dev/null +++ b/tests/ui/parallel-rustc/assert-found_cycle-issue-115223.rs @@ -0,0 +1,31 @@ +// Test for #115223, which causes a deadlock bug without finding the cycle +//@ build-pass +#![crate_name = "foo"] + +use std::ops; + +pub struct Foo; + +impl Foo { + pub fn foo(&mut self) {} +} + +pub struct Bar { + foo: Foo, +} + +impl ops::Deref for Bar { + type Target = Foo; + + fn deref(&self) -> &Foo { + &self.foo + } +} + +impl ops::DerefMut for Bar { + fn deref_mut(&mut self) -> &mut Foo { + &mut self.foo + } +} + +fn main() {} diff --git a/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr b/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr index b80d0f92fcfa..a5c6ad5e90ba 100644 --- a/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr +++ b/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr @@ -1,12 +1,22 @@ +error[E0391]: cycle detected when checking if `FOO` is a trivial const --> $DIR/cycle_crash-issue-135870.rs:6:1 | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^ | +note: ...which requires building MIR for `FOO`... + --> $DIR/cycle_crash-issue-135870.rs:6:1 | LL | const FOO: usize = FOO; + | ^^^^^^^^^^^^^^^^ + = note: ...which again requires checking if `FOO` is a trivial const, completing the cycle +note: cycle used when simplifying constant for the type system `FOO` + --> $DIR/cycle_crash-issue-135870.rs:6:1 + | +LL | const FOO: usize = FOO; + | ^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0391`. \ No newline at end of file +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs new file mode 100644 index 000000000000..8bc11ce31d19 --- /dev/null +++ b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.rs @@ -0,0 +1,12 @@ +// Test for #151358, assertion failed: !worker_thread.is_null() +//~^ ERROR cycle detected when looking up span for `Default` +// +//@ compile-flags: -Z threads=2 +//@ compare-output-by-lines + +trait Default {} +use std::num::NonZero; +fn main() { + NonZero(); + todo!(); +} diff --git a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr new file mode 100644 index 000000000000..9c1d7b1de33a --- /dev/null +++ b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr @@ -0,0 +1,9 @@ +error[E0391]: cycle detected when looking up span for `Default` + | + = note: ...which immediately requires looking up span for `Default` again + = note: cycle used when perform lints prior to AST lowering + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.rs b/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.rs new file mode 100644 index 000000000000..0108ada8c08c --- /dev/null +++ b/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.rs @@ -0,0 +1,18 @@ +// Regression test for #153391. +// +//@ edition:2024 +//@ compile-flags: -Z threads=16 +//@ compare-output-by-lines +//@ ignore-test (#142063) + +trait A { + fn g() -> B; + //~^ ERROR expected a type, found a trait +} + +trait B { + fn bar(&self, x: &A); + //~^ ERROR expected a type, found a trait +} + +fn main() {} diff --git a/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.stderr b/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.stderr new file mode 100644 index 000000000000..4d348cf22f4e --- /dev/null +++ b/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.stderr @@ -0,0 +1,31 @@ +error[E0782]: expected a type, found a trait + --> $DIR/fn-sig-cycle-ice-153391.rs:8:15 + | +LL | fn g() -> B; + | ^ + | +help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as you return a single underlying type + | +LL | fn g() -> impl B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/fn-sig-cycle-ice-153391.rs:13:23 + | +LL | fn bar(&self, x: &A); + | ^ + | + = note: `A` is dyn-incompatible, otherwise a trait object could be used +help: use a new generic type parameter, constrained by `A` + | +LL - fn bar(&self, x: &A); +LL + fn bar(&self, x: &T); + | +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(&self, x: &impl A); + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-120757.rs b/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-120757.rs new file mode 100644 index 000000000000..ef484c38ccad --- /dev/null +++ b/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-120757.rs @@ -0,0 +1,127 @@ +// Test for #120757, deadlock due to query cycle + +#![feature(generic_const_exprs)] + +trait TensorDimension { + const DIM: usize; + const ISSCALAR: bool = Self::DIM == 0; + fn is_scalar(&self) -> bool { + Self::ISSCALAR + } +} + +trait TensorSize: TensorDimension { + fn size(&self) -> [usize; Self::DIM]; + fn inbounds(&self, index: [usize; Self::DIM]) -> bool { + index.iter().zip(self.size().iter()).all(|(i, s)| i < s) + } +} + +trait Broadcastable: TensorSize + Sized { + type Element; + fn bget(&self, index: [usize; Self::DIM]) -> Option; + fn lazy_updim( + &self, + size: [usize; NEWDIM], + ) -> LazyUpdim { + assert!( + NEWDIM >= Self::DIM, + "Updimmed tensor cannot have fewer indices than the initial one." + ); + LazyUpdim { size, reference: &self } + } + fn bmap T>(&self, foo: F) -> BMap { + BMap { reference: self, closure: foo } + } +} + +struct LazyUpdim<'a, T: Broadcastable, const OLDDIM: usize, const DIM: usize> { + size: [usize; DIM], + reference: &'a T, +} + +impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T, { T::DIM }, DIM> { + const DIM: usize = DIM; +} +impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> { + fn size(&self) -> [usize; DIM] { + //~^ ERROR method not compatible with trait + self.size + } +} +impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> { + type Element = T::Element; + fn bget(&self, index: [usize; DIM]) -> Option { + //~^ ERROR method not compatible with trait + assert!(DIM >= T::DIM); + if !self.inbounds(index) { + //~^ ERROR unconstrained generic constant + //~| ERROR mismatched types + return None; + } + let size = self.size(); + //~^ ERROR unconstrained generic constant + + let newindex: [usize; T::DIM] = Default::default(); + //~^ ERROR the trait bound `[usize; T::DIM]: Default` is not satisfied + self.reference.bget(newindex) + } +} + +struct BMap<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> { + reference: &'a T, + closure: F, +} + +impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorDimension + for BMap<'a, R, T, F, DIM> +{ + const DIM: usize = DIM; +} +impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSize + for BMap<'a, R, T, F, DIM> +{ + fn size(&self) -> [usize; DIM] { + //~^ ERROR method not compatible with trait + self.reference.size() + //~^ ERROR unconstrained generic constant + //~| ERROR mismatched types + } +} +impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcastable + for BMap<'a, R, T, F, DIM> +{ + type Element = R; + fn bget(&self, index: [usize; DIM]) -> Option { + //~^ ERROR method not compatible with trait + self.reference.bget(index).map(ns_window) + //~^ ERROR unconstrained generic constant + //~| ERROR mismatched types + //~| ERROR cannot find value `ns_window` in this scope + } +} + +impl TensorDimension for Vec { + const DIM: usize = 1; +} +impl TensorSize for Vec { + fn size(&self) -> [usize; 1] { + //~^ ERROR method not compatible with trait + [self.len()] + } +} +impl Broadcastable for Vec { + type Element = T; + fn bget(&self, index: [usize; 1]) -> Option { + //~^ ERROR method not compatible with trait + self.get(index[0]).cloned() + } +} + +fn main() { + let v = vec![1, 2, 3]; + let bv = v.lazy_updim([3, 4]); + let bbv = bv.bmap(|x| x * x); + + println!("The size of v is {:?}", bbv.bget([0, 2]).expect("Out of bounds.")); +} diff --git a/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-120757.stderr b/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-120757.stderr new file mode 100644 index 000000000000..4e8cbdb31951 --- /dev/null +++ b/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-120757.stderr @@ -0,0 +1,166 @@ +error[E0425]: cannot find value `ns_window` in this scope + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:97:40 + | +LL | self.reference.bget(index).map(ns_window) + | ^^^^^^^^^ not found in this scope + +error[E0308]: method not compatible with trait + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:47:5 + | +LL | fn size(&self) -> [usize; DIM] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error[E0308]: method not compatible with trait + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:54:5 + | +LL | fn bget(&self, index: [usize; DIM]) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error[E0308]: method not compatible with trait + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:84:5 + | +LL | fn size(&self) -> [usize; DIM] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error[E0308]: method not compatible with trait + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:95:5 + | +LL | fn bget(&self, index: [usize; DIM]) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error[E0308]: method not compatible with trait + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:108:5 + | +LL | fn size(&self) -> [usize; 1] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1` + | + = note: expected constant `Self::DIM` + found constant `1` + +error[E0308]: method not compatible with trait + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:115:5 + | +LL | fn bget(&self, index: [usize; 1]) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1` + | + = note: expected constant `Self::DIM` + found constant `1` + +error: unconstrained generic constant + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:57:13 + | +LL | if !self.inbounds(index) { + | ^^^^ + | +note: required by a bound in `TensorSize::inbounds` + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:15:39 + | +LL | fn inbounds(&self, index: [usize; Self::DIM]) -> bool { + | ^^^^^^^^^ required by this bound in `TensorSize::inbounds` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:57:27 + | +LL | if !self.inbounds(index) { + | ^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error: unconstrained generic constant + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:62:25 + | +LL | let size = self.size(); + | ^^^^ + | +note: required by a bound in `TensorSize::size` + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:14:31 + | +LL | fn size(&self) -> [usize; Self::DIM]; + | ^^^^^^^^^ required by this bound in `TensorSize::size` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0277]: the trait bound `[usize; T::DIM]: Default` is not satisfied + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:65:41 + | +LL | let newindex: [usize; T::DIM] = Default::default(); + | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; T::DIM]` + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> where [usize; T::DIM]: Default { + | ++++++++++++++++++++++++++++++ + +error: unconstrained generic constant + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:86:24 + | +LL | self.reference.size() + | ^^^^ + | +note: required by a bound in `TensorSize::size` + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:14:31 + | +LL | fn size(&self) -> [usize; Self::DIM]; + | ^^^^^^^^^ required by this bound in `TensorSize::size` +help: try adding a `where` bound + | +LL | fn size(&self) -> [usize; DIM] where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:86:9 + | +LL | self.reference.size() + | ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM` + | + = note: expected constant `DIM` + found constant `Self::DIM` + +error: unconstrained generic constant + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:97:9 + | +LL | self.reference.bget(index).map(ns_window) + | ^^^^^^^^^^^^^^ + | +note: required by a bound in `Broadcastable::bget` + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:22:35 + | +LL | fn bget(&self, index: [usize; Self::DIM]) -> Option; + | ^^^^^^^^^ required by this bound in `Broadcastable::bget` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/generic-const-exprs-deadlock-issue-120757.rs:97:29 + | +LL | self.reference.bget(index).map(ns_window) + | ^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error: aborting due to 15 previous errors + +Some errors have detailed explanations: E0277, E0308, E0425. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-134978.rs b/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-134978.rs new file mode 100644 index 000000000000..ccc03a44cf70 --- /dev/null +++ b/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-134978.rs @@ -0,0 +1,20 @@ +// Test for #134978, deadlock detected as we're unable to find a query cycle to break + +#![feature(generic_const_exprs)] + +pub struct Struct; + +impl Struct { + pub const OK: usize = 0; +} + +fn main() { + function::<0>(); +} + +fn function() +where + [(); Struct::<{ NUM_CARDS + 0 }>::OK]:, + //~^ ERROR cycle detected when building an abstract representation +{ +} diff --git a/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-134978.stderr b/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-134978.stderr new file mode 100644 index 000000000000..a27c1079bd81 --- /dev/null +++ b/tests/ui/parallel-rustc/generic-const-exprs-deadlock-issue-134978.stderr @@ -0,0 +1,29 @@ +error[E0391]: cycle detected when building an abstract representation for `function::{constant#0}` + --> $DIR/generic-const-exprs-deadlock-issue-134978.rs:17:10 + | +LL | [(); Struct::<{ NUM_CARDS + 0 }>::OK]:, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires building THIR for `function::{constant#0}`... + --> $DIR/generic-const-exprs-deadlock-issue-134978.rs:17:10 + | +LL | [(); Struct::<{ NUM_CARDS + 0 }>::OK]:, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `function::{constant#0}`... + --> $DIR/generic-const-exprs-deadlock-issue-134978.rs:17:10 + | +LL | [(); Struct::<{ NUM_CARDS + 0 }>::OK]:, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires building an abstract representation for `function::{constant#0}`, completing the cycle +note: cycle used when checking that `function` is well-formed + --> $DIR/generic-const-exprs-deadlock-issue-134978.rs:15:1 + | +LL | / fn function() +LL | | where +LL | | [(); Struct::<{ NUM_CARDS + 0 }>::OK]:, + | |___________________________________________^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/parallel-rustc/infer-unwrap-none-issue-120786.rs b/tests/ui/parallel-rustc/infer-unwrap-none-issue-120786.rs new file mode 100644 index 000000000000..f617e20804a2 --- /dev/null +++ b/tests/ui/parallel-rustc/infer-unwrap-none-issue-120786.rs @@ -0,0 +1,82 @@ +// Test for #120786, which causes an ice bug: infer: `None` + +fn no_err() { + |x: u32, y| x; + //~^ ERROR type annotations needed + let _ = String::from("x"); +} + +fn err() { + String::from("x".as_ref()); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed +} + +fn arg_pat_closure_err() { + |x| String::from("x".as_ref()); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed +} + +fn local_pat_closure_err() { + let _ = "x".as_ref(); + //~^ ERROR type annotations needed +} + +fn err_first_arg_pat() { + String::from("x".as_ref()); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed + |x: String| x; +} + +fn err_second_arg_pat() { + |x: String| x; + String::from("x".as_ref()); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed +} + +fn err_mid_arg_pat() { + |x: String| x; + |x: String| x; + |x: String| x; + |x: String| x; + String::from("x".as_ref()); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed + |x: String| x; + |x: String| x; + |x: String| x; + |x: String| x; +} + +fn err_first_local_pat() { + String::from("x".as_ref()); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed + let _ = String::from("x"); +} + +fn err_second_local_pat() { + let _ = String::from("x"); + String::from("x".as_ref()); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed +} + +fn err_mid_local_pat() { + let _ = String::from("x"); + let _ = String::from("x"); + let _ = String::from("x"); + let _ = String::from("x"); + String::from("x".as_ref()); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed + let _ = String::from("x"); + let _ = String::from("x"); + let _ = String::from("x"); + let _ = String::from("x"); +} + +fn main() {} diff --git a/tests/ui/parallel-rustc/infer-unwrap-none-issue-120786.stderr b/tests/ui/parallel-rustc/infer-unwrap-none-issue-120786.stderr new file mode 100644 index 000000000000..3be18fc59e73 --- /dev/null +++ b/tests/ui/parallel-rustc/infer-unwrap-none-issue-120786.stderr @@ -0,0 +1,256 @@ +error[E0282]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:4:14 + | +LL | |x: u32, y| x; + | ^ + | +help: consider giving this closure parameter an explicit type + | +LL | |x: u32, y: /* Type */| x; + | ++++++++++++ + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:10:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^ cannot infer type for reference `&_` + | + = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate: + - impl From<&String> for String; + - impl From<&str> for String; + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:10:22 + | +LL | String::from("x".as_ref()); + | ^^^^^^ + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: try using a fully qualified path to specify the expected types + | +LL - String::from("x".as_ref()); +LL + String::from(>::as_ref("x")); + | + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:16:9 + | +LL | |x| String::from("x".as_ref()); + | ^^^^^^ cannot infer type for reference `&_` + | + = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate: + - impl From<&String> for String; + - impl From<&str> for String; + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:16:26 + | +LL | |x| String::from("x".as_ref()); + | ^^^^^^ + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: try using a fully qualified path to specify the expected types + | +LL - |x| String::from("x".as_ref()); +LL + |x| String::from(>::as_ref("x")); + | + +error[E0283]: type annotations needed for `&_` + --> $DIR/infer-unwrap-none-issue-120786.rs:22:9 + | +LL | let _ = "x".as_ref(); + | ^ ------ type must be known at this point + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: consider giving this pattern a type, where the type for type parameter `T` is specified + | +LL | let _: &T = "x".as_ref(); + | ++++ + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:27:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^ cannot infer type for reference `&_` + | + = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate: + - impl From<&String> for String; + - impl From<&str> for String; + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:27:22 + | +LL | String::from("x".as_ref()); + | ^^^^^^ + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: try using a fully qualified path to specify the expected types + | +LL - String::from("x".as_ref()); +LL + String::from(>::as_ref("x")); + | + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:35:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^ cannot infer type for reference `&_` + | + = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate: + - impl From<&String> for String; + - impl From<&str> for String; + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:35:22 + | +LL | String::from("x".as_ref()); + | ^^^^^^ + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: try using a fully qualified path to specify the expected types + | +LL - String::from("x".as_ref()); +LL + String::from(>::as_ref("x")); + | + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:45:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^ cannot infer type for reference `&_` + | + = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate: + - impl From<&String> for String; + - impl From<&str> for String; + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:45:22 + | +LL | String::from("x".as_ref()); + | ^^^^^^ + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: try using a fully qualified path to specify the expected types + | +LL - String::from("x".as_ref()); +LL + String::from(>::as_ref("x")); + | + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:55:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^ cannot infer type for reference `&_` + | + = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate: + - impl From<&String> for String; + - impl From<&str> for String; + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:55:22 + | +LL | String::from("x".as_ref()); + | ^^^^^^ + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: try using a fully qualified path to specify the expected types + | +LL - String::from("x".as_ref()); +LL + String::from(>::as_ref("x")); + | + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:63:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^ cannot infer type for reference `&_` + | + = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate: + - impl From<&String> for String; + - impl From<&str> for String; + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:63:22 + | +LL | String::from("x".as_ref()); + | ^^^^^^ + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: try using a fully qualified path to specify the expected types + | +LL - String::from("x".as_ref()); +LL + String::from(>::as_ref("x")); + | + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:73:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^ cannot infer type for reference `&_` + | + = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate: + - impl From<&String> for String; + - impl From<&str> for String; + +error[E0283]: type annotations needed + --> $DIR/infer-unwrap-none-issue-120786.rs:73:22 + | +LL | String::from("x".as_ref()); + | ^^^^^^ + | + = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef for str; + - impl AsRef<[u8]> for str; + - impl AsRef for str; +help: try using a fully qualified path to specify the expected types + | +LL - String::from("x".as_ref()); +LL + String::from(>::as_ref("x")); + | + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0282, E0283. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/parallel-rustc/nested-type-alias-cycle-issue-129911.rs b/tests/ui/parallel-rustc/nested-type-alias-cycle-issue-129911.rs new file mode 100644 index 000000000000..1fd058db29d4 --- /dev/null +++ b/tests/ui/parallel-rustc/nested-type-alias-cycle-issue-129911.rs @@ -0,0 +1,89 @@ +// Test for #129911, deadlock detected as we're unable to find a query cycle to break + +fn main() { + type KooArc = Frc< + //~^ ERROR cannot find type `Frc` in this scope + { + { + { + {}; + } + type Frc = Frc<{}>::Arc;; + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + } + type Frc = Frc< + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + { + { + { + {}; + } + type Frc = Frc<{}>::Arc;; + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + } + type Frc = Frc< + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + { + { + { + {}; + } + type Frc = Frc<{}>::Arc;; + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + } + type Frc = Frc< + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + { + { + { + {}; + } + type Frc = Frc<{}>::Arc;; + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + } + type Frc = Frc< + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + { + { + { + { + {}; + } + type Frc = Frc<{}>::Arc;; + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + }; + } + type Frc = Frc< + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + { + { + { + {}; + }; + } + type Frc = Frc<{}>::Arc;; + //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR cycle detected when expanding type alias + }, + >::Arc;; + }, + >::Arc;; + }, + >::Arc;; + }, + >::Arc;; + }, + >::Arc;; + }, + >::Arc; +} diff --git a/tests/ui/parallel-rustc/nested-type-alias-cycle-issue-129911.stderr b/tests/ui/parallel-rustc/nested-type-alias-cycle-issue-129911.stderr new file mode 100644 index 000000000000..b1ece1747989 --- /dev/null +++ b/tests/ui/parallel-rustc/nested-type-alias-cycle-issue-129911.stderr @@ -0,0 +1,391 @@ +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:11:28 + | +LL | type Frc = Frc<{}>::Arc;; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:11:22 + | +LL | type Frc = Frc<{}>::Arc;; + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:11:28 + | +LL | type Frc = Frc<{}>::Arc;; + | ^^^^^^^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:11:17 + | +LL | type Frc = Frc<{}>::Arc;; + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:15:24 + | +LL | type Frc = Frc< + | ________________________^^^- + | | | + | | expected 0 generic arguments +... | +LL | | }, +LL | | >::Arc;; + | |_____________- help: remove the unnecessary generics + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:15:18 + | +LL | type Frc = Frc< + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:15:24 + | +LL | type Frc = Frc< + | ________________________^ +... | +LL | | }, +LL | | >::Arc;; + | |_____________^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:15:13 + | +LL | type Frc = Frc< + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:23:36 + | +LL | type Frc = Frc<{}>::Arc;; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:23:30 + | +LL | type Frc = Frc<{}>::Arc;; + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:23:36 + | +LL | type Frc = Frc<{}>::Arc;; + | ^^^^^^^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:23:25 + | +LL | type Frc = Frc<{}>::Arc;; + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:27:32 + | +LL | type Frc = Frc< + | ________________________________^^^- + | | | + | | expected 0 generic arguments +... | +LL | | }, +LL | | >::Arc;; + | |_____________________- help: remove the unnecessary generics + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:27:26 + | +LL | type Frc = Frc< + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:27:32 + | +LL | type Frc = Frc< + | ________________________________^ +... | +LL | | }, +LL | | >::Arc;; + | |_____________________^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:27:21 + | +LL | type Frc = Frc< + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:35:44 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:35:38 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:35:44 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^^^^^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:35:33 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:39:40 + | +LL | ... type Frc = Frc< + | __________________________________^^^- + | | | + | | expected 0 generic arguments +... | +LL | | ... }, +LL | | ... >::Arc;; + | |_______________________- help: remove the unnecessary generics + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:39:34 + | +LL | ... type Frc = Frc< + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:39:40 + | +LL | ... type Frc = Frc< + | __________________________________^ +... | +LL | | ... }, +LL | | ... >::Arc;; + | |_______________________^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:39:29 + | +LL | ... type Frc = Frc< + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:47:52 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:47:46 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:47:52 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^^^^^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:47:41 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:51:48 + | +LL | ... type Frc = Frc< + | __________________________________^^^- + | | | + | | expected 0 generic arguments +... | +LL | | ... }, +LL | | ... >::Arc;; + | |_______________________- help: remove the unnecessary generics + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:51:42 + | +LL | ... type Frc = Frc< + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:51:48 + | +LL | ... type Frc = Frc< + | __________________________________^ +... | +LL | | ... }, +LL | | ... >::Arc;; + | |_______________________^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:51:37 + | +LL | ... type Frc = Frc< + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:60:64 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:60:58 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:60:64 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^^^^^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:60:53 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:65:56 + | +LL | ... type Frc = Frc< + | __________________________________^^^- + | | | + | | expected 0 generic arguments +... | +LL | | ... }, +LL | | ... >::Arc;; + | |_______________________- help: remove the unnecessary generics + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:65:50 + | +LL | ... type Frc = Frc< + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:65:56 + | +LL | ... type Frc = Frc< + | __________________________________^ +... | +LL | | ... }, +LL | | ... >::Arc;; + | |_______________________^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:65:45 + | +LL | ... type Frc = Frc< + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/nested-type-alias-cycle-issue-129911.rs:74:64 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: type alias defined here, with 0 generic parameters + --> $DIR/nested-type-alias-cycle-issue-129911.rs:74:58 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^ + +error[E0391]: cycle detected when expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` + --> $DIR/nested-type-alias-cycle-issue-129911.rs:74:64 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^^^^^ + | + = note: ...which immediately requires expanding type alias `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when checking that `main::KooArc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc::{constant#0}::Frc` is well-formed + --> $DIR/nested-type-alias-cycle-issue-129911.rs:74:53 + | +LL | ... type Frc = Frc<{}>::Arc;; + | ^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0433]: cannot find type `Frc` in this scope + --> $DIR/nested-type-alias-cycle-issue-129911.rs:4:19 + | +LL | type KooArc = Frc< + | ^^^ use of undeclared type `Frc` + +error: aborting due to 23 previous errors + +Some errors have detailed explanations: E0107, E0391, E0433. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/parallel-rustc/recursive-impl-trait-deadlock-issue-129912.rs b/tests/ui/parallel-rustc/recursive-impl-trait-deadlock-issue-129912.rs new file mode 100644 index 000000000000..5b0bd19fff0b --- /dev/null +++ b/tests/ui/parallel-rustc/recursive-impl-trait-deadlock-issue-129912.rs @@ -0,0 +1,97 @@ +// Test for #129912, which causes a deadlock bug without finding a cycle + +#![feature(generators)] +//~^ ERROR feature has been removed +#![allow(unconditional_recursion)] + +fn option(i: i32) -> impl Sync { + if generator_sig() < 0 { None } else { Sized((option(i - Sized), i)) } + //~^ ERROR expected value, found trait `Sized` + //~| ERROR expected function, tuple struct or tuple variant, found trait `Sized` +} + +fn tuple() -> impl Sized { + (tuple(),) +} + +fn array() -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + [array()] +} + +fn ptr() -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + &ptr() as *const impl Sized + //~^ ERROR `impl Trait` is not allowed in cast expression types +} + +fn fn_ptr() -> impl Sized { + fn_ptr as fn() -> _ +} + +fn closure_capture() -> impl Sized { + let x = closure_capture(); + move || { + x; + } +} + +fn closure_ref_capture() -> impl Sized { + let x = closure_ref_capture(); + move || { + &x; + } +} + +fn closure_sig() -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + || closure_sig() +} + +fn generator_sig() -> impl Sized { + || i + //~^ ERROR cannot find value `i` in this scope +} + +fn generator_capture() -> impl i32 { + //~^ ERROR expected trait, found builtin type `i32` + let x = 1(); + move || { + yield; + //~^ ERROR yield syntax is experimental + //~| ERROR yield syntax is experimental + //~| ERROR `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + x; + } +} + +fn substs_change() -> impl Sized { + (substs_change::<&T>(),) +} + +fn generator_hold() -> impl generator_capture { + //~^ ERROR expected trait, found function `generator_capture` + move || { + let x = (); + yield; + //~^ ERROR yield syntax is experimental + //~| ERROR yield syntax is experimental + //~| ERROR `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + x virtual ; + //~^ ERROR expected one of + } +} + +fn use_fn_ptr() -> impl Sized { + fn_ptr() +} + +fn mutual_recursion() -> impl Sync { + mutual_recursion_b() +} + +fn mutual_recursion_b() -> impl Sized { + mutual_recursion() +} + +fn main() {} diff --git a/tests/ui/parallel-rustc/recursive-impl-trait-deadlock-issue-129912.stderr b/tests/ui/parallel-rustc/recursive-impl-trait-deadlock-issue-129912.stderr new file mode 100644 index 000000000000..420fb36d5600 --- /dev/null +++ b/tests/ui/parallel-rustc/recursive-impl-trait-deadlock-issue-129912.stderr @@ -0,0 +1,137 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found reserved keyword `virtual` + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:80:11 + | +LL | x virtual ; + | ^^^^^^^ expected one of 8 possible tokens + +error[E0557]: feature has been removed + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:3:12 + | +LL | #![feature(generators)] + | ^^^^^^^^^^ feature has been removed + | + = note: removed in 1.75.0; see for more information + = note: renamed to `coroutines` + +error[E0423]: expected value, found trait `Sized` + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:8:62 + | +LL | if generator_sig() < 0 { None } else { Sized((option(i - Sized), i)) } + | ^^^^^ not a value + +error[E0425]: cannot find value `i` in this scope + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:52:8 + | +LL | || i + | ^ not found in this scope + +error[E0404]: expected trait, found builtin type `i32` + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:56:32 + | +LL | fn generator_capture() -> impl i32 { + | ^^^ not a trait + +error[E0404]: expected trait, found function `generator_capture` + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:72:29 + | +LL | fn generator_hold() -> impl generator_capture { + | ^^^^^^^^^^^^^^^^^ not a trait + +error[E0658]: yield syntax is experimental + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:60:9 + | +LL | yield; + | ^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(yield_expr)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: yield syntax is experimental + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:76:9 + | +LL | yield; + | ^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(yield_expr)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in cast expression types + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:24:22 + | +LL | &ptr() as *const impl Sized + | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + +error[E0658]: yield syntax is experimental + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:60:9 + | +LL | yield; + | ^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(yield_expr)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:60:9 + | +LL | yield; + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] move || { + | ++++++++++++ + +error[E0658]: yield syntax is experimental + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:76:9 + | +LL | yield; + | ^^^^^ + | + = note: see issue #43122 for more information + = help: add `#![feature(yield_expr)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:76:9 + | +LL | yield; + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] move || { + | ++++++++++++ + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:17:15 + | +LL | fn array() -> _ { + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:22:13 + | +LL | fn ptr() -> _ { + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:46:21 + | +LL | fn closure_sig() -> _ { + | ^ not allowed in type signatures + +error[E0423]: expected function, tuple struct or tuple variant, found trait `Sized` + --> $DIR/recursive-impl-trait-deadlock-issue-129912.rs:8:44 + | +LL | if generator_sig() < 0 { None } else { Sized((option(i - Sized), i)) } + | ^^^^^ not a function, tuple struct or tuple variant + +error: aborting due to 17 previous errors + +Some errors have detailed explanations: E0121, E0404, E0423, E0425, E0557, E0562, E0658. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/parallel-rustc/recursive-struct-oncelock-issue-151226.rs b/tests/ui/parallel-rustc/recursive-struct-oncelock-issue-151226.rs new file mode 100644 index 000000000000..69cbd578325c --- /dev/null +++ b/tests/ui/parallel-rustc/recursive-struct-oncelock-issue-151226.rs @@ -0,0 +1,9 @@ +// Test for #151226, Unable to verify registry association +// +//@ compile-flags: -Z threads=2 +//@ compare-output-by-lines + +struct A(std::sync::OnceLock); +//~^ ERROR recursive type `A` has infinite size +static B: A<()> = todo!(); +fn main() {} diff --git a/tests/ui/parallel-rustc/recursive-struct-oncelock-issue-151226.stderr b/tests/ui/parallel-rustc/recursive-struct-oncelock-issue-151226.stderr new file mode 100644 index 000000000000..2a51ee930779 --- /dev/null +++ b/tests/ui/parallel-rustc/recursive-struct-oncelock-issue-151226.stderr @@ -0,0 +1,14 @@ +error[E0072]: recursive type `A` has infinite size + --> $DIR/recursive-struct-oncelock-issue-151226.rs:6:1 + | +LL | struct A(std::sync::OnceLock); + | ^^^^^^^^^^^ ------------------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | struct A(Box>); + | ++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/parallel-rustc/recursive-trait-fn-sig-issue-142064.rs b/tests/ui/parallel-rustc/recursive-trait-fn-sig-issue-142064.rs new file mode 100644 index 000000000000..5ae2f936333f --- /dev/null +++ b/tests/ui/parallel-rustc/recursive-trait-fn-sig-issue-142064.rs @@ -0,0 +1,18 @@ +// Test for #142064, internal error: entered unreachable code +// +//@ compile-flags: -Zthreads=2 +//@ compare-output-by-lines + +#![crate_type = "rlib"] +trait A { fn foo() -> A; } +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition +//~| WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition +//~| ERROR the trait `A` is not dyn compatible +trait B { fn foo() -> A; } +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition +//~| WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition +//~| ERROR the trait `A` is not dyn compatible diff --git a/tests/ui/parallel-rustc/recursive-trait-fn-sig-issue-142064.stderr b/tests/ui/parallel-rustc/recursive-trait-fn-sig-issue-142064.stderr new file mode 100644 index 000000000000..540f70ec1e15 --- /dev/null +++ b/tests/ui/parallel-rustc/recursive-trait-fn-sig-issue-142064.stderr @@ -0,0 +1,114 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/recursive-trait-fn-sig-issue-142064.rs:7:23 + | +LL | trait A { fn foo() -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default +help: if this is a dyn-compatible trait, use `dyn` + | +LL | trait A { fn foo() -> dyn A; } + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/recursive-trait-fn-sig-issue-142064.rs:13:23 + | +LL | trait B { fn foo() -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: if this is a dyn-compatible trait, use `dyn` + | +LL | trait B { fn foo() -> dyn A; } + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/recursive-trait-fn-sig-issue-142064.rs:7:23 + | +LL | trait A { fn foo() -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: if this is a dyn-compatible trait, use `dyn` + | +LL | trait A { fn foo() -> dyn A; } + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/recursive-trait-fn-sig-issue-142064.rs:13:23 + | +LL | trait B { fn foo() -> A; } + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: if this is a dyn-compatible trait, use `dyn` + | +LL | trait B { fn foo() -> dyn A; } + | +++ + +error[E0038]: the trait `A` is not dyn compatible + --> $DIR/recursive-trait-fn-sig-issue-142064.rs:7:23 + | +LL | trait A { fn foo() -> A; } + | ^ `A` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/recursive-trait-fn-sig-issue-142064.rs:7:14 + | +LL | trait A { fn foo() -> A; } + | - ^^^ ...because associated function `foo` has no `self` parameter + | | + | this trait is not dyn compatible... +help: consider turning `foo` into a method by giving it a `&self` argument + | +LL | trait A { fn foo(&self) -> A; } + | +++++ +help: alternatively, consider constraining `foo` so it does not apply to trait objects + | +LL | trait A { fn foo() -> A where Self: Sized; } + | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - trait A { fn foo() -> A; } +LL + trait A { fn foo() -> Self; } + | + +error[E0038]: the trait `A` is not dyn compatible + --> $DIR/recursive-trait-fn-sig-issue-142064.rs:13:23 + | +LL | trait B { fn foo() -> A; } + | ^ `A` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/recursive-trait-fn-sig-issue-142064.rs:7:14 + | +LL | trait A { fn foo() -> A; } + | - ^^^ ...because associated function `foo` has no `self` parameter + | | + | this trait is not dyn compatible... +help: consider turning `foo` into a method by giving it a `&self` argument + | +LL | trait A { fn foo(&self) -> A; } + | +++++ +help: alternatively, consider constraining `foo` so it does not apply to trait objects + | +LL | trait A { fn foo() -> A where Self: Sized; } + | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - trait B { fn foo() -> A; } +LL + trait B { fn foo() -> Self; } + | + +error: aborting due to 2 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/parallel-rustc/recursive-type-with-transmutability-issue-120759.rs b/tests/ui/parallel-rustc/recursive-type-with-transmutability-issue-120759.rs new file mode 100644 index 000000000000..cee66985dd4a --- /dev/null +++ b/tests/ui/parallel-rustc/recursive-type-with-transmutability-issue-120759.rs @@ -0,0 +1,26 @@ +// Test for #120759, deadlock detected without any query + +#![crate_type = "lib"] +#![feature(transmutability)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + //~^ ERROR unresolved import `std::mem::BikeshedIntrinsicFrom` + pub struct Context; + + pub fn is_maybe_transmutable(&self, cpu: &mut CPU) + //~^ ERROR `self` parameter is only allowed in associated functions + //~| ERROR cannot find type `CPU` in this scope + where + Dst: BikeshedIntrinsicFrom, + { + } +} + +fn should_pad_explicitly_packed_field() { + #[repr(C)] + struct ExplicitlyPadded(ExplicitlyPadded); + //~^ ERROR recursive type `ExplicitlyPadded` has infinite size + + assert::is_maybe_transmutable::(); +} diff --git a/tests/ui/parallel-rustc/recursive-type-with-transmutability-issue-120759.stderr b/tests/ui/parallel-rustc/recursive-type-with-transmutability-issue-120759.stderr new file mode 100644 index 000000000000..c21418c04116 --- /dev/null +++ b/tests/ui/parallel-rustc/recursive-type-with-transmutability-issue-120759.stderr @@ -0,0 +1,35 @@ +error: `self` parameter is only allowed in associated functions + --> $DIR/recursive-type-with-transmutability-issue-120759.rs:11:44 + | +LL | pub fn is_maybe_transmutable(&self, cpu: &mut CPU) + | ^^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error[E0432]: unresolved import `std::mem::BikeshedIntrinsicFrom` + --> $DIR/recursive-type-with-transmutability-issue-120759.rs:7:28 + | +LL | use std::mem::{Assume, BikeshedIntrinsicFrom}; + | ^^^^^^^^^^^^^^^^^^^^^ no `BikeshedIntrinsicFrom` in `mem` + +error[E0425]: cannot find type `CPU` in this scope + --> $DIR/recursive-type-with-transmutability-issue-120759.rs:11:61 + | +LL | pub fn is_maybe_transmutable(&self, cpu: &mut CPU) + | ^^^ not found in this scope + +error[E0072]: recursive type `ExplicitlyPadded` has infinite size + --> $DIR/recursive-type-with-transmutability-issue-120759.rs:22:5 + | +LL | struct ExplicitlyPadded(ExplicitlyPadded); + | ^^^^^^^^^^^^^^^^^^^^^^^ ---------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | struct ExplicitlyPadded(Box); + | ++++ + + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0072, E0425, E0432. +For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/parallel-rustc/ty-variance-issue-124423.rs b/tests/ui/parallel-rustc/ty-variance-issue-124423.rs index 8d7f29f77641..501b0fca7bf5 100644 --- a/tests/ui/parallel-rustc/ty-variance-issue-124423.rs +++ b/tests/ui/parallel-rustc/ty-variance-issue-124423.rs @@ -43,7 +43,7 @@ fn x<'b>(_: &'a impl Copy + 'a) -> Box { Box::u32(x) } //~| ERROR use of undeclared lifetime name `'a` //~| ERROR use of undeclared lifetime name `'a` //~| ERROR at least one trait is required for an object type -//~| ERROR no function or associated item named `u32` found for struct `Box<_, _>` in the current scope +//~| ERROR no associated function or constant named `u32` found for struct `Box<_, _>` in the current scope fn elided4(_: &impl Copy + 'a) -> new { x(x) } //~^ ERROR ambiguous `+` in a type diff --git a/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr b/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr index bf9ad85dfc5c..2246a22eb60d 100644 --- a/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr +++ b/tests/ui/parallel-rustc/ty-variance-issue-124423.stderr @@ -243,12 +243,6 @@ error[E0425]: cannot find type `new` in this scope LL | fn elided4(_: &impl Copy + 'a) -> new { x(x) } | ^^^ not found in this scope -error[E0224]: at least one trait is required for an object type - --> $DIR/ty-variance-issue-124423.rs:35:39 - | -LL | fn elided3(_: &impl Copy + 'a) -> Box { Box::new(x) } - | ^^^^^^ - error[E0224]: at least one trait is required for an object type --> $DIR/ty-variance-issue-124423.rs:41:40 | @@ -261,23 +255,30 @@ error[E0224]: at least one trait is required for an object type LL | impl<'a> LifetimeTrait<'a> for &'a Box {} | ^^^^^^ +error[E0224]: at least one trait is required for an object type + --> $DIR/ty-variance-issue-124423.rs:35:39 + | +LL | fn elided3(_: &impl Copy + 'a) -> Box { Box::new(x) } + | ^^^^^^ + error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/ty-variance-issue-124423.rs:8:34 | LL | fn elided(_: &impl Copy + 'a) -> _ { x } | ^ not allowed in type signatures -error[E0599]: no function or associated item named `u32` found for struct `Box<_, _>` in the current scope +error[E0599]: no associated function or constant named `u32` found for struct `Box<_, _>` in the current scope --> $DIR/ty-variance-issue-124423.rs:41:55 | LL | fn x<'b>(_: &'a impl Copy + 'a) -> Box { Box::u32(x) } - | ^^^ function or associated item not found in `Box<_, _>` + | ^^^ associated function or constant not found in `Box<_, _>` | note: if you're trying to build a new `Box<_, _>` consider using one of the following associated functions: Box::::new Box::::new_uninit Box::::new_zeroed Box::::try_new + and 27 others --> $SRC_DIR/alloc/src/boxed.rs:LL:COL error: aborting due to 30 previous errors diff --git a/tests/ui/parallel-rustc/ty-variance-issue-127971.rs b/tests/ui/parallel-rustc/ty-variance-issue-127971.rs index a17916843e70..db2dc8e4c856 100644 --- a/tests/ui/parallel-rustc/ty-variance-issue-127971.rs +++ b/tests/ui/parallel-rustc/ty-variance-issue-127971.rs @@ -20,6 +20,6 @@ fn x<'b>(_: &'a impl Copy + 'a) -> Box { Box::u32(x) } //~| ERROR use of undeclared lifetime name `'a` //~| ERROR use of undeclared lifetime name `'a` //~| ERROR at least one trait is required for an object type -//~| ERROR no function or associated item named `u32` found for struct `Box<_, _>` in the current scope +//~| ERROR no associated function or constant named `u32` found for struct `Box<_, _>` in the current scope fn main() {} diff --git a/tests/ui/parallel-rustc/ty-variance-issue-127971.stderr b/tests/ui/parallel-rustc/ty-variance-issue-127971.stderr index 55d52d35f4a8..47286d90d681 100644 --- a/tests/ui/parallel-rustc/ty-variance-issue-127971.stderr +++ b/tests/ui/parallel-rustc/ty-variance-issue-127971.stderr @@ -93,20 +93,21 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures LL | fn elided(_: &impl Copy + 'a) -> _ { x } | ^ not allowed in type signatures -error[E0599]: no function or associated item named `u32` found for struct `Box<_, _>` in the current scope +error[E0599]: no associated function or constant named `u32` found for struct `Box<_, _>` in the current scope --> $DIR/ty-variance-issue-127971.rs:18:55 | LL | fn x<'b>(_: &'a impl Copy + 'a) -> Box { Box::u32(x) } - | ^^^ function or associated item not found in `Box<_, _>` + | ^^^ associated function or constant not found in `Box<_, _>` | note: if you're trying to build a new `Box<_, _>` consider using one of the following associated functions: Box::::new Box::::new_uninit Box::::new_zeroed Box::::try_new + and 27 others --> $SRC_DIR/alloc/src/boxed.rs:LL:COL error: aborting due to 11 previous errors Some errors have detailed explanations: E0121, E0224, E0261, E0599. -For more information about an error, try `rustc --explain E0121`. \ No newline at end of file +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/parallel-rustc/unexpected-type-issue-120601.stderr b/tests/ui/parallel-rustc/unexpected-type-issue-120601.stderr index da225ad82bc7..70471719a70d 100644 --- a/tests/ui/parallel-rustc/unexpected-type-issue-120601.stderr +++ b/tests/ui/parallel-rustc/unexpected-type-issue-120601.stderr @@ -1,4 +1,5 @@ error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/unexpected-type-issue-120601.rs:10:1 | LL | async fn foo() -> Result<(), ()> { | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -7,6 +8,7 @@ LL | async fn foo() -> Result<(), ()> { = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/unexpected-type-issue-120601.rs:16:1 | LL | async fn tuple() -> Tuple { | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -15,6 +17,7 @@ LL | async fn tuple() -> Tuple { = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/unexpected-type-issue-120601.rs:21:1 | LL | async fn match_() { | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -22,12 +25,8 @@ LL | async fn match_() { = help: pass `--edition 2024` to `rustc` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0425]: cannot find function, tuple struct or tuple variant `Unstable2` in this scope - | -LL | Unstable2(()) - | ^^^^^^^^^ not found in this scope - error[E0308]: mismatched types + --> $DIR/unexpected-type-issue-120601.rs:23:9 | LL | match tuple() { | ------- this expression has type `impl Future` @@ -41,7 +40,13 @@ help: consider `await`ing on the `Future` LL | match tuple().await { | ++++++ +error[E0425]: cannot find function, tuple struct or tuple variant `Unstable2` in this scope + --> $DIR/unexpected-type-issue-120601.rs:11:5 + | +LL | Unstable2(()) + | ^^^^^^^^^ not found in this scope + error: aborting due to 5 previous errors Some errors have detailed explanations: E0308, E0425, E0670. -For more information about an error, try `rustc --explain E0308`. \ No newline at end of file +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/assoc/assoc-static-semantic-fail.rs b/tests/ui/parser/assoc/assoc-static-semantic-fail.rs index 403160f1253a..de0cee6ff996 100644 --- a/tests/ui/parser/assoc/assoc-static-semantic-fail.rs +++ b/tests/ui/parser/assoc/assoc-static-semantic-fail.rs @@ -1,7 +1,6 @@ // Semantically, we do not allow e.g., `static X: u8 = 0;` as an associated item. #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete fn main() {} diff --git a/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr b/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr index cc21df77353f..4ac3528a6d42 100644 --- a/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr +++ b/tests/ui/parser/assoc/assoc-static-semantic-fail.stderr @@ -1,17 +1,17 @@ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:10:5 + --> $DIR/assoc-static-semantic-fail.rs:9:5 | LL | static IA: u8 = 0; | ^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:12:5 + --> $DIR/assoc-static-semantic-fail.rs:11:5 | LL | static IB: u8; | ^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:15:5 + --> $DIR/assoc-static-semantic-fail.rs:14:5 | LL | default static IC: u8 = 0; | ^^^^^^^ `default` because of this @@ -19,13 +19,13 @@ LL | default static IC: u8 = 0; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:15:5 + --> $DIR/assoc-static-semantic-fail.rs:14:5 | LL | default static IC: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:18:16 + --> $DIR/assoc-static-semantic-fail.rs:17:16 | LL | pub(crate) default static ID: u8; | ^^^^^^^ `default` because of this @@ -33,25 +33,25 @@ LL | pub(crate) default static ID: u8; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:18:5 + --> $DIR/assoc-static-semantic-fail.rs:17:5 | LL | pub(crate) default static ID: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:25:5 + --> $DIR/assoc-static-semantic-fail.rs:24:5 | LL | static TA: u8 = 0; | ^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:27:5 + --> $DIR/assoc-static-semantic-fail.rs:26:5 | LL | static TB: u8; | ^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:29:5 + --> $DIR/assoc-static-semantic-fail.rs:28:5 | LL | default static TC: u8 = 0; | ^^^^^^^ `default` because of this @@ -59,13 +59,13 @@ LL | default static TC: u8 = 0; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:29:5 + --> $DIR/assoc-static-semantic-fail.rs:28:5 | LL | default static TC: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:32:16 + --> $DIR/assoc-static-semantic-fail.rs:31:16 | LL | pub(crate) default static TD: u8; | ^^^^^^^ `default` because of this @@ -73,25 +73,25 @@ LL | pub(crate) default static TD: u8; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:32:5 + --> $DIR/assoc-static-semantic-fail.rs:31:5 | LL | pub(crate) default static TD: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:39:5 + --> $DIR/assoc-static-semantic-fail.rs:38:5 | LL | static TA: u8 = 0; | ^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:41:5 + --> $DIR/assoc-static-semantic-fail.rs:40:5 | LL | static TB: u8; | ^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:44:5 + --> $DIR/assoc-static-semantic-fail.rs:43:5 | LL | default static TC: u8 = 0; | ^^^^^^^ `default` because of this @@ -99,13 +99,13 @@ LL | default static TC: u8 = 0; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:44:5 + --> $DIR/assoc-static-semantic-fail.rs:43:5 | LL | default static TC: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:47:9 + --> $DIR/assoc-static-semantic-fail.rs:46:9 | LL | pub default static TD: u8; | ^^^^^^^ `default` because of this @@ -113,13 +113,13 @@ LL | pub default static TD: u8; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:47:5 + --> $DIR/assoc-static-semantic-fail.rs:46:5 | LL | pub default static TD: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: associated constant in `impl` without body - --> $DIR/assoc-static-semantic-fail.rs:12:5 + --> $DIR/assoc-static-semantic-fail.rs:11:5 | LL | static IB: u8; | ^^^^^^^^^^^^^- @@ -127,7 +127,7 @@ LL | static IB: u8; | help: provide a definition for the constant: `= ;` error: associated constant in `impl` without body - --> $DIR/assoc-static-semantic-fail.rs:18:5 + --> $DIR/assoc-static-semantic-fail.rs:17:5 | LL | pub(crate) default static ID: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -135,7 +135,7 @@ LL | pub(crate) default static ID: u8; | help: provide a definition for the constant: `= ;` error[E0449]: visibility qualifiers are not permitted here - --> $DIR/assoc-static-semantic-fail.rs:32:5 + --> $DIR/assoc-static-semantic-fail.rs:31:5 | LL | pub(crate) default static TD: u8; | ^^^^^^^^^^ help: remove the qualifier @@ -143,7 +143,7 @@ LL | pub(crate) default static TD: u8; = note: trait items always share the visibility of their trait error: associated constant in `impl` without body - --> $DIR/assoc-static-semantic-fail.rs:41:5 + --> $DIR/assoc-static-semantic-fail.rs:40:5 | LL | static TB: u8; | ^^^^^^^^^^^^^- @@ -151,7 +151,7 @@ LL | static TB: u8; | help: provide a definition for the constant: `= ;` error: associated constant in `impl` without body - --> $DIR/assoc-static-semantic-fail.rs:47:5 + --> $DIR/assoc-static-semantic-fail.rs:46:5 | LL | pub default static TD: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -159,23 +159,13 @@ LL | pub default static TD: u8; | help: provide a definition for the constant: `= ;` error[E0449]: visibility qualifiers are not permitted here - --> $DIR/assoc-static-semantic-fail.rs:47:5 + --> $DIR/assoc-static-semantic-fail.rs:46:5 | LL | pub default static TD: u8; | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/assoc-static-semantic-fail.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 24 previous errors; 1 warning emitted +error: aborting due to 24 previous errors For more information about this error, try `rustc --explain E0449`. diff --git a/tests/ui/parser/default.rs b/tests/ui/parser/default.rs index d1058ceb2a1c..81821ce23877 100644 --- a/tests/ui/parser/default.rs +++ b/tests/ui/parser/default.rs @@ -1,7 +1,6 @@ // Test successful and unsuccessful parsing of the `default` contextual keyword #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait Foo { fn foo() -> T; diff --git a/tests/ui/parser/default.stderr b/tests/ui/parser/default.stderr index c420e5a774d2..1f2312d0c6e8 100644 --- a/tests/ui/parser/default.stderr +++ b/tests/ui/parser/default.stderr @@ -1,5 +1,5 @@ error: `default` is not followed by an item - --> $DIR/default.rs:23:5 + --> $DIR/default.rs:22:5 | LL | default pub fn foo() -> T { T::default() } | ^^^^^^^ the `default` qualifier @@ -7,7 +7,7 @@ LL | default pub fn foo() -> T { T::default() } = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` error: non-item in item list - --> $DIR/default.rs:23:13 + --> $DIR/default.rs:22:13 | LL | impl Foo for u32 { | - item list starts here @@ -18,25 +18,15 @@ LL | } | - item list ends here error[E0449]: visibility qualifiers are not permitted here - --> $DIR/default.rs:17:5 + --> $DIR/default.rs:16:5 | LL | pub default fn foo() -> T { | ^^^ help: remove the qualifier | = note: trait items always share the visibility of their trait -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/default.rs:22:1 + --> $DIR/default.rs:21:1 | LL | fn foo() -> T; | -------------------------- `foo` from trait @@ -44,7 +34,7 @@ LL | fn foo() -> T; LL | impl Foo for u32 { | ^^^^^^^^^^^^^^^^ missing `foo` in implementation -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0449. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/parser/defaultness-invalid-places-fail-semantic.rs b/tests/ui/parser/defaultness-invalid-places-fail-semantic.rs index bff53f66e19d..f27404008313 100644 --- a/tests/ui/parser/defaultness-invalid-places-fail-semantic.rs +++ b/tests/ui/parser/defaultness-invalid-places-fail-semantic.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] fn main() {} diff --git a/tests/ui/parser/defaultness-invalid-places-fail-semantic.stderr b/tests/ui/parser/defaultness-invalid-places-fail-semantic.stderr index 41fad3a5de34..4adb0ab25c6f 100644 --- a/tests/ui/parser/defaultness-invalid-places-fail-semantic.stderr +++ b/tests/ui/parser/defaultness-invalid-places-fail-semantic.stderr @@ -70,15 +70,5 @@ LL | default fn h() {} | | | `default` because of this -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/defaultness-invalid-places-fail-semantic.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 9 previous errors; 1 warning emitted +error: aborting due to 9 previous errors diff --git a/tests/ui/parser/emoji-identifiers.rs b/tests/ui/parser/emoji-identifiers.rs index b50c046bcb20..cbd2e54c5522 100644 --- a/tests/ui/parser/emoji-identifiers.rs +++ b/tests/ui/parser/emoji-identifiers.rs @@ -6,7 +6,7 @@ fn full_of_✨() -> 👀 { //~ ERROR identifiers cannot contain emoji } } fn i_like_to_😅_a_lot() -> 👀 { //~ ERROR identifiers cannot contain emoji - 👀::full_of✨() //~ ERROR no function or associated item named `full_of✨` found for struct `👀` + 👀::full_of✨() //~ ERROR no associated function or constant named `full_of✨` found for struct `👀` //~^ ERROR identifiers cannot contain emoji } fn main() { diff --git a/tests/ui/parser/emoji-identifiers.stderr b/tests/ui/parser/emoji-identifiers.stderr index 016ed0401caf..a6532f9c51b0 100644 --- a/tests/ui/parser/emoji-identifiers.stderr +++ b/tests/ui/parser/emoji-identifiers.stderr @@ -65,14 +65,14 @@ LL | let 🦀 = 1; LL | dbg!(🦀); | ^^ -error[E0599]: no function or associated item named `full_of✨` found for struct `👀` in the current scope +error[E0599]: no associated function or constant named `full_of✨` found for struct `👀` in the current scope --> $DIR/emoji-identifiers.rs:9:8 | LL | struct 👀; - | --------- function or associated item `full_of✨` not found for this struct + | --------- associated function or constant `full_of✨` not found for this struct ... LL | 👀::full_of✨() - | ^^^^^^^^^ function or associated item not found in `👀` + | ^^^^^^^^^ associated function or constant not found in `👀` | note: if you're trying to build a new `👀`, consider using `👀::full_of_✨` which returns `👀` --> $DIR/emoji-identifiers.rs:4:5 diff --git a/tests/ui/parser/macro/unicode-control-codepoints-macros.stderr b/tests/ui/parser/macro/unicode-control-codepoints-macros.stderr index 22fb1b945c65..b1d9c9d01874 100644 --- a/tests/ui/parser/macro/unicode-control-codepoints-macros.stderr +++ b/tests/ui/parser/macro/unicode-control-codepoints-macros.stderr @@ -6,7 +6,7 @@ LL | /// �test� RTL in doc in vec | = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen = note: if their presence wasn't intentional, you can remove them - = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}', '\u{2066}' + = note: if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as '\u{202e}', '\u{2066}' = note: `#[deny(text_direction_codepoint_in_literal)]` on by default error: unicode codepoint changing visible direction of text present in doc comment @@ -19,7 +19,7 @@ LL | | */ | = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen = note: if their presence wasn't intentional, you can remove them - = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}', '\u{2066}' + = note: if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as '\u{202e}', '\u{2066}' error: unicode codepoint changing visible direction of text present in doc comment --> $DIR/unicode-control-codepoints-macros.rs:33:9 @@ -31,7 +31,7 @@ LL | | */ | = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen = note: if their presence wasn't intentional, you can remove them - = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}', '\u{2066}' + = note: if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as '\u{202e}', '\u{2066}' error: unicode codepoint changing visible direction of text present in doc comment --> $DIR/unicode-control-codepoints-macros.rs:41:9 @@ -41,7 +41,7 @@ LL | /// �test� RTL in doc in proc macro | = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen = note: if their presence wasn't intentional, you can remove them - = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}', '\u{2066}' + = note: if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as '\u{202e}', '\u{2066}' error: unicode codepoint changing visible direction of text present in doc comment --> $DIR/unicode-control-codepoints-macros.rs:46:9 @@ -51,7 +51,7 @@ LL | /// �test� RTL in doc in proc macro | = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen = note: if their presence wasn't intentional, you can remove them - = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}', '\u{2066}' + = note: if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as '\u{202e}', '\u{2066}' error: aborting due to 5 previous errors diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 83c88d1085ef..6f91967b8b82 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -24,7 +24,9 @@ error[E0308]: mismatched types --> $DIR/pat-lt-bracket-6.rs:10:30 | LL | const RECOVERY_WITNESS: () = 0; - | ^ expected `()`, found integer + | -- ^ expected `()`, found integer + | | + | expected because of the type of the constant error: aborting due to 3 previous errors diff --git a/tests/ui/parser/pat-lt-bracket-7.stderr b/tests/ui/parser/pat-lt-bracket-7.stderr index cc457a4e64e2..5cdb94cb8176 100644 --- a/tests/ui/parser/pat-lt-bracket-7.stderr +++ b/tests/ui/parser/pat-lt-bracket-7.stderr @@ -11,7 +11,9 @@ error[E0308]: mismatched types --> $DIR/pat-lt-bracket-7.rs:9:30 | LL | const RECOVERY_WITNESS: () = 0; - | ^ expected `()`, found integer + | -- ^ expected `()`, found integer + | | + | expected because of the type of the constant error: aborting due to 2 previous errors diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr index 45f39fefe5e3..56c78b01ea39 100644 --- a/tests/ui/parser/recover/array-type-no-semi.stderr +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -17,7 +17,12 @@ LL | let a: [i32, ]; | - ^ expected `;` or `]` | | | while parsing the type for `a` - | help: use `=` if you meant to assign + | +help: use `=` if you meant to assign + | +LL - let a: [i32, ]; +LL + let a = [i32, ]; + | error: expected `;` or `]`, found `,` --> $DIR/array-type-no-semi.rs:12:16 diff --git a/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr b/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr index 15c27bb9451b..94e5d44064f8 100644 --- a/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr +++ b/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr @@ -13,7 +13,12 @@ LL | let _: std::env::temp_dir().join("foo"); | - ^ expected one of `!`, `+`, `->`, `::`, `;`, or `=` | | | while parsing the type for `_` - | help: use `=` if you meant to assign + | +help: use `=` if you meant to assign + | +LL - let _: std::env::temp_dir().join("foo"); +LL + let _ = std::env::temp_dir().join("foo"); + | error: aborting due to 2 previous errors diff --git a/tests/ui/structs-enums/recover-enum-with-bad-where.rs b/tests/ui/parser/recover/recover-enum-with-bad-where.rs similarity index 100% rename from tests/ui/structs-enums/recover-enum-with-bad-where.rs rename to tests/ui/parser/recover/recover-enum-with-bad-where.rs diff --git a/tests/ui/structs-enums/recover-enum-with-bad-where.stderr b/tests/ui/parser/recover/recover-enum-with-bad-where.stderr similarity index 100% rename from tests/ui/structs-enums/recover-enum-with-bad-where.stderr rename to tests/ui/parser/recover/recover-enum-with-bad-where.stderr diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr b/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr index 2bc7952def79..8b784d02a01d 100644 --- a/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr +++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr @@ -14,7 +14,9 @@ error[E0308]: mismatched types --> $DIR/recover-for-loop-parens-around-head.rs:13:40 | LL | const _RECOVERY_WITNESS: u32 = 0u8; - | ^^^ expected `u32`, found `u8` + | --- ^^^ expected `u32`, found `u8` + | | + | expected because of the type of the constant | help: change the type of the numeric literal from `u8` to `u32` | diff --git a/tests/ui/obsolete-in-place/bad.rs b/tests/ui/parser/removed-syntax/removed-syntax-obsolete-in-place.rs similarity index 100% rename from tests/ui/obsolete-in-place/bad.rs rename to tests/ui/parser/removed-syntax/removed-syntax-obsolete-in-place.rs diff --git a/tests/ui/obsolete-in-place/bad.stderr b/tests/ui/parser/removed-syntax/removed-syntax-obsolete-in-place.stderr similarity index 77% rename from tests/ui/obsolete-in-place/bad.stderr rename to tests/ui/parser/removed-syntax/removed-syntax-obsolete-in-place.stderr index a1321a46351a..7cdc85be349a 100644 --- a/tests/ui/obsolete-in-place/bad.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-obsolete-in-place.stderr @@ -1,5 +1,5 @@ error: unexpected token: `<-` - --> $DIR/bad.rs:5:7 + --> $DIR/removed-syntax-obsolete-in-place.rs:5:7 | LL | x <- y; | ^^ @@ -10,7 +10,7 @@ LL | x < - y; | + error: expected expression, found keyword `in` - --> $DIR/bad.rs:10:5 + --> $DIR/removed-syntax-obsolete-in-place.rs:10:5 | LL | in(foo) { bar }; | ^^ expected expression diff --git a/tests/ui/parser/shebang/multiline-attrib.rs b/tests/ui/parser/shebang/multiline-attrib.rs index 2d2e02986386..d67ba5facd9f 100644 --- a/tests/ui/parser/shebang/multiline-attrib.rs +++ b/tests/ui/parser/shebang/multiline-attrib.rs @@ -1,7 +1,7 @@ #! [allow(unused_variables)] //@ check-pass -//@ reference: input.shebang.inner-attribute +//@ reference: shebang.syntax-description fn main() { let x = 5; diff --git a/tests/ui/parser/shebang/regular-attrib.rs b/tests/ui/parser/shebang/regular-attrib.rs index c2ac25661ef0..f711b81c72fe 100644 --- a/tests/ui/parser/shebang/regular-attrib.rs +++ b/tests/ui/parser/shebang/regular-attrib.rs @@ -1,6 +1,6 @@ #![allow(unused_variables)] //@ check-pass -//@ reference: input.shebang.inner-attribute +//@ reference: shebang.syntax-description fn main() { let x = 5; } diff --git a/tests/ui/parser/shebang/shebang-and-attrib.rs b/tests/ui/parser/shebang/shebang-and-attrib.rs index d73db6b22f05..e3e52b5c7504 100644 --- a/tests/ui/parser/shebang/shebang-and-attrib.rs +++ b/tests/ui/parser/shebang/shebang-and-attrib.rs @@ -1,7 +1,7 @@ #!/usr/bin/env run-cargo-script //@ check-pass -//@ reference: input.shebang.inner-attribute +//@ reference: shebang.syntax-description #![allow(unused_variables)] diff --git a/tests/ui/parser/shebang/shebang-doc-comment.rs b/tests/ui/parser/shebang/shebang-doc-comment.rs index 4992c758325a..976a2b390712 100644 --- a/tests/ui/parser/shebang/shebang-doc-comment.rs +++ b/tests/ui/parser/shebang/shebang-doc-comment.rs @@ -2,4 +2,4 @@ [allow(unused_variables)] //~^ ERROR expected item, found `[` -//@ reference: input.shebang.inner-attribute +//@ reference: shebang.syntax-description diff --git a/tests/ui/parser/shebang/sneaky-attrib.rs b/tests/ui/parser/shebang/sneaky-attrib.rs index e22c45cc39f5..b9c4adbe2bb2 100644 --- a/tests/ui/parser/shebang/sneaky-attrib.rs +++ b/tests/ui/parser/shebang/sneaky-attrib.rs @@ -11,7 +11,7 @@ [allow(unused_variables)] //@ check-pass -//@ reference: input.shebang.inner-attribute +//@ reference: shebang.syntax-description fn main() { let x = 5; } diff --git a/tests/ui/parser/unicode-control-codepoints.stderr b/tests/ui/parser/unicode-control-codepoints.stderr index 7978c1435f60..3b273f8212fa 100644 --- a/tests/ui/parser/unicode-control-codepoints.stderr +++ b/tests/ui/parser/unicode-control-codepoints.stderr @@ -232,7 +232,7 @@ LL | /** '�'); */fn foo() {} | = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen = note: if their presence wasn't intentional, you can remove them - = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}' + = note: if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as '\u{202e}' error: unicode codepoint changing visible direction of text present in doc comment --> $DIR/unicode-control-codepoints.rs:46:1 @@ -244,7 +244,7 @@ LL | | * '�'); */fn bar() {} | = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen = note: if their presence wasn't intentional, you can remove them - = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}' + = note: if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as '\u{202e}' error: aborting due to 20 previous errors diff --git a/tests/ui/parser/unicode-control-doc-comment-issue-153096.rs b/tests/ui/parser/unicode-control-doc-comment-issue-153096.rs new file mode 100644 index 000000000000..a7998daa72fd --- /dev/null +++ b/tests/ui/parser/unicode-control-doc-comment-issue-153096.rs @@ -0,0 +1,8 @@ +//@ edition: 2024 + +#[allow(unused)] +/// ⁨א⁩, ⁨ב⁩, ⁨ג⁩, ⁨ד⁩, ⁨ה⁩ +//~^ ERROR unicode codepoint changing visible direction of text present in doc comment +fn foo() {} + +fn main() {} diff --git a/tests/ui/parser/unicode-control-doc-comment-issue-153096.stderr b/tests/ui/parser/unicode-control-doc-comment-issue-153096.stderr new file mode 100644 index 000000000000..668a7844da63 --- /dev/null +++ b/tests/ui/parser/unicode-control-doc-comment-issue-153096.stderr @@ -0,0 +1,13 @@ +error: unicode codepoint changing visible direction of text present in doc comment + --> $DIR/unicode-control-doc-comment-issue-153096.rs:4:1 + | +LL | /// �א�, �ב�, �ג�, �ד�, �ה� + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this doc comment contains invisible unicode text flow control codepoints + | + = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + = note: if their presence wasn't intentional, you can remove them + = note: if you need to keep them and make them explicit in source, rewrite this doc comment as a `#[doc = "..."]` attribute and use Unicode escapes such as '\u{2068}', '\u{2069}', '\u{2068}', '\u{2069}', '\u{2068}', '\u{2069}', '\u{2068}', '\u{2069}', '\u{2068}', '\u{2069}' + = note: `#[deny(text_direction_codepoint_in_literal)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/pattern/by-move-pattern-binding.stderr b/tests/ui/pattern/by-move-pattern-binding.stderr index 203e37dc387c..4a65bf3ea27f 100644 --- a/tests/ui/pattern/by-move-pattern-binding.stderr +++ b/tests/ui/pattern/by-move-pattern-binding.stderr @@ -5,10 +5,7 @@ LL | match &s.x { | ^^^^ LL | &E::Foo => {} LL | &E::Bar(identifier) => f(identifier.clone()) - | ---------- - | | - | data moved here - | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait + | ---------- data moved here because `identifier` has type `String`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -22,8 +19,7 @@ error[E0507]: cannot move out of a shared reference LL | if let &E::Bar(identifier) = &s.x { | ---------- ^^^^ | | - | data moved here - | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait + | data moved here because `identifier` has type `String`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -37,8 +33,7 @@ error[E0507]: cannot move out of a shared reference LL | let &E::Bar(identifier) = &s.x else { | ---------- ^^^^ | | - | data moved here - | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait + | data moved here because `identifier` has type `String`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/pattern/deref-patterns/basic.rs b/tests/ui/pattern/deref-patterns/basic.rs index dee4521e1f95..0cb80b43944d 100644 --- a/tests/ui/pattern/deref-patterns/basic.rs +++ b/tests/ui/pattern/deref-patterns/basic.rs @@ -1,7 +1,6 @@ //@ run-pass //@ check-run-results #![feature(deref_patterns)] -#![expect(incomplete_features)] fn main() { test(Some(String::from("42"))); diff --git a/tests/ui/pattern/deref-patterns/bindings.rs b/tests/ui/pattern/deref-patterns/bindings.rs index 92c01d737bac..c3165ebf6cef 100644 --- a/tests/ui/pattern/deref-patterns/bindings.rs +++ b/tests/ui/pattern/deref-patterns/bindings.rs @@ -1,7 +1,6 @@ //@ revisions: explicit implicit //@ run-pass #![feature(deref_patterns)] -#![allow(incomplete_features)] use std::rc::Rc; diff --git a/tests/ui/pattern/deref-patterns/branch.rs b/tests/ui/pattern/deref-patterns/branch.rs index 9d72b35fd2f1..5b87742eb319 100644 --- a/tests/ui/pattern/deref-patterns/branch.rs +++ b/tests/ui/pattern/deref-patterns/branch.rs @@ -2,7 +2,6 @@ //@ run-pass // Test the execution of deref patterns. #![feature(deref_patterns)] -#![allow(incomplete_features)] #[cfg(explicit)] fn branch(vec: Vec) -> u32 { diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs index fdcc6cb46111..633044a59772 100644 --- a/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs @@ -5,7 +5,6 @@ //@ dont-require-annotations: NOTE #![feature(deref_patterns)] -#![expect(incomplete_features)] fn main() { // Baseline 1: under normal circumstances, byte string literal patterns have type `&[u8; N]`, diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr index 046682004be7..531d5ba292c4 100644 --- a/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:13:12 + --> $DIR/byte-string-type-errors.rs:12:12 | LL | if let b"test" = () {} | ^^^^^^^ -- this expression has type `()` @@ -7,7 +7,7 @@ LL | if let b"test" = () {} | expected `()`, found `&[u8; 4]` error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:20:12 + --> $DIR/byte-string-type-errors.rs:19:12 | LL | if let b"test" = &[] as &[i8] {} | ^^^^^^^ ------------ this expression has type `&[i8]` @@ -18,7 +18,7 @@ LL | if let b"test" = &[] as &[i8] {} found reference `&'static [u8]` error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:25:12 + --> $DIR/byte-string-type-errors.rs:24:12 | LL | if let b"test" = *(&[] as &[i8]) {} | ^^^^^^^ --------------- this expression has type `[i8]` @@ -29,7 +29,7 @@ LL | if let b"test" = *(&[] as &[i8]) {} found slice `[u8]` error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:30:12 + --> $DIR/byte-string-type-errors.rs:29:12 | LL | if let b"test" = [()] {} | ^^^^^^^ ---- this expression has type `[(); 1]` @@ -40,7 +40,7 @@ LL | if let b"test" = [()] {} found array `[u8; 4]` error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:33:12 + --> $DIR/byte-string-type-errors.rs:32:12 | LL | if let b"test" = *b"this array is too long" {} | ^^^^^^^ -------------------------- this expression has type `[u8; 22]` @@ -48,7 +48,7 @@ LL | if let b"test" = *b"this array is too long" {} | expected an array with a size of 22, found one with a size of 4 error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:39:12 + --> $DIR/byte-string-type-errors.rs:38:12 | LL | if let b"test" = &mut () {} | ^^^^^^^ ------- this expression has type `&mut ()` @@ -56,7 +56,7 @@ LL | if let b"test" = &mut () {} | expected `()`, found `&[u8; 4]` error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:44:12 + --> $DIR/byte-string-type-errors.rs:43:12 | LL | if let b"test" = &mut [] as &mut [i8] {} | ^^^^^^^ -------------------- this expression has type `&mut [i8]` @@ -67,7 +67,7 @@ LL | if let b"test" = &mut [] as &mut [i8] {} found slice `[u8]` error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:48:12 + --> $DIR/byte-string-type-errors.rs:47:12 | LL | if let b"test" = &mut [()] {} | ^^^^^^^ --------- this expression has type `&mut [(); 1]` @@ -78,7 +78,7 @@ LL | if let b"test" = &mut [()] {} found array `[u8; 4]` error[E0308]: mismatched types - --> $DIR/byte-string-type-errors.rs:52:12 + --> $DIR/byte-string-type-errors.rs:51:12 | LL | if let b"test" = &mut *b"this array is too long" {} | ^^^^^^^ ------------------------------- this expression has type `&mut [u8; 22]` diff --git a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs index 2b4746e33e67..36d9ae70efdd 100644 --- a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs +++ b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs @@ -1,5 +1,4 @@ #![feature(deref_patterns)] -#![allow(incomplete_features)] use std::rc::Rc; diff --git a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr index a548ac5909a8..119b86d52885 100644 --- a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr +++ b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr @@ -1,14 +1,11 @@ error[E0508]: cannot move out of type `[Struct]`, a non-copy slice - --> $DIR/cant_move_out_of_pattern.rs:9:11 + --> $DIR/cant_move_out_of_pattern.rs:8:11 | LL | match b { | ^ cannot move out of here LL | LL | deref!([x]) => x, - | - - | | - | data moved here - | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait + | - data moved here because `x` has type `Struct`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -16,16 +13,13 @@ LL | deref!([ref x]) => x, | +++ error[E0507]: cannot move out of a shared reference - --> $DIR/cant_move_out_of_pattern.rs:17:11 + --> $DIR/cant_move_out_of_pattern.rs:16:11 | LL | match rc { | ^^ LL | LL | deref!(x) => x, - | - - | | - | data moved here - | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait + | - data moved here because `x` has type `Struct`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -33,16 +27,13 @@ LL | deref!(ref x) => x, | +++ error[E0508]: cannot move out of type `[Struct]`, a non-copy slice - --> $DIR/cant_move_out_of_pattern.rs:25:11 + --> $DIR/cant_move_out_of_pattern.rs:24:11 | LL | match b { | ^ cannot move out of here LL | LL | [x] => x, - | - - | | - | data moved here - | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait + | - data moved here because `x` has type `Struct`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -50,16 +41,13 @@ LL | [ref x] => x, | +++ error[E0507]: cannot move out of a shared reference - --> $DIR/cant_move_out_of_pattern.rs:35:11 + --> $DIR/cant_move_out_of_pattern.rs:34:11 | LL | match rc { | ^^ LL | LL | Container(x) => x, - | - - | | - | data moved here - | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait + | - data moved here because `x` has type `Struct`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/pattern/deref-patterns/closure_capture.rs b/tests/ui/pattern/deref-patterns/closure_capture.rs index 497ec622b0cf..c02c82e9ea0c 100644 --- a/tests/ui/pattern/deref-patterns/closure_capture.rs +++ b/tests/ui/pattern/deref-patterns/closure_capture.rs @@ -1,6 +1,5 @@ //@ run-pass #![feature(deref_patterns)] -#![allow(incomplete_features)] use std::rc::Rc; diff --git a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs index 3a2531f4b95e..08dec4885846 100644 --- a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs +++ b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs @@ -8,7 +8,6 @@ //! we'd get without `deref_patterns` enabled. #![cfg_attr(deref_patterns, feature(deref_patterns))] -#![cfg_attr(deref_patterns, expect(incomplete_features))] fn uninferred() -> T { unimplemented!() } diff --git a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr index 61079718c5d5..74f558af4e95 100644 --- a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr +++ b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/const-pats-do-not-mislead-inference.rs:33:12 + --> $DIR/const-pats-do-not-mislead-inference.rs:32:12 | LL | if let b"..." = &&x {} | ^^^^^^ --- this expression has type `&&_` @@ -10,7 +10,7 @@ LL | if let b"..." = &&x {} found reference `&'static [u8; 3]` error[E0308]: mismatched types - --> $DIR/const-pats-do-not-mislead-inference.rs:39:12 + --> $DIR/const-pats-do-not-mislead-inference.rs:38:12 | LL | if let "..." = &Box::new(x) {} | ^^^^^ ------------ this expression has type `&Box<_>` @@ -19,13 +19,13 @@ LL | if let "..." = &Box::new(x) {} | = note: expected reference `&Box<_>` found reference `&'static str` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | if let "..." = &*Box::new(x) {} | + error[E0308]: mismatched types - --> $DIR/const-pats-do-not-mislead-inference.rs:45:12 + --> $DIR/const-pats-do-not-mislead-inference.rs:44:12 | LL | if let b"..." = Box::new(&x) {} | ^^^^^^ ------------ this expression has type `Box<&_>` @@ -34,13 +34,13 @@ LL | if let b"..." = Box::new(&x) {} | = note: expected struct `Box<&_>` found reference `&'static [u8; 3]` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | if let b"..." = *Box::new(&x) {} | + error[E0308]: mismatched types - --> $DIR/const-pats-do-not-mislead-inference.rs:51:12 + --> $DIR/const-pats-do-not-mislead-inference.rs:50:12 | LL | if let "..." = &mut x {} | ^^^^^ ------ this expression has type `&mut _` diff --git a/tests/ui/pattern/deref-patterns/default-infer.rs b/tests/ui/pattern/deref-patterns/default-infer.rs index fb0b2add132a..38c8793a9b44 100644 --- a/tests/ui/pattern/deref-patterns/default-infer.rs +++ b/tests/ui/pattern/deref-patterns/default-infer.rs @@ -1,6 +1,5 @@ //@ check-pass #![feature(deref_patterns)] -#![expect(incomplete_features)] fn main() { match <_ as Default>::default() { diff --git a/tests/ui/pattern/deref-patterns/deref-box.rs b/tests/ui/pattern/deref-patterns/deref-box.rs index 39b23dcab51e..1af13f82f3f9 100644 --- a/tests/ui/pattern/deref-patterns/deref-box.rs +++ b/tests/ui/pattern/deref-patterns/deref-box.rs @@ -3,7 +3,6 @@ //! and `DerefMut::deref_mut`. Test that they work as expected. #![feature(deref_patterns)] -#![expect(incomplete_features)] fn unbox_1(b: Box) -> T { let deref!(x) = b; diff --git a/tests/ui/pattern/deref-patterns/dont-ice-on-slice-in-deref-pat-in-closure.rs b/tests/ui/pattern/deref-patterns/dont-ice-on-slice-in-deref-pat-in-closure.rs index e1a37b9c65f4..e656ef9a4380 100644 --- a/tests/ui/pattern/deref-patterns/dont-ice-on-slice-in-deref-pat-in-closure.rs +++ b/tests/ui/pattern/deref-patterns/dont-ice-on-slice-in-deref-pat-in-closure.rs @@ -3,7 +3,6 @@ //! inside a deref pattern inside a closure: rust-lang/rust#125059 #![feature(deref_patterns)] -#![allow(incomplete_features, unused)] fn simple_vec(vec: Vec) -> u32 { (|| match Vec::::new() { diff --git a/tests/ui/pattern/deref-patterns/fake_borrows.rs b/tests/ui/pattern/deref-patterns/fake_borrows.rs index fba2873fd02a..74292fe25d8c 100644 --- a/tests/ui/pattern/deref-patterns/fake_borrows.rs +++ b/tests/ui/pattern/deref-patterns/fake_borrows.rs @@ -1,5 +1,4 @@ #![feature(deref_patterns)] -#![allow(incomplete_features)] #[rustfmt::skip] fn main() { diff --git a/tests/ui/pattern/deref-patterns/fake_borrows.stderr b/tests/ui/pattern/deref-patterns/fake_borrows.stderr index 7dc3001739e6..312de4760a45 100644 --- a/tests/ui/pattern/deref-patterns/fake_borrows.stderr +++ b/tests/ui/pattern/deref-patterns/fake_borrows.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable - --> $DIR/fake_borrows.rs:9:16 + --> $DIR/fake_borrows.rs:8:16 | LL | match v { | - immutable borrow occurs here @@ -10,7 +10,7 @@ LL | _ if { v[0] = true; false } => {} | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable - --> $DIR/fake_borrows.rs:16:16 + --> $DIR/fake_borrows.rs:15:16 | LL | match v { | - immutable borrow occurs here @@ -21,7 +21,7 @@ LL | _ if { v[0] = true; false } => {} | mutable borrow occurs here error[E0510]: cannot assign `*b` in match guard - --> $DIR/fake_borrows.rs:26:16 + --> $DIR/fake_borrows.rs:25:16 | LL | match b { | - value is immutable in match guard @@ -30,7 +30,7 @@ LL | _ if { *b = true; false } => {} | ^^^^^^^^^ cannot assign error[E0510]: cannot assign `*b` in match guard - --> $DIR/fake_borrows.rs:33:16 + --> $DIR/fake_borrows.rs:32:16 | LL | match b { | - value is immutable in match guard diff --git a/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs index fbc742aa8477..b775cb3ac756 100644 --- a/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs +++ b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs @@ -1,5 +1,4 @@ #![feature(deref_patterns)] -#![expect(incomplete_features)] fn main() { let vec![const { vec![] }]: Vec = vec![]; diff --git a/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr index 48728acbc291..d18ca2589bbc 100644 --- a/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr +++ b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr @@ -1,5 +1,5 @@ error[E0532]: expected a pattern, found a function call - --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9 + --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:4:9 | LL | let vec![const { vec![] }]: Vec = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant @@ -7,7 +7,7 @@ LL | let vec![const { vec![] }]: Vec = vec![]; = note: function calls are not allowed in patterns: error[E0532]: expected a pattern, found a function call - --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9 + --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:4:9 | LL | let vec![const { vec![] }]: Vec = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant @@ -15,7 +15,7 @@ LL | let vec![const { vec![] }]: Vec = vec![]; = note: function calls are not allowed in patterns: error: arbitrary expressions aren't allowed in patterns - --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:14 + --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:4:14 | LL | let vec![const { vec![] }]: Vec = vec![]; | ^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | let vec![const { vec![] }]: Vec = vec![]; = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead error[E0164]: expected tuple struct or tuple variant, found associated function `::alloc::boxed::Box::new_uninit` - --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9 + --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:4:9 | LL | let vec![const { vec![] }]: Vec = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns diff --git a/tests/ui/pattern/deref-patterns/implicit-const-deref.rs b/tests/ui/pattern/deref-patterns/implicit-const-deref.rs index 70f89629bc22..4aa5695c7399 100644 --- a/tests/ui/pattern/deref-patterns/implicit-const-deref.rs +++ b/tests/ui/pattern/deref-patterns/implicit-const-deref.rs @@ -4,7 +4,6 @@ //! scrutinee and end up with a type error; this would prevent us from reporting that only constants //! supporting structural equality can be used as patterns. #![feature(deref_patterns)] -#![allow(incomplete_features)] const EMPTY: Vec<()> = Vec::new(); diff --git a/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr b/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr index 6d4301846287..7c176162ad18 100644 --- a/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr +++ b/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr @@ -1,5 +1,5 @@ error: constant of non-structural type `Vec<()>` in a pattern - --> $DIR/implicit-const-deref.rs:15:9 + --> $DIR/implicit-const-deref.rs:14:9 | LL | const EMPTY: Vec<()> = Vec::new(); | -------------------- constant defined here @@ -9,9 +9,14 @@ LL | EMPTY => {} | --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | - = note: `Vec<()>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns + = note: `Vec<()>` is not usable in patterns | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: add a condition to the match arm checking for equality + | +LL - EMPTY => {} +LL + binding if binding == EMPTY => {} + | error: aborting due to 1 previous error diff --git a/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs index 24770261edc5..107ae12f3b74 100644 --- a/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs +++ b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs @@ -1,7 +1,6 @@ //@ run-pass //! Test that implicit deref patterns interact as expected with `Cow` constructor patterns. #![feature(deref_patterns)] -#![allow(incomplete_features)] use std::borrow::Cow; use std::rc::Rc; diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr index 3d938a7e23fc..edc70048ecf2 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.stderr +++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr @@ -18,7 +18,7 @@ LL | 0 => {} | = note: expected struct `Box<{integer}>` found type `{integer}` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *Box::new(0) { | + diff --git a/tests/ui/pattern/deref-patterns/recursion-limit.rs b/tests/ui/pattern/deref-patterns/recursion-limit.rs index c5fe520f6f1a..75c64cb1f539 100644 --- a/tests/ui/pattern/deref-patterns/recursion-limit.rs +++ b/tests/ui/pattern/deref-patterns/recursion-limit.rs @@ -1,6 +1,5 @@ //! Test that implicit deref patterns respect the recursion limit #![feature(deref_patterns)] -#![allow(incomplete_features)] #![recursion_limit = "8"] use std::ops::Deref; diff --git a/tests/ui/pattern/deref-patterns/recursion-limit.stderr b/tests/ui/pattern/deref-patterns/recursion-limit.stderr index 7c140e4493e7..e7f6a272432e 100644 --- a/tests/ui/pattern/deref-patterns/recursion-limit.stderr +++ b/tests/ui/pattern/deref-patterns/recursion-limit.stderr @@ -1,5 +1,5 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Cyclic` - --> $DIR/recursion-limit.rs:18:9 + --> $DIR/recursion-limit.rs:17:9 | LL | () => {} | ^^ deref recursion limit reached @@ -7,13 +7,13 @@ LL | () => {} = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`recursion_limit`) error[E0277]: the trait bound `Cyclic: DerefPure` is not satisfied - --> $DIR/recursion-limit.rs:18:9 + --> $DIR/recursion-limit.rs:17:9 | LL | () => {} | ^^ unsatisfied trait bound | help: the nightly-only, unstable trait `DerefPure` is not implemented for `Cyclic` - --> $DIR/recursion-limit.rs:8:1 + --> $DIR/recursion-limit.rs:7:1 | LL | struct Cyclic; | ^^^^^^^^^^^^^ diff --git a/tests/ui/pattern/deref-patterns/ref-mut.rs b/tests/ui/pattern/deref-patterns/ref-mut.rs index 43738671346d..7751a13565e8 100644 --- a/tests/ui/pattern/deref-patterns/ref-mut.rs +++ b/tests/ui/pattern/deref-patterns/ref-mut.rs @@ -1,5 +1,4 @@ #![feature(deref_patterns)] -//~^ WARN the feature `deref_patterns` is incomplete use std::rc::Rc; diff --git a/tests/ui/pattern/deref-patterns/ref-mut.stderr b/tests/ui/pattern/deref-patterns/ref-mut.stderr index 24a35b418e95..1359410de827 100644 --- a/tests/ui/pattern/deref-patterns/ref-mut.stderr +++ b/tests/ui/pattern/deref-patterns/ref-mut.stderr @@ -1,14 +1,5 @@ -warning: the feature `deref_patterns` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/ref-mut.rs:1:12 - | -LL | #![feature(deref_patterns)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #87121 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied - --> $DIR/ref-mut.rs:17:9 + --> $DIR/ref-mut.rs:16:9 | LL | deref!(x) => {} | ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>` @@ -16,11 +7,11 @@ LL | deref!(x) => {} = note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Rc<({integer},)>: DerefMut` is not satisfied - --> $DIR/ref-mut.rs:22:9 + --> $DIR/ref-mut.rs:21:9 | LL | (x,) => {} | ^^^^ the trait `DerefMut` is not implemented for `Rc<({integer},)>` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/pattern/deref-patterns/refs.rs b/tests/ui/pattern/deref-patterns/refs.rs index 51826225856b..13566510e7a5 100644 --- a/tests/ui/pattern/deref-patterns/refs.rs +++ b/tests/ui/pattern/deref-patterns/refs.rs @@ -1,6 +1,5 @@ //@ check-pass #![feature(deref_patterns)] -#![expect(incomplete_features)] fn foo(s: &String) -> i32 { match *s { diff --git a/tests/ui/pattern/deref-patterns/strings.rs b/tests/ui/pattern/deref-patterns/strings.rs index fac15a9aee3d..5b6cfb9425d6 100644 --- a/tests/ui/pattern/deref-patterns/strings.rs +++ b/tests/ui/pattern/deref-patterns/strings.rs @@ -2,7 +2,6 @@ //! Test deref patterns using string and bytestring literals. #![feature(deref_patterns)] -#![allow(incomplete_features)] fn main() { for (test_in, test_expect) in [("zero", 0), ("one", 1), ("two", 2)] { diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs index 3a7ce9d1deb3..a1a055d5f0e7 100644 --- a/tests/ui/pattern/deref-patterns/typeck.rs +++ b/tests/ui/pattern/deref-patterns/typeck.rs @@ -1,6 +1,5 @@ //@ check-pass #![feature(deref_patterns)] -#![allow(incomplete_features)] use std::rc::Rc; diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.rs b/tests/ui/pattern/deref-patterns/typeck_fail.rs index 6ae87bb7bc36..14ddb670e57f 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.rs +++ b/tests/ui/pattern/deref-patterns/typeck_fail.rs @@ -1,5 +1,4 @@ #![feature(deref_patterns)] -#![allow(incomplete_features)] fn main() { // Make sure we don't try implicitly dereferncing any ADT. diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.stderr b/tests/ui/pattern/deref-patterns/typeck_fail.stderr index fc29caac5630..6e81e9f6a064 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.stderr +++ b/tests/ui/pattern/deref-patterns/typeck_fail.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:7:9 + --> $DIR/typeck_fail.rs:6:9 | LL | match Some(0) { | ------- this expression has type `Option<{integer}>` diff --git a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs index 9e95f4ec4096..db76e6fb7f94 100644 --- a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs +++ b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs @@ -1,5 +1,4 @@ #![feature(deref_patterns)] -#![allow(incomplete_features)] struct MyPointer; diff --git a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr index 3ee6efefe697..3b680b4238a0 100644 --- a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr +++ b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `MyPointer: DerefPure` is not satisfied - --> $DIR/unsatisfied-bounds.rs:17:9 + --> $DIR/unsatisfied-bounds.rs:16:9 | LL | () => {} | ^^ unsatisfied trait bound | help: the nightly-only, unstable trait `DerefPure` is not implemented for `MyPointer` - --> $DIR/unsatisfied-bounds.rs:4:1 + --> $DIR/unsatisfied-bounds.rs:3:1 | LL | struct MyPointer; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs b/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs index 03419030e72f..17de65380169 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs +++ b/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs @@ -4,7 +4,6 @@ // FIXME(deref_patterns): On stabilization, cases for deref patterns could be worked into that file // to keep the tests for empty types in one place and test more thoroughly. #![feature(deref_patterns)] -#![expect(incomplete_features)] #![deny(unreachable_patterns)] enum Void {} diff --git a/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr b/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr index e32477085661..4eb49b54b83b 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr +++ b/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `deref!(Some(_))` not covered - --> $DIR/empty-types.rs:21:11 + --> $DIR/empty-types.rs:20:11 | LL | match box_opt_void { | ^^^^^^^^^^^^ pattern `deref!(Some(_))` not covered @@ -15,7 +15,7 @@ LL + deref!(Some(_)) => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:35:11 + --> $DIR/empty-types.rs:34:11 | LL | match *box_opt_void { | ^^^^^^^^^^^^^ pattern `Some(_)` not covered diff --git a/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs index f567dc07bb59..8858f628217c 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs +++ b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs @@ -2,7 +2,6 @@ //! doesn't support this, so make sure we catch it beforehand. As a consequence, it takes priority //! over non-exhaustive match and unreachable pattern errors. #![feature(deref_patterns)] -#![expect(incomplete_features)] #![deny(unreachable_patterns)] use std::borrow::Cow; diff --git a/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr index 5ad24164b985..3d036afc9e90 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr +++ b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr @@ -1,5 +1,5 @@ error: mix of deref patterns and normal constructors - --> $DIR/mixed-constructors.rs:16:9 + --> $DIR/mixed-constructors.rs:15:9 | LL | false => {} | ^^^^^ matches on the result of dereferencing `Cow<'_, bool>` @@ -7,7 +7,7 @@ LL | Cow::Borrowed(_) => {} | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` error: mix of deref patterns and normal constructors - --> $DIR/mixed-constructors.rs:22:9 + --> $DIR/mixed-constructors.rs:21:9 | LL | Cow::Borrowed(_) => {} | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` @@ -15,7 +15,7 @@ LL | true => {} | ^^^^ matches on the result of dereferencing `Cow<'_, bool>` error: mix of deref patterns and normal constructors - --> $DIR/mixed-constructors.rs:29:9 + --> $DIR/mixed-constructors.rs:28:9 | LL | Cow::Owned(_) => {} | ^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` @@ -23,7 +23,7 @@ LL | false => {} | ^^^^^ matches on the result of dereferencing `Cow<'_, bool>` error: mix of deref patterns and normal constructors - --> $DIR/mixed-constructors.rs:36:10 + --> $DIR/mixed-constructors.rs:35:10 | LL | (Cow::Borrowed(_), 0) => {} | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` @@ -31,7 +31,7 @@ LL | (true, 0) => {} | ^^^^ matches on the result of dereferencing `Cow<'_, bool>` error: mix of deref patterns and normal constructors - --> $DIR/mixed-constructors.rs:43:13 + --> $DIR/mixed-constructors.rs:42:13 | LL | (0, Cow::Borrowed(_)) => {} | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` diff --git a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs index bab6308223e5..64f5f14f199a 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs +++ b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs @@ -1,6 +1,5 @@ //! Test non-exhaustive matches involving deref patterns. #![feature(deref_patterns)] -#![expect(incomplete_features)] #![deny(unreachable_patterns)] fn main() { diff --git a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr index a1abd5f0e3f4..75c8b1864c78 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr +++ b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `deref!(true)` not covered - --> $DIR/non-exhaustive.rs:7:11 + --> $DIR/non-exhaustive.rs:6:11 | LL | match Box::new(false) { | ^^^^^^^^^^^^^^^ pattern `deref!(true)` not covered @@ -14,7 +14,7 @@ LL + deref!(true) => todo!() | error[E0004]: non-exhaustive patterns: `deref!(deref!(false))` not covered - --> $DIR/non-exhaustive.rs:12:11 + --> $DIR/non-exhaustive.rs:11:11 | LL | match Box::new(Box::new(false)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!(deref!(false))` not covered @@ -29,7 +29,7 @@ LL + deref!(deref!(false)) => todo!() | error[E0004]: non-exhaustive patterns: `deref!((true, deref!(true)))` and `deref!((false, deref!(false)))` not covered - --> $DIR/non-exhaustive.rs:17:11 + --> $DIR/non-exhaustive.rs:16:11 | LL | match Box::new((true, Box::new(false))) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `deref!((true, deref!(true)))` and `deref!((false, deref!(false)))` not covered @@ -44,7 +44,7 @@ LL + deref!((true, deref!(true))) | deref!((false, deref!(false))) => to | error[E0004]: non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered - --> $DIR/non-exhaustive.rs:24:11 + --> $DIR/non-exhaustive.rs:23:11 | LL | match Box::new((Box::new(T::A), Box::new(T::A))) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!((deref!(T::C), _))` not covered diff --git a/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs index 2677fc54dedc..5559ee8f5566 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs +++ b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs @@ -1,6 +1,5 @@ //! Test unreachable patterns involving deref patterns. #![feature(deref_patterns)] -#![expect(incomplete_features)] #![deny(unreachable_patterns)] fn main() { diff --git a/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr index 045e11be3196..88ac7b2351a7 100644 --- a/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr +++ b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/unreachable-patterns.rs:10:9 + --> $DIR/unreachable-patterns.rs:9:9 | LL | false => {} | ----- matches all the relevant values @@ -7,13 +7,13 @@ LL | false => {} | ^^^^^ no value can reach this | note: the lint level is defined here - --> $DIR/unreachable-patterns.rs:4:9 + --> $DIR/unreachable-patterns.rs:3:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/unreachable-patterns.rs:16:9 + --> $DIR/unreachable-patterns.rs:15:9 | LL | true => {} | ---- matches all the relevant values @@ -22,13 +22,13 @@ LL | true => {} | ^^^^ no value can reach this error: unreachable pattern - --> $DIR/unreachable-patterns.rs:23:9 + --> $DIR/unreachable-patterns.rs:22:9 | LL | _ => {} | ^ no value can reach this | note: multiple earlier patterns match some of the same values - --> $DIR/unreachable-patterns.rs:23:9 + --> $DIR/unreachable-patterns.rs:22:9 | LL | (true, _) => {} | --------- matches some of the same values @@ -40,7 +40,7 @@ LL | _ => {} | ^ collectively making this unreachable error: unreachable pattern - --> $DIR/unreachable-patterns.rs:29:9 + --> $DIR/unreachable-patterns.rs:28:9 | LL | (T::A | T::B, T::A | T::C) => {} | -------------------------- matches all the relevant values @@ -48,7 +48,7 @@ LL | (T::A, T::C) => {} | ^^^^^^^^^^^^ no value can reach this error: unreachable pattern - --> $DIR/unreachable-patterns.rs:30:9 + --> $DIR/unreachable-patterns.rs:29:9 | LL | (T::A | T::B, T::A | T::C) => {} | -------------------------- matches all the relevant values diff --git a/tests/ui/pattern/issue-115599.stderr b/tests/ui/pattern/issue-115599.stderr index ed465ea0bbad..f776623ff75b 100644 --- a/tests/ui/pattern/issue-115599.stderr +++ b/tests/ui/pattern/issue-115599.stderr @@ -9,9 +9,14 @@ LL | if let CONST_STRING = empty_str {} | --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | - = note: `Vec` must be annotated with `#[derive(PartialEq)]` to be usable in patterns + = note: `Vec` is not usable in patterns | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: check for equality instead of pattern matching + | +LL - if let CONST_STRING = empty_str {} +LL + if CONST_STRING == empty_str {} + | error: aborting due to 1 previous error diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr index 85379d6605bc..6e974b4f4da0 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a mutable reference LL | let (a, mut b) = &mut p; | ----- ^^^^^^ | | - | data moved here - | move occurs because `b` has type `U`, which does not implement the `Copy` trait + | data moved here because `b` has type `U`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr index 494e5e2b2e85..2be222d19e68 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | let (a, mut b) = &p; | ----- ^^ | | - | data moved here - | move occurs because `b` has type `U`, which does not implement the `Copy` trait + | data moved here because `b` has type `U`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/pattern/mut-pattern-of-immutable-borrow.stderr b/tests/ui/pattern/mut-pattern-of-immutable-borrow.stderr index be1b5fadb0dd..f9ef1efa6b2e 100644 --- a/tests/ui/pattern/mut-pattern-of-immutable-borrow.stderr +++ b/tests/ui/pattern/mut-pattern-of-immutable-borrow.stderr @@ -4,10 +4,7 @@ error[E0507]: cannot move out of `arg.field` as enum variant `Some` which is beh LL | match arg.field { | ^^^^^^^^^ LL | Some(s) => s.push('a'), - | - - | | - | data moved here - | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | - data moved here because `s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here | @@ -31,10 +28,7 @@ error[E0507]: cannot move out of a shared reference LL | match &arg.field { | ^^^^^^^^^^ LL | Some(mut s) => s.push('a'), - | ----- - | | - | data moved here - | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | ----- data moved here because `s` has type `String`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/pattern/non-structural-match-types-cycle-err.rs b/tests/ui/pattern/non-structural-match-types-cycle-err.rs index a8e494c35b0c..3bc1964eb21f 100644 --- a/tests/ui/pattern/non-structural-match-types-cycle-err.rs +++ b/tests/ui/pattern/non-structural-match-types-cycle-err.rs @@ -1,5 +1,5 @@ //@ edition:2021 - +//@ ignore-parallel-frontend query cycle struct AnyOption(T); impl AnyOption { const NONE: Option = None; diff --git a/tests/ui/pattern/pattern-match-invalid-variant.stderr b/tests/ui/pattern/pattern-match-invalid-variant.stderr index 08a99f696f6d..94373afeb2e6 100644 --- a/tests/ui/pattern/pattern-match-invalid-variant.stderr +++ b/tests/ui/pattern/pattern-match-invalid-variant.stderr @@ -1,11 +1,11 @@ -error[E0599]: no variant or associated item named `Hsl` found for enum `Color` in the current scope +error[E0599]: no variant, associated function, or constant named `Hsl` found for enum `Color` in the current scope --> $DIR/pattern-match-invalid-variant.rs:14:16 | LL | enum Color { - | ---------- variant or associated item `Hsl` not found for this enum + | ---------- variant, associated function, or constant `Hsl` not found for this enum ... LL | Color::Hsl(h, s, l) => { - | ^^^ variant or associated item not found in `Color` + | ^^^ variant, associated function, or constant not found in `Color` error: aborting due to 1 previous error diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2021.stderr index 6391619fddf0..ba1654c64d92 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2021.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | data moved here because `x` has type `&mut u32`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr index 1106342e62e4..102d44e7b523 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr @@ -4,8 +4,7 @@ error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array LL | let [&x] = &[&mut 0]; | - ^^^^^^^^^ cannot move out of here | | - | data moved here - | move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait + | data moved here because `x` has type `&mut i32`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -18,8 +17,7 @@ error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array LL | let [&x] = &mut [&mut 0]; | - ^^^^^^^^^^^^^ cannot move out of here | | - | data moved here - | move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait + | data moved here because `x` has type `&mut i32`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | @@ -32,8 +30,7 @@ error[E0507]: cannot move out of a shared reference LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | data moved here because `x` has type `&mut u32`, which does not implement the `Copy` trait | help: consider removing the borrow | @@ -69,8 +66,7 @@ error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array LL | let [&mut x] = &mut [&mut 0]; | - ^^^^^^^^^^^^^ cannot move out of here | | - | data moved here - | move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait + | data moved here because `x` has type `&mut i32`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr index ac84fdf7f95f..f9e61394cb51 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr @@ -36,8 +36,7 @@ error[E0507]: cannot move out of a shared reference LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | data moved here because `x` has type `&mut u32`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2021.stderr index 0e431326cb91..ac53c0dc89f8 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2021.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | data moved here because `x` has type `&mut u32`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr index 0e431326cb91..ac53c0dc89f8 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ | | - | data moved here - | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | data moved here because `x` has type `&mut u32`, which does not implement the `Copy` trait | help: consider removing the borrow | diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr index 01fcfdc8be6e..4963e80ec8cc 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr @@ -4,13 +4,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let Foo(mut x) = &Foo(0); | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:25:9 | LL | let Foo(mut x) = &Foo(0); | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/migration_lint.rs:7:9 | @@ -27,13 +27,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let Foo(mut x) = &mut Foo(0); | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:30:9 | LL | let Foo(mut x) = &mut Foo(0); | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(mut x) = &mut Foo(0); @@ -45,13 +45,13 @@ error: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2 LL | let Foo(ref x) = &Foo(0); | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:35:9 | LL | let Foo(ref x) = &Foo(0); | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: remove the unnecessary binding modifier | LL - let Foo(ref x) = &Foo(0); @@ -64,13 +64,13 @@ error: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2 LL | let Foo(ref x) = &mut Foo(0); | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:40:9 | LL | let Foo(ref x) = &mut Foo(0); | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(ref x) = &mut Foo(0); @@ -82,13 +82,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&x) = &Foo(&0); | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:57:9 | LL | let Foo(&x) = &Foo(&0); | ^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&x) = &Foo(&0); @@ -100,13 +100,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&mut x) = &Foo(&mut 0); | ^^^^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:62:9 | LL | let Foo(&mut x) = &Foo(&mut 0); | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&mut x) = &Foo(&mut 0); @@ -118,13 +118,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&x) = &mut Foo(&0); | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:67:9 | LL | let Foo(&x) = &mut Foo(&0); | ^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(&x) = &mut Foo(&0); @@ -136,13 +136,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&mut x) = &mut Foo(&mut 0); | ^^^^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:72:9 | LL | let Foo(&mut x) = &mut Foo(&mut 0); | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(&mut x) = &mut Foo(&mut 0); @@ -154,13 +154,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | if let Some(&x) = &&&&&Some(&0u8) { | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:81:12 | LL | if let Some(&x) = &&&&&Some(&0u8) { | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&Some(&x) = &&&&&Some(&0u8) { @@ -172,13 +172,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) { | ^^^^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:87:12 | LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) { | ^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) { @@ -190,13 +190,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | if let Some(&x) = &&&&&mut Some(&0u8) { | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:93:12 | LL | if let Some(&x) = &&&&&mut Some(&0u8) { | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) { @@ -208,13 +208,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { | ^^^^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:99:12 | LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { | ^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) { @@ -226,13 +226,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:111:9 | LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using variable binding modes | LL | let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 }; @@ -246,13 +246,13 @@ LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:117:9 | LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 }; @@ -266,13 +266,13 @@ LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:124:12 | LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } = @@ -306,8 +306,6 @@ LL | let [&mut [ref a]] = &mut [&mut &[0]]; | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:145:15 | @@ -318,6 +316,8 @@ note: matching on a reference type with a non-reference pattern implicitly borro | LL | let [&mut [ref a]] = &mut [&mut &[0]]; | ^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | let &mut [&mut &[ref a]] = &mut [&mut &[0]]; @@ -329,13 +329,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let [&(_)] = &[&0]; | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:150:9 | LL | let [&(_)] = &[&0]; | ^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&(_)] = &[&0]; @@ -349,13 +349,13 @@ LL | let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; | | | explicit `ref` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:157:9 | LL | let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: remove the unnecessary binding modifiers | LL - let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; @@ -370,13 +370,13 @@ LL | let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 }; | | | explicit `ref` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:164:9 | LL | let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &mut Struct { ref a, ref mut b, ref mut c } = &mut Struct { a: 0, b: 0, c: 0 }; @@ -390,13 +390,13 @@ LL | let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:172:9 | LL | let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &mut &Struct { a: &[ref a], b: &mut [&[ref b]], ref c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; @@ -408,13 +408,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&ref a) = &Foo(&0); | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:180:9 | LL | let Foo(&ref a) = &Foo(&0); | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&ref a) = &Foo(&0); @@ -426,13 +426,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:186:9 | LL | let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); | ^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &(&a, ref b, &[ref c], &mut [&mut (ref d, &[ref e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); @@ -444,13 +444,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let (a, [b], [mut c]) = &(0, &mut [0], &[0]); | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:196:9 | LL | let (a, [b], [mut c]) = &(0, &mut [0], &[0]); | ^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &(ref a, &mut [ref b], &[mut c]) = &(0, &mut [0], &[0]); @@ -464,13 +464,13 @@ LL | let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0])); | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:204:9 | LL | let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0])); | ^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | let &(&a, &mut (ref b, &[ref c])) = &(&0, &mut (0, &[0])); @@ -482,13 +482,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let [mut a @ b] = &[0]; | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:212:9 | LL | let [mut a @ b] = &[0]; | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &[mut a @ ref b] = &[0]; @@ -500,13 +500,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let [a @ mut b] = &[0]; | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:219:9 | LL | let [a @ mut b] = &[0]; | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &[ref a @ mut b] = &[0]; @@ -520,8 +520,6 @@ LL | let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2]; | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:226:31 | @@ -532,6 +530,8 @@ note: matching on a reference type with a non-reference pattern implicitly borro | LL | let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2]; | ^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | let [&Foo(&ref a @ ref b), &Foo(&ref c @ d)] = [&Foo(&0); 2]; @@ -545,8 +545,6 @@ LL | let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:235:33 | @@ -557,6 +555,8 @@ note: matching on a reference type with a non-reference pattern implicitly borro | LL | let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; | ^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; @@ -586,13 +586,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0]; | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:249:9 | LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&migration_lint_macros::bind_ref!(a)] = &[&0]; @@ -606,13 +606,13 @@ LL | let (mut a, ref b) = &(0, 0); | | | `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:255:9 | LL | let (mut a, ref b) = &(0, 0); | ^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &(mut a, ref b) = &(0, 0); @@ -626,13 +626,13 @@ LL | let (mut a, &b) = &(0, &0); | | | `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:261:9 | LL | let (mut a, &b) = &(0, &0); | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &(mut a, &b) = &(0, &0); @@ -647,13 +647,13 @@ LL | let (mut a, ref b, &c) = &(0, 0, &0); | | explicit `ref` binding modifier not allowed when implicitly borrowing | `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:267:9 | LL | let (mut a, ref b, &c) = &(0, 0, &0); | ^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &(mut a, ref b, &c) = &(0, 0, &0); diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs index 83ad8c76bb1c..21edb9ceeff4 100644 --- a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs +++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs @@ -6,6 +6,7 @@ #![expect(incomplete_features)] fn good_fn_item(((x if x) | x): bool) -> bool { x } +//~^ ERROR: used binding `x` is possibly-uninitialized [E0381] fn bad_fn_item_1(x: bool, ((y if x) | y): bool) {} //~^ ERROR cannot find value `x` in this scope diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr index 44e42f142707..a95ffdd42532 100644 --- a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr +++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr @@ -1,5 +1,5 @@ error[E0408]: variable `y` is not bound in all patterns - --> $DIR/name-resolution.rs:37:10 + --> $DIR/name-resolution.rs:38:10 | LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, | ^^^^^^^^^^^^ - variable not in all patterns @@ -13,7 +13,7 @@ LL + ((Ok(x) if y) | (Err(x) if x),) => x && y, | error[E0408]: variable `x` is not bound in all patterns - --> $DIR/name-resolution.rs:37:25 + --> $DIR/name-resolution.rs:38:25 | LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, | - ^^^^^^^^^^^^^ pattern doesn't bind `x` @@ -27,7 +27,7 @@ LL + ((Ok(y) if y) | (Err(y) if x),) => x && y, | error[E0408]: variable `x` is not bound in all patterns - --> $DIR/name-resolution.rs:63:28 + --> $DIR/name-resolution.rs:64:28 | LL | Some(x if x > 0) | None => {} | - ^^^^ pattern doesn't bind `x` @@ -35,7 +35,7 @@ LL | Some(x if x > 0) | None => {} | variable not in all patterns error[E0425]: cannot find value `x` in this scope - --> $DIR/name-resolution.rs:10:34 + --> $DIR/name-resolution.rs:11:34 | LL | fn bad_fn_item_1(x: bool, ((y if x) | y): bool) {} | ^ @@ -47,7 +47,7 @@ LL + fn bad_fn_item_1(x: bool, ((y if y) | y): bool) {} | error[E0425]: cannot find value `y` in this scope - --> $DIR/name-resolution.rs:12:25 + --> $DIR/name-resolution.rs:13:25 | LL | fn bad_fn_item_2(((x if y) | x): bool, y: bool) {} | ^ @@ -59,7 +59,7 @@ LL + fn bad_fn_item_2(((x if x) | x): bool, y: bool) {} | error[E0425]: cannot find value `x` in this scope - --> $DIR/name-resolution.rs:20:18 + --> $DIR/name-resolution.rs:21:18 | LL | (x, y if x) => x && y, | ^ @@ -71,7 +71,7 @@ LL + (x, y if y) => x && y, | error[E0425]: cannot find value `y` in this scope - --> $DIR/name-resolution.rs:22:15 + --> $DIR/name-resolution.rs:23:15 | LL | (x if y, y) => x && y, | ^ @@ -83,7 +83,7 @@ LL + (x if x, y) => x && y, | error[E0425]: cannot find value `x` in this scope - --> $DIR/name-resolution.rs:29:20 + --> $DIR/name-resolution.rs:30:20 | LL | (x @ (y if x),) => x && y, | ^ @@ -95,7 +95,7 @@ LL + (x @ (y if y),) => x && y, | error[E0425]: cannot find value `y` in this scope - --> $DIR/name-resolution.rs:37:20 + --> $DIR/name-resolution.rs:38:20 | LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, | ^ @@ -107,7 +107,7 @@ LL + ((Ok(x) if x) | (Err(y) if x),) => x && y, | error[E0425]: cannot find value `x` in this scope - --> $DIR/name-resolution.rs:37:36 + --> $DIR/name-resolution.rs:38:36 | LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, | ^ @@ -119,13 +119,13 @@ LL + ((Ok(x) if y) | (Err(y) if y),) => x && y, | error[E0425]: cannot find value `nonexistent` in this scope - --> $DIR/name-resolution.rs:44:15 + --> $DIR/name-resolution.rs:45:15 | LL | let (_ if nonexistent) = true; | ^^^^^^^^^^^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> $DIR/name-resolution.rs:46:22 + --> $DIR/name-resolution.rs:47:22 | LL | if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } | ^ @@ -137,7 +137,7 @@ LL + if let ((x, y if y) | (x if y, y)) = (true, true) { x && y; } | error[E0425]: cannot find value `y` in this scope - --> $DIR/name-resolution.rs:46:33 + --> $DIR/name-resolution.rs:47:33 | LL | if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } | ^ @@ -149,7 +149,7 @@ LL + if let ((x, y if x) | (x if x, y)) = (true, true) { x && y; } | error[E0425]: cannot find value `x` in this scope - --> $DIR/name-resolution.rs:49:25 + --> $DIR/name-resolution.rs:50:25 | LL | while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } | ^ @@ -161,7 +161,7 @@ LL + while let ((x, y if y) | (x if y, y)) = (true, true) { x && y; } | error[E0425]: cannot find value `y` in this scope - --> $DIR/name-resolution.rs:49:36 + --> $DIR/name-resolution.rs:50:36 | LL | while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } | ^ @@ -173,7 +173,7 @@ LL + while let ((x, y if x) | (x if x, y)) = (true, true) { x && y; } | error[E0425]: cannot find value `x` in this scope - --> $DIR/name-resolution.rs:52:19 + --> $DIR/name-resolution.rs:53:19 | LL | for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } | ^ @@ -185,7 +185,7 @@ LL + for ((x, y if y) | (x if y, y)) in [(true, true)] { x && y; } | error[E0425]: cannot find value `y` in this scope - --> $DIR/name-resolution.rs:52:30 + --> $DIR/name-resolution.rs:53:30 | LL | for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } | ^ @@ -197,7 +197,7 @@ LL + for ((x, y if x) | (x if x, y)) in [(true, true)] { x && y; } | error[E0425]: cannot find value `y` in this scope - --> $DIR/name-resolution.rs:57:13 + --> $DIR/name-resolution.rs:58:13 | LL | (|(x if y), (y if x)| x && y)(true, true); | ^ @@ -209,7 +209,7 @@ LL + (|(x if x), (y if x)| x && y)(true, true); | error[E0425]: cannot find value `x` in this scope - --> $DIR/name-resolution.rs:57:23 + --> $DIR/name-resolution.rs:58:23 | LL | (|(x if y), (y if x)| x && y)(true, true); | ^ @@ -221,7 +221,7 @@ LL + (|(x if y), (y if y)| x && y)(true, true); | error[E0308]: mismatched types - --> $DIR/name-resolution.rs:75:18 + --> $DIR/name-resolution.rs:76:18 | LL | local if local => 0, | ^^^^^ expected `bool`, found `({integer}, {integer})` @@ -229,7 +229,16 @@ LL | local if local => 0, = note: expected type `bool` found tuple `({integer}, {integer})` -error: aborting due to 20 previous errors +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/name-resolution.rs:8:49 + | +LL | fn good_fn_item(((x if x) | x): bool) -> bool { x } + | - - ^ `x` used here but it is possibly-uninitialized + | | | + | | binding initialized here in some conditions + | binding declared here but left uninitialized -Some errors have detailed explanations: E0308, E0408, E0425. +error: aborting due to 21 previous errors + +Some errors have detailed explanations: E0308, E0381, E0408, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr index f9da0430f2ef..66aa551c5884 100644 --- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr +++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for MyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: check for equality instead of pattern matching + | +LL - if let CONSTANT = &&MyType { +LL + if CONSTANT == &&MyType { + | error: aborting due to 1 previous error diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr index d26ba93e7211..75a633cd49a3 100644 --- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/empty-types.rs:48:9 + --> $DIR/empty-types.rs:47:9 | LL | _ => {} | ^------ @@ -9,13 +9,13 @@ LL | _ => {} | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here - --> $DIR/empty-types.rs:14:9 + --> $DIR/empty-types.rs:13:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:51:9 + --> $DIR/empty-types.rs:50:9 | LL | _x => {} | ^^------ @@ -26,7 +26,7 @@ LL | _x => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `&!` is non-empty - --> $DIR/empty-types.rs:55:11 + --> $DIR/empty-types.rs:54:11 | LL | match ref_never {} | ^^^^^^^^^ @@ -41,7 +41,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:69:9 + --> $DIR/empty-types.rs:68:9 | LL | (_, _) => {} | ^^^^^^------ @@ -52,7 +52,7 @@ LL | (_, _) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:75:9 + --> $DIR/empty-types.rs:74:9 | LL | _ => {} | ^------ @@ -63,7 +63,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:78:9 + --> $DIR/empty-types.rs:77:9 | LL | (_, _) => {} | ^^^^^^------ @@ -74,7 +74,7 @@ LL | (_, _) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:82:9 + --> $DIR/empty-types.rs:81:9 | LL | _ => {} | ^------ @@ -85,7 +85,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(_)` not covered - --> $DIR/empty-types.rs:86:11 + --> $DIR/empty-types.rs:85:11 | LL | match res_u32_never {} | ^^^^^^^^^^^^^ pattern `Ok(_)` not covered @@ -104,7 +104,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:93:9 + --> $DIR/empty-types.rs:92:9 | LL | Err(_) => {} | ^^^^^^------ @@ -115,7 +115,7 @@ LL | Err(_) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:98:9 + --> $DIR/empty-types.rs:97:9 | LL | Err(_) => {} | ^^^^^^------ @@ -126,7 +126,7 @@ LL | Err(_) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered - --> $DIR/empty-types.rs:95:11 + --> $DIR/empty-types.rs:94:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered @@ -144,7 +144,7 @@ LL ~ Ok(1_u32..=u32::MAX) => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:101:9 + --> $DIR/empty-types.rs:100:9 | LL | let Ok(_x) = res_u32_never.as_ref(); | ^^^^^^ pattern `Err(_)` not covered @@ -158,7 +158,7 @@ LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ error: unreachable pattern - --> $DIR/empty-types.rs:111:9 + --> $DIR/empty-types.rs:110:9 | LL | _ => {} | ^------ @@ -169,7 +169,18 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:114:9 + --> $DIR/empty-types.rs:113:9 + | +LL | Ok(_) => {} + | ^^^^^------ + | | + | matches no values because `Result` is uninhabited + | help: remove the match arm + | + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types + +error: unreachable pattern + --> $DIR/empty-types.rs:116:9 | LL | Ok(_) => {} | ^^^^^------ @@ -182,17 +193,6 @@ LL | Ok(_) => {} error: unreachable pattern --> $DIR/empty-types.rs:117:9 | -LL | Ok(_) => {} - | ^^^^^------ - | | - | matches no values because `Result` is uninhabited - | help: remove the match arm - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/empty-types.rs:118:9 - | LL | _ => {} | ^------ | | @@ -202,7 +202,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:121:9 + --> $DIR/empty-types.rs:120:9 | LL | Ok(_) => {} | ^^^^^------ @@ -213,7 +213,7 @@ LL | Ok(_) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:122:9 + --> $DIR/empty-types.rs:121:9 | LL | Err(_) => {} | ^^^^^^------ @@ -224,7 +224,7 @@ LL | Err(_) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:131:13 + --> $DIR/empty-types.rs:130:13 | LL | _ => {} | ^------ @@ -235,7 +235,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:134:13 + --> $DIR/empty-types.rs:133:13 | LL | _ if false => {} | ^--------------- @@ -246,7 +246,7 @@ LL | _ if false => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:142:13 + --> $DIR/empty-types.rs:141:13 | LL | Some(_) => {} | ^^^^^^^------ @@ -257,7 +257,7 @@ LL | Some(_) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:146:13 + --> $DIR/empty-types.rs:145:13 | LL | None => {} | ---- matches all the relevant values @@ -265,7 +265,7 @@ LL | _ => {} | ^ no value can reach this error: unreachable pattern - --> $DIR/empty-types.rs:198:13 + --> $DIR/empty-types.rs:197:13 | LL | _ => {} | ^------ @@ -276,7 +276,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:203:13 + --> $DIR/empty-types.rs:202:13 | LL | _ => {} | ^------ @@ -287,7 +287,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:208:13 + --> $DIR/empty-types.rs:207:13 | LL | _ => {} | ^------ @@ -298,7 +298,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:213:13 + --> $DIR/empty-types.rs:212:13 | LL | _ => {} | ^------ @@ -309,7 +309,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:219:13 + --> $DIR/empty-types.rs:218:13 | LL | _ => {} | ^------ @@ -320,7 +320,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:280:9 + --> $DIR/empty-types.rs:279:9 | LL | _ => {} | ^------ @@ -331,7 +331,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:283:9 + --> $DIR/empty-types.rs:282:9 | LL | (_, _) => {} | ^^^^^^------ @@ -342,7 +342,7 @@ LL | (_, _) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:286:9 + --> $DIR/empty-types.rs:285:9 | LL | Ok(_) => {} | ^^^^^------ @@ -353,7 +353,7 @@ LL | Ok(_) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:287:9 + --> $DIR/empty-types.rs:286:9 | LL | Err(_) => {} | ^^^^^^------ @@ -364,7 +364,7 @@ LL | Err(_) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty - --> $DIR/empty-types.rs:326:11 + --> $DIR/empty-types.rs:325:11 | LL | match slice_never {} | ^^^^^^^^^^^ @@ -378,7 +378,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `&[]` not covered - --> $DIR/empty-types.rs:337:11 + --> $DIR/empty-types.rs:336:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[]` not covered @@ -391,7 +391,7 @@ LL + &[] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` not covered - --> $DIR/empty-types.rs:351:11 + --> $DIR/empty-types.rs:350:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[]` not covered @@ -405,7 +405,7 @@ LL + &[] => todo!() | error[E0004]: non-exhaustive patterns: type `[!]` is non-empty - --> $DIR/empty-types.rs:358:11 + --> $DIR/empty-types.rs:357:11 | LL | match *slice_never {} | ^^^^^^^^^^^^ @@ -419,7 +419,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:367:9 + --> $DIR/empty-types.rs:366:9 | LL | _ => {} | ^------ @@ -430,7 +430,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:370:9 + --> $DIR/empty-types.rs:369:9 | LL | [_, _, _] => {} | ^^^^^^^^^------ @@ -441,7 +441,7 @@ LL | [_, _, _] => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:373:9 + --> $DIR/empty-types.rs:372:9 | LL | [_, ..] => {} | ^^^^^^^------ @@ -452,7 +452,7 @@ LL | [_, ..] => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty - --> $DIR/empty-types.rs:387:11 + --> $DIR/empty-types.rs:386:11 | LL | match array_0_never {} | ^^^^^^^^^^^^^ @@ -466,7 +466,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:394:9 + --> $DIR/empty-types.rs:393:9 | LL | [] => {} | -- matches all the relevant values @@ -474,7 +474,7 @@ LL | _ => {} | ^ no value can reach this error[E0004]: non-exhaustive patterns: `[]` not covered - --> $DIR/empty-types.rs:396:11 + --> $DIR/empty-types.rs:395:11 | LL | match array_0_never { | ^^^^^^^^^^^^^ pattern `[]` not covered @@ -488,7 +488,7 @@ LL + [] => todo!() | error: unreachable pattern - --> $DIR/empty-types.rs:415:9 + --> $DIR/empty-types.rs:414:9 | LL | Some(_) => {} | ^^^^^^^------ @@ -499,7 +499,7 @@ LL | Some(_) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:420:9 + --> $DIR/empty-types.rs:419:9 | LL | Some(_a) => {} | ^^^^^^^^------ @@ -510,7 +510,7 @@ LL | Some(_a) => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:425:9 + --> $DIR/empty-types.rs:424:9 | LL | None => {} | ---- matches all the relevant values @@ -519,7 +519,7 @@ LL | _ => {} | ^ no value can reach this error: unreachable pattern - --> $DIR/empty-types.rs:430:9 + --> $DIR/empty-types.rs:429:9 | LL | None => {} | ---- matches all the relevant values @@ -528,7 +528,7 @@ LL | _a => {} | ^^ no value can reach this error: unreachable pattern - --> $DIR/empty-types.rs:602:9 + --> $DIR/empty-types.rs:601:9 | LL | _ => {} | ^------ @@ -539,7 +539,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:605:9 + --> $DIR/empty-types.rs:604:9 | LL | _x => {} | ^^------ @@ -550,7 +550,7 @@ LL | _x => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:608:9 + --> $DIR/empty-types.rs:607:9 | LL | _ if false => {} | ^--------------- @@ -561,7 +561,7 @@ LL | _ if false => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:611:9 + --> $DIR/empty-types.rs:610:9 | LL | _x if false => {} | ^^--------------- diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr index 55d6eb82a346..046c0d5f6588 100644 --- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr +++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr @@ -1,14 +1,5 @@ -warning: the feature `never_patterns` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/empty-types.rs:11:33 - | -LL | #![cfg_attr(never_pats, feature(never_patterns))] - | ^^^^^^^^^^^^^^ - | - = note: see issue #118155 for more information - = note: `#[warn(incomplete_features)]` on by default - error: unreachable pattern - --> $DIR/empty-types.rs:48:9 + --> $DIR/empty-types.rs:47:9 | LL | _ => {} | ^------ @@ -18,13 +9,13 @@ LL | _ => {} | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here - --> $DIR/empty-types.rs:14:9 + --> $DIR/empty-types.rs:13:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:51:9 + --> $DIR/empty-types.rs:50:9 | LL | _x => {} | ^^------ @@ -35,7 +26,7 @@ LL | _x => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `&!` is non-empty - --> $DIR/empty-types.rs:55:11 + --> $DIR/empty-types.rs:54:11 | LL | match ref_never {} | ^^^^^^^^^ @@ -50,7 +41,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:82:9 + --> $DIR/empty-types.rs:81:9 | LL | _ => {} | ^------ @@ -61,7 +52,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(_)` not covered - --> $DIR/empty-types.rs:86:11 + --> $DIR/empty-types.rs:85:11 | LL | match res_u32_never {} | ^^^^^^^^^^^^^ pattern `Ok(_)` not covered @@ -80,7 +71,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered - --> $DIR/empty-types.rs:95:11 + --> $DIR/empty-types.rs:94:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered @@ -98,7 +89,7 @@ LL ~ Ok(1_u32..=u32::MAX) => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:101:9 + --> $DIR/empty-types.rs:100:9 | LL | let Ok(_x) = res_u32_never.as_ref(); | ^^^^^^ pattern `Err(_)` not covered @@ -112,7 +103,7 @@ LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:105:9 + --> $DIR/empty-types.rs:104:9 | LL | let Ok(_x) = &res_u32_never; | ^^^^^^ pattern `&Err(!)` not covered @@ -126,7 +117,7 @@ LL | let Ok(_x) = &res_u32_never else { todo!() }; | ++++++++++++++++ error: unreachable pattern - --> $DIR/empty-types.rs:131:13 + --> $DIR/empty-types.rs:130:13 | LL | _ => {} | ^------ @@ -137,7 +128,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:134:13 + --> $DIR/empty-types.rs:133:13 | LL | _ if false => {} | ^--------------- @@ -148,7 +139,7 @@ LL | _ if false => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Some(!)` not covered - --> $DIR/empty-types.rs:155:15 + --> $DIR/empty-types.rs:154:15 | LL | match *ref_opt_void { | ^^^^^^^^^^^^^ pattern `Some(!)` not covered @@ -167,7 +158,7 @@ LL + Some(!) | error: unreachable pattern - --> $DIR/empty-types.rs:198:13 + --> $DIR/empty-types.rs:197:13 | LL | _ => {} | ^------ @@ -178,7 +169,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:203:13 + --> $DIR/empty-types.rs:202:13 | LL | _ => {} | ^------ @@ -189,7 +180,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:208:13 + --> $DIR/empty-types.rs:207:13 | LL | _ => {} | ^------ @@ -200,7 +191,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:213:13 + --> $DIR/empty-types.rs:212:13 | LL | _ => {} | ^------ @@ -211,7 +202,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:219:13 + --> $DIR/empty-types.rs:218:13 | LL | _ => {} | ^------ @@ -222,7 +213,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:280:9 + --> $DIR/empty-types.rs:279:9 | LL | _ => {} | ^------ @@ -233,7 +224,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:296:13 + --> $DIR/empty-types.rs:295:13 | LL | let Ok(_) = *ptr_result_never_err; | ^^^^^ pattern `Err(!)` not covered @@ -247,7 +238,7 @@ LL | if let Ok(_) = *ptr_result_never_err { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:315:11 + --> $DIR/empty-types.rs:314:11 | LL | match *x {} | ^^ @@ -261,7 +252,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty - --> $DIR/empty-types.rs:317:11 + --> $DIR/empty-types.rs:316:11 | LL | match *x {} | ^^ @@ -275,7 +266,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `Ok(!)` and `Err(!)` not covered - --> $DIR/empty-types.rs:319:11 + --> $DIR/empty-types.rs:318:11 | LL | match *x {} | ^^ patterns `Ok(!)` and `Err(!)` not covered @@ -297,7 +288,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty - --> $DIR/empty-types.rs:321:11 + --> $DIR/empty-types.rs:320:11 | LL | match *x {} | ^^ @@ -311,7 +302,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty - --> $DIR/empty-types.rs:326:11 + --> $DIR/empty-types.rs:325:11 | LL | match slice_never {} | ^^^^^^^^^^^ @@ -325,7 +316,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `&[!, ..]` not covered - --> $DIR/empty-types.rs:328:11 + --> $DIR/empty-types.rs:327:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[!, ..]` not covered @@ -339,7 +330,7 @@ LL + &[!, ..] | error[E0004]: non-exhaustive patterns: `&[]`, `&[!]` and `&[!, !]` not covered - --> $DIR/empty-types.rs:337:11 + --> $DIR/empty-types.rs:336:11 | LL | match slice_never { | ^^^^^^^^^^^ patterns `&[]`, `&[!]` and `&[!, !]` not covered @@ -352,7 +343,7 @@ LL + &[] | &[!] | &[!, !] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` and `&[!, ..]` not covered - --> $DIR/empty-types.rs:351:11 + --> $DIR/empty-types.rs:350:11 | LL | match slice_never { | ^^^^^^^^^^^ patterns `&[]` and `&[!, ..]` not covered @@ -366,7 +357,7 @@ LL + &[] | &[!, ..] => todo!() | error[E0004]: non-exhaustive patterns: type `[!]` is non-empty - --> $DIR/empty-types.rs:358:11 + --> $DIR/empty-types.rs:357:11 | LL | match *slice_never {} | ^^^^^^^^^^^^ @@ -380,7 +371,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty - --> $DIR/empty-types.rs:387:11 + --> $DIR/empty-types.rs:386:11 | LL | match array_0_never {} | ^^^^^^^^^^^^^ @@ -394,7 +385,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:394:9 + --> $DIR/empty-types.rs:393:9 | LL | [] => {} | -- matches all the relevant values @@ -402,7 +393,7 @@ LL | _ => {} | ^ no value can reach this error[E0004]: non-exhaustive patterns: `[]` not covered - --> $DIR/empty-types.rs:396:11 + --> $DIR/empty-types.rs:395:11 | LL | match array_0_never { | ^^^^^^^^^^^^^ pattern `[]` not covered @@ -416,7 +407,7 @@ LL + [] => todo!() | error[E0004]: non-exhaustive patterns: `&Some(!)` not covered - --> $DIR/empty-types.rs:450:11 + --> $DIR/empty-types.rs:449:11 | LL | match ref_opt_never { | ^^^^^^^^^^^^^ pattern `&Some(!)` not covered @@ -435,7 +426,7 @@ LL + &Some(!) | error[E0004]: non-exhaustive patterns: `Some(!)` not covered - --> $DIR/empty-types.rs:491:11 + --> $DIR/empty-types.rs:490:11 | LL | match *ref_opt_never { | ^^^^^^^^^^^^^^ pattern `Some(!)` not covered @@ -454,7 +445,7 @@ LL + Some(!) | error[E0004]: non-exhaustive patterns: `Err(!)` not covered - --> $DIR/empty-types.rs:539:11 + --> $DIR/empty-types.rs:538:11 | LL | match *ref_res_never { | ^^^^^^^^^^^^^^ pattern `Err(!)` not covered @@ -473,7 +464,7 @@ LL + Err(!) | error[E0004]: non-exhaustive patterns: `Err(!)` not covered - --> $DIR/empty-types.rs:550:11 + --> $DIR/empty-types.rs:549:11 | LL | match *ref_res_never { | ^^^^^^^^^^^^^^ pattern `Err(!)` not covered @@ -492,7 +483,7 @@ LL + Err(!) | error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:569:11 + --> $DIR/empty-types.rs:568:11 | LL | match *ref_tuple_half_never {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -506,7 +497,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:602:9 + --> $DIR/empty-types.rs:601:9 | LL | _ => {} | ^------ @@ -517,7 +508,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:605:9 + --> $DIR/empty-types.rs:604:9 | LL | _x => {} | ^^------ @@ -528,7 +519,7 @@ LL | _x => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:608:9 + --> $DIR/empty-types.rs:607:9 | LL | _ if false => {} | ^--------------- @@ -539,7 +530,7 @@ LL | _ if false => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:611:9 + --> $DIR/empty-types.rs:610:9 | LL | _x if false => {} | ^^--------------- @@ -550,7 +541,7 @@ LL | _x if false => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `&!` not covered - --> $DIR/empty-types.rs:636:11 + --> $DIR/empty-types.rs:635:11 | LL | match ref_never { | ^^^^^^^^^ pattern `&!` not covered @@ -566,7 +557,7 @@ LL + &! | error[E0004]: non-exhaustive patterns: `Ok(!)` not covered - --> $DIR/empty-types.rs:652:11 + --> $DIR/empty-types.rs:651:11 | LL | match *ref_result_never { | ^^^^^^^^^^^^^^^^^ pattern `Ok(!)` not covered @@ -585,7 +576,7 @@ LL + Ok(!) | error[E0004]: non-exhaustive patterns: `Some(!)` not covered - --> $DIR/empty-types.rs:672:11 + --> $DIR/empty-types.rs:671:11 | LL | match *x { | ^^ pattern `Some(!)` not covered @@ -603,7 +594,7 @@ LL ~ None => {}, LL + Some(!) | -error: aborting due to 42 previous errors; 1 warning emitted +error: aborting due to 42 previous errors 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-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr index 0ed8c2119967..ba158c1176b3 100644 --- a/tests/ui/pattern/usefulness/empty-types.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/empty-types.rs:48:9 + --> $DIR/empty-types.rs:47:9 | LL | _ => {} | ^------ @@ -9,13 +9,13 @@ LL | _ => {} | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here - --> $DIR/empty-types.rs:14:9 + --> $DIR/empty-types.rs:13:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:51:9 + --> $DIR/empty-types.rs:50:9 | LL | _x => {} | ^^------ @@ -26,7 +26,7 @@ LL | _x => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `&!` is non-empty - --> $DIR/empty-types.rs:55:11 + --> $DIR/empty-types.rs:54:11 | LL | match ref_never {} | ^^^^^^^^^ @@ -41,7 +41,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:82:9 + --> $DIR/empty-types.rs:81:9 | LL | _ => {} | ^------ @@ -52,7 +52,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(_)` not covered - --> $DIR/empty-types.rs:86:11 + --> $DIR/empty-types.rs:85:11 | LL | match res_u32_never {} | ^^^^^^^^^^^^^ pattern `Ok(_)` not covered @@ -71,7 +71,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered - --> $DIR/empty-types.rs:95:11 + --> $DIR/empty-types.rs:94:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered @@ -89,7 +89,7 @@ LL ~ Ok(1_u32..=u32::MAX) => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:101:9 + --> $DIR/empty-types.rs:100:9 | LL | let Ok(_x) = res_u32_never.as_ref(); | ^^^^^^ pattern `Err(_)` not covered @@ -103,7 +103,7 @@ LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:105:9 + --> $DIR/empty-types.rs:104:9 | LL | let Ok(_x) = &res_u32_never; | ^^^^^^ pattern `&Err(_)` not covered @@ -117,7 +117,7 @@ LL | let Ok(_x) = &res_u32_never else { todo!() }; | ++++++++++++++++ error: unreachable pattern - --> $DIR/empty-types.rs:131:13 + --> $DIR/empty-types.rs:130:13 | LL | _ => {} | ^------ @@ -128,7 +128,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:134:13 + --> $DIR/empty-types.rs:133:13 | LL | _ if false => {} | ^--------------- @@ -139,7 +139,7 @@ LL | _ if false => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:155:15 + --> $DIR/empty-types.rs:154:15 | LL | match *ref_opt_void { | ^^^^^^^^^^^^^ pattern `Some(_)` not covered @@ -158,7 +158,7 @@ LL + Some(_) => todo!() | error: unreachable pattern - --> $DIR/empty-types.rs:198:13 + --> $DIR/empty-types.rs:197:13 | LL | _ => {} | ^------ @@ -169,7 +169,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:203:13 + --> $DIR/empty-types.rs:202:13 | LL | _ => {} | ^------ @@ -180,7 +180,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:208:13 + --> $DIR/empty-types.rs:207:13 | LL | _ => {} | ^------ @@ -191,7 +191,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:213:13 + --> $DIR/empty-types.rs:212:13 | LL | _ => {} | ^------ @@ -202,7 +202,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:219:13 + --> $DIR/empty-types.rs:218:13 | LL | _ => {} | ^------ @@ -213,7 +213,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:280:9 + --> $DIR/empty-types.rs:279:9 | LL | _ => {} | ^------ @@ -224,7 +224,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:296:13 + --> $DIR/empty-types.rs:295:13 | LL | let Ok(_) = *ptr_result_never_err; | ^^^^^ pattern `Err(_)` not covered @@ -238,7 +238,7 @@ LL | if let Ok(_) = *ptr_result_never_err { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:315:11 + --> $DIR/empty-types.rs:314:11 | LL | match *x {} | ^^ @@ -252,7 +252,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty - --> $DIR/empty-types.rs:317:11 + --> $DIR/empty-types.rs:316:11 | LL | match *x {} | ^^ @@ -266,7 +266,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered - --> $DIR/empty-types.rs:319:11 + --> $DIR/empty-types.rs:318:11 | LL | match *x {} | ^^ patterns `Ok(_)` and `Err(_)` not covered @@ -288,7 +288,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty - --> $DIR/empty-types.rs:321:11 + --> $DIR/empty-types.rs:320:11 | LL | match *x {} | ^^ @@ -302,7 +302,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty - --> $DIR/empty-types.rs:326:11 + --> $DIR/empty-types.rs:325:11 | LL | match slice_never {} | ^^^^^^^^^^^ @@ -316,7 +316,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered - --> $DIR/empty-types.rs:328:11 + --> $DIR/empty-types.rs:327:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[_, ..]` not covered @@ -330,7 +330,7 @@ LL + &[_, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[]`, `&[_]` and `&[_, _]` not covered - --> $DIR/empty-types.rs:337:11 + --> $DIR/empty-types.rs:336:11 | LL | match slice_never { | ^^^^^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _]` not covered @@ -343,7 +343,7 @@ LL + &[] | &[_] | &[_, _] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered - --> $DIR/empty-types.rs:351:11 + --> $DIR/empty-types.rs:350:11 | LL | match slice_never { | ^^^^^^^^^^^ patterns `&[]` and `&[_, ..]` not covered @@ -357,7 +357,7 @@ LL + &[] | &[_, ..] => todo!() | error[E0004]: non-exhaustive patterns: type `[!]` is non-empty - --> $DIR/empty-types.rs:358:11 + --> $DIR/empty-types.rs:357:11 | LL | match *slice_never {} | ^^^^^^^^^^^^ @@ -371,7 +371,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty - --> $DIR/empty-types.rs:387:11 + --> $DIR/empty-types.rs:386:11 | LL | match array_0_never {} | ^^^^^^^^^^^^^ @@ -385,7 +385,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:394:9 + --> $DIR/empty-types.rs:393:9 | LL | [] => {} | -- matches all the relevant values @@ -393,7 +393,7 @@ LL | _ => {} | ^ no value can reach this error[E0004]: non-exhaustive patterns: `[]` not covered - --> $DIR/empty-types.rs:396:11 + --> $DIR/empty-types.rs:395:11 | LL | match array_0_never { | ^^^^^^^^^^^^^ pattern `[]` not covered @@ -407,7 +407,7 @@ LL + [] => todo!() | error[E0004]: non-exhaustive patterns: `&Some(_)` not covered - --> $DIR/empty-types.rs:450:11 + --> $DIR/empty-types.rs:449:11 | LL | match ref_opt_never { | ^^^^^^^^^^^^^ pattern `&Some(_)` not covered @@ -426,7 +426,7 @@ LL + &Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:491:11 + --> $DIR/empty-types.rs:490:11 | LL | match *ref_opt_never { | ^^^^^^^^^^^^^^ pattern `Some(_)` not covered @@ -445,7 +445,7 @@ LL + Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:539:11 + --> $DIR/empty-types.rs:538:11 | LL | match *ref_res_never { | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -464,7 +464,7 @@ LL + Err(_) => todo!() | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:550:11 + --> $DIR/empty-types.rs:549:11 | LL | match *ref_res_never { | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -483,7 +483,7 @@ LL + Err(_) => todo!() | error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:569:11 + --> $DIR/empty-types.rs:568:11 | LL | match *ref_tuple_half_never {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL ~ } | error: unreachable pattern - --> $DIR/empty-types.rs:602:9 + --> $DIR/empty-types.rs:601:9 | LL | _ => {} | ^------ @@ -508,7 +508,7 @@ LL | _ => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:605:9 + --> $DIR/empty-types.rs:604:9 | LL | _x => {} | ^^------ @@ -519,7 +519,7 @@ LL | _x => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:608:9 + --> $DIR/empty-types.rs:607:9 | LL | _ if false => {} | ^--------------- @@ -530,7 +530,7 @@ LL | _ if false => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-types.rs:611:9 + --> $DIR/empty-types.rs:610:9 | LL | _x if false => {} | ^^--------------- @@ -541,7 +541,7 @@ LL | _x if false => {} = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `&_` not covered - --> $DIR/empty-types.rs:636:11 + --> $DIR/empty-types.rs:635:11 | LL | match ref_never { | ^^^^^^^^^ pattern `&_` not covered @@ -557,7 +557,7 @@ LL + &_ => todo!() | error[E0004]: non-exhaustive patterns: `Ok(_)` not covered - --> $DIR/empty-types.rs:652:11 + --> $DIR/empty-types.rs:651:11 | LL | match *ref_result_never { | ^^^^^^^^^^^^^^^^^ pattern `Ok(_)` not covered @@ -576,7 +576,7 @@ LL + Ok(_) => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:672:11 + --> $DIR/empty-types.rs:671:11 | LL | match *x { | ^^ pattern `Some(_)` not covered diff --git a/tests/ui/pattern/usefulness/empty-types.rs b/tests/ui/pattern/usefulness/empty-types.rs index a503295fc874..d4fdb7c1dd46 100644 --- a/tests/ui/pattern/usefulness/empty-types.rs +++ b/tests/ui/pattern/usefulness/empty-types.rs @@ -9,7 +9,6 @@ #![feature(never_type)] #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))] #![cfg_attr(never_pats, feature(never_patterns))] -//[never_pats]~^ WARN the feature `never_patterns` is incomplete #![allow(dead_code, unreachable_code)] #![deny(unreachable_patterns)] diff --git a/tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs index a95665f126d1..b5a0c6e4404e 100644 --- a/tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs +++ b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(pin_ergonomics)] -//~^ WARN the feature `pin_ergonomics` is incomplete use std::pin::Pin; diff --git a/tests/ui/pin-ergonomics/coerce-non-pointer-pin.stderr b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.stderr deleted file mode 100644 index 2deb5b09884c..000000000000 --- a/tests/ui/pin-ergonomics/coerce-non-pointer-pin.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `pin_ergonomics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/coerce-non-pointer-pin.rs:3:12 - | -LL | #![feature(pin_ergonomics)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #130494 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr index 0e55a5170284..e35e22d0ec24 100644 --- a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr @@ -8,7 +8,7 @@ LL | let Foo { x, y } = foo.as_mut(); | = note: expected struct `Pin<&mut Foo>` found struct `Foo<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let Foo { x, y } = *foo.as_mut(); | + @@ -23,7 +23,7 @@ LL | Foo { x, y } => {} | = note: expected struct `Pin<&mut Foo>` found struct `Foo<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *foo.as_mut() { | + @@ -38,7 +38,7 @@ LL | Foo { x, y } => {} | = note: expected struct `Pin<&mut Foo>` found struct `Foo<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let _ = || match *foo.as_mut() { | + @@ -53,7 +53,7 @@ LL | let Foo { x, y } = foo; | = note: expected struct `Pin<&Foo>` found struct `Foo<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let Foo { x, y } = *foo; | + @@ -68,7 +68,7 @@ LL | Foo { x, y } => {} | = note: expected struct `Pin<&Foo>` found struct `Foo<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *foo { | + @@ -83,7 +83,7 @@ LL | Foo { x, y } => {} | = note: expected struct `Pin<&Foo>` found struct `Foo<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let _ = || match *foo { | + @@ -98,7 +98,7 @@ LL | let Bar(x, y) = bar.as_mut(); | = note: expected struct `Pin<&mut Bar>` found struct `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let Bar(x, y) = *bar.as_mut(); | + @@ -113,7 +113,7 @@ LL | Bar(x, y) => {} | = note: expected struct `Pin<&mut Bar>` found struct `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *bar.as_mut() { | + @@ -128,7 +128,7 @@ LL | Bar(x, y) => {} | = note: expected struct `Pin<&mut Bar>` found struct `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let _ = || match *bar.as_mut() { | + @@ -143,7 +143,7 @@ LL | let Bar(x, y) = bar; | = note: expected struct `Pin<&Bar>` found struct `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let Bar(x, y) = *bar; | + @@ -158,7 +158,7 @@ LL | Bar(x, y) => {} | = note: expected struct `Pin<&Bar>` found struct `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *bar { | + @@ -173,7 +173,7 @@ LL | Bar(x, y) => {} | = note: expected struct `Pin<&Bar>` found struct `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let _ = || match *bar { | + @@ -188,7 +188,7 @@ LL | let NonPinProject { x } = foo; | = note: expected struct `Pin<&mut NonPinProject>` found struct `NonPinProject<_>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let NonPinProject { x } = *foo; | + @@ -203,7 +203,7 @@ LL | let NonPinProject { x } = bar; | = note: expected struct `Pin<&NonPinProject>` found struct `NonPinProject<_>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let NonPinProject { x } = *bar; | + @@ -218,7 +218,7 @@ LL | NonPinProject { x } => {} | = note: expected struct `Pin<&mut NonPinProject>` found struct `NonPinProject<_>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *foo { | + @@ -233,7 +233,7 @@ LL | NonPinProject { x } => {} | = note: expected struct `Pin<&NonPinProject>` found struct `NonPinProject<_>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *bar { | + diff --git a/tests/ui/pin-ergonomics/pattern-matching.normal.stderr b/tests/ui/pin-ergonomics/pattern-matching.normal.stderr index 8ec481fba9e0..409013c34024 100644 --- a/tests/ui/pin-ergonomics/pattern-matching.normal.stderr +++ b/tests/ui/pin-ergonomics/pattern-matching.normal.stderr @@ -28,7 +28,7 @@ LL | let Foo { x, y } = foo_mut; | = note: expected struct `Pin<&mut Foo>` found struct `Foo<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let Foo { x, y } = *foo_mut; | + @@ -43,7 +43,7 @@ LL | let Foo { x, y } = foo_const; | = note: expected struct `Pin<&Foo>` found struct `Foo<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let Foo { x, y } = *foo_const; | + @@ -58,7 +58,7 @@ LL | Bar::Foo(x, y) => { | = note: expected struct `Pin<&mut Bar>` found enum `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *bar_mut { | + @@ -73,7 +73,7 @@ LL | _ if let Bar::Bar { x, y } = bar_mut => { | = note: expected struct `Pin<&mut Bar>` found enum `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | _ if let Bar::Bar { x, y } = *bar_mut => { | + @@ -88,7 +88,7 @@ LL | Bar::Bar { x, y } => { | = note: expected struct `Pin<&Bar>` found enum `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | match *bar_const { | + @@ -103,7 +103,7 @@ LL | _ if let Bar::Foo(x, y) = bar_const => { | = note: expected struct `Pin<&Bar>` found enum `Bar<_, _>` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | _ if let Bar::Foo(x, y) = *bar_const => { | + @@ -118,7 +118,7 @@ LL | let (Foo { x, y },) = foo_mut; | = note: expected struct `Pin<&mut (Foo,)>` found tuple `(_,)` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let (Foo { x, y },) = *foo_mut; | + @@ -133,7 +133,7 @@ LL | let (Foo { x, y },) = foo_const; | = note: expected struct `Pin<&(Foo,)>` found tuple `(_,)` -help: consider dereferencing to access the inner value using the Deref trait +help: consider dereferencing to access the inner value using the `Deref` trait | LL | let (Foo { x, y },) = *foo_const; | + diff --git a/tests/ui/pin-ergonomics/pin-coercion-check.normal.stderr b/tests/ui/pin-ergonomics/pin-coercion-check.normal.stderr new file mode 100644 index 000000000000..0806ad64448c --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion-check.normal.stderr @@ -0,0 +1,227 @@ +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:9:36 + | +LL | |x: Pin<&mut T>| -> &mut T { x.get_mut() }; + | ^^^^^^^ the trait `Unpin` is not implemented for `T` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope +note: required by a bound in `Pin::<&'a mut T>::get_mut` + --> $SRC_DIR/core/src/pin.rs:LL:COL +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn get() { + | ++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:18:34 + | +LL | |x: Pin<&mut T>| -> &mut T { x }; + | ------ ^ expected `&mut T`, found `Pin<&mut T>` + | | + | expected `&mut T` because of return type + | + = note: expected mutable reference `&mut T` + found struct `Pin<&mut T>` +help: consider mutably borrowing here + | +LL | |x: Pin<&mut T>| -> &mut T { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:21:30 + | +LL | |x: Pin<&mut T>| -> &T { x }; + | -- ^ expected `&T`, found `Pin<&mut T>` + | | + | expected `&T` because of return type + | + = note: expected reference `&T` + found struct `Pin<&mut T>` +help: consider borrowing here + | +LL | |x: Pin<&mut T>| -> &T { &x }; + | + + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:24:26 + | +LL | |x: Pin<&T>| -> &T { x }; + | -- ^ expected `&T`, found `Pin<&T>` + | | + | expected `&T` because of return type + | + = note: expected reference `&T` + found struct `Pin<&T>` +help: consider borrowing here + | +LL | |x: Pin<&T>| -> &T { &x }; + | + + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:27:30 + | +LL | |x: Pin<&T>| -> &mut T { x }; + | ------ ^ expected `&mut T`, found `Pin<&T>` + | | + | expected `&mut T` because of return type + | + = note: expected mutable reference `&mut T` + found struct `Pin<&T>` +help: consider mutably borrowing here + | +LL | |x: Pin<&T>| -> &mut T { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:31:34 + | +LL | |x: Pin<&mut U>| -> &mut U { x }; + | ------ ^ expected `&mut U`, found `Pin<&mut U>` + | | + | expected `&mut U` because of return type + | + = note: expected mutable reference `&mut U` + found struct `Pin<&mut U>` +help: consider mutably borrowing here + | +LL | |x: Pin<&mut U>| -> &mut U { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:33:30 + | +LL | |x: Pin<&mut U>| -> &U { x }; + | -- ^ expected `&U`, found `Pin<&mut U>` + | | + | expected `&U` because of return type + | + = note: expected reference `&U` + found struct `Pin<&mut U>` +help: consider borrowing here + | +LL | |x: Pin<&mut U>| -> &U { &x }; + | + + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:35:26 + | +LL | |x: Pin<&U>| -> &U { x }; + | -- ^ expected `&U`, found `Pin<&U>` + | | + | expected `&U` because of return type + | + = note: expected reference `&U` + found struct `Pin<&U>` +help: consider borrowing here + | +LL | |x: Pin<&U>| -> &U { &x }; + | + + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:37:30 + | +LL | |x: Pin<&U>| -> &mut U { x }; + | ------ ^ expected `&mut U`, found `Pin<&U>` + | | + | expected `&mut U` because of return type + | + = note: expected mutable reference `&mut U` + found struct `Pin<&U>` +help: consider mutably borrowing here + | +LL | |x: Pin<&U>| -> &mut U { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:43:34 + | +LL | |x: &mut T| -> Pin<&mut T> { x }; + | ----------- ^ expected `Pin<&mut T>`, found `&mut T` + | | + | expected `Pin<&mut T>` because of return type + | + = note: expected struct `Pin<&mut T>` + found mutable reference `&mut T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:46:30 + | +LL | |x: &mut T| -> Pin<&T> { x }; + | ------- ^ expected `Pin<&T>`, found `&mut T` + | | + | expected `Pin<&T>` because of return type + | + = note: expected struct `Pin<&T>` + found mutable reference `&mut T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:49:26 + | +LL | |x: &T| -> Pin<&T> { x }; + | ------- ^ expected `Pin<&T>`, found `&T` + | | + | expected `Pin<&T>` because of return type + | + = note: expected struct `Pin<&T>` + found reference `&T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:52:30 + | +LL | |x: &T| -> Pin<&mut T> { x }; + | ----------- ^ expected `Pin<&mut T>`, found `&T` + | | + | expected `Pin<&mut T>` because of return type + | + = note: expected struct `Pin<&mut T>` + found reference `&T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:56:34 + | +LL | |x: &mut U| -> Pin<&mut U> { x }; + | ----------- ^ expected `Pin<&mut U>`, found `&mut U` + | | + | expected `Pin<&mut U>` because of return type + | + = note: expected struct `Pin<&mut U>` + found mutable reference `&mut U` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:58:30 + | +LL | |x: &mut U| -> Pin<&U> { x }; + | ------- ^ expected `Pin<&U>`, found `&mut U` + | | + | expected `Pin<&U>` because of return type + | + = note: expected struct `Pin<&U>` + found mutable reference `&mut U` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:60:26 + | +LL | |x: &U| -> Pin<&U> { x }; + | ------- ^ expected `Pin<&U>`, found `&U` + | | + | expected `Pin<&U>` because of return type + | + = note: expected struct `Pin<&U>` + found reference `&U` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:62:30 + | +LL | |x: &U| -> Pin<&mut U> { x }; + | ----------- ^ expected `Pin<&mut U>`, found `&U` + | | + | expected `Pin<&mut U>` because of return type + | + = note: expected struct `Pin<&mut U>` + found reference `&U` + +error: aborting due to 17 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr b/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr new file mode 100644 index 000000000000..3dc59cecb3c1 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr @@ -0,0 +1,155 @@ +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:9:36 + | +LL | |x: Pin<&mut T>| -> &mut T { x.get_mut() }; + | ^^^^^^^ the trait `Unpin` is not implemented for `T` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope +note: required by a bound in `Pin::<&'a mut T>::get_mut` + --> $SRC_DIR/core/src/pin.rs:LL:COL +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn get() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:18:34 + | +LL | |x: Pin<&mut T>| -> &mut T { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `Pin<&mut T>` to `&mut T` +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn pin_to_ref() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:21:30 + | +LL | |x: Pin<&mut T>| -> &T { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `Pin<&mut T>` to `&T` +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn pin_to_ref() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:24:26 + | +LL | |x: Pin<&T>| -> &T { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `Pin<&T>` to `&T` +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn pin_to_ref() { + | ++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:27:30 + | +LL | |x: Pin<&T>| -> &mut T { x }; + | ------ ^ types differ in mutability + | | + | expected `&mut T` because of return type + | + = note: expected mutable reference `&mut T` + found struct `Pin<&T>` +help: consider mutably borrowing here + | +LL | |x: Pin<&T>| -> &mut T { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:37:30 + | +LL | |x: Pin<&U>| -> &mut U { x }; + | ------ ^ types differ in mutability + | | + | expected `&mut U` because of return type + | + = note: expected mutable reference `&mut U` + found struct `Pin<&U>` +help: consider mutably borrowing here + | +LL | |x: Pin<&U>| -> &mut U { &mut x }; + | ++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:43:34 + | +LL | |x: &mut T| -> Pin<&mut T> { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `&mut T` to `Pin<&mut T>` +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn ref_to_pin() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:46:30 + | +LL | |x: &mut T| -> Pin<&T> { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `&mut T` to `Pin<&T>` +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn ref_to_pin() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:49:26 + | +LL | |x: &T| -> Pin<&T> { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `&T` to `Pin<&T>` +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn ref_to_pin() { + | ++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:52:30 + | +LL | |x: &T| -> Pin<&mut T> { x }; + | ----------- ^ types differ in mutability + | | + | expected `Pin<&mut T>` because of return type + | + = note: expected struct `Pin<&mut T>` + found reference `&T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:62:30 + | +LL | |x: &U| -> Pin<&mut U> { x }; + | ----------- ^ types differ in mutability + | | + | expected `Pin<&mut U>` because of return type + | + = note: expected struct `Pin<&mut U>` + found reference `&U` + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/pin-ergonomics/pin-coercion-check.rs b/tests/ui/pin-ergonomics/pin-coercion-check.rs new file mode 100644 index 000000000000..9b51851219cc --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion-check.rs @@ -0,0 +1,66 @@ +//@ revisions: pin_ergonomics normal +//@ edition:2024 +#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))] +#![allow(incomplete_features)] + +use std::pin::Pin; + +fn get() { + |x: Pin<&mut T>| -> &mut T { x.get_mut() }; //~ ERROR `T` cannot be unpinned + |x: Pin<&T>| -> &T { x.get_ref() }; + + |x: Pin<&mut U>| -> &mut U { x.get_mut() }; + |x: Pin<&U>| -> &U { x.get_ref() }; +} + +fn pin_to_ref() { + // T: !Unpin + |x: Pin<&mut T>| -> &mut T { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: Pin<&mut T>| -> &T { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: Pin<&T>| -> &T { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: Pin<&T>| -> &mut T { x }; + //~^ ERROR mismatched types + + // U: Unpin + |x: Pin<&mut U>| -> &mut U { x }; + //[normal]~^ ERROR mismatched types + |x: Pin<&mut U>| -> &U { x }; + //[normal]~^ ERROR mismatched types + |x: Pin<&U>| -> &U { x }; + //[normal]~^ ERROR mismatched types + |x: Pin<&U>| -> &mut U { x }; + //~^ ERROR mismatched types +} + +fn ref_to_pin() { + // T: !Unpin + |x: &mut T| -> Pin<&mut T> { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: &mut T| -> Pin<&T> { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: &T| -> Pin<&T> { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: &T| -> Pin<&mut T> { x }; + //~^ ERROR mismatched types + + // U: Unpin + |x: &mut U| -> Pin<&mut U> { x }; + //[normal]~^ ERROR mismatched types + |x: &mut U| -> Pin<&U> { x }; + //[normal]~^ ERROR mismatched types + |x: &U| -> Pin<&U> { x }; + //[normal]~^ ERROR mismatched types + |x: &U| -> Pin<&mut U> { x }; + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pin-coercion.rs b/tests/ui/pin-ergonomics/pin-coercion.rs new file mode 100644 index 000000000000..6ace4b97edb3 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion.rs @@ -0,0 +1,56 @@ +//@ run-pass +//@ edition:2024 +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] +#![deny(dead_code)] + +use std::cell::RefCell; + +fn coerce_mut_to_pin_mut(x: &mut T) -> &pin mut T { + x +} +fn coerce_ref_to_pin_ref(x: &T) -> &pin const T { + x +} +fn coerce_pin_mut_to_mut(x: &pin mut T) -> &mut T { + x +} +fn coerce_pin_ref_to_ref(x: &pin const T) -> &T { + x +} + +fn coerce_pin_mut_to_ref(x: &pin mut T) -> &T { + x +} +fn coerce_mut_to_pin_ref(x: &mut T) -> &pin const T { + x +} + +fn test(x: &mut RefCell) { + let mut x: &pin mut _ = coerce_mut_to_pin_mut(x); + x.get_mut().get_mut().push_str("&mut T -> &pin mut T\n"); + let x_ref: &_ = coerce_pin_mut_to_ref(x.as_mut()); + x_ref.borrow_mut().push_str("&pin mut T -> &T\n"); + let x: &mut _ = coerce_pin_mut_to_mut(x); + x.get_mut().push_str("&pin mut T -> &mut T\n"); + let x: &pin const _ = coerce_mut_to_pin_ref(x); + x.borrow_mut().push_str("&mut T -> &pin const T\n"); + let x: &_ = coerce_pin_ref_to_ref(x); + x.borrow_mut().push_str("&pin const T -> &T\n"); + let x: &pin const _ = coerce_ref_to_pin_ref(x); + x.borrow_mut().push_str("&T -> &pin const T\n"); +} + +fn main() { + let mut x = RefCell::new(String::new()); + test(&mut x); + assert_eq!( + x.borrow().as_str(), + "&mut T -> &pin mut T\n\ + &pin mut T -> &T\n\ + &pin mut T -> &mut T\n\ + &mut T -> &pin const T\n\ + &pin const T -> &T\n\ + &T -> &pin const T\n" + ); +} diff --git a/tests/ui/pin-ergonomics/pin-pattern.stderr b/tests/ui/pin-ergonomics/pin-pattern.stderr index 49f7a396f3ce..c0e8b2d40c70 100644 --- a/tests/ui/pin-ergonomics/pin-pattern.stderr +++ b/tests/ui/pin-ergonomics/pin-pattern.stderr @@ -91,8 +91,7 @@ error[E0507]: cannot move out of `foo_mut.pointer` which is behind a mutable ref LL | let &pin mut Foo(x) = foo_mut; | - ^^^^^^^ | | - | data moved here - | move occurs because `x` has type `T`, which does not implement the `Copy` trait + | data moved here because `x` has type `T`, which does not implement the `Copy` trait | help: consider removing the pinned mutable borrow | @@ -106,8 +105,7 @@ error[E0507]: cannot move out of `foo_const.pointer` which is behind a shared re LL | let &pin const Foo(x) = foo_const; | - ^^^^^^^^^ | | - | data moved here - | move occurs because `x` has type `T`, which does not implement the `Copy` trait + | data moved here because `x` has type `T`, which does not implement the `Copy` trait | help: consider removing the pinned borrow | @@ -138,8 +136,7 @@ error[E0507]: cannot move out of a mutable reference LL | ((&pin mut x,),): &'a pin mut (&'a mut (&'a pin mut Foo,),), | ^^^^^^^^^^^-^^^^ | | - | data moved here - | move occurs because `x` has type `Foo`, which does not implement the `Copy` trait + | data moved here because `x` has type `Foo`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.stderr b/tests/ui/pin-ergonomics/pin_v2-attr.stderr index 8f8a9f3b3a19..5c8a455114c4 100644 --- a/tests/ui/pin-ergonomics/pin_v2-attr.stderr +++ b/tests/ui/pin-ergonomics/pin_v2-attr.stderr @@ -116,14 +116,6 @@ LL | #[pin_v2] | = help: `#[pin_v2]` can only be applied to data types -error: `#[pin_v2]` attribute cannot be used on delegations - --> $DIR/pin_v2-attr.rs:58:5 - | -LL | #[pin_v2] - | ^^^^^^^^^ - | - = help: `#[pin_v2]` can only be applied to data types - error: `#[pin_v2]` attribute cannot be used on inherent methods --> $DIR/pin_v2-attr.rs:61:5 | @@ -308,5 +300,13 @@ LL | #[pin_v2] | = help: `#[pin_v2]` can only be applied to data types +error: `#[pin_v2]` attribute cannot be used on delegations + --> $DIR/pin_v2-attr.rs:58:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can only be applied to data types + error: aborting due to 39 previous errors diff --git a/tests/ui/precondition-checks/alignment.rs b/tests/ui/precondition-checks/alignment.rs index 038a625bed7e..3f0eae47a157 100644 --- a/tests/ui/precondition-checks/alignment.rs +++ b/tests/ui/precondition-checks/alignment.rs @@ -6,6 +6,6 @@ fn main() { unsafe { - std::ptr::Alignment::new_unchecked(0); + std::mem::Alignment::new_unchecked(0); } } diff --git a/tests/ui/privacy/private-in-public-warn.rs b/tests/ui/privacy/private-in-public-warn.rs index 6a0ac2b9ade7..299fe9a75d4c 100644 --- a/tests/ui/privacy/private-in-public-warn.rs +++ b/tests/ui/privacy/private-in-public-warn.rs @@ -49,10 +49,10 @@ pub trait Tr3 { fn f(arg: T) {} //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::f` fn g() -> impl PrivTr; - //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::g::{anon_assoc#0}` + //~^ ERROR private trait `traits::PrivTr` in public interface //~| ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::g::{anon_assoc#0}` fn h() -> impl PrivTr {} - //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::h::{anon_assoc#0}` + //~^ ERROR private trait `traits::PrivTr` in public interface //~| ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::h::{anon_assoc#0}` } impl Pub {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Pub` @@ -93,13 +93,13 @@ pub trait Tr4: PubTr> {} //~ ERROR type `generics::Priv` is more priva pub trait Tr5 { fn required() -> impl PrivTr>; - //~^ ERROR trait `generics::PrivTr>` is more private than the item `Tr5::required::{anon_assoc#0}` - //~| ERROR type `generics::Priv<()>` is more private than the item `Tr5::required::{anon_assoc#0}` + //~^ ERROR private trait `generics::PrivTr>` in public interface + //~| ERROR private type `generics::Priv<()>` in public interface //~| ERROR trait `generics::PrivTr>` is more private than the item `Tr5::required::{anon_assoc#0}` //~| ERROR type `generics::Priv<()>` is more private than the item `Tr5::required::{anon_assoc#0}` fn provided() -> impl PrivTr> {} - //~^ ERROR trait `generics::PrivTr>` is more private than the item `Tr5::provided::{anon_assoc#0}` - //~| ERROR type `generics::Priv<()>` is more private than the item `Tr5::provided::{anon_assoc#0}` + //~^ ERROR private trait `generics::PrivTr>` in public interface + //~| ERROR private type `generics::Priv<()>` in public interface //~| ERROR trait `generics::PrivTr>` is more private than the item `Tr5::provided::{anon_assoc#0}` //~| ERROR type `generics::Priv<()>` is more private than the item `Tr5::provided::{anon_assoc#0}` } diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr index 1fd648f13a8c..649b117b40af 100644 --- a/tests/ui/privacy/private-in-public-warn.stderr +++ b/tests/ui/privacy/private-in-public-warn.stderr @@ -194,17 +194,14 @@ note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` LL | trait PrivTr {} | ^^^^^^^^^^^^ -error: trait `traits::PrivTr` is more private than the item `traits::Tr3::g::{anon_assoc#0}` +error[E0446]: private trait `traits::PrivTr` in public interface --> $DIR/private-in-public-warn.rs:51:19 | -LL | fn g() -> impl PrivTr; - | ^^^^^^^^^^^ opaque type `traits::Tr3::g::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:37:5 - | LL | trait PrivTr {} - | ^^^^^^^^^^^^ + | ------------ `traits::PrivTr` declared as private +... +LL | fn g() -> impl PrivTr; + | ^^^^^^^^^^^ can't leak private trait error: trait `traits::PrivTr` is more private than the item `traits::Tr3::g::{anon_assoc#0}` --> $DIR/private-in-public-warn.rs:51:19 @@ -218,17 +215,14 @@ note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` LL | trait PrivTr {} | ^^^^^^^^^^^^ -error: trait `traits::PrivTr` is more private than the item `traits::Tr3::h::{anon_assoc#0}` +error[E0446]: private trait `traits::PrivTr` in public interface --> $DIR/private-in-public-warn.rs:54:19 | -LL | fn h() -> impl PrivTr {} - | ^^^^^^^^^^^ opaque type `traits::Tr3::h::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but trait `traits::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:37:5 - | LL | trait PrivTr {} - | ^^^^^^^^^^^^ + | ------------ `traits::PrivTr` declared as private +... +LL | fn h() -> impl PrivTr {} + | ^^^^^^^^^^^ can't leak private trait error: trait `traits::PrivTr` is more private than the item `traits::Tr3::h::{anon_assoc#0}` --> $DIR/private-in-public-warn.rs:54:19 @@ -350,29 +344,23 @@ note: but type `generics::Priv` is only usable at visibility `pub(self)` LL | struct Priv(T); | ^^^^^^^^^^^^^^^^^^^ -error: trait `generics::PrivTr>` is more private than the item `Tr5::required::{anon_assoc#0}` +error[E0446]: private trait `generics::PrivTr>` in public interface --> $DIR/private-in-public-warn.rs:95:26 | -LL | fn required() -> impl PrivTr>; - | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::required::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but trait `generics::PrivTr>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:84:5 - | LL | trait PrivTr {} - | ^^^^^^^^^^^^^^^ + | --------------- `generics::PrivTr>` declared as private +... +LL | fn required() -> impl PrivTr>; + | ^^^^^^^^^^^^^^^^^^^^^ can't leak private trait -error: type `generics::Priv<()>` is more private than the item `Tr5::required::{anon_assoc#0}` +error[E0446]: private type `generics::Priv<()>` in public interface --> $DIR/private-in-public-warn.rs:95:26 | -LL | fn required() -> impl PrivTr>; - | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::required::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but type `generics::Priv<()>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:82:5 - | LL | struct Priv(T); - | ^^^^^^^^^^^^^^^^^^^ + | ------------------- `generics::Priv<()>` declared as private +... +LL | fn required() -> impl PrivTr>; + | ^^^^^^^^^^^^^^^^^^^^^ can't leak private type error: trait `generics::PrivTr>` is more private than the item `Tr5::required::{anon_assoc#0}` --> $DIR/private-in-public-warn.rs:95:26 @@ -398,29 +386,23 @@ note: but type `generics::Priv<()>` is only usable at visibility `pub(self)` LL | struct Priv(T); | ^^^^^^^^^^^^^^^^^^^ -error: trait `generics::PrivTr>` is more private than the item `Tr5::provided::{anon_assoc#0}` +error[E0446]: private trait `generics::PrivTr>` in public interface --> $DIR/private-in-public-warn.rs:100:26 | -LL | fn provided() -> impl PrivTr> {} - | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::provided::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but trait `generics::PrivTr>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:84:5 - | LL | trait PrivTr {} - | ^^^^^^^^^^^^^^^ + | --------------- `generics::PrivTr>` declared as private +... +LL | fn provided() -> impl PrivTr> {} + | ^^^^^^^^^^^^^^^^^^^^^ can't leak private trait -error: type `generics::Priv<()>` is more private than the item `Tr5::provided::{anon_assoc#0}` +error[E0446]: private type `generics::Priv<()>` in public interface --> $DIR/private-in-public-warn.rs:100:26 | -LL | fn provided() -> impl PrivTr> {} - | ^^^^^^^^^^^^^^^^^^^^^ opaque type `Tr5::provided::{anon_assoc#0}` is reachable at visibility `pub(crate)` - | -note: but type `generics::Priv<()>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:82:5 - | LL | struct Priv(T); - | ^^^^^^^^^^^^^^^^^^^ + | ------------------- `generics::Priv<()>` declared as private +... +LL | fn provided() -> impl PrivTr> {} + | ^^^^^^^^^^^^^^^^^^^^^ can't leak private type error: trait `generics::PrivTr>` is more private than the item `Tr5::provided::{anon_assoc#0}` --> $DIR/private-in-public-warn.rs:100:26 diff --git a/tests/ui/privacy/private-unit-struct-assignment.stderr b/tests/ui/privacy/private-unit-struct-assignment.stderr index 8c36a08846d8..110ee19d5ff4 100644 --- a/tests/ui/privacy/private-unit-struct-assignment.stderr +++ b/tests/ui/privacy/private-unit-struct-assignment.stderr @@ -13,9 +13,6 @@ LL | struct C; error[E0308]: mismatched types --> $DIR/private-unit-struct-assignment.rs:8:5 | -LL | struct C; - | -------- unit struct defined here -... LL | A::C = 1; | ^^^^ - this expression has type `{integer}` | | diff --git a/tests/ui/privacy/ufc-method-call.different_name.stderr b/tests/ui/privacy/ufc-method-call.different_name.stderr index 16496c480dd1..5d722c62255f 100644 --- a/tests/ui/privacy/ufc-method-call.different_name.stderr +++ b/tests/ui/privacy/ufc-method-call.different_name.stderr @@ -1,14 +1,13 @@ -error[E0599]: no function or associated item named `foo` found for struct `Foo` in the current scope +error[E0599]: no associated function or constant named `foo` found for struct `Foo` in the current scope --> $DIR/ufc-method-call.rs:27:27 | LL | pub struct Foo(T); - | ----------------- function or associated item `foo` not found for this struct + | ----------------- associated function or constant `foo` not found for this struct ... LL | test::Foo::::foo(); - | ^^^ function or associated item not found in `Foo` + | ^^^ associated function or constant not found in `Foo` | - = note: the function or associated item was found for - - `Foo` + = note: the associated function or constant was found for `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/privacy/ufc-method-call.rs b/tests/ui/privacy/ufc-method-call.rs index 525d9a9eee90..87efbc79ea24 100644 --- a/tests/ui/privacy/ufc-method-call.rs +++ b/tests/ui/privacy/ufc-method-call.rs @@ -26,5 +26,5 @@ fn bar() {} fn main() { test::Foo::::foo(); //[same_name]~^ ERROR associated function `foo` is private - //[different_name]~^^ ERROR no function or associated item named `foo` found for struct `Foo` + //[different_name]~^^ ERROR no associated function or constant named `foo` found for struct `Foo` } diff --git a/tests/ui/proc-macro/any-panic-payload.rs b/tests/ui/proc-macro/any-panic-payload.rs new file mode 100644 index 000000000000..7a83a4e73a04 --- /dev/null +++ b/tests/ui/proc-macro/any-panic-payload.rs @@ -0,0 +1,17 @@ +//! Make sure that proc-macros which panic with a payload other than +//! `String` or `&'static str` do not ICE. +//@ proc-macro: any-panic-payload.rs + +extern crate any_panic_payload; + +use any_panic_payload::*; + +cause_panic!(); //~ ERROR proc macro panicked + +#[cause_panic_attr] //~ ERROR custom attribute panicked +struct A; + +#[derive(CausePanic)] //~ ERROR proc-macro derive panicked +struct B; + +fn main() {} diff --git a/tests/ui/proc-macro/any-panic-payload.stderr b/tests/ui/proc-macro/any-panic-payload.stderr new file mode 100644 index 000000000000..bb369b80e920 --- /dev/null +++ b/tests/ui/proc-macro/any-panic-payload.stderr @@ -0,0 +1,20 @@ +error: proc macro panicked + --> $DIR/any-panic-payload.rs:9:1 + | +LL | cause_panic!(); + | ^^^^^^^^^^^^^^ + +error: custom attribute panicked + --> $DIR/any-panic-payload.rs:11:1 + | +LL | #[cause_panic_attr] + | ^^^^^^^^^^^^^^^^^^^ + +error: proc-macro derive panicked + --> $DIR/any-panic-payload.rs:14:10 + | +LL | #[derive(CausePanic)] + | ^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/proc-macro/auxiliary/any-panic-payload.rs b/tests/ui/proc-macro/auxiliary/any-panic-payload.rs new file mode 100644 index 000000000000..e78f82506831 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/any-panic-payload.rs @@ -0,0 +1,22 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; + +fn boom() -> TokenStream { + std::panic::panic_any(42) +} + +#[proc_macro] +pub fn cause_panic(_: TokenStream) -> TokenStream { + boom() +} + +#[proc_macro_attribute] +pub fn cause_panic_attr(_: TokenStream, _: TokenStream) -> TokenStream { + boom() +} + +#[proc_macro_derive(CausePanic)] +pub fn cause_panic_derive(_: TokenStream) -> TokenStream { + boom() +} diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr index 09908160542d..1d7b5ab8c6af 100644 --- a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr +++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr @@ -5,7 +5,7 @@ LL | #![derive(Debug)] | ^^^^^^^^^^^^^^^^^ LL | #[allow(dead_code)] LL | struct Test {} - | ---- the inner attribute doesn't annotate this struct + | -------------- the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | diff --git a/tests/ui/proc-macro/macro-brackets.stderr b/tests/ui/proc-macro/macro-brackets.stderr index f14b5fed6b9e..00c1c6b0f4cf 100644 --- a/tests/ui/proc-macro/macro-brackets.stderr +++ b/tests/ui/proc-macro/macro-brackets.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/macro-brackets.rs:11:21 | LL | id![static X: u32 = 'a';]; - | ^^^ expected `u32`, found `char` + | --- ^^^ expected `u32`, found `char` + | | + | expected because of the type of the static | help: you can cast a `char` to a `u32`, since a `char` always occupies 4 bytes | diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index b5db9922b31a..a03e567bd48a 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,7 +1,7 @@ Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:26:37: 26:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:26:43: 26:44 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:26:44: 26:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:26:45: 26:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:26:50: 26:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:26:51: 26:53 (#3) }] Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }] -#![feature /* 0#0 */(prelude_import)] +#![feature /* 0#0 */(prelude_import /* 0#0 */)] //@ aux-build:make-macro.rs //@ proc-macro: meta-macro.rs //@ edition:2018 @@ -30,7 +30,8 @@ macro_rules! produce_it */ { () => { - meta_macro::print_def_site!($crate::dummy!()); + meta_macro /* 0#0 */::print_def_site /* 0#0 + */!($crate /* 0#0 */::dummy /* 0#0 */!()); // `print_def_site!` will respan the `$crate` identifier // with `Span::def_site()`. This should cause it to resolve // relative to `meta_macro`, *not* `make_macro` (despite diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index e45abab03b4c..61b55782e6e9 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -20,7 +20,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nonterminal-token-hygiene.rs:23:27: 23:32 (#4), }, ] -#![feature /* 0#0 */(prelude_import)] +#![feature /* 0#0 */(prelude_import /* 0#0 */)] #![no_std /* 0#0 */] // Make sure that marks from declarative macros are applied to tokens in nonterminal. @@ -34,7 +34,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ //@ proc-macro: test-macros.rs //@ edition: 2015 -#![feature /* 0#0 */(decl_macro)] +#![feature /* 0#0 */(decl_macro /* 0#0 */)] #![no_std /* 0#0 */] extern crate core /* 0#2 */; #[prelude_import /* 0#1 */] @@ -49,15 +49,22 @@ macro_rules! outer /* 0#0 */ { - ($item:item) => + ($item /* 0#0 */:item /* 0#0 */) => { - macro inner() { print_bang! { $item } } inner!(); + macro /* 0#0 */ inner /* 0#0 */() + { print_bang /* 0#0 */! { $item /* 0#0 */ } } inner /* 0#0 + */!(); }; } struct S /* 0#0 */; -macro inner /* 0#3 */ { () => { print_bang! { struct S; } } } +macro inner + /* + 0#3 + */ { + () => { print_bang /* 0#3 */! { struct /* 0#0 */ S /* 0#0 */; } } +} struct S /* 0#5 */; // OK, not a duplicate definition of `S` diff --git a/tests/ui/range/new_range_stability.rs b/tests/ui/range/new_range_stability.rs index 2d129fb6815f..71a0f02e5896 100644 --- a/tests/ui/range/new_range_stability.rs +++ b/tests/ui/range/new_range_stability.rs @@ -1,6 +1,12 @@ // Stable -use std::range::{RangeInclusive, RangeInclusiveIter, RangeToInclusive}; +use std::range::{ + RangeInclusive, + RangeInclusiveIter, + RangeToInclusive, + RangeFrom, + RangeFromIter, +}; fn range_inclusive(mut r: RangeInclusive) { &[1, 2, 3][r]; // Indexing @@ -13,7 +19,7 @@ fn range_inclusive(mut r: RangeInclusive) { let mut i = r.into_iter(); i.next(); - i.remainder(); + i.remainder(); //~ ERROR unstable } fn range_to_inclusive(mut r: RangeToInclusive) { @@ -23,15 +29,27 @@ fn range_to_inclusive(mut r: RangeToInclusive) { r.contains(&5); } +fn range_from(mut r: RangeFrom) { + &[1, 2, 3][r]; // Indexing + + r.start; + r.contains(&5); + r.iter(); + + let mut i = r.into_iter(); + i.next(); + + // Left unstable + i.remainder(); //~ ERROR unstable +} + // Unstable module use std::range::legacy; //~ ERROR unstable // Unstable types -use std::range::RangeFrom; //~ ERROR unstable use std::range::Range; //~ ERROR unstable -use std::range::RangeFromIter; //~ ERROR unstable use std::range::RangeIter; //~ ERROR unstable fn main() {} diff --git a/tests/ui/range/new_range_stability.stderr b/tests/ui/range/new_range_stability.stderr index b5a7e06e5f2e..64ef6a416687 100644 --- a/tests/ui/range/new_range_stability.stderr +++ b/tests/ui/range/new_range_stability.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:28:5 + --> $DIR/new_range_stability.rs:48:5 | LL | use std::range::legacy; | ^^^^^^^^^^^^^^^^^^ @@ -9,17 +9,7 @@ LL | use std::range::legacy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:32:5 - | -LL | use std::range::RangeFrom; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #125687 for more information - = help: add `#![feature(new_range_api)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:33:5 + --> $DIR/new_range_stability.rs:52:5 | LL | use std::range::Range; | ^^^^^^^^^^^^^^^^^ @@ -29,17 +19,7 @@ LL | use std::range::Range; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:34:5 - | -LL | use std::range::RangeFromIter; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #125687 for more information - = help: add `#![feature(new_range_api)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:35:5 + --> $DIR/new_range_stability.rs:53:5 | LL | use std::range::RangeIter; | ^^^^^^^^^^^^^^^^^^^^^ @@ -48,6 +28,26 @@ LL | use std::range::RangeIter; = help: add `#![feature(new_range_api)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: use of unstable library feature `new_range_remainder` + --> $DIR/new_range_stability.rs:22:7 + | +LL | i.remainder(); + | ^^^^^^^^^ + | + = note: see issue #154458 for more information + = help: add `#![feature(new_range_remainder)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `new_range_remainder` + --> $DIR/new_range_stability.rs:43:7 + | +LL | i.remainder(); + | ^^^^^^^^^ + | + = note: see issue #154458 for more information + = help: add `#![feature(new_range_remainder)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/reachable/never-pattern-closure-param-array.rs b/tests/ui/reachable/never-pattern-closure-param-array.rs new file mode 100644 index 000000000000..83bbc4b39b77 --- /dev/null +++ b/tests/ui/reachable/never-pattern-closure-param-array.rs @@ -0,0 +1,13 @@ +//@ check-pass +//@ edition: 2024 + +#![feature(never_patterns)] +#![allow(incomplete_features)] +#![allow(unreachable_code)] + +fn main() { + let _ = Some({ + return; + }) + .map(|!| [1]); +} diff --git a/tests/ui/recursion_limit/issue-40003.rs b/tests/ui/recursion/future-stream-buffer-unordered-40003.rs similarity index 100% rename from tests/ui/recursion_limit/issue-40003.rs rename to tests/ui/recursion/future-stream-buffer-unordered-40003.rs diff --git a/tests/ui/recursion/issue-23302-3.rs b/tests/ui/recursion/issue-23302-3.rs index da75f3307988..2e29433ae22d 100644 --- a/tests/ui/recursion/issue-23302-3.rs +++ b/tests/ui/recursion/issue-23302-3.rs @@ -1,5 +1,5 @@ const A: i32 = B; //~ ERROR cycle detected - +//@ ignore-parallel-frontend query cycle const B: i32 = A; fn main() { } diff --git a/tests/ui/recursion_limit/empty.rs b/tests/ui/recursion/recursion_limit/empty.rs similarity index 100% rename from tests/ui/recursion_limit/empty.rs rename to tests/ui/recursion/recursion_limit/empty.rs diff --git a/tests/ui/recursion_limit/empty.stderr b/tests/ui/recursion/recursion_limit/empty.stderr similarity index 100% rename from tests/ui/recursion_limit/empty.stderr rename to tests/ui/recursion/recursion_limit/empty.stderr diff --git a/tests/ui/recursion_limit/issue-105700.rs b/tests/ui/recursion/recursion_limit/invalid-attribute-105700.rs similarity index 100% rename from tests/ui/recursion_limit/issue-105700.rs rename to tests/ui/recursion/recursion_limit/invalid-attribute-105700.rs diff --git a/tests/ui/recursion_limit/issue-105700.stderr b/tests/ui/recursion/recursion_limit/invalid-attribute-105700.stderr similarity index 66% rename from tests/ui/recursion_limit/issue-105700.stderr rename to tests/ui/recursion/recursion_limit/invalid-attribute-105700.stderr index fd53d248c4e0..31e230cc6400 100644 --- a/tests/ui/recursion_limit/issue-105700.stderr +++ b/tests/ui/recursion/recursion_limit/invalid-attribute-105700.stderr @@ -1,10 +1,10 @@ error: recursion limit reached while expanding `#[invalid_attribute]` - --> $DIR/issue-105700.rs:6:1 + --> $DIR/invalid-attribute-105700.rs:6:1 | LL | #![invalid_attribute] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`issue_105700`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`invalid_attribute_105700`) error: aborting due to 1 previous error diff --git a/tests/ui/recursion_limit/invalid_digit.rs b/tests/ui/recursion/recursion_limit/invalid_digit.rs similarity index 100% rename from tests/ui/recursion_limit/invalid_digit.rs rename to tests/ui/recursion/recursion_limit/invalid_digit.rs diff --git a/tests/ui/recursion_limit/invalid_digit.stderr b/tests/ui/recursion/recursion_limit/invalid_digit.stderr similarity index 100% rename from tests/ui/recursion_limit/invalid_digit.stderr rename to tests/ui/recursion/recursion_limit/invalid_digit.stderr diff --git a/tests/ui/recursion_limit/invalid_digit_type.rs b/tests/ui/recursion/recursion_limit/invalid_digit_type.rs similarity index 100% rename from tests/ui/recursion_limit/invalid_digit_type.rs rename to tests/ui/recursion/recursion_limit/invalid_digit_type.rs diff --git a/tests/ui/recursion_limit/invalid_digit_type.stderr b/tests/ui/recursion/recursion_limit/invalid_digit_type.stderr similarity index 100% rename from tests/ui/recursion_limit/invalid_digit_type.stderr rename to tests/ui/recursion/recursion_limit/invalid_digit_type.stderr diff --git a/tests/ui/recursion_limit/invalid_macro.rs b/tests/ui/recursion/recursion_limit/invalid_macro.rs similarity index 100% rename from tests/ui/recursion_limit/invalid_macro.rs rename to tests/ui/recursion/recursion_limit/invalid_macro.rs diff --git a/tests/ui/recursion_limit/invalid_macro.stderr b/tests/ui/recursion/recursion_limit/invalid_macro.stderr similarity index 100% rename from tests/ui/recursion_limit/invalid_macro.stderr rename to tests/ui/recursion/recursion_limit/invalid_macro.stderr diff --git a/tests/ui/recursion/recursion_limit/min-recursion-limit-attr-lower-than-default.rs b/tests/ui/recursion/recursion_limit/min-recursion-limit-attr-lower-than-default.rs new file mode 100644 index 000000000000..d9de45b5735e --- /dev/null +++ b/tests/ui/recursion/recursion_limit/min-recursion-limit-attr-lower-than-default.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Z min-recursion-limit=0 +//@ check-pass + +// Checks that `min-recursion-limit` cannot lower the default recursion limit + +macro_rules! count { + () => {}; + ($_:tt $($rest:tt)*) => { count!($($rest)*) }; +} + +fn main() { + // 100 + count!( + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + ); +} diff --git a/tests/ui/recursion/recursion_limit/min-recursion-limit-attr-wins.rs b/tests/ui/recursion/recursion_limit/min-recursion-limit-attr-wins.rs new file mode 100644 index 000000000000..44c9f76f3785 --- /dev/null +++ b/tests/ui/recursion/recursion_limit/min-recursion-limit-attr-wins.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Z min-recursion-limit=256 +//@ check-pass +#![recursion_limit = "128"] + +macro_rules! count { + () => {}; + ($_:tt $($rest:tt)*) => { count!($($rest)*) }; +} + +fn main() { + // 200 + count!( + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + ); +} diff --git a/tests/ui/recursion/recursion_limit/min-recursion-limit-cli-wins.rs b/tests/ui/recursion/recursion_limit/min-recursion-limit-cli-wins.rs new file mode 100644 index 000000000000..10dc9cfe06b2 --- /dev/null +++ b/tests/ui/recursion/recursion_limit/min-recursion-limit-cli-wins.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Z min-recursion-limit=64 +//@ check-pass +#![recursion_limit = "256"] + +macro_rules! count { + () => {}; + ($_:tt $($rest:tt)*) => { count!($($rest)*) }; +} + +fn main() { + // 200 + count!( + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + ); +} diff --git a/tests/ui/recursion/recursion_limit/min-recursion-limit-no-attr.rs b/tests/ui/recursion/recursion_limit/min-recursion-limit-no-attr.rs new file mode 100644 index 000000000000..f918ec86c141 --- /dev/null +++ b/tests/ui/recursion/recursion_limit/min-recursion-limit-no-attr.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Z min-recursion-limit=256 +//@ check-pass + +macro_rules! count { + () => {}; + ($_:tt $($rest:tt)*) => { count!($($rest)*) }; +} + +fn main() { + // 200 + count!( + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + a a a a a a a a a a a a a a a a a a a a + ); +} diff --git a/tests/ui/recursion_limit/no-value.rs b/tests/ui/recursion/recursion_limit/no-value.rs similarity index 100% rename from tests/ui/recursion_limit/no-value.rs rename to tests/ui/recursion/recursion_limit/no-value.rs diff --git a/tests/ui/recursion_limit/no-value.stderr b/tests/ui/recursion/recursion_limit/no-value.stderr similarity index 100% rename from tests/ui/recursion_limit/no-value.stderr rename to tests/ui/recursion/recursion_limit/no-value.stderr diff --git a/tests/ui/recursion_limit/overflow.rs b/tests/ui/recursion/recursion_limit/overflow.rs similarity index 100% rename from tests/ui/recursion_limit/overflow.rs rename to tests/ui/recursion/recursion_limit/overflow.rs diff --git a/tests/ui/recursion_limit/overflow.stderr b/tests/ui/recursion/recursion_limit/overflow.stderr similarity index 100% rename from tests/ui/recursion_limit/overflow.stderr rename to tests/ui/recursion/recursion_limit/overflow.stderr diff --git a/tests/ui/recursion_limit/zero-overflow.rs b/tests/ui/recursion/recursion_limit/zero-overflow.rs similarity index 100% rename from tests/ui/recursion_limit/zero-overflow.rs rename to tests/ui/recursion/recursion_limit/zero-overflow.rs diff --git a/tests/ui/recursion_limit/zero-overflow.stderr b/tests/ui/recursion/recursion_limit/zero-overflow.stderr similarity index 100% rename from tests/ui/recursion_limit/zero-overflow.stderr rename to tests/ui/recursion/recursion_limit/zero-overflow.stderr diff --git a/tests/ui/recursion_limit/zero.rs b/tests/ui/recursion/recursion_limit/zero.rs similarity index 100% rename from tests/ui/recursion_limit/zero.rs rename to tests/ui/recursion/recursion_limit/zero.rs diff --git a/tests/ui/recursion_limit/zero.stderr b/tests/ui/recursion/recursion_limit/zero.stderr similarity index 100% rename from tests/ui/recursion_limit/zero.stderr rename to tests/ui/recursion/recursion_limit/zero.stderr diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs deleted file mode 100644 index 3d4a30507884..000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod rev_variant_struct_region { - struct Foo<'a> { - x: fn(&'a i32), - } - enum Bar<'a,'b> { - V(&'a Foo<'b>) - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs deleted file mode 100644 index 2e0d1b36ca59..000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_region { - struct Foo<'a> { - x: &'a i32, - } - enum Bar<'a,'b> { - V(&'a Foo<'b>) - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs deleted file mode 100644 index baf7874bc1a6..000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_type { - struct Foo { - x: fn(T) - } - enum Bar<'a,'b> { - V(&'a Foo<&'b i32>) - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs deleted file mode 100644 index b8392c967b10..000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_type { - struct Foo { - x: T - } - enum Bar<'a,'b> { - V(&'a Foo<&'b i32>) - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs deleted file mode 100644 index 6a50248cb70b..000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod rev_variant_struct_region { - struct Foo<'a> { - x: fn(&'a i32), - } - struct Bar<'a,'b> { - f: &'a Foo<'b> - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs deleted file mode 100644 index 17564bcbf269..000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_region { - struct Foo<'a> { - x: &'a i32, - } - struct Bar<'a,'b> { - f: &'a Foo<'b> - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs deleted file mode 100644 index 33961de7d6a4..000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod rev_variant_struct_type { - struct Foo { - x: fn(T) - } - struct Bar<'a,'b> { - f: &'a Foo<&'b i32> - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs deleted file mode 100644 index c5238086fc05..000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_type { - struct Foo { - x: T - } - struct Bar<'a,'b> { - f: &'a Foo<&'b i32> - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type.rs b/tests/ui/regions/regions-outlives-nominal-type.rs new file mode 100644 index 000000000000..177d064042dd --- /dev/null +++ b/tests/ui/regions/regions-outlives-nominal-type.rs @@ -0,0 +1,80 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +//@ check-pass + +mod variant_enum_region { + struct Foo<'a> { + x: &'a i32, + } + enum Bar<'a, 'b> { + V(&'a Foo<'b>), + } +} + +mod rev_variant_enum_region { + struct Foo<'a> { + x: fn(&'a i32), + } + enum Bar<'a, 'b> { + V(&'a Foo<'b>), + } +} + +mod variant_enum_type { + struct Foo { + x: T, + } + enum Bar<'a, 'b> { + V(&'a Foo<&'b i32>), + } +} + +mod rev_variant_enum_type { + struct Foo { + x: fn(T), + } + enum Bar<'a, 'b> { + V(&'a Foo<&'b i32>), + } +} + +mod variant_struct_region { + struct Foo<'a> { + x: &'a i32, + } + struct Bar<'a, 'b> { + f: &'a Foo<'b>, + } +} + +mod rev_variant_struct_region { + struct Foo<'a> { + x: fn(&'a i32), + } + struct Bar<'a, 'b> { + f: &'a Foo<'b>, + } +} + +mod variant_struct_type { + struct Foo { + x: T, + } + struct Bar<'a, 'b> { + f: &'a Foo<&'b i32>, + } +} + +mod rev_variant_struct_type { + struct Foo { + x: fn(T), + } + struct Bar<'a, 'b> { + f: &'a Foo<&'b i32>, + } +} + +fn main() {} diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index eb9581b8f7ae..e2cecf9973b8 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -15,24 +15,32 @@ error[E0308]: mismatched types | LL | let b = [0; ()]; | ^^ expected `usize`, found `()` + | + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:12:17 | LL | let c = [0; true]; | ^^^^ expected `usize`, found `bool` + | + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:15:17 | LL | let d = [0; 0.5]; | ^^^ expected `usize`, found floating-point number + | + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:18:17 | LL | let e = [0; "foo"]; | ^^^^^ expected `usize`, found `&str` + | + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:21:17 @@ -41,6 +49,7 @@ LL | let f = [0; -4_isize]; | ^^^^^^^^ expected `usize`, found `isize` | = note: `-4_isize` cannot fit into type `usize` + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:25:23 @@ -49,6 +58,7 @@ LL | let g = [0_usize; -1_isize]; | ^^^^^^^^ expected `usize`, found `isize` | = note: `-1_isize` cannot fit into type `usize` + = note: array length can only be `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:29:17 @@ -56,6 +66,7 @@ error[E0308]: mismatched types LL | let h = [0; 4u8]; | ^^^ expected `usize`, found `u8` | + = note: array length can only be `usize` help: change the type of the numeric literal from `u8` to `usize` | LL - let h = [0; 4u8]; @@ -67,6 +78,8 @@ error[E0308]: mismatched types | LL | let i = [0; I { i: () }]; | ^^^^^^^^^^^ expected `usize`, found `I` + | + = note: array length can only be `usize` error: aborting due to 9 previous errors diff --git a/tests/ui/empty/auxiliary/empty-struct.rs b/tests/ui/resolve/auxiliary/empty-struct.rs similarity index 100% rename from tests/ui/empty/auxiliary/empty-struct.rs rename to tests/ui/resolve/auxiliary/empty-struct.rs diff --git a/tests/ui/resolve/auxiliary/open-ns-mod-my_api.rs b/tests/ui/resolve/auxiliary/open-ns-mod-my_api.rs new file mode 100644 index 000000000000..dc8b5720c0c1 --- /dev/null +++ b/tests/ui/resolve/auxiliary/open-ns-mod-my_api.rs @@ -0,0 +1,9 @@ +pub mod utils { + pub fn root_helper() { + println!("root_helper"); + } +} + +pub fn root_function() -> String { + "my_api root!".to_string() +} diff --git a/tests/ui/resolve/auxiliary/open-ns-my_api.rs b/tests/ui/resolve/auxiliary/open-ns-my_api.rs new file mode 100644 index 000000000000..be4bf31f0fbc --- /dev/null +++ b/tests/ui/resolve/auxiliary/open-ns-my_api.rs @@ -0,0 +1,3 @@ +pub fn root_function() -> String { + "my_api root!".to_string() +} diff --git a/tests/ui/resolve/auxiliary/open-ns-my_api_core.rs b/tests/ui/resolve/auxiliary/open-ns-my_api_core.rs new file mode 100644 index 000000000000..41418f1516f6 --- /dev/null +++ b/tests/ui/resolve/auxiliary/open-ns-my_api_core.rs @@ -0,0 +1,15 @@ +// #![crate_name = "my_api::core"] + +pub mod util { + pub fn core_mod_fn() -> String { + format!("core_fn from my_api::core::util",) + } +} + +pub fn core_fn() -> String { + format!("core_fn from my_api::core!",) +} + +pub fn core_fn2() -> String { + format!("core_fn2 from my_api::core!",) +} diff --git a/tests/ui/resolve/auxiliary/open-ns-my_api_utils.rs b/tests/ui/resolve/auxiliary/open-ns-my_api_utils.rs new file mode 100644 index 000000000000..d2af20728bd5 --- /dev/null +++ b/tests/ui/resolve/auxiliary/open-ns-my_api_utils.rs @@ -0,0 +1,13 @@ +pub mod util { + pub fn util_mod_helper() -> String { + format!("Helper from my_api::utils::util",) + } +} + +pub fn utils_helper() -> String { + format!("Helper from my_api::utils!",) +} + +pub fn get_u32() -> u32 { + 1 +} diff --git a/tests/ui/empty/empty-struct-braces-expr.rs b/tests/ui/resolve/empty-struct-braces-expr.rs similarity index 78% rename from tests/ui/empty/empty-struct-braces-expr.rs rename to tests/ui/resolve/empty-struct-braces-expr.rs index c10f76b92196..f6a174290e34 100644 --- a/tests/ui/empty/empty-struct-braces-expr.rs +++ b/tests/ui/resolve/empty-struct-braces-expr.rs @@ -22,8 +22,8 @@ fn main() { let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1` let xe1 = XEmpty1(); //~^ ERROR expected function, tuple struct or tuple variant, found struct `XEmpty1` - let xe3 = XE::Empty3; //~ ERROR no variant or associated item named `Empty3` found for enum - let xe3 = XE::Empty3(); //~ ERROR no variant or associated item named `Empty3` found for enum + let xe3 = XE::Empty3; //~ ERROR no variant, associated function, or constant named `Empty3` found for enum + let xe3 = XE::Empty3(); //~ ERROR no variant, associated function, or constant named `Empty3` found for enum XE::Empty1 {}; //~ ERROR no variant named `Empty1` found for enum `empty_struct::XE` } diff --git a/tests/ui/empty/empty-struct-braces-expr.stderr b/tests/ui/resolve/empty-struct-braces-expr.stderr similarity index 89% rename from tests/ui/empty/empty-struct-braces-expr.stderr rename to tests/ui/resolve/empty-struct-braces-expr.stderr index a176107a06e2..f496708512a4 100644 --- a/tests/ui/empty/empty-struct-braces-expr.stderr +++ b/tests/ui/resolve/empty-struct-braces-expr.stderr @@ -117,22 +117,22 @@ LL - let xe1 = XEmpty1(); LL + let xe1 = XEmpty2(); | -error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope +error[E0599]: no variant, associated function, or constant named `Empty3` found for enum `empty_struct::XE` in the current scope --> $DIR/empty-struct-braces-expr.rs:25:19 | LL | let xe3 = XE::Empty3; - | ^^^^^^ variant or associated item not found in `empty_struct::XE` + | ^^^^^^ variant, associated function, or constant not found in `empty_struct::XE` | help: there is a variant with a similar name | LL | let xe3 = XE::XEmpty3; | + -error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope +error[E0599]: no variant, associated function, or constant named `Empty3` found for enum `empty_struct::XE` in the current scope --> $DIR/empty-struct-braces-expr.rs:26:19 | LL | let xe3 = XE::Empty3(); - | ^^^^^^ variant or associated item not found in `empty_struct::XE` + | ^^^^^^ variant, associated function, or constant not found in `empty_struct::XE` | help: there is a variant with a similar name | diff --git a/tests/ui/empty/empty-struct-braces-pat-1.rs b/tests/ui/resolve/empty-struct-braces-pat-1.rs similarity index 100% rename from tests/ui/empty/empty-struct-braces-pat-1.rs rename to tests/ui/resolve/empty-struct-braces-pat-1.rs diff --git a/tests/ui/empty/empty-struct-braces-pat-1.stderr b/tests/ui/resolve/empty-struct-braces-pat-1.stderr similarity index 100% rename from tests/ui/empty/empty-struct-braces-pat-1.stderr rename to tests/ui/resolve/empty-struct-braces-pat-1.stderr diff --git a/tests/ui/empty/empty-struct-braces-pat-2.rs b/tests/ui/resolve/empty-struct-braces-pat-2.rs similarity index 100% rename from tests/ui/empty/empty-struct-braces-pat-2.rs rename to tests/ui/resolve/empty-struct-braces-pat-2.rs diff --git a/tests/ui/empty/empty-struct-braces-pat-2.stderr b/tests/ui/resolve/empty-struct-braces-pat-2.stderr similarity index 100% rename from tests/ui/empty/empty-struct-braces-pat-2.stderr rename to tests/ui/resolve/empty-struct-braces-pat-2.stderr diff --git a/tests/ui/empty/empty-struct-braces-pat-3.rs b/tests/ui/resolve/empty-struct-braces-pat-3.rs similarity index 100% rename from tests/ui/empty/empty-struct-braces-pat-3.rs rename to tests/ui/resolve/empty-struct-braces-pat-3.rs diff --git a/tests/ui/empty/empty-struct-braces-pat-3.stderr b/tests/ui/resolve/empty-struct-braces-pat-3.stderr similarity index 100% rename from tests/ui/empty/empty-struct-braces-pat-3.stderr rename to tests/ui/resolve/empty-struct-braces-pat-3.stderr diff --git a/tests/ui/empty/empty-struct-tuple-pat.rs b/tests/ui/resolve/empty-struct-tuple-pat.rs similarity index 100% rename from tests/ui/empty/empty-struct-tuple-pat.rs rename to tests/ui/resolve/empty-struct-tuple-pat.rs diff --git a/tests/ui/empty/empty-struct-tuple-pat.stderr b/tests/ui/resolve/empty-struct-tuple-pat.stderr similarity index 100% rename from tests/ui/empty/empty-struct-tuple-pat.stderr rename to tests/ui/resolve/empty-struct-tuple-pat.stderr diff --git a/tests/ui/empty/empty-struct-unit-expr.rs b/tests/ui/resolve/empty-struct-unit-expr.rs similarity index 100% rename from tests/ui/empty/empty-struct-unit-expr.rs rename to tests/ui/resolve/empty-struct-unit-expr.rs diff --git a/tests/ui/empty/empty-struct-unit-expr.stderr b/tests/ui/resolve/empty-struct-unit-expr.stderr similarity index 100% rename from tests/ui/empty/empty-struct-unit-expr.stderr rename to tests/ui/resolve/empty-struct-unit-expr.stderr diff --git a/tests/ui/empty/empty-struct-unit-pat.rs b/tests/ui/resolve/empty-struct-unit-pat.rs similarity index 100% rename from tests/ui/empty/empty-struct-unit-pat.rs rename to tests/ui/resolve/empty-struct-unit-pat.rs diff --git a/tests/ui/empty/empty-struct-unit-pat.stderr b/tests/ui/resolve/empty-struct-unit-pat.stderr similarity index 100% rename from tests/ui/empty/empty-struct-unit-pat.stderr rename to tests/ui/resolve/empty-struct-unit-pat.stderr diff --git a/tests/ui/resolve/filter-intrinsics.rs b/tests/ui/resolve/filter-intrinsics.rs index 8d6d22817dc5..9998bec1ad4f 100644 --- a/tests/ui/resolve/filter-intrinsics.rs +++ b/tests/ui/resolve/filter-intrinsics.rs @@ -3,8 +3,8 @@ fn main() { let _ = transmute::(); //~^ ERROR cannot find - // Should suggest `std::intrinsics::fabsf64`, + // Should suggest `std::intrinsics::fabs`, // since there is no non-intrinsic to suggest. - let _ = fabsf64(1.0); + let _ = fabs(1.0); //~^ ERROR cannot find } diff --git a/tests/ui/resolve/filter-intrinsics.stderr b/tests/ui/resolve/filter-intrinsics.stderr index 9c9e92f6d4f8..3870cfcb1080 100644 --- a/tests/ui/resolve/filter-intrinsics.stderr +++ b/tests/ui/resolve/filter-intrinsics.stderr @@ -9,15 +9,15 @@ help: consider importing this function LL + use std::mem::transmute; | -error[E0425]: cannot find function `fabsf64` in this scope +error[E0425]: cannot find function `fabs` in this scope --> $DIR/filter-intrinsics.rs:8:13 | -LL | let _ = fabsf64(1.0); - | ^^^^^^^ not found in this scope +LL | let _ = fabs(1.0); + | ^^^^ not found in this scope | help: consider importing this function | -LL + use std::intrinsics::fabsf64; +LL + use std::intrinsics::fabs; | error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/issue-82865.rs b/tests/ui/resolve/issue-82865.rs index 545ca63e0b82..230725155d8a 100644 --- a/tests/ui/resolve/issue-82865.rs +++ b/tests/ui/resolve/issue-82865.rs @@ -6,7 +6,7 @@ use x::y::z; //~ ERROR: cannot find module or crate `x` macro mac () { - Box::z //~ ERROR: no function or associated item + Box::z //~ ERROR: no associated function or constant } fn main() { diff --git a/tests/ui/resolve/issue-82865.stderr b/tests/ui/resolve/issue-82865.stderr index 90059ad5a965..198f7f8e32aa 100644 --- a/tests/ui/resolve/issue-82865.stderr +++ b/tests/ui/resolve/issue-82865.stderr @@ -9,11 +9,11 @@ help: you might be missing a crate named `x`, add it to your project and import LL + extern crate x; | -error[E0599]: no function or associated item named `z` found for struct `Box<_, _>` in the current scope +error[E0599]: no associated function or constant named `z` found for struct `Box<_, _>` in the current scope --> $DIR/issue-82865.rs:9:10 | LL | Box::z - | ^ function or associated item not found in `Box<_, _>` + | ^ associated function or constant not found in `Box<_, _>` ... LL | mac!(); | ------ in this macro invocation diff --git a/tests/ui/resolve/missing-associated-items.rs b/tests/ui/resolve/missing-associated-items.rs index 72d6cbb3f149..1308ce5f592c 100644 --- a/tests/ui/resolve/missing-associated-items.rs +++ b/tests/ui/resolve/missing-associated-items.rs @@ -14,8 +14,8 @@ fn use_token(token: &Token) { } fn main() { - use_token(&Token::Homura); //~ ERROR no variant or associated item named `Homura` - Struct::method(); //~ ERROR no function or associated item named `method` found - Struct::method; //~ ERROR no function or associated item named `method` found - Struct::Assoc; //~ ERROR no associated item named `Assoc` found + use_token(&Token::Homura); //~ ERROR no variant, associated function, or constant named `Homura` + Struct::method(); //~ ERROR no associated function or constant named `method` found + Struct::method; //~ ERROR no associated function or constant named `method` found + Struct::Assoc; //~ ERROR no associated function or constant named `Assoc` found } diff --git a/tests/ui/resolve/missing-associated-items.stderr b/tests/ui/resolve/missing-associated-items.stderr index d27a3a644aee..3bc63ded6bc8 100644 --- a/tests/ui/resolve/missing-associated-items.stderr +++ b/tests/ui/resolve/missing-associated-items.stderr @@ -1,38 +1,38 @@ -error[E0599]: no variant or associated item named `Homura` found for enum `Token` in the current scope +error[E0599]: no variant, associated function, or constant named `Homura` found for enum `Token` in the current scope --> $DIR/missing-associated-items.rs:17:23 | LL | enum Token { - | ---------- variant or associated item `Homura` not found for this enum + | ---------- variant, associated function, or constant `Homura` not found for this enum ... LL | use_token(&Token::Homura); - | ^^^^^^ variant or associated item not found in `Token` + | ^^^^^^ variant, associated function, or constant not found in `Token` -error[E0599]: no function or associated item named `method` found for struct `Struct` in the current scope +error[E0599]: no associated function or constant named `method` found for struct `Struct` in the current scope --> $DIR/missing-associated-items.rs:18:13 | LL | struct Struct { - | ------------- function or associated item `method` not found for this struct + | ------------- associated function or constant `method` not found for this struct ... LL | Struct::method(); - | ^^^^^^ function or associated item not found in `Struct` + | ^^^^^^ associated function or constant not found in `Struct` -error[E0599]: no function or associated item named `method` found for struct `Struct` in the current scope +error[E0599]: no associated function or constant named `method` found for struct `Struct` in the current scope --> $DIR/missing-associated-items.rs:19:13 | LL | struct Struct { - | ------------- function or associated item `method` not found for this struct + | ------------- associated function or constant `method` not found for this struct ... LL | Struct::method; - | ^^^^^^ function or associated item not found in `Struct` + | ^^^^^^ associated function or constant not found in `Struct` -error[E0599]: no associated item named `Assoc` found for struct `Struct` in the current scope +error[E0599]: no associated function or constant named `Assoc` found for struct `Struct` in the current scope --> $DIR/missing-associated-items.rs:20:13 | LL | struct Struct { - | ------------- associated item `Assoc` not found for this struct + | ------------- associated function or constant `Assoc` not found for this struct ... LL | Struct::Assoc; - | ^^^^^ associated item not found in `Struct` + | ^^^^^ associated function or constant not found in `Struct` error: aborting due to 4 previous errors diff --git a/tests/ui/resolve/name-clash-nullary.stderr b/tests/ui/resolve/name-clash-nullary.stderr index 08e7fe9a678a..1a3f434b6277 100644 --- a/tests/ui/resolve/name-clash-nullary.stderr +++ b/tests/ui/resolve/name-clash-nullary.stderr @@ -5,9 +5,19 @@ LL | let None: isize = 42; | ^^^^ ----- expected due to this | | | expected `isize`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected type `isize` found enum `Option<_>` +help: introduce a new binding instead + | +LL - let None: isize = 42; +LL + let other_none: isize = 42; + | error: aborting due to 1 previous error diff --git a/tests/ui/resolve/open-ns-1.rs b/tests/ui/resolve/open-ns-1.rs new file mode 100644 index 000000000000..e77ddbe58122 --- /dev/null +++ b/tests/ui/resolve/open-ns-1.rs @@ -0,0 +1,19 @@ +//@ aux-crate:my_api=open-ns-my_api.rs +//@ aux-crate:my_api::utils=open-ns-my_api_utils.rs +//@ aux-crate:my_api::core=open-ns-my_api_core.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use my_api::root_function; +use my_api::utils::util; +//~^ ERROR unresolved import `my_api::utils` + +fn main() { + let _ = root_function(); + let _ = my_api::root_function(); + let _ = my_api::utils::utils_helper(); + //~^ ERROR cannot find `utils` in `my_api` [E0433] + let _ = util::util_mod_helper(); + let _ = my_api::core::core_fn(); + //~^ ERROR cannot find `core` in `my_api` [E0433] +} diff --git a/tests/ui/resolve/open-ns-1.stderr b/tests/ui/resolve/open-ns-1.stderr new file mode 100644 index 000000000000..65b9c6a355ce --- /dev/null +++ b/tests/ui/resolve/open-ns-1.stderr @@ -0,0 +1,22 @@ +error[E0432]: unresolved import `my_api::utils` + --> $DIR/open-ns-1.rs:8:13 + | +LL | use my_api::utils::util; + | ^^^^^ could not find `utils` in `my_api` + +error[E0433]: cannot find `utils` in `my_api` + --> $DIR/open-ns-1.rs:14:21 + | +LL | let _ = my_api::utils::utils_helper(); + | ^^^^^ could not find `utils` in `my_api` + +error[E0433]: cannot find `core` in `my_api` + --> $DIR/open-ns-1.rs:17:21 + | +LL | let _ = my_api::core::core_fn(); + | ^^^^ could not find `core` in `my_api` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/open-ns-10.rs b/tests/ui/resolve/open-ns-10.rs new file mode 100644 index 000000000000..b05a0ab270df --- /dev/null +++ b/tests/ui/resolve/open-ns-10.rs @@ -0,0 +1,8 @@ +// Tests that namespaced crate names are limited to two segments + +//@ aux-crate: nscrate::three::segments=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 +//~? ERROR crate name `nscrate::three::segments` passed to `--extern` can have at most two segments. + +fn main() {} diff --git a/tests/ui/resolve/open-ns-10.stderr b/tests/ui/resolve/open-ns-10.stderr new file mode 100644 index 000000000000..fdef748c6fa7 --- /dev/null +++ b/tests/ui/resolve/open-ns-10.stderr @@ -0,0 +1,2 @@ +error: crate name `nscrate::three::segments` passed to `--extern` can have at most two segments. + diff --git a/tests/ui/resolve/open-ns-11.rs b/tests/ui/resolve/open-ns-11.rs new file mode 100644 index 000000000000..90e85a9ffc04 --- /dev/null +++ b/tests/ui/resolve/open-ns-11.rs @@ -0,0 +1,12 @@ +// Tests that std has higher precedence than an open module with the same name. + +//@ aux-crate: std::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use std::utils::get_u32; +//~^ ERROR unresolved import `std::utils` + +fn main() { + let _ = get_u32(); +} diff --git a/tests/ui/resolve/open-ns-11.stderr b/tests/ui/resolve/open-ns-11.stderr new file mode 100644 index 000000000000..cb073bc985a9 --- /dev/null +++ b/tests/ui/resolve/open-ns-11.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `std::utils` + --> $DIR/open-ns-11.rs:7:10 + | +LL | use std::utils::get_u32; + | ^^^^^ could not find `utils` in `std` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/open-ns-2.rs b/tests/ui/resolve/open-ns-2.rs new file mode 100644 index 000000000000..6165a4102be0 --- /dev/null +++ b/tests/ui/resolve/open-ns-2.rs @@ -0,0 +1,18 @@ +//@ aux-crate: my_api=open-ns-my_api.rs +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ aux-crate: my_api::core=open-ns-my_api_core.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use my_api::core::{core_fn, core_fn2}; +//~^ ERROR unresolved import `my_api::core` [E0432] +use my_api::utils::*; +//~^ ERROR unresolved import `my_api::utils` [E0432] +use my_api::*; + +fn main() { + let _ = root_function(); + let _ = utils_helper(); + let _ = core_fn(); + let _ = core_fn2(); +} diff --git a/tests/ui/resolve/open-ns-2.stderr b/tests/ui/resolve/open-ns-2.stderr new file mode 100644 index 000000000000..0e221234c517 --- /dev/null +++ b/tests/ui/resolve/open-ns-2.stderr @@ -0,0 +1,15 @@ +error[E0432]: unresolved import `my_api::core` + --> $DIR/open-ns-2.rs:7:13 + | +LL | use my_api::core::{core_fn, core_fn2}; + | ^^^^ could not find `core` in `my_api` + +error[E0432]: unresolved import `my_api::utils` + --> $DIR/open-ns-2.rs:9:13 + | +LL | use my_api::utils::*; + | ^^^^^ could not find `utils` in `my_api` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/open-ns-3.rs b/tests/ui/resolve/open-ns-3.rs new file mode 100644 index 000000000000..9c78999fe368 --- /dev/null +++ b/tests/ui/resolve/open-ns-3.rs @@ -0,0 +1,14 @@ +// This test should fail with `utils_helper` being unresolvable in `my_api::utils`. +// If a crate contains a module that overlaps with a namespaced crate name, then +// the namespaced crate will not be used in name resolution. + +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ aux-crate: my_api=open-ns-mod-my_api.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +fn main() { + let _ = my_api::utils::root_helper(); + let _ = my_api::utils::utils_helper(); + //~^ ERROR cannot find function `utils_helper` in module `my_api::utils` [E0425] +} diff --git a/tests/ui/resolve/open-ns-3.stderr b/tests/ui/resolve/open-ns-3.stderr new file mode 100644 index 000000000000..8ae261af0142 --- /dev/null +++ b/tests/ui/resolve/open-ns-3.stderr @@ -0,0 +1,19 @@ +error[E0425]: cannot find function `utils_helper` in module `my_api::utils` + --> $DIR/open-ns-3.rs:12:28 + | +LL | let _ = my_api::utils::utils_helper(); + | ^^^^^^^^^^^^ not found in `my_api::utils` + | +help: consider importing this function + | +LL + use my_api::utils::utils_helper; + | +help: if you import `utils_helper`, refer to it directly + | +LL - let _ = my_api::utils::utils_helper(); +LL + let _ = utils_helper(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/open-ns-4.rs b/tests/ui/resolve/open-ns-4.rs new file mode 100644 index 000000000000..4db3ad4c80a1 --- /dev/null +++ b/tests/ui/resolve/open-ns-4.rs @@ -0,0 +1,12 @@ +// This tests that namespaced crates are shadowed. + +//@ aux-crate: my_api=open-ns-my_api.rs +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +fn main() { + let _ = my_api::root_function(); + let _ = my_api::utils::utils_helper(); + //~^ ERROR cannot find `utils` in `my_api` [E0433] +} diff --git a/tests/ui/resolve/open-ns-4.stderr b/tests/ui/resolve/open-ns-4.stderr new file mode 100644 index 000000000000..2e6872c57986 --- /dev/null +++ b/tests/ui/resolve/open-ns-4.stderr @@ -0,0 +1,9 @@ +error[E0433]: cannot find `utils` in `my_api` + --> $DIR/open-ns-4.rs:10:21 + | +LL | let _ = my_api::utils::utils_helper(); + | ^^^^^ could not find `utils` in `my_api` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/resolve/open-ns-5.rs b/tests/ui/resolve/open-ns-5.rs new file mode 100644 index 000000000000..8776da3106cf --- /dev/null +++ b/tests/ui/resolve/open-ns-5.rs @@ -0,0 +1,18 @@ +// Tests that namespaced crate names work inside macros. + +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 +//@ check-pass + +macro_rules! import_and_call { + ($import_path:path, $fn_name:ident) => {{ + use $import_path; + $fn_name(); + }}; +} + +fn main() { + import_and_call!(my_api::utils::utils_helper, utils_helper); + let _x = 4 + 5; +} diff --git a/tests/ui/resolve/open-ns-6.rs b/tests/ui/resolve/open-ns-6.rs new file mode 100644 index 000000000000..856858aac43a --- /dev/null +++ b/tests/ui/resolve/open-ns-6.rs @@ -0,0 +1,13 @@ +// Tests that open modules are resolvable. + +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 +//@ check-pass + +use my_api; +use my_api::utils::utils_helper; + +fn main() { + let _ = utils_helper(); +} diff --git a/tests/ui/resolve/open-ns-7.rs b/tests/ui/resolve/open-ns-7.rs new file mode 100644 index 000000000000..cf16c594fa40 --- /dev/null +++ b/tests/ui/resolve/open-ns-7.rs @@ -0,0 +1,14 @@ +// Tests that namespaced crates cannot be resolved if shadowed. + +//@ aux-crate: my_api=open-ns-my_api.rs +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use my_api::utils::utils_helper; +//~^ ERROR unresolved import `my_api::utils` [E0432] + +fn main() { + let _ = my_api::utils::utils_helper(); + //~^ ERROR cannot find `utils` in `my_api` [E0433] +} diff --git a/tests/ui/resolve/open-ns-7.stderr b/tests/ui/resolve/open-ns-7.stderr new file mode 100644 index 000000000000..b00854753983 --- /dev/null +++ b/tests/ui/resolve/open-ns-7.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `my_api::utils` + --> $DIR/open-ns-7.rs:8:13 + | +LL | use my_api::utils::utils_helper; + | ^^^^^ could not find `utils` in `my_api` + +error[E0433]: cannot find `utils` in `my_api` + --> $DIR/open-ns-7.rs:12:21 + | +LL | let _ = my_api::utils::utils_helper(); + | ^^^^^ could not find `utils` in `my_api` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/open-ns-8.rs b/tests/ui/resolve/open-ns-8.rs new file mode 100644 index 000000000000..46aafb66e63a --- /dev/null +++ b/tests/ui/resolve/open-ns-8.rs @@ -0,0 +1,23 @@ +// Tests that a macro-generated item has higher precendence than a namespaced crate +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 +//@ check-pass + +macro_rules! define { + () => { + pub mod my_api { + pub mod utils { + pub fn get_u32() -> u32 { + 2 + } + } + } + }; +} + +fn main() { + define!(); + let res = my_api::utils::get_u32(); + assert_eq!(res, 2); +} diff --git a/tests/ui/resolve/open-ns-9.rs b/tests/ui/resolve/open-ns-9.rs new file mode 100644 index 000000000000..7ded0b383d8d --- /dev/null +++ b/tests/ui/resolve/open-ns-9.rs @@ -0,0 +1,25 @@ +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use my_api::utils::get_u32; +//~^ ERROR `my_api` is ambiguous [E0659] + +macro_rules! define { + () => { + pub mod my_api { + pub mod utils { + pub fn get_u32() -> u32 { + 2 + } + } + } + }; +} + +define!(); + +fn main() { + let val = get_u32(); + assert_eq!(val, 2); +} diff --git a/tests/ui/resolve/open-ns-9.stderr b/tests/ui/resolve/open-ns-9.stderr new file mode 100644 index 000000000000..675f487823e5 --- /dev/null +++ b/tests/ui/resolve/open-ns-9.stderr @@ -0,0 +1,27 @@ +error[E0659]: `my_api` is ambiguous + --> $DIR/open-ns-9.rs:5:5 + | +LL | use my_api::utils::get_u32; + | ^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `my_api` could refer to a namespaced crate passed with `--extern` +note: `my_api` could also refer to the module defined here + --> $DIR/open-ns-9.rs:10:9 + | +LL | / pub mod my_api { +LL | | pub mod utils { +LL | | pub fn get_u32() -> u32 { +LL | | 2 +... | +LL | | } + | |_________^ +... +LL | define!(); + | --------- in this macro invocation + = help: use `crate::my_api` to refer to this module unambiguously + = note: this error originates in the macro `define` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/resolve/path-attr-in-const-block.rs b/tests/ui/resolve/path-attr-in-const-block.rs index 0ca356b1ddf0..076511d26d6d 100644 --- a/tests/ui/resolve/path-attr-in-const-block.rs +++ b/tests/ui/resolve/path-attr-in-const-block.rs @@ -5,6 +5,5 @@ fn main() { const { #![path = foo!()] //~^ ERROR: cannot find macro `foo` in this scope - //~| ERROR: attribute value must be a literal } } diff --git a/tests/ui/resolve/path-attr-in-const-block.stderr b/tests/ui/resolve/path-attr-in-const-block.stderr index 19d2745577be..8f9e58157c80 100644 --- a/tests/ui/resolve/path-attr-in-const-block.stderr +++ b/tests/ui/resolve/path-attr-in-const-block.stderr @@ -4,11 +4,5 @@ error: cannot find macro `foo` in this scope LL | #![path = foo!()] | ^^^ -error: attribute value must be a literal - --> $DIR/path-attr-in-const-block.rs:6:19 - | -LL | #![path = foo!()] - | ^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/resolve/proc_macro_generated_packed.rs b/tests/ui/resolve/proc_macro_generated_packed.rs index a8175895af04..e35f50911663 100644 --- a/tests/ui/resolve/proc_macro_generated_packed.rs +++ b/tests/ui/resolve/proc_macro_generated_packed.rs @@ -1,6 +1,6 @@ //! This test ICEs because the `repr(packed)` attribute //! was generated by a proc macro, so `#[derive]` didn't see it. - +//@ ignore-parallel-frontend failed to collect active jobs //@proc-macro: proc_macro_generate_packed.rs //@known-bug: #120873 //@ failure-status: 101 diff --git a/tests/ui/resolve/pub-in-path-153848.rs b/tests/ui/resolve/pub-in-path-153848.rs new file mode 100644 index 000000000000..40045e96987f --- /dev/null +++ b/tests/ui/resolve/pub-in-path-153848.rs @@ -0,0 +1,9 @@ +//@ edition: 2015 + +pub(in a) mod aa { //~ ERROR cannot find module or crate `a` in the crate root +} +mod test { + #[cfg(test)] + use super::a; +} +fn main() {} diff --git a/tests/ui/resolve/pub-in-path-153848.stderr b/tests/ui/resolve/pub-in-path-153848.stderr new file mode 100644 index 000000000000..06973a4c0bf3 --- /dev/null +++ b/tests/ui/resolve/pub-in-path-153848.stderr @@ -0,0 +1,21 @@ +error[E0433]: cannot find module or crate `a` in the crate root + --> $DIR/pub-in-path-153848.rs:3:8 + | +LL | pub(in a) mod aa { + | ^ use of unresolved module or unlinked crate `a` + | +note: found an item that was configured out + --> $DIR/pub-in-path-153848.rs:7:16 + | +LL | #[cfg(test)] + | ---- the item is gated here +LL | use super::a; + | ^ +help: you might be missing a crate named `a`, add it to your project and import it in your code + | +LL + extern crate a; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/resolve/resolve-self-in-impl.rs b/tests/ui/resolve/resolve-self-in-impl.rs index d0872d1b76f2..c05a7146fe08 100644 --- a/tests/ui/resolve/resolve-self-in-impl.rs +++ b/tests/ui/resolve/resolve-self-in-impl.rs @@ -1,5 +1,5 @@ #![feature(associated_type_defaults)] - +//@ ignore-parallel-frontend query cycle struct S(T); trait Tr { type A = (); diff --git a/tests/ui/resolve/suggestions/suggest-builder-fn.rs b/tests/ui/resolve/suggestions/suggest-builder-fn.rs index 959675ef2c99..4552ed5382e9 100644 --- a/tests/ui/resolve/suggestions/suggest-builder-fn.rs +++ b/tests/ui/resolve/suggestions/suggest-builder-fn.rs @@ -50,15 +50,15 @@ fn build_private() -> Self { fn main() { // `new` not found on `TcpStream` and `connect` should be suggested let _stream = TcpStream::new(); - //~^ ERROR no function or associated item named `new` found + //~^ ERROR no associated function or constant named `new` found // Although `new` is found on `>` it should not be // suggested because `u8` does not meet the `T: SomeTrait` constraint let _foo = Foo::::new(); - //~^ ERROR the function or associated item `new` exists for struct `Foo`, but its trait bounds were not satisfied + //~^ ERROR the associated function or constant `new` exists for struct `Foo`, but its trait bounds were not satisfied // Should suggest only `::build()` and `SomeMod::::build_public()`. // Other methods should not suggested because they are private or are not a builder let _bar = Bar::new(); - //~^ ERROR no function or associated item named `new` found + //~^ ERROR no associated function or constant named `new` found } diff --git a/tests/ui/resolve/suggestions/suggest-builder-fn.stderr b/tests/ui/resolve/suggestions/suggest-builder-fn.stderr index 9c5eed35ccff..1eabb8effac9 100644 --- a/tests/ui/resolve/suggestions/suggest-builder-fn.stderr +++ b/tests/ui/resolve/suggestions/suggest-builder-fn.stderr @@ -1,22 +1,22 @@ -error[E0599]: no function or associated item named `new` found for struct `TcpStream` in the current scope +error[E0599]: no associated function or constant named `new` found for struct `TcpStream` in the current scope --> $DIR/suggest-builder-fn.rs:52:29 | LL | let _stream = TcpStream::new(); - | ^^^ function or associated item not found in `TcpStream` + | ^^^ associated function or constant not found in `TcpStream` | note: if you're trying to build a new `TcpStream` consider using one of the following associated functions: TcpStream::connect TcpStream::connect_timeout --> $SRC_DIR/std/src/net/tcp.rs:LL:COL -error[E0599]: the function or associated item `new` exists for struct `Foo`, but its trait bounds were not satisfied +error[E0599]: the associated function or constant `new` exists for struct `Foo`, but its trait bounds were not satisfied --> $DIR/suggest-builder-fn.rs:57:27 | LL | struct Foo { - | ------------- function or associated item `new` not found for this struct + | ------------- associated function or constant `new` not found for this struct ... LL | let _foo = Foo::::new(); - | ^^^ function or associated item cannot be called on `Foo` due to unsatisfied trait bounds + | ^^^ associated function or constant cannot be called on `Foo` due to unsatisfied trait bounds | note: trait bound `u8: SomeTrait` was not satisfied --> $DIR/suggest-builder-fn.rs:12:9 @@ -26,14 +26,14 @@ LL | impl Foo { | | | unsatisfied trait bound introduced here -error[E0599]: no function or associated item named `new` found for struct `Bar` in the current scope +error[E0599]: no associated function or constant named `new` found for struct `Bar` in the current scope --> $DIR/suggest-builder-fn.rs:62:21 | LL | struct Bar; - | ---------- function or associated item `new` not found for this struct + | ---------- associated function or constant `new` not found for this struct ... LL | let _bar = Bar::new(); - | ^^^ function or associated item not found in `Bar` + | ^^^ associated function or constant not found in `Bar` | note: if you're trying to build a new `Bar` consider using one of the following associated functions: Bar::build diff --git a/tests/ui/resolve/typo-suggestion-mistyped-in-path.rs b/tests/ui/resolve/typo-suggestion-mistyped-in-path.rs index 706564dc9b21..dfbb8f1e0a51 100644 --- a/tests/ui/resolve/typo-suggestion-mistyped-in-path.rs +++ b/tests/ui/resolve/typo-suggestion-mistyped-in-path.rs @@ -1,5 +1,5 @@ struct Struct; -//~^ NOTE function or associated item `fob` not found for this struct +//~^ NOTE associated function or constant `fob` not found for this struct impl Struct { fn foo() { } @@ -21,8 +21,8 @@ trait Trait { fn main() { Struct::fob(); - //~^ ERROR no function or associated item named `fob` found for struct `Struct` in the current scope - //~| NOTE function or associated item not found in `Struct` + //~^ ERROR no associated function or constant named `fob` found for struct `Struct` in the current scope + //~| NOTE associated function or constant not found in `Struct` Struc::foo(); //~^ ERROR cannot find type `Struc` diff --git a/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr b/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr index b1afa703eb03..98412559d666 100644 --- a/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr +++ b/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr @@ -9,14 +9,14 @@ help: a struct with a similar name exists LL | module::Struct::foo(); | + -error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope +error[E0599]: no associated function or constant named `fob` found for struct `Struct` in the current scope --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13 | LL | struct Struct; - | ------------- function or associated item `fob` not found for this struct + | ------------- associated function or constant `fob` not found for this struct ... LL | Struct::fob(); - | ^^^ function or associated item not found in `Struct` + | ^^^ associated function or constant not found in `Struct` | help: there is an associated function `foo` with a similar name | diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.rs b/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.rs index a66c44644177..8dff48de60aa 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.rs @@ -1,7 +1,6 @@ // Make sure we consider `!` to be a union read. #![feature(never_type, never_patterns)] -//~^ WARN the feature `never_patterns` is incomplete union U { a: !, diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.stderr index d7dc7a47e728..c415e26f6e27 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/never-pattern-is-a-read.stderr @@ -1,20 +1,11 @@ -warning: the feature `never_patterns` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/never-pattern-is-a-read.rs:3:24 - | -LL | #![feature(never_type, never_patterns)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #118155 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/never-pattern-is-a-read.rs:12:16 + --> $DIR/never-pattern-is-a-read.rs:11:16 | LL | let U { a: ! } = u; | ^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr index 8787d140e17f..ebba8253e07f 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } +LL + binding if binding == WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr index ec836db02ad8..849b5cc11622 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } +LL + binding if binding == WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr index fdc16fe300c2..cb19c4131325 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } +LL + binding if binding == WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr index b46fc041f14b..8dffde7713e3 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } +LL + binding if binding == WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr index 70f39aa01d82..7b47540017a7 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } +LL + binding if binding == WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr index fceb3acb025e..958b731616f1 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } +LL + binding if binding == WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr index 34fffd99c2c9..295b2a71f70f 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for B { | ^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } +LL + binding if binding == RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } + | error: constant of non-structural type `B` in a pattern --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:42:9 @@ -33,6 +38,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for B { | ^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } +LL + binding if binding == RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } + | error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs index 74394698fbcd..cb6ab974c5e4 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs @@ -16,8 +16,8 @@ fn eq(&self, _: &Foo) -> bool { fn main() { let y = Foo { x: 1 }; match y { - FOO => { } + FOO => {} //~^ ERROR constant of non-structural type `Foo` in a pattern - _ => { } + _ => {} } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr index bbcab3b62d0e..1d216a668381 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr @@ -7,7 +7,7 @@ LL | struct Foo { LL | const FOO: Foo = Foo { x: 0 }; | -------------- constant defined here ... -LL | FOO => { } +LL | FOO => {} | ^^^ constant of non-structural type | note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details @@ -15,6 +15,11 @@ note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; | LL | impl PartialEq for Foo { | ^^^^^^^^^^^^^^^^^^^^^^ +help: add a condition to the match arm checking for equality + | +LL - FOO => {} +LL + binding if binding == FOO => {} + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr index 1c8e8d5b0a7d..12b89ba10bfd 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr @@ -11,7 +11,12 @@ LL | FOO => {}, | | | expected `&Foo`, found `Foo` | `FOO` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_foo` + | +help: introduce a new binding instead + | +LL - FOO => {}, +LL + other_foo => {}, + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr index 8f720daf11ee..48aba17db3c2 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr @@ -4,8 +4,7 @@ error[E0507]: cannot move out of a shared reference LL | for (n, mut m) in &tups { | ----- ^^^^^ | | - | data moved here - | move occurs because `m` has type `Foo`, which does not implement the `Copy` trait + | data moved here because `m` has type `Foo`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs index 46fdfd678cc6..c54f08e9256f 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs @@ -5,7 +5,7 @@ fn main() { let foo = 22; match foo { - u32::XXX => { } //~ ERROR no associated item named + u32::XXX => { } //~ ERROR no associated function or constant named _ => { } } } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr index 6000507c5897..51b08cde6eb0 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `XXX` found for type `u32` in the current scope +error[E0599]: no associated function or constant named `XXX` found for type `u32` in the current scope --> $DIR/no-double-error.rs:8:14 | LL | u32::XXX => { } - | ^^^ associated item not found in `u32` + | ^^^ associated function or constant not found in `u32` error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs index 074e1ceb791c..53f99760d88f 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -1,11 +1,30 @@ #[track_caller] -extern "C" fn f() {} -//~^^ ERROR `#[track_caller]` requires Rust ABI +//~^ ERROR `#[track_caller]` can only be used with the Rust ABI +extern "C" fn c_fn() {} + +#[track_caller] +extern "Rust" fn rust_fn() {} extern "C" { #[track_caller] - fn g(); - //~^^ ERROR `#[track_caller]` requires Rust ABI + //~^ ERROR `#[track_caller]` can only be used with the Rust ABI + fn c_extern(); +} + +extern "Rust" { + #[track_caller] + fn rust_extern(); +} + +struct S; + +impl S { + #[track_caller] + //~^ ERROR `#[track_caller]` can only be used with the Rust ABI + extern "C" fn c_method() {} + + #[track_caller] + extern "Rust" fn rust_method() {} } fn main() {} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr index bcc0c8170e65..f5cba7b8a011 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -1,15 +1,29 @@ -error[E0737]: `#[track_caller]` requires Rust ABI +error[E0737]: `#[track_caller]` can only be used with the Rust ABI --> $DIR/error-with-invalid-abi.rs:1:1 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ using `#[track_caller]` here +LL | +LL | extern "C" fn c_fn() {} + | ---------- not using the Rust ABI because of this -error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/error-with-invalid-abi.rs:6:5 +error[E0737]: `#[track_caller]` can only be used with the Rust ABI + --> $DIR/error-with-invalid-abi.rs:9:5 + | +LL | extern "C" { + | ---------- not using the Rust ABI because of this +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ using `#[track_caller]` here + +error[E0737]: `#[track_caller]` can only be used with the Rust ABI + --> $DIR/error-with-invalid-abi.rs:22:5 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ using `#[track_caller]` here +LL | +LL | extern "C" fn c_method() {} + | ---------- not using the Rust ABI because of this -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0737`. diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs index a4baf1fe4b97..a136c3ffeefa 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs @@ -3,7 +3,7 @@ use std::arch::naked_asm; #[track_caller] //~ ERROR [E0736] -//~^ ERROR `#[track_caller]` requires Rust ABI +//~^ ERROR `#[track_caller]` can only be used with the Rust ABI #[unsafe(naked)] extern "C" fn f() { unsafe { @@ -15,7 +15,7 @@ extern "C" fn f() { impl S { #[track_caller] //~ ERROR [E0736] - //~^ ERROR `#[track_caller]` requires Rust ABI + //~^ ERROR `#[track_caller]` can only be used with the Rust ABI #[unsafe(naked)] extern "C" fn g() { unsafe { diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr index 303608061388..90ed76e8b1b9 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr @@ -1,3 +1,21 @@ +error[E0737]: `#[track_caller]` can only be used with the Rust ABI + --> $DIR/error-with-naked.rs:5:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ using `#[track_caller]` here +... +LL | extern "C" fn f() { + | ---------- not using the Rust ABI because of this + +error[E0737]: `#[track_caller]` can only be used with the Rust ABI + --> $DIR/error-with-naked.rs:17:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ using `#[track_caller]` here +... +LL | extern "C" fn g() { + | ---------- not using the Rust ABI because of this + error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/error-with-naked.rs:5:3 | @@ -16,18 +34,6 @@ LL | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here -error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/error-with-naked.rs:5:1 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ - -error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/error-with-naked.rs:17:5 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ - error: aborting due to 4 previous errors Some errors have detailed explanations: E0736, E0737. diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index f8ef315b9cc7..7ce5ebf81e31 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -1,13 +1,21 @@ error[E0382]: use of moved value: `a` - --> $DIR/dbg-macro-move-semantics.rs:9:13 + --> $DIR/dbg-macro-move-semantics.rs:9:18 | LL | let a = NoCopy(0); | - move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait LL | let _ = dbg!(a); - | ------- value moved here + | - value moved here LL | let _ = dbg!(a); - | ^^^^^^^ value used here after move + | ^ value used here after move | +note: if `NoCopy` implemented `Clone`, you could clone the value + --> $DIR/dbg-macro-move-semantics.rs:4:1 + | +LL | struct NoCopy(usize); + | ^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _ = dbg!(a); + | - you could clone this value help: consider borrowing instead of transferring ownership | LL | let _ = dbg!(&a); diff --git a/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed index 435857224ac3..e7c10f71b831 100644 --- a/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed +++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed @@ -1,7 +1,7 @@ //@ edition:2018 //@ aux-build:edition-lint-infer-outlives-macro.rs //@ run-rustfix - +//@ ignore-parallel-frontend `note`s on different source lines #![deny(explicit_outlives_requirements)] #![allow(dead_code)] diff --git a/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs index 6c879231a168..a39d766263e9 100644 --- a/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs +++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs @@ -1,7 +1,7 @@ //@ edition:2018 //@ aux-build:edition-lint-infer-outlives-macro.rs //@ run-rustfix - +//@ ignore-parallel-frontend `note`s on different source lines #![deny(explicit_outlives_requirements)] #![allow(dead_code)] diff --git a/tests/ui/rust-2018/trait-import-suggestions.rs b/tests/ui/rust-2018/trait-import-suggestions.rs index 5a5eeacedfcc..dce01de8c894 100644 --- a/tests/ui/rust-2018/trait-import-suggestions.rs +++ b/tests/ui/rust-2018/trait-import-suggestions.rs @@ -27,5 +27,5 @@ fn main() { let x: u32 = 22; x.bar(); //~ ERROR no method named `bar` x.baz(); //~ ERROR no method named `baz` - let y = u32::from_str("33"); //~ ERROR no function or associated item named `from_str` + let y = u32::from_str("33"); //~ ERROR no associated function or constant named `from_str` } diff --git a/tests/ui/rust-2018/trait-import-suggestions.stderr b/tests/ui/rust-2018/trait-import-suggestions.stderr index 488044ee8524..721ba0c50d78 100644 --- a/tests/ui/rust-2018/trait-import-suggestions.stderr +++ b/tests/ui/rust-2018/trait-import-suggestions.stderr @@ -49,11 +49,11 @@ LL - x.baz(); LL + x.bar(); | -error[E0599]: no function or associated item named `from_str` found for type `u32` in the current scope +error[E0599]: no associated function or constant named `from_str` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:30:18 | LL | let y = u32::from_str("33"); - | ^^^^^^^^ function or associated item not found in `u32` + | ^^^^^^^^ associated function or constant not found in `u32` | = help: items from traits can only be used if the trait is in scope help: trait `FromStr` which provides `from_str` is implemented but not in scope; perhaps you want to import it diff --git a/tests/ui/rust-2018/uniform-paths/issue-87932.rs b/tests/ui/rust-2018/uniform-paths/issue-87932.rs index d24d4b8b4820..cde7fe7a8ea6 100644 --- a/tests/ui/rust-2018/uniform-paths/issue-87932.rs +++ b/tests/ui/rust-2018/uniform-paths/issue-87932.rs @@ -11,5 +11,5 @@ fn deserialize() { fn main() { A::deserialize(); - //~^ ERROR no function or associated item named `deserialize` found for struct `A` + //~^ ERROR no associated function or constant named `deserialize` found for struct `A` } diff --git a/tests/ui/rust-2018/uniform-paths/issue-87932.stderr b/tests/ui/rust-2018/uniform-paths/issue-87932.stderr index 3e6fc3ff2a56..c408b747b506 100644 --- a/tests/ui/rust-2018/uniform-paths/issue-87932.stderr +++ b/tests/ui/rust-2018/uniform-paths/issue-87932.stderr @@ -1,11 +1,11 @@ -error[E0599]: no function or associated item named `deserialize` found for struct `A` in the current scope +error[E0599]: no associated function or constant named `deserialize` found for struct `A` in the current scope --> $DIR/issue-87932.rs:13:8 | LL | pub struct A {} - | ------------ function or associated item `deserialize` not found for this struct + | ------------ associated function or constant `deserialize` not found for this struct ... LL | A::deserialize(); - | ^^^^^^^^^^^ function or associated item not found in `A` + | ^^^^^^^^^^^ associated function or constant not found in `A` | = help: items from traits can only be used if the trait is in scope help: trait `Deserialize` which provides `deserialize` is implemented but not in scope; perhaps you want to import it diff --git a/tests/ui/rust-2024/unsafe-before_exec-suggestion.fixed b/tests/ui/rust-2024/unsafe-before_exec-suggestion.fixed index d850428cc1a5..da3e69489814 100644 --- a/tests/ui/rust-2024/unsafe-before_exec-suggestion.fixed +++ b/tests/ui/rust-2024/unsafe-before_exec-suggestion.fixed @@ -10,7 +10,7 @@ use std::os::unix::process::CommandExt; #[allow(deprecated)] fn main() { let mut cmd = Command::new("sleep"); - // TODO: Audit that the closure is async-signal-safe. + // FIXME: Audit that the closure is async-signal-safe. unsafe { cmd.before_exec(|| Ok(())) }; //~^ ERROR call to deprecated safe function //~| WARN this is accepted in the current edition diff --git a/tests/ui/rust-2024/unsafe-before_exec-suggestion.stderr b/tests/ui/rust-2024/unsafe-before_exec-suggestion.stderr index 33893f30ceca..d4b961df55ee 100644 --- a/tests/ui/rust-2024/unsafe-before_exec-suggestion.stderr +++ b/tests/ui/rust-2024/unsafe-before_exec-suggestion.stderr @@ -13,7 +13,7 @@ LL | #![deny(deprecated_safe_2024)] | ^^^^^^^^^^^^^^^^^^^^ help: you can wrap the call in an `unsafe` block if you can guarantee that the closure is async-signal-safe | -LL + // TODO: Audit that the closure is async-signal-safe. +LL + // FIXME: Audit that the closure is async-signal-safe. LL ~ unsafe { cmd.before_exec(|| Ok(())) }; | diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.fixed b/tests/ui/rust-2024/unsafe-env-suggestion.fixed index 912d082832c4..183e67af6fae 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.fixed +++ b/tests/ui/rust-2024/unsafe-env-suggestion.fixed @@ -7,11 +7,11 @@ use std::env; #[deny(unused_unsafe)] fn main() { - // TODO: Audit that the environment access only happens in single-threaded code. + // FIXME: Audit that the environment access only happens in single-threaded code. unsafe { env::set_var("FOO", "BAR") }; //~^ ERROR call to deprecated safe function //~| WARN this is accepted in the current edition - // TODO: Audit that the environment access only happens in single-threaded code. + // FIXME: Audit that the environment access only happens in single-threaded code. unsafe { env::remove_var("FOO") }; //~^ ERROR call to deprecated safe function //~| WARN this is accepted in the current edition diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.stderr b/tests/ui/rust-2024/unsafe-env-suggestion.stderr index 151e80bb5d9e..234d77b2dc9f 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.stderr +++ b/tests/ui/rust-2024/unsafe-env-suggestion.stderr @@ -13,7 +13,7 @@ LL | #![deny(deprecated_safe_2024)] | ^^^^^^^^^^^^^^^^^^^^ help: you can wrap the call in an `unsafe` block if you can guarantee that the environment access only happens in single-threaded code | -LL + // TODO: Audit that the environment access only happens in single-threaded code. +LL + // FIXME: Audit that the environment access only happens in single-threaded code. LL ~ unsafe { env::set_var("FOO", "BAR") }; | @@ -27,7 +27,7 @@ LL | env::remove_var("FOO"); = note: for more information, see help: you can wrap the call in an `unsafe` block if you can guarantee that the environment access only happens in single-threaded code | -LL + // TODO: Audit that the environment access only happens in single-threaded code. +LL + // FIXME: Audit that the environment access only happens in single-threaded code. LL ~ unsafe { env::remove_var("FOO") }; | diff --git a/tests/ui/sanitize-attr/invalid-sanitize.rs b/tests/ui/sanitize-attr/invalid-sanitize.rs index 6846b6ff228b..5574661fcf5d 100644 --- a/tests/ui/sanitize-attr/invalid-sanitize.rs +++ b/tests/ui/sanitize-attr/invalid-sanitize.rs @@ -4,12 +4,12 @@ #[sanitize(brontosaurus = "off")] //~ ERROR malformed `sanitize` attribute input fn main() {} -#[sanitize(address = "off")] //~ ERROR multiple `sanitize` attributes #[sanitize(address = "off")] +#[sanitize(address = "off")] //~ ERROR multiple `sanitize` attributes fn multiple_consistent() {} -#[sanitize(address = "on")] //~ ERROR multiple `sanitize` attributes -#[sanitize(address = "off")] +#[sanitize(address = "on")] +#[sanitize(address = "off")] //~ ERROR multiple `sanitize` attributes fn multiple_inconsistent() {} #[sanitize(address = "bogus")] //~ ERROR malformed `sanitize` attribute input diff --git a/tests/ui/sanitize-attr/invalid-sanitize.stderr b/tests/ui/sanitize-attr/invalid-sanitize.stderr index 26ef31603d88..699902ffea05 100644 --- a/tests/ui/sanitize-attr/invalid-sanitize.stderr +++ b/tests/ui/sanitize-attr/invalid-sanitize.stderr @@ -4,31 +4,31 @@ error[E0539]: malformed `sanitize` attribute input LL | #[sanitize(brontosaurus = "off")] | ^^^^^^^^^^^------------^^^^^^^^^^ | | - | valid arguments are "address", "cfi", "kcfi", "memory", "memtag", "shadow_call_stack", "thread", "hwaddress" or "realtime" + | valid arguments are "address", "kernel_address", "cfi", "kcfi", "memory", "memtag", "shadow_call_stack", "thread", "hwaddress", "kernel_hwaddress" or "realtime" error: multiple `sanitize` attributes - --> $DIR/invalid-sanitize.rs:7:1 + --> $DIR/invalid-sanitize.rs:8:1 | LL | #[sanitize(address = "off")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/invalid-sanitize.rs:8:1 + --> $DIR/invalid-sanitize.rs:7:1 | LL | #[sanitize(address = "off")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: multiple `sanitize` attributes - --> $DIR/invalid-sanitize.rs:11:1 - | -LL | #[sanitize(address = "on")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here --> $DIR/invalid-sanitize.rs:12:1 | LL | #[sanitize(address = "off")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/invalid-sanitize.rs:11:1 + | +LL | #[sanitize(address = "on")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:15:1 diff --git a/tests/ui/sanitizer/cfg-khwasan.rs b/tests/ui/sanitizer/cfg-khwasan.rs new file mode 100644 index 000000000000..27a2f6030d0b --- /dev/null +++ b/tests/ui/sanitizer/cfg-khwasan.rs @@ -0,0 +1,20 @@ +// Verifies that when compiling with -Zsanitizer=kernel-hwaddress, +// the `#[cfg(sanitize = "hwaddress")]` attribute is configured. + +//@ add-minicore +//@ check-pass +//@ compile-flags: -Zsanitizer=kernel-hwaddress --target aarch64-unknown-none +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc + +#![crate_type = "rlib"] +#![feature(cfg_sanitize, no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +const _: fn() -> () = main; + +#[cfg(sanitize = "hwaddress")] +fn main() {} diff --git a/tests/ui/sanitizer/incompatible-khwasan.rs b/tests/ui/sanitizer/incompatible-khwasan.rs new file mode 100644 index 000000000000..eb6a5d33a472 --- /dev/null +++ b/tests/ui/sanitizer/incompatible-khwasan.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Z sanitizer=kernel-hwaddress -Z sanitizer=kernel-address --target aarch64-unknown-none +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc + +#![feature(no_core)] +#![no_core] +#![no_main] + +//~? ERROR `-Zsanitizer=kernel-address` is incompatible with `-Zsanitizer=kernel-hwaddress` diff --git a/tests/ui/sanitizer/incompatible-khwasan.stderr b/tests/ui/sanitizer/incompatible-khwasan.stderr new file mode 100644 index 000000000000..35246fb26623 --- /dev/null +++ b/tests/ui/sanitizer/incompatible-khwasan.stderr @@ -0,0 +1,4 @@ +error: `-Zsanitizer=kernel-address` is incompatible with `-Zsanitizer=kernel-hwaddress` + +error: aborting due to 1 previous error + diff --git a/tests/ui/sanitizer/kcfi-arity-requires-llvm-21-0-0.rs b/tests/ui/sanitizer/kcfi-arity-requires-llvm-21-0-0.rs deleted file mode 100644 index c3046708e4eb..000000000000 --- a/tests/ui/sanitizer/kcfi-arity-requires-llvm-21-0-0.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Verifies that `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later. -// -//@ needs-sanitizer-kcfi -//@ compile-flags: -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity -//@ build-fail -//@ max-llvm-major-version: 20 - -//~? ERROR `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later -#![feature(no_core)] -#![no_core] -#![no_main] diff --git a/tests/ui/sanitizer/kcfi-arity-requires-llvm-21-0-0.stderr b/tests/ui/sanitizer/kcfi-arity-requires-llvm-21-0-0.stderr deleted file mode 100644 index c5f886e3a390..000000000000 --- a/tests/ui/sanitizer/kcfi-arity-requires-llvm-21-0-0.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later - -error: aborting due to 1 previous error - diff --git a/tests/ui/sanitizer/unsupported-target-khwasan.rs b/tests/ui/sanitizer/unsupported-target-khwasan.rs new file mode 100644 index 000000000000..bef6d95e57b2 --- /dev/null +++ b/tests/ui/sanitizer/unsupported-target-khwasan.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Z sanitizer=kernel-hwaddress --target x86_64-unknown-none +//@ needs-llvm-components: x86 +//@ ignore-backends: gcc + +#![feature(no_core)] +#![no_core] +#![no_main] + +//~? ERROR kernel-hwaddress sanitizer is not supported for this target diff --git a/tests/ui/sanitizer/unsupported-target-khwasan.stderr b/tests/ui/sanitizer/unsupported-target-khwasan.stderr new file mode 100644 index 000000000000..8b122a610ee4 --- /dev/null +++ b/tests/ui/sanitizer/unsupported-target-khwasan.stderr @@ -0,0 +1,4 @@ +error: kernel-hwaddress sanitizer is not supported for this target + +error: aborting due to 1 previous error + diff --git a/tests/ui/scalable-vectors/bad-architectures.rs b/tests/ui/scalable-vectors/bad-architectures.rs new file mode 100644 index 000000000000..3323423316bf --- /dev/null +++ b/tests/ui/scalable-vectors/bad-architectures.rs @@ -0,0 +1,13 @@ +//@ ignore-aarch64 +//@ ignore-riscv32 +//@ ignore-riscv64 + +// Confirm that non-AArch64 and non-RISC-V targets error when compiling scalable vectors +// (see #153593) + +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +#[rustc_scalable_vector(4)] +//~^ ERROR: scalable vectors are not supported on this architecture +struct ScalableVec(i32); diff --git a/tests/ui/scalable-vectors/bad-architectures.stderr b/tests/ui/scalable-vectors/bad-architectures.stderr new file mode 100644 index 000000000000..94308a40e77d --- /dev/null +++ b/tests/ui/scalable-vectors/bad-architectures.stderr @@ -0,0 +1,8 @@ +error: scalable vectors are not supported on this architecture + --> $DIR/bad-architectures.rs:11:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/scalable-vectors/fn-trait.rs b/tests/ui/scalable-vectors/fn-trait.rs index 5203b5fa0efd..47b29202a671 100644 --- a/tests/ui/scalable-vectors/fn-trait.rs +++ b/tests/ui/scalable-vectors/fn-trait.rs @@ -1,3 +1,4 @@ +//@ only-aarch64 #![allow(internal_features)] #![feature(rustc_attrs)] diff --git a/tests/ui/scalable-vectors/fn-trait.stderr b/tests/ui/scalable-vectors/fn-trait.stderr index 4d00272dd1b5..8945069b10f8 100644 --- a/tests/ui/scalable-vectors/fn-trait.stderr +++ b/tests/ui/scalable-vectors/fn-trait.stderr @@ -1,5 +1,5 @@ error: scalable vectors cannot be tuple fields - --> $DIR/fn-trait.rs:9:8 + --> $DIR/fn-trait.rs:10:8 | LL | T: Fn(ScalableSimdFloat), | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/scalable-vectors/illegal_init.rs b/tests/ui/scalable-vectors/illegal-init.rs similarity index 94% rename from tests/ui/scalable-vectors/illegal_init.rs rename to tests/ui/scalable-vectors/illegal-init.rs index e8c0447fea42..c37a10b3f886 100644 --- a/tests/ui/scalable-vectors/illegal_init.rs +++ b/tests/ui/scalable-vectors/illegal-init.rs @@ -1,3 +1,4 @@ +//@ only-aarch64 #![allow(incomplete_features, internal_features)] #![feature(rustc_attrs)] diff --git a/tests/ui/scalable-vectors/illegal_init.stderr b/tests/ui/scalable-vectors/illegal-init.stderr similarity index 87% rename from tests/ui/scalable-vectors/illegal_init.stderr rename to tests/ui/scalable-vectors/illegal-init.stderr index db0fffcf3b77..0cd99cf52d50 100644 --- a/tests/ui/scalable-vectors/illegal_init.stderr +++ b/tests/ui/scalable-vectors/illegal-init.stderr @@ -1,5 +1,5 @@ error: scalable vector types cannot be initialised using their constructor - --> $DIR/illegal_init.rs:8:15 + --> $DIR/illegal-init.rs:9:15 | LL | let foo = svint32_t(1); | ^^^^^^^^^ you can create scalable vectors using intrinsics diff --git a/tests/ui/scalable-vectors/illformed-element-type.rs b/tests/ui/scalable-vectors/illformed-element-type.rs index 469ca006f5e9..8461b0a067ff 100644 --- a/tests/ui/scalable-vectors/illformed-element-type.rs +++ b/tests/ui/scalable-vectors/illformed-element-type.rs @@ -1,4 +1,5 @@ //@ compile-flags: --crate-type=lib +//@ only-aarch64 #![allow(internal_features)] #![feature(extern_types)] #![feature(never_type)] diff --git a/tests/ui/scalable-vectors/illformed-element-type.stderr b/tests/ui/scalable-vectors/illformed-element-type.stderr index f8ca8b76215f..52a434657070 100644 --- a/tests/ui/scalable-vectors/illformed-element-type.stderr +++ b/tests/ui/scalable-vectors/illformed-element-type.stderr @@ -1,5 +1,5 @@ error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:15:1 + --> $DIR/illformed-element-type.rs:16:1 | LL | struct TyChar(char); | ^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct TyChar(char); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:19:1 + --> $DIR/illformed-element-type.rs:20:1 | LL | struct TyConstPtr(*const u8); | ^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | struct TyConstPtr(*const u8); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:23:1 + --> $DIR/illformed-element-type.rs:24:1 | LL | struct TyMutPtr(*mut u8); | ^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | struct TyMutPtr(*mut u8); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:27:1 + --> $DIR/illformed-element-type.rs:28:1 | LL | struct TyStruct(Foo); | ^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | struct TyStruct(Foo); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:31:1 + --> $DIR/illformed-element-type.rs:32:1 | LL | struct TyEnum(Bar); | ^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | struct TyEnum(Bar); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:35:1 + --> $DIR/illformed-element-type.rs:36:1 | LL | struct TyUnion(Baz); | ^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | struct TyUnion(Baz); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:39:1 + --> $DIR/illformed-element-type.rs:40:1 | LL | struct TyForeign(Qux); | ^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | struct TyForeign(Qux); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:43:1 + --> $DIR/illformed-element-type.rs:44:1 | LL | struct TyArray([u32; 4]); | ^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | struct TyArray([u32; 4]); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:47:1 + --> $DIR/illformed-element-type.rs:48:1 | LL | struct TySlice([u32]); | ^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | struct TySlice([u32]); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:51:1 + --> $DIR/illformed-element-type.rs:52:1 | LL | struct TyRef<'a>(&'a u32); | ^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | struct TyRef<'a>(&'a u32); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:55:1 + --> $DIR/illformed-element-type.rs:56:1 | LL | struct TyFnPtr(fn(u32) -> u32); | ^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | struct TyFnPtr(fn(u32) -> u32); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:59:1 + --> $DIR/illformed-element-type.rs:60:1 | LL | struct TyDyn(dyn std::io::Write); | ^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | struct TyDyn(dyn std::io::Write); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:63:1 + --> $DIR/illformed-element-type.rs:64:1 | LL | struct TyNever(!); | ^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | struct TyNever(!); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:67:1 + --> $DIR/illformed-element-type.rs:68:1 | LL | struct TyTuple((u32, u32)); | ^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | struct TyTuple((u32, u32)); = help: only `u*`, `i*`, `f*` and `bool` types are accepted error: element type of a scalable vector must be a primitive scalar - --> $DIR/illformed-element-type.rs:77:1 + --> $DIR/illformed-element-type.rs:78:1 | LL | struct TyInvalidAlias(InvalidAlias); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs index 4f89a8f9055e..37d516144ca3 100644 --- a/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs +++ b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs @@ -1,4 +1,5 @@ //@ compile-flags: --crate-type=lib +//@ only-aarch64 #![allow(internal_features)] #![feature(rustc_attrs)] diff --git a/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr index f5fd963204a2..6cf1394471f3 100644 --- a/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr +++ b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr @@ -1,35 +1,35 @@ error: scalable vectors must be tuple structs - --> $DIR/illformed-tuples-of-scalable-vectors.rs:15:1 + --> $DIR/illformed-tuples-of-scalable-vectors.rs:16:1 | LL | struct Struct { x: ValidI64, y: ValidI64 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: all fields in a scalable vector struct must be the same type - --> $DIR/illformed-tuples-of-scalable-vectors.rs:19:39 + --> $DIR/illformed-tuples-of-scalable-vectors.rs:20:39 | LL | struct DifferentVectorTypes(ValidI64, ValidI32); | ^^^^^^^^ error: scalable vector structs can only have scalable vector fields - --> $DIR/illformed-tuples-of-scalable-vectors.rs:23:23 + --> $DIR/illformed-tuples-of-scalable-vectors.rs:24:23 | LL | struct NonVectorTypes(u32, u64); | ^^^ error: scalable vector structs can only have scalable vector fields - --> $DIR/illformed-tuples-of-scalable-vectors.rs:27:32 + --> $DIR/illformed-tuples-of-scalable-vectors.rs:28:32 | LL | struct DifferentNonVectorTypes(u32, u64); | ^^^ error: scalable vector structs can only have scalable vector fields - --> $DIR/illformed-tuples-of-scalable-vectors.rs:31:34 + --> $DIR/illformed-tuples-of-scalable-vectors.rs:32:34 | LL | struct SomeVectorTypes(ValidI64, u64); | ^^^ error: scalable vector structs cannot contain other scalable vector structs - --> $DIR/illformed-tuples-of-scalable-vectors.rs:35:20 + --> $DIR/illformed-tuples-of-scalable-vectors.rs:36:20 | LL | struct NestedTuple(ValidTuple, ValidTuple); | ^^^^^^^^^^ diff --git a/tests/ui/scalable-vectors/illformed-within-types.rs b/tests/ui/scalable-vectors/illformed-within-types.rs index 81d960e4d4e1..d34d1ba2d7eb 100644 --- a/tests/ui/scalable-vectors/illformed-within-types.rs +++ b/tests/ui/scalable-vectors/illformed-within-types.rs @@ -1,4 +1,5 @@ //@ compile-flags: --crate-type=lib +//@ only-aarch64 #![allow(internal_features)] #![feature(rustc_attrs)] diff --git a/tests/ui/scalable-vectors/illformed-within-types.stderr b/tests/ui/scalable-vectors/illformed-within-types.stderr index e76ef26f2aa4..b95452779f60 100644 --- a/tests/ui/scalable-vectors/illformed-within-types.stderr +++ b/tests/ui/scalable-vectors/illformed-within-types.stderr @@ -1,29 +1,29 @@ error: scalable vectors cannot be fields of a struct - --> $DIR/illformed-within-types.rs:9:8 + --> $DIR/illformed-within-types.rs:10:8 | LL | x: ValidI64, | ^^^^^^^^ error: scalable vectors cannot be tuple fields - --> $DIR/illformed-within-types.rs:11:15 + --> $DIR/illformed-within-types.rs:12:15 | LL | in_tuple: (ValidI64,), | ^^^^^^^^^^^ error: scalable vectors cannot be fields of a struct - --> $DIR/illformed-within-types.rs:15:20 + --> $DIR/illformed-within-types.rs:16:20 | LL | struct TupleStruct(ValidI64); | ^^^^^^^^ error: scalable vectors cannot be fields of a variant - --> $DIR/illformed-within-types.rs:19:26 + --> $DIR/illformed-within-types.rs:20:26 | LL | StructVariant { _ty: ValidI64 }, | ^^^^^^^^ error: scalable vectors cannot be fields of a variant - --> $DIR/illformed-within-types.rs:21:18 + --> $DIR/illformed-within-types.rs:22:18 | LL | TupleVariant(ValidI64), | ^^^^^^^^ diff --git a/tests/ui/scalable-vectors/illformed.rs b/tests/ui/scalable-vectors/illformed.rs index de135413a9f2..0122b3735ff2 100644 --- a/tests/ui/scalable-vectors/illformed.rs +++ b/tests/ui/scalable-vectors/illformed.rs @@ -1,7 +1,11 @@ //@ compile-flags: --crate-type=lib +//@ only-aarch64 #![allow(internal_features)] #![feature(rustc_attrs)] +#[rustc_scalable_vector(4)] +struct Valid(f32); + #[rustc_scalable_vector(4)] struct NoFieldsStructWithElementCount {} //~^ ERROR: scalable vectors must have a single field @@ -18,16 +22,16 @@ struct NoFieldsStructWithElementCount {} #[rustc_scalable_vector] struct NoFieldsStructWithoutElementCount {} -//~^ ERROR: scalable vectors must have a single field +//~^ ERROR: scalable vector tuples must have at least one field //~^^ ERROR: scalable vectors must be tuple structs #[rustc_scalable_vector] struct NoFieldsTupleWithoutElementCount(); -//~^ ERROR: scalable vectors must have a single field +//~^ ERROR: scalable vector tuples must have at least one field #[rustc_scalable_vector] struct NoFieldsUnitWithoutElementCount; -//~^ ERROR: scalable vectors must have a single field +//~^ ERROR: scalable vector tuples must have at least one field //~^^ ERROR: scalable vectors must be tuple structs #[rustc_scalable_vector(4)] @@ -57,3 +61,8 @@ struct MultipleFieldsStructWithoutElementCount { #[rustc_scalable_vector(2)] struct SingleFieldStruct { _ty: f64 } //~^ ERROR: scalable vectors must be tuple structs + +#[rustc_scalable_vector] +struct TooManyFieldsWithoutElementCount( + Valid, Valid, Valid, Valid, Valid, Valid, Valid, Valid, Valid); +//~^^ ERROR: scalable vector tuples can have at most eight fields diff --git a/tests/ui/scalable-vectors/illformed.stderr b/tests/ui/scalable-vectors/illformed.stderr index bdf519c91058..29640f023e21 100644 --- a/tests/ui/scalable-vectors/illformed.stderr +++ b/tests/ui/scalable-vectors/illformed.stderr @@ -1,29 +1,29 @@ error: scalable vectors must be tuple structs - --> $DIR/illformed.rs:6:1 + --> $DIR/illformed.rs:10:1 | LL | struct NoFieldsStructWithElementCount {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: scalable vectors must be tuple structs - --> $DIR/illformed.rs:15:1 + --> $DIR/illformed.rs:19:1 | LL | struct NoFieldsUnitWithElementCount; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: scalable vectors must be tuple structs - --> $DIR/illformed.rs:20:1 + --> $DIR/illformed.rs:24:1 | LL | struct NoFieldsStructWithoutElementCount {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: scalable vectors must be tuple structs - --> $DIR/illformed.rs:29:1 + --> $DIR/illformed.rs:33:1 | LL | struct NoFieldsUnitWithoutElementCount; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: scalable vectors must be tuple structs - --> $DIR/illformed.rs:34:1 + --> $DIR/illformed.rs:38:1 | LL | / struct MultipleFieldsStructWithElementCount { LL | | @@ -34,7 +34,7 @@ LL | | } | |_^ error: scalable vectors must be tuple structs - --> $DIR/illformed.rs:46:1 + --> $DIR/illformed.rs:50:1 | LL | / struct MultipleFieldsStructWithoutElementCount { LL | | @@ -44,13 +44,13 @@ LL | | } | |_^ error: scalable vectors must be tuple structs - --> $DIR/illformed.rs:58:1 + --> $DIR/illformed.rs:62:1 | LL | struct SingleFieldStruct { _ty: f64 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: scalable vectors must have a single field - --> $DIR/illformed.rs:6:1 + --> $DIR/illformed.rs:10:1 | LL | struct NoFieldsStructWithElementCount {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ LL | struct NoFieldsStructWithElementCount {} = help: scalable vector types' only field must be a primitive scalar type error: scalable vectors must have a single field - --> $DIR/illformed.rs:11:1 + --> $DIR/illformed.rs:15:1 | LL | struct NoFieldsTupleWithElementCount(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,31 +66,31 @@ LL | struct NoFieldsTupleWithElementCount(); = help: scalable vector types' only field must be a primitive scalar type error: scalable vectors must have a single field - --> $DIR/illformed.rs:15:1 + --> $DIR/illformed.rs:19:1 | LL | struct NoFieldsUnitWithElementCount; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: scalable vector types' only field must be a primitive scalar type -error: scalable vectors must have a single field - --> $DIR/illformed.rs:20:1 +error: scalable vector tuples must have at least one field + --> $DIR/illformed.rs:24:1 | LL | struct NoFieldsStructWithoutElementCount {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: tuples of scalable vectors can only contain multiple of the same scalable vector type -error: scalable vectors must have a single field - --> $DIR/illformed.rs:25:1 +error: scalable vector tuples must have at least one field + --> $DIR/illformed.rs:29:1 | LL | struct NoFieldsTupleWithoutElementCount(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: tuples of scalable vectors can only contain multiple of the same scalable vector type -error: scalable vectors must have a single field - --> $DIR/illformed.rs:29:1 +error: scalable vector tuples must have at least one field + --> $DIR/illformed.rs:33:1 | LL | struct NoFieldsUnitWithoutElementCount; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -98,28 +98,36 @@ LL | struct NoFieldsUnitWithoutElementCount; = help: tuples of scalable vectors can only contain multiple of the same scalable vector type error: scalable vectors cannot have multiple fields - --> $DIR/illformed.rs:34:1 + --> $DIR/illformed.rs:38:1 | LL | struct MultipleFieldsStructWithElementCount { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: scalable vectors cannot have multiple fields - --> $DIR/illformed.rs:42:1 + --> $DIR/illformed.rs:46:1 | LL | struct MultipleFieldsTupleWithElementCount(f32, u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: scalable vector structs can only have scalable vector fields - --> $DIR/illformed.rs:48:5 + --> $DIR/illformed.rs:52:5 | LL | _ty: f32, | ^^^^^^^^ error: scalable vector structs can only have scalable vector fields - --> $DIR/illformed.rs:54:47 + --> $DIR/illformed.rs:58:47 | LL | struct MultipleFieldsTupleWithoutElementCount(f32, u32); | ^^^ -error: aborting due to 17 previous errors +error: scalable vector tuples can have at most eight fields + --> $DIR/illformed.rs:66:1 + | +LL | struct TooManyFieldsWithoutElementCount( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: tuples of scalable vectors can only contain multiple of the same scalable vector type + +error: aborting due to 18 previous errors diff --git a/tests/ui/scalable-vectors/invalid.rs b/tests/ui/scalable-vectors/invalid.rs index 90e9839c9e11..0b6a915e5ccd 100644 --- a/tests/ui/scalable-vectors/invalid.rs +++ b/tests/ui/scalable-vectors/invalid.rs @@ -1,4 +1,5 @@ //@ edition: 2024 +//@ only-aarch64 #![allow(internal_features, unused_imports, unused_macros)] #![feature(extern_types)] #![feature(gen_blocks)] diff --git a/tests/ui/scalable-vectors/invalid.stderr b/tests/ui/scalable-vectors/invalid.stderr index d73b5abf7030..a8ef99e2f8bc 100644 --- a/tests/ui/scalable-vectors/invalid.stderr +++ b/tests/ui/scalable-vectors/invalid.stderr @@ -1,11 +1,11 @@ error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters - --> $DIR/invalid.rs:109:11 + --> $DIR/invalid.rs:110:11 | LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[rustc_scalable_vector]` attribute cannot be used on extern crates - --> $DIR/invalid.rs:9:1 + --> $DIR/invalid.rs:10:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on use statements - --> $DIR/invalid.rs:13:1 + --> $DIR/invalid.rs:14:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on statics - --> $DIR/invalid.rs:17:1 + --> $DIR/invalid.rs:18:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on constants - --> $DIR/invalid.rs:21:1 + --> $DIR/invalid.rs:22:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on modules - --> $DIR/invalid.rs:25:1 + --> $DIR/invalid.rs:26:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on foreign modules - --> $DIR/invalid.rs:30:1 + --> $DIR/invalid.rs:31:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on foreign statics - --> $DIR/invalid.rs:33:5 + --> $DIR/invalid.rs:34:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on foreign types - --> $DIR/invalid.rs:36:5 + --> $DIR/invalid.rs:37:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on foreign functions - --> $DIR/invalid.rs:39:5 + --> $DIR/invalid.rs:40:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on type aliases - --> $DIR/invalid.rs:44:1 + --> $DIR/invalid.rs:45:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on enums - --> $DIR/invalid.rs:48:1 + --> $DIR/invalid.rs:49:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on type parameters - --> $DIR/invalid.rs:50:10 + --> $DIR/invalid.rs:51:10 | LL | enum Bar<#[rustc_scalable_vector(4)] T> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -101,7 +101,7 @@ LL | enum Bar<#[rustc_scalable_vector(4)] T> { = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on enum variants - --> $DIR/invalid.rs:52:5 + --> $DIR/invalid.rs:53:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on struct fields - --> $DIR/invalid.rs:58:5 + --> $DIR/invalid.rs:59:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on unions - --> $DIR/invalid.rs:63:1 + --> $DIR/invalid.rs:64:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on traits - --> $DIR/invalid.rs:70:1 + --> $DIR/invalid.rs:71:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on associated types - --> $DIR/invalid.rs:73:5 + --> $DIR/invalid.rs:74:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -141,7 +141,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on associated consts - --> $DIR/invalid.rs:76:5 + --> $DIR/invalid.rs:77:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on provided trait methods - --> $DIR/invalid.rs:79:5 + --> $DIR/invalid.rs:80:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on trait aliases - --> $DIR/invalid.rs:84:1 + --> $DIR/invalid.rs:85:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on inherent impl blocks - --> $DIR/invalid.rs:88:1 + --> $DIR/invalid.rs:89:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on inherent methods - --> $DIR/invalid.rs:91:5 + --> $DIR/invalid.rs:92:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on trait impl blocks - --> $DIR/invalid.rs:96:1 + --> $DIR/invalid.rs:97:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on macro defs - --> $DIR/invalid.rs:103:1 + --> $DIR/invalid.rs:104:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on functions - --> $DIR/invalid.rs:107:1 + --> $DIR/invalid.rs:108:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on function params - --> $DIR/invalid.rs:109:11 + --> $DIR/invalid.rs:110:11 | LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -213,7 +213,7 @@ LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {} = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on functions - --> $DIR/invalid.rs:113:1 + --> $DIR/invalid.rs:114:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -221,7 +221,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on functions - --> $DIR/invalid.rs:117:1 + --> $DIR/invalid.rs:118:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on functions - --> $DIR/invalid.rs:121:1 + --> $DIR/invalid.rs:122:1 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -237,7 +237,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on closures - --> $DIR/invalid.rs:126:14 + --> $DIR/invalid.rs:127:14 | LL | let _x = #[rustc_scalable_vector(4)] || { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,7 +245,7 @@ LL | let _x = #[rustc_scalable_vector(4)] || { }; = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on expressions - --> $DIR/invalid.rs:128:14 + --> $DIR/invalid.rs:129:14 | LL | let _y = #[rustc_scalable_vector(4)] 3 + 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | let _y = #[rustc_scalable_vector(4)] 3 + 4; = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on statements - --> $DIR/invalid.rs:130:5 + --> $DIR/invalid.rs:131:5 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -261,7 +261,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error: `#[rustc_scalable_vector]` attribute cannot be used on match arms - --> $DIR/invalid.rs:135:9 + --> $DIR/invalid.rs:136:9 | LL | #[rustc_scalable_vector(4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -269,7 +269,7 @@ LL | #[rustc_scalable_vector(4)] = help: `#[rustc_scalable_vector]` can only be applied to structs error[E0539]: malformed `rustc_scalable_vector` attribute input - --> $DIR/invalid.rs:142:1 + --> $DIR/invalid.rs:143:1 | LL | #[rustc_scalable_vector("4")] | ^^^^^^^^^^^^^^^^^^^^^^^^---^^ @@ -286,7 +286,7 @@ LL + #[rustc_scalable_vector] | error[E0805]: malformed `rustc_scalable_vector` attribute input - --> $DIR/invalid.rs:146:1 + --> $DIR/invalid.rs:147:1 | LL | #[rustc_scalable_vector(4, 2)] | ^^^^^^^^^^^^^^^^^^^^^^^------^ @@ -303,7 +303,7 @@ LL + #[rustc_scalable_vector] | error[E0539]: malformed `rustc_scalable_vector` attribute input - --> $DIR/invalid.rs:150:1 + --> $DIR/invalid.rs:151:1 | LL | #[rustc_scalable_vector(count = "4")] | ^^^^^^^^^^^^^^^^^^^^^^^^-----------^^ @@ -320,7 +320,7 @@ LL + #[rustc_scalable_vector] | error: element count in `rustc_scalable_vector` is too large: `65536` - --> $DIR/invalid.rs:154:1 + --> $DIR/invalid.rs:155:1 | LL | #[rustc_scalable_vector(65536)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +328,7 @@ LL | #[rustc_scalable_vector(65536)] = note: the value may not exceed `u16::MAX` error: scalable vector structs can only have scalable vector fields - --> $DIR/invalid.rs:162:18 + --> $DIR/invalid.rs:163:18 | LL | struct OkayNoArg(f32); | ^^^ diff --git a/tests/ui/scalable-vectors/wellformed-arrays.rs b/tests/ui/scalable-vectors/wellformed-arrays.rs index b8f0bf291eea..6a26a8595fa6 100644 --- a/tests/ui/scalable-vectors/wellformed-arrays.rs +++ b/tests/ui/scalable-vectors/wellformed-arrays.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: --crate-type=lib +//@ only-aarch64 #![feature(rustc_attrs)] #[rustc_scalable_vector(16)] diff --git a/tests/ui/scalable-vectors/wellformed.rs b/tests/ui/scalable-vectors/wellformed.rs index cb6a22d6c433..da300d53ef88 100644 --- a/tests/ui/scalable-vectors/wellformed.rs +++ b/tests/ui/scalable-vectors/wellformed.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: --crate-type=lib +//@ only-aarch64 #![feature(rustc_attrs)] #[rustc_scalable_vector(16)] diff --git a/tests/ui/self/issue-61882.stderr b/tests/ui/self/issue-61882.stderr index 96f4e41de174..867e3e97ac37 100644 --- a/tests/ui/self/issue-61882.stderr +++ b/tests/ui/self/issue-61882.stderr @@ -16,7 +16,9 @@ error[E0308]: mismatched types --> $DIR/issue-61882.rs:4:22 | LL | const B: A = Self(0); - | ^^^^^^^ expected `A`, found `A` + | ----- ^^^^^^^ expected `A`, found `A` + | | + | expected because of the type of the associated constant | = note: expected struct `A` found struct `A` diff --git a/tests/ui/shadowed/shadowing-generic-item.rs b/tests/ui/shadowed/shadowing-generic-item.rs index c3a0ced04e7f..8a81530aab42 100644 --- a/tests/ui/shadowed/shadowing-generic-item.rs +++ b/tests/ui/shadowed/shadowing-generic-item.rs @@ -9,7 +9,7 @@ mod Foo { pub fn f() {} } fn g() { - Foo::f(); //~ ERROR no function or associated item named `f` + Foo::f(); //~ ERROR no associated function or constant named `f` } fn main() {} diff --git a/tests/ui/shadowed/shadowing-generic-item.stderr b/tests/ui/shadowed/shadowing-generic-item.stderr index 55a0bb36ea80..eb517b1a9cdb 100644 --- a/tests/ui/shadowed/shadowing-generic-item.stderr +++ b/tests/ui/shadowed/shadowing-generic-item.stderr @@ -8,13 +8,13 @@ LL | fn f() { LL | let t = T { i: 0 }; | ^ not a struct, variant or union type -error[E0599]: no function or associated item named `f` found for type parameter `Foo` in the current scope +error[E0599]: no associated function or constant named `f` found for type parameter `Foo` in the current scope --> $DIR/shadowing-generic-item.rs:12:10 | LL | fn g() { - | --- function or associated item `f` not found for this type parameter + | --- associated function or constant `f` not found for this type parameter LL | Foo::f(); - | ^ function or associated item not found in `Foo` + | ^ associated function or constant not found in `Foo` error: aborting due to 2 previous errors diff --git a/tests/ui/simd/const-err-trumps-simd-err.rs b/tests/ui/simd/const-err-trumps-simd-err.rs index 33f0abb06f3e..282d5dabf72f 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.rs +++ b/tests/ui/simd/const-err-trumps-simd-err.rs @@ -1,6 +1,6 @@ //@build-fail //@ dont-require-annotations: NOTE - +//@ ignore-parallel-frontend post-monomorphization errors //! Make sure that monomorphization-time const errors from `static_assert` take priority over the //! error from simd_extract. Basically this checks that if a const fails to evaluate in some //! function, we don't bother codegen'ing the function. diff --git a/tests/ui/simd/intrinsic/float-minmax-pass.rs b/tests/ui/simd/intrinsic/float-minmax-pass.rs index 4b6a35556ed5..8ef5d85385a4 100644 --- a/tests/ui/simd/intrinsic/float-minmax-pass.rs +++ b/tests/ui/simd/intrinsic/float-minmax-pass.rs @@ -1,8 +1,8 @@ //@ run-pass //@ ignore-emscripten -//@ compile-flags: --cfg minisimd_const +//@ compile-flags: --cfg minisimd_const -O -// Test that the simd_f{min,max} intrinsics produce the correct results. +// Test that the simd_{min,max}imum_number_nsz intrinsics produce the correct results. #![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)] #![allow(non_camel_case_types)] @@ -12,39 +12,38 @@ use minisimd::*; use std::intrinsics::simd::*; +use std::hint::black_box; const fn minmax() { let x = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); let y = f32x4::from_array([2.0, 1.0, 4.0, 3.0]); - #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] let nan = f32::NAN; - // MIPS hardware except MIPS R6 treats f32::NAN as SNAN. Clear the signaling bit. - // See https://github.com/rust-lang/rust/issues/52746. - #[cfg(any(target_arch = "mips", target_arch = "mips64"))] - let nan = f32::from_bits(f32::NAN.to_bits() - 1); + // The "-1" works because we rely on `NAN` to have an all-0 payload, so the signaling + // bit is the least significant non-zero bit. + let snan = f32::from_bits(f32::NAN.to_bits() - 1); - let n = f32x4::from_array([nan, nan, nan, nan]); + let n = f32x4::from_array([nan, nan, snan, snan]); unsafe { - let min0 = simd_fmin(x, y); - let min1 = simd_fmin(y, x); + let min0 = simd_minimum_number_nsz(x, y); + let min1 = simd_minimum_number_nsz(y, black_box(x)); assert_eq!(min0, min1); let e = f32x4::from_array([1.0, 1.0, 3.0, 3.0]); assert_eq!(min0, e); - let minn = simd_fmin(x, n); + let minn = simd_minimum_number_nsz(x, n); assert_eq!(minn, x); - let minn = simd_fmin(y, n); + let minn = simd_minimum_number_nsz(black_box(y), n); assert_eq!(minn, y); - let max0 = simd_fmax(x, y); - let max1 = simd_fmax(y, x); + let max0 = simd_maximum_number_nsz(x, y); + let max1 = simd_maximum_number_nsz(y, black_box(x)); assert_eq!(max0, max1); let e = f32x4::from_array([2.0, 2.0, 4.0, 4.0]); assert_eq!(max0, e); - let maxn = simd_fmax(x, n); + let maxn = simd_maximum_number_nsz(x, n); assert_eq!(maxn, x); - let maxn = simd_fmax(y, n); + let maxn = simd_maximum_number_nsz(n, black_box(y)); assert_eq!(maxn, y); } } diff --git a/tests/ui/span/issue-42234-unknown-receiver-type.stderr b/tests/ui/span/issue-42234-unknown-receiver-type.stderr index f16006a8e085..9ebe7d64584d 100644 --- a/tests/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/tests/ui/span/issue-42234-unknown-receiver-type.stderr @@ -12,10 +12,10 @@ LL | let x: Option<_> = None::; | +++++ error[E0282]: type annotations needed - --> $DIR/issue-42234-unknown-receiver-type.rs:12:10 + --> $DIR/issue-42234-unknown-receiver-type.rs:12:16 | LL | .sum::<_>() - | ^^^ cannot infer type of the type parameter `S` declared on the method `sum` + | ^ cannot infer type of the type parameter `S` declared on the method `sum` error: aborting due to 2 previous errors diff --git a/tests/ui/span/issue-43927-non-ADT-derive.stderr b/tests/ui/span/issue-43927-non-ADT-derive.stderr index 27ed561f5be8..8742f34c45c6 100644 --- a/tests/ui/span/issue-43927-non-ADT-derive.stderr +++ b/tests/ui/span/issue-43927-non-ADT-derive.stderr @@ -5,7 +5,7 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | struct DerivedOn; - | --------- the inner attribute doesn't annotate this struct + | ----------------- the inner attribute doesn't annotate this item | help: perhaps you meant to use an outer attribute | diff --git a/tests/ui/span/multiline-span-simple.stderr b/tests/ui/span/multiline-span-simple.stderr index e013b3c06bc1..ea7aff370fe1 100644 --- a/tests/ui/span/multiline-span-simple.stderr +++ b/tests/ui/span/multiline-span-simple.stderr @@ -1,8 +1,13 @@ error[E0277]: cannot add `()` to `u32` --> $DIR/multiline-span-simple.rs:13:18 | -LL | foo(1 as u32 + - | ^ no implementation for `u32 + ()` +LL | foo(1 as u32 + + | -------- ^ no implementation for `u32 + ()` +LL | +LL | / bar(x, +LL | | +LL | | y), + | |______________- | = help: the trait `Add<()>` is not implemented for `u32` help: the following other types implement trait `Add` diff --git a/tests/ui/specialization/assoc-ty-graph-cycle.rs b/tests/ui/specialization/assoc-ty-graph-cycle.rs index 083b03028f08..16be58e27098 100644 --- a/tests/ui/specialization/assoc-ty-graph-cycle.rs +++ b/tests/ui/specialization/assoc-ty-graph-cycle.rs @@ -2,7 +2,7 @@ // Make sure we don't crash with a cycle error during coherence. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Trait { type Assoc; diff --git a/tests/ui/specialization/assoc-ty-graph-cycle.stderr b/tests/ui/specialization/assoc-ty-graph-cycle.stderr deleted file mode 100644 index f5529c24d3e8..000000000000 --- a/tests/ui/specialization/assoc-ty-graph-cycle.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/assoc-ty-graph-cycle.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.rs b/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.rs index 1691530fa0a5..a0073d518689 100644 --- a/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.rs +++ b/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.rs @@ -1,5 +1,5 @@ // regression test for #118987 -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Assoc { type Output; diff --git a/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.stderr b/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.stderr index e950268fa1b3..8ccf0c23dbd9 100644 --- a/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.stderr +++ b/tests/ui/specialization/coherence/default-impl-normalization-ambig-2.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-impl-normalization-ambig-2.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `u16: Assoc` is not satisfied --> $DIR/default-impl-normalization-ambig-2.rs:17:14 | @@ -20,6 +10,6 @@ help: the trait `Assoc` is implemented for `u8` LL | impl Assoc for u8 {} | ^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/specialization/coherence/default-item-normalization-ambig-1.rs b/tests/ui/specialization/coherence/default-item-normalization-ambig-1.rs index af7cf332d5f4..24142a472fde 100644 --- a/tests/ui/specialization/coherence/default-item-normalization-ambig-1.rs +++ b/tests/ui/specialization/coherence/default-item-normalization-ambig-1.rs @@ -1,5 +1,5 @@ // regression test for #73299. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait X { type U; diff --git a/tests/ui/specialization/coherence/default-item-normalization-ambig-1.stderr b/tests/ui/specialization/coherence/default-item-normalization-ambig-1.stderr index a15151cc9c41..f45c4e55572b 100644 --- a/tests/ui/specialization/coherence/default-item-normalization-ambig-1.stderr +++ b/tests/ui/specialization/coherence/default-item-normalization-ambig-1.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-item-normalization-ambig-1.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0119]: conflicting implementations of trait `Y` for type `<() as X>::U` --> $DIR/default-item-normalization-ambig-1.rs:20:1 | @@ -16,6 +6,6 @@ LL | impl Y for <() as X>::U {} LL | impl Y for ::U {} | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<() as X>::U` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/cross-crate-defaults.rs b/tests/ui/specialization/cross-crate-defaults.rs index c9204461e206..0a2d6e973dc1 100644 --- a/tests/ui/specialization/cross-crate-defaults.rs +++ b/tests/ui/specialization/cross-crate-defaults.rs @@ -2,7 +2,7 @@ //@ aux-build:cross_crates_defaults.rs -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] extern crate cross_crates_defaults; diff --git a/tests/ui/specialization/cross-crate-defaults.stderr b/tests/ui/specialization/cross-crate-defaults.stderr deleted file mode 100644 index ee5c77a76be4..000000000000 --- a/tests/ui/specialization/cross-crate-defaults.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/cross-crate-defaults.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/ctfe/default-assoc-const.rs b/tests/ui/specialization/ctfe/default-assoc-const.rs index 083aedece51a..644e56f5ccc5 100644 --- a/tests/ui/specialization/ctfe/default-assoc-const.rs +++ b/tests/ui/specialization/ctfe/default-assoc-const.rs @@ -1,7 +1,6 @@ //! Regression test for revealing associated types through specialization during const eval. //@ check-pass #![feature(specialization)] -//~^ WARNING the feature `specialization` is incomplete and may not be safe to use trait Foo { const ASSOC: usize; diff --git a/tests/ui/specialization/ctfe/default-assoc-const.stderr b/tests/ui/specialization/ctfe/default-assoc-const.stderr deleted file mode 100644 index 933b6dcf8f99..000000000000 --- a/tests/ui/specialization/ctfe/default-assoc-const.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-assoc-const.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/ctfe/default-assoc-type.rs b/tests/ui/specialization/ctfe/default-assoc-type.rs index 0ceba2dc4977..0415cd3da5c1 100644 --- a/tests/ui/specialization/ctfe/default-assoc-type.rs +++ b/tests/ui/specialization/ctfe/default-assoc-type.rs @@ -2,7 +2,6 @@ //! even if they rely on specialization. //@ check-pass #![feature(specialization)] -//~^ WARNING the feature `specialization` is incomplete and may not be safe to use trait Foo { type Assoc: Trait; diff --git a/tests/ui/specialization/ctfe/default-assoc-type.stderr b/tests/ui/specialization/ctfe/default-assoc-type.stderr deleted file mode 100644 index 23fa213caffb..000000000000 --- a/tests/ui/specialization/ctfe/default-assoc-type.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-assoc-type.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/default-associated-type-bound-1.rs b/tests/ui/specialization/default-associated-type-bound-1.rs index c043114b565c..8e889a61f158 100644 --- a/tests/ui/specialization/default-associated-type-bound-1.rs +++ b/tests/ui/specialization/default-associated-type-bound-1.rs @@ -2,7 +2,6 @@ // bounds on them. #![feature(specialization)] -//~^ WARNING `specialization` is incomplete trait X { type U: Clone; diff --git a/tests/ui/specialization/default-associated-type-bound-1.stderr b/tests/ui/specialization/default-associated-type-bound-1.stderr index aa6f69578aaf..70408145e803 100644 --- a/tests/ui/specialization/default-associated-type-bound-1.stderr +++ b/tests/ui/specialization/default-associated-type-bound-1.stderr @@ -1,15 +1,5 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-associated-type-bound-1.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/default-associated-type-bound-1.rs:18:22 + --> $DIR/default-associated-type-bound-1.rs:17:22 | LL | default type U = str; | ^^^ the trait `Clone` is not implemented for `str` @@ -17,11 +7,11 @@ LL | default type U = str; help: the trait `Clone` is implemented for `String` --> $SRC_DIR/alloc/src/string.rs:LL:COL note: required by a bound in `X::U` - --> $DIR/default-associated-type-bound-1.rs:8:13 + --> $DIR/default-associated-type-bound-1.rs:7:13 | LL | type U: Clone; | ^^^^^ required by this bound in `X::U` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/specialization/default-associated-type-bound-2.rs b/tests/ui/specialization/default-associated-type-bound-2.rs index 0a21b1f09106..9ea31f34c5cb 100644 --- a/tests/ui/specialization/default-associated-type-bound-2.rs +++ b/tests/ui/specialization/default-associated-type-bound-2.rs @@ -1,6 +1,5 @@ // Check that generic predicates are also checked for default associated types. #![feature(specialization)] -//~^ WARNING `specialization` is incomplete trait X { type U: PartialEq; diff --git a/tests/ui/specialization/default-associated-type-bound-2.stderr b/tests/ui/specialization/default-associated-type-bound-2.stderr index e02a945d9a9b..3d3fdbad2640 100644 --- a/tests/ui/specialization/default-associated-type-bound-2.stderr +++ b/tests/ui/specialization/default-associated-type-bound-2.stderr @@ -1,22 +1,12 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-associated-type-bound-2.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: can't compare `&'static B` with `B` - --> $DIR/default-associated-type-bound-2.rs:16:22 + --> $DIR/default-associated-type-bound-2.rs:15:22 | LL | default type U = &'static B; | ^^^^^^^^^^ no implementation for `&'static B == B` | = help: the trait `PartialEq` is not implemented for `&'static B` note: required by a bound in `X::U` - --> $DIR/default-associated-type-bound-2.rs:6:13 + --> $DIR/default-associated-type-bound-2.rs:5:13 | LL | type U: PartialEq; | ^^^^^^^^^^^^ required by this bound in `X::U` @@ -25,6 +15,6 @@ help: consider introducing a `where` clause, but there might be an alternative b LL | impl X for T where &'static B: PartialEq { | ++++++++++++++++++++++++++++++ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/specialization/default-generic-associated-type-bound.rs b/tests/ui/specialization/default-generic-associated-type-bound.rs index 31a0685d004b..7cdb6c2052cf 100644 --- a/tests/ui/specialization/default-generic-associated-type-bound.rs +++ b/tests/ui/specialization/default-generic-associated-type-bound.rs @@ -1,7 +1,6 @@ // Check that default generics associated types are validated. #![feature(specialization)] -//~^ WARNING `specialization` is incomplete trait X { type U<'a>: PartialEq<&'a Self> where Self: 'a; diff --git a/tests/ui/specialization/default-generic-associated-type-bound.stderr b/tests/ui/specialization/default-generic-associated-type-bound.stderr index 57d67ac526ac..7c2bde84a367 100644 --- a/tests/ui/specialization/default-generic-associated-type-bound.stderr +++ b/tests/ui/specialization/default-generic-associated-type-bound.stderr @@ -1,22 +1,12 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-generic-associated-type-bound.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: can't compare `T` with `T` - --> $DIR/default-generic-associated-type-bound.rs:17:26 + --> $DIR/default-generic-associated-type-bound.rs:16:26 | LL | default type U<'a> = &'a T; | ^^^^^ no implementation for `T == T` | = note: required for `&'a T` to implement `PartialEq` note: required by a bound in `X::U` - --> $DIR/default-generic-associated-type-bound.rs:7:17 + --> $DIR/default-generic-associated-type-bound.rs:6:17 | LL | type U<'a>: PartialEq<&'a Self> where Self: 'a; | ^^^^^^^^^^^^^^^^^^^ required by this bound in `X::U` @@ -25,6 +15,6 @@ help: consider further restricting type parameter `T` with trait `PartialEq` LL | impl X for T { | +++++++++++++++++++++ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/specialization/defaultimpl/allowed-cross-crate.rs b/tests/ui/specialization/defaultimpl/allowed-cross-crate.rs index 697a62ca547f..1a6c3832b16d 100644 --- a/tests/ui/specialization/defaultimpl/allowed-cross-crate.rs +++ b/tests/ui/specialization/defaultimpl/allowed-cross-crate.rs @@ -5,7 +5,7 @@ //@ aux-build:go_trait.rs -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] extern crate go_trait; diff --git a/tests/ui/specialization/defaultimpl/allowed-cross-crate.stderr b/tests/ui/specialization/defaultimpl/allowed-cross-crate.stderr deleted file mode 100644 index 02f13d461c3c..000000000000 --- a/tests/ui/specialization/defaultimpl/allowed-cross-crate.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/allowed-cross-crate.rs:8:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/defaultimpl/out-of-order.rs b/tests/ui/specialization/defaultimpl/out-of-order.rs index 2274946df697..bd3bfe2b8659 100644 --- a/tests/ui/specialization/defaultimpl/out-of-order.rs +++ b/tests/ui/specialization/defaultimpl/out-of-order.rs @@ -2,7 +2,7 @@ // Test that you can list the more specific impl before the more general one. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo { type Out; diff --git a/tests/ui/specialization/defaultimpl/out-of-order.stderr b/tests/ui/specialization/defaultimpl/out-of-order.stderr deleted file mode 100644 index 2cf1ac90959e..000000000000 --- a/tests/ui/specialization/defaultimpl/out-of-order.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/out-of-order.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/defaultimpl/overlap-projection.rs b/tests/ui/specialization/defaultimpl/overlap-projection.rs index da466e6671c9..1af10400e5fa 100644 --- a/tests/ui/specialization/defaultimpl/overlap-projection.rs +++ b/tests/ui/specialization/defaultimpl/overlap-projection.rs @@ -4,7 +4,7 @@ // projections involve specialization, so long as the associated type is // provided by the most specialized impl. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Assoc { type Output; diff --git a/tests/ui/specialization/defaultimpl/overlap-projection.stderr b/tests/ui/specialization/defaultimpl/overlap-projection.stderr deleted file mode 100644 index 75fdfafd9d1a..000000000000 --- a/tests/ui/specialization/defaultimpl/overlap-projection.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-projection.rs:7:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/defaultimpl/projection.rs b/tests/ui/specialization/defaultimpl/projection.rs index 7a77c76a5ac5..9a2fc8d8f526 100644 --- a/tests/ui/specialization/defaultimpl/projection.rs +++ b/tests/ui/specialization/defaultimpl/projection.rs @@ -1,7 +1,7 @@ //@ run-pass #![allow(dead_code)] -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Make sure we *can* project non-defaulted associated types // cf ui/specialization/specialization-default-projection.rs diff --git a/tests/ui/specialization/defaultimpl/projection.stderr b/tests/ui/specialization/defaultimpl/projection.stderr deleted file mode 100644 index cc3fe8237a74..000000000000 --- a/tests/ui/specialization/defaultimpl/projection.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/projection.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/defaultimpl/specialization-no-default.rs b/tests/ui/specialization/defaultimpl/specialization-no-default.rs index ddc32337306f..a3b1d09680ac 100644 --- a/tests/ui/specialization/defaultimpl/specialization-no-default.rs +++ b/tests/ui/specialization/defaultimpl/specialization-no-default.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Check a number of scenarios in which one impl tries to override another, // without correctly using `default`. diff --git a/tests/ui/specialization/defaultimpl/specialization-no-default.stderr b/tests/ui/specialization/defaultimpl/specialization-no-default.stderr index f9e62a99baee..60c489d287ca 100644 --- a/tests/ui/specialization/defaultimpl/specialization-no-default.stderr +++ b/tests/ui/specialization/defaultimpl/specialization-no-default.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-no-default.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 | @@ -63,6 +53,6 @@ LL | fn redundant(&self) {} | = note: to specialize, `redundant` in the parent `impl` must be marked `default` -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0520`. diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs b/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs index eb4ecf24a300..b88bf5251062 100644 --- a/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs +++ b/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs @@ -3,7 +3,7 @@ // Tests that we can combine a default impl that supplies one method with a // full impl that supplies the other, and they can invoke one another. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo { fn foo_one(&self) -> &'static str; diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr b/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr deleted file mode 100644 index 407c1ab77200..000000000000 --- a/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-trait-item-not-implemented-rpass.rs:6:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 3c5414469fac..2a121e61aaa9 100644 --- a/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -1,6 +1,6 @@ // Tests that default impls do not have to supply all items but regular impls do. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo { fn foo_one(&self) -> &'static str; diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr b/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr index d3441b0e8b92..ae336da5d4a8 100644 --- a/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr +++ b/tests/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-trait-item-not-implemented.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0046]: not all trait items implemented, missing: `foo_two` --> $DIR/specialization-trait-item-not-implemented.rs:18:1 | @@ -17,6 +7,6 @@ LL | fn foo_two(&self) -> &'static str; LL | impl Foo for MyStruct {} | ^^^^^^^^^^^^^^^^^^^^^ missing `foo_two` in implementation -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs index 344dd7bb288e..2867a00e6bb5 100644 --- a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs +++ b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -2,7 +2,7 @@ // - default impls do not have to supply all items and // - a default impl does not count as an impl (in this case, an incomplete default impl). -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo { fn foo_one(&self) -> &'static str; diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 74f81bb023ef..7cec84b1af6d 100644 --- a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-trait-not-implemented.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope --> $DIR/specialization-trait-not-implemented.rs:22:29 | @@ -24,6 +14,6 @@ note: `Foo` defines an item `foo_one`, perhaps you need to implement it LL | trait Foo { | ^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/specialization/defaultimpl/specialization-wfcheck.rs b/tests/ui/specialization/defaultimpl/specialization-wfcheck.rs index eb18d6eaac45..51b63f034808 100644 --- a/tests/ui/specialization/defaultimpl/specialization-wfcheck.rs +++ b/tests/ui/specialization/defaultimpl/specialization-wfcheck.rs @@ -1,6 +1,6 @@ // Tests that a default impl still has to have a WF trait ref. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo<'a, T: Eq + 'a> { } diff --git a/tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr index 4a51a7dfa47f..aaf020450d39 100644 --- a/tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr +++ b/tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-wfcheck.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `U: Eq` is not satisfied --> $DIR/specialization-wfcheck.rs:7:17 | @@ -24,6 +14,6 @@ help: consider restricting type parameter `U` with trait `Eq` LL | default impl Foo<'static, U> for () {} | ++++++++++++++ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/specialization/defaultimpl/validation.rs b/tests/ui/specialization/defaultimpl/validation.rs index 78f6099c3dd9..3504d3ef28ae 100644 --- a/tests/ui/specialization/defaultimpl/validation.rs +++ b/tests/ui/specialization/defaultimpl/validation.rs @@ -1,5 +1,5 @@ #![feature(negative_impls)] -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] struct S; struct Z; diff --git a/tests/ui/specialization/defaultimpl/validation.stderr b/tests/ui/specialization/defaultimpl/validation.stderr index a8dfef2dcfb1..99ae6def93bb 100644 --- a/tests/ui/specialization/defaultimpl/validation.stderr +++ b/tests/ui/specialization/defaultimpl/validation.stderr @@ -8,16 +8,6 @@ LL | default impl S {} | = note: only trait implementations may be annotated with `default` -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/validation.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0367]: `!Send` impl requires `Z: Send` but the struct it is implemented for does not --> $DIR/validation.rs:12:1 | @@ -58,7 +48,7 @@ error[E0750]: negative impls cannot be default impls LL | default impl !Tr for S {} | ^^^^^^^ ^ -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors Some errors have detailed explanations: E0367, E0750. For more information about an error, try `rustc --explain E0367`. diff --git a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs index 559c23455275..f0a40efde19e 100644 --- a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs +++ b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs @@ -1,7 +1,7 @@ // This test previously tried to use a tainted `EvalCtxt` when emitting // an error during coherence. #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete + trait Iterate<'a> { type Ty: Valid; } diff --git a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr index 611fef1df66b..5db98e73af60 100644 --- a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr +++ b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/fuzzing-ice-134905.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `(): Valid` is not satisfied --> $DIR/fuzzing-ice-134905.rs:12:23 | @@ -34,7 +24,7 @@ LL | impl<'a, T> Eq for T where >::Ty: Valid {} = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0210, E0277. For more information about an error, try `rustc --explain E0210`. diff --git a/tests/ui/specialization/issue-35376.rs b/tests/ui/specialization/issue-35376.rs index 786f22967ebd..df4361bc9391 100644 --- a/tests/ui/specialization/issue-35376.rs +++ b/tests/ui/specialization/issue-35376.rs @@ -1,6 +1,5 @@ //@ check-pass #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete fn main() {} diff --git a/tests/ui/specialization/issue-35376.stderr b/tests/ui/specialization/issue-35376.stderr deleted file mode 100644 index 6c4167f3f9fa..000000000000 --- a/tests/ui/specialization/issue-35376.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-35376.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/issue-36804.rs b/tests/ui/specialization/issue-36804.rs index 5ed0c1aaf20d..c0c188ff6926 100644 --- a/tests/ui/specialization/issue-36804.rs +++ b/tests/ui/specialization/issue-36804.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] pub struct Cloned(I); diff --git a/tests/ui/specialization/issue-36804.stderr b/tests/ui/specialization/issue-36804.stderr deleted file mode 100644 index c2113b25f193..000000000000 --- a/tests/ui/specialization/issue-36804.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-36804.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/issue-38091-2.rs b/tests/ui/specialization/issue-38091-2.rs index da276031378d..bd62a0835e4e 100644 --- a/tests/ui/specialization/issue-38091-2.rs +++ b/tests/ui/specialization/issue-38091-2.rs @@ -2,7 +2,6 @@ //~^ ERROR overflow evaluating the requirement `i32: Check` #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait Iterate<'a> { type Ty: Valid; diff --git a/tests/ui/specialization/issue-38091-2.stderr b/tests/ui/specialization/issue-38091-2.stderr index 828a8e933994..d0a15e609753 100644 --- a/tests/ui/specialization/issue-38091-2.stderr +++ b/tests/ui/specialization/issue-38091-2.stderr @@ -1,17 +1,7 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-38091-2.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0275]: overflow evaluating the requirement `i32: Check` | note: required for `i32` to implement `Iterate<'_>` - --> $DIR/issue-38091-2.rs:11:13 + --> $DIR/issue-38091-2.rs:10:13 | LL | impl<'a, T> Iterate<'a> for T | ^^^^^^^^^^^ ^ @@ -19,6 +9,6 @@ LL | where LL | T: Check, | ----- unsatisfied trait bound introduced here -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/specialization/issue-38091.rs b/tests/ui/specialization/issue-38091.rs index 5b398368a673..06236aa76c7b 100644 --- a/tests/ui/specialization/issue-38091.rs +++ b/tests/ui/specialization/issue-38091.rs @@ -1,5 +1,4 @@ #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait Iterate<'a> { type Ty: Valid; diff --git a/tests/ui/specialization/issue-38091.stderr b/tests/ui/specialization/issue-38091.stderr index eb64383e18bb..91ea3db70311 100644 --- a/tests/ui/specialization/issue-38091.stderr +++ b/tests/ui/specialization/issue-38091.stderr @@ -1,30 +1,20 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-38091.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0277]: the trait bound `(): Valid` is not satisfied - --> $DIR/issue-38091.rs:12:23 + --> $DIR/issue-38091.rs:11:23 | LL | default type Ty = (); | ^^ the trait `Valid` is not implemented for `()` | help: this trait has no implementations, consider adding one - --> $DIR/issue-38091.rs:20:1 + --> $DIR/issue-38091.rs:19:1 | LL | trait Valid {} | ^^^^^^^^^^^ note: required by a bound in `Iterate::Ty` - --> $DIR/issue-38091.rs:5:14 + --> $DIR/issue-38091.rs:4:14 | LL | type Ty: Valid; | ^^^^^ required by this bound in `Iterate::Ty` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/specialization/issue-39448.rs b/tests/ui/specialization/issue-39448.rs index 1c8843d983a4..4d07b11f6bfc 100644 --- a/tests/ui/specialization/issue-39448.rs +++ b/tests/ui/specialization/issue-39448.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Regression test for a specialization-related ICE (#39448). diff --git a/tests/ui/specialization/issue-39448.stderr b/tests/ui/specialization/issue-39448.stderr index e2c5f8c48468..09f2cede808b 100644 --- a/tests/ui/specialization/issue-39448.stderr +++ b/tests/ui/specialization/issue-39448.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-39448.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0391]: cycle detected when computing whether impls specialize one another --> $DIR/issue-39448.rs:24:1 | @@ -23,6 +13,6 @@ LL | trait FromA { | ^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/specialization/issue-39618.rs b/tests/ui/specialization/issue-39618.rs index 14a6fcf572ea..d6346a92495a 100644 --- a/tests/ui/specialization/issue-39618.rs +++ b/tests/ui/specialization/issue-39618.rs @@ -2,7 +2,7 @@ // FIXME(JohnTitor): Centril pointed out this looks suspicions, we should revisit here. // More context: https://github.com/rust-lang/rust/pull/69192#discussion_r379846796 -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo { fn foo(&self); diff --git a/tests/ui/specialization/issue-39618.stderr b/tests/ui/specialization/issue-39618.stderr index 756162ce92c3..ca3c250fefe9 100644 --- a/tests/ui/specialization/issue-39618.stderr +++ b/tests/ui/specialization/issue-39618.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-39618.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0391]: cycle detected when computing whether impls specialize one another --> $DIR/issue-39618.rs:19:1 | @@ -23,6 +13,6 @@ LL | trait Foo { | ^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/specialization/issue-50452-fail.rs b/tests/ui/specialization/issue-50452-fail.rs index fe21e9b6ede5..3096ac38da96 100644 --- a/tests/ui/specialization/issue-50452-fail.rs +++ b/tests/ui/specialization/issue-50452-fail.rs @@ -1,5 +1,4 @@ #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete pub trait Foo { fn foo(); diff --git a/tests/ui/specialization/issue-50452-fail.stderr b/tests/ui/specialization/issue-50452-fail.stderr index 7ac4b39993cd..5bca4cc7f13f 100644 --- a/tests/ui/specialization/issue-50452-fail.stderr +++ b/tests/ui/specialization/issue-50452-fail.stderr @@ -1,15 +1,5 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-50452-fail.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/issue-50452-fail.rs:10:5 + --> $DIR/issue-50452-fail.rs:9:5 | LL | fn foo() {} | ^^^^^^^^ cannot specialize default item `foo` @@ -19,6 +9,6 @@ LL | impl Foo for T { | = note: to specialize, `foo` in the parent `impl` must be marked `default` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0520`. diff --git a/tests/ui/specialization/issue-50452.rs b/tests/ui/specialization/issue-50452.rs index c379825feda9..629ae80f6a64 100644 --- a/tests/ui/specialization/issue-50452.rs +++ b/tests/ui/specialization/issue-50452.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] pub trait Foo { fn foo(); diff --git a/tests/ui/specialization/issue-50452.stderr b/tests/ui/specialization/issue-50452.stderr deleted file mode 100644 index 48cab9dcdb7a..000000000000 --- a/tests/ui/specialization/issue-50452.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-50452.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/issue-52050.rs b/tests/ui/specialization/issue-52050.rs index 804658702066..1e1bfe9cf075 100644 --- a/tests/ui/specialization/issue-52050.rs +++ b/tests/ui/specialization/issue-52050.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Regression test for #52050: when inserting the blanket impl `I` // into the tree, we had to replace the child node for `Foo`, which diff --git a/tests/ui/specialization/issue-52050.stderr b/tests/ui/specialization/issue-52050.stderr index 3b0cac514643..b8368c6312de 100644 --- a/tests/ui/specialization/issue-52050.stderr +++ b/tests/ui/specialization/issue-52050.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-52050.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()` --> $DIR/issue-52050.rs:28:1 | @@ -21,6 +11,6 @@ LL | impl IntoPyDictPointer for () | = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/issue-63716-parse-async.rs b/tests/ui/specialization/issue-63716-parse-async.rs index 00c0b291a1ad..26fd84bbf31f 100644 --- a/tests/ui/specialization/issue-63716-parse-async.rs +++ b/tests/ui/specialization/issue-63716-parse-async.rs @@ -4,7 +4,7 @@ //@ check-pass //@ edition:2018 -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] fn main() {} diff --git a/tests/ui/specialization/issue-63716-parse-async.stderr b/tests/ui/specialization/issue-63716-parse-async.stderr deleted file mode 100644 index a00572da8f54..000000000000 --- a/tests/ui/specialization/issue-63716-parse-async.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-63716-parse-async.rs:7:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/issue-70442.rs b/tests/ui/specialization/issue-70442.rs index fb82b0db09b5..c2168b30ba52 100644 --- a/tests/ui/specialization/issue-70442.rs +++ b/tests/ui/specialization/issue-70442.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] //@ check-pass diff --git a/tests/ui/specialization/issue-70442.stderr b/tests/ui/specialization/issue-70442.stderr deleted file mode 100644 index aa72c32866a2..000000000000 --- a/tests/ui/specialization/issue-70442.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-70442.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/non-defaulted-item-fail.rs b/tests/ui/specialization/non-defaulted-item-fail.rs index b7d6ac829dd1..403f718d7dd9 100644 --- a/tests/ui/specialization/non-defaulted-item-fail.rs +++ b/tests/ui/specialization/non-defaulted-item-fail.rs @@ -1,5 +1,4 @@ #![feature(specialization, associated_type_defaults)] -//~^ WARN the feature `specialization` is incomplete // Test that attempting to override a non-default method or one not in the // parent impl causes an error. diff --git a/tests/ui/specialization/non-defaulted-item-fail.stderr b/tests/ui/specialization/non-defaulted-item-fail.stderr index 9d62a353da72..739f1711ec44 100644 --- a/tests/ui/specialization/non-defaulted-item-fail.stderr +++ b/tests/ui/specialization/non-defaulted-item-fail.stderr @@ -1,15 +1,5 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/non-defaulted-item-fail.rs:1:12 - | -LL | #![feature(specialization, associated_type_defaults)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:30:5 + --> $DIR/non-defaulted-item-fail.rs:29:5 | LL | impl Foo for Box { | ---------------------- parent `impl` is here @@ -20,7 +10,7 @@ LL | type Ty = Vec<()>; = note: to specialize, `Ty` in the parent `impl` must be marked `default` error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:32:5 + --> $DIR/non-defaulted-item-fail.rs:31:5 | LL | impl Foo for Box { | ---------------------- parent `impl` is here @@ -31,7 +21,7 @@ LL | const CONST: u8 = 42; = note: to specialize, `CONST` in the parent `impl` must be marked `default` error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:34:5 + --> $DIR/non-defaulted-item-fail.rs:33:5 | LL | impl Foo for Box { | ---------------------- parent `impl` is here @@ -42,7 +32,7 @@ LL | fn foo(&self) -> bool { true } = note: to specialize, `foo` in the parent `impl` must be marked `default` error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:46:5 + --> $DIR/non-defaulted-item-fail.rs:45:5 | LL | impl Foo for Vec {} | ---------------------- parent `impl` is here @@ -53,7 +43,7 @@ LL | type Ty = Vec<()>; = note: to specialize, `Ty` in the parent `impl` must be marked `default` error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:48:5 + --> $DIR/non-defaulted-item-fail.rs:47:5 | LL | impl Foo for Vec {} | ---------------------- parent `impl` is here @@ -64,7 +54,7 @@ LL | const CONST: u8 = 42; = note: to specialize, `CONST` in the parent `impl` must be marked `default` error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:50:5 + --> $DIR/non-defaulted-item-fail.rs:49:5 | LL | impl Foo for Vec {} | ---------------------- parent `impl` is here @@ -74,6 +64,6 @@ LL | fn foo(&self) -> bool { true } | = note: to specialize, `foo` in the parent `impl` must be marked `default` -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0520`. diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs index 578a46c67400..0cf609289127 100644 --- a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs @@ -1,8 +1,6 @@ // Regression test for #140571. The compiler used to ICE #![feature(min_generic_const_args, specialization)] -//~^ WARN the feature `specialization` is incomplete -//~| WARN the feature `min_generic_const_args` is incomplete pub trait IsVoid { diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr index 9361f7d6222f..3ec3e83cc1d4 100644 --- a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr @@ -1,29 +1,11 @@ -warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:12 - | -LL | #![feature(min_generic_const_args, specialization)] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #132980 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:36 - | -LL | #![feature(min_generic_const_args, specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - error[E0119]: conflicting implementations of trait `Maybe<()>` for type `()` - --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:20:1 + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:18:1 | LL | impl Maybe for T {} | ---------------------- first implementation here LL | impl Maybe for () where T: NotVoid + ?Sized {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` -error: aborting due to 1 previous error; 2 warnings emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr b/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr deleted file mode 100644 index 7e3df0c83f9f..000000000000 --- a/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/prefer-specializing-impl-over-default.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr b/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr deleted file mode 100644 index 7e3df0c83f9f..000000000000 --- a/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/prefer-specializing-impl-over-default.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.rs b/tests/ui/specialization/prefer-specializing-impl-over-default.rs index af6837b30caf..4fa5b3e86c87 100644 --- a/tests/ui/specialization/prefer-specializing-impl-over-default.rs +++ b/tests/ui/specialization/prefer-specializing-impl-over-default.rs @@ -3,7 +3,6 @@ //@[next] compile-flags: -Znext-solver //@ check-pass #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait WithAssoc: 'static { type Assoc; diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.next.stderr b/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.next.stderr deleted file mode 100644 index 17918a77821d..000000000000 --- a/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.next.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/source-impl-requires-constraining-predicates-ambig.rs:14:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.rs b/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.rs index 2296cd8a9375..ff56965a94c8 100644 --- a/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.rs +++ b/tests/ui/specialization/source-impl-requires-constraining-predicates-ambig.rs @@ -12,7 +12,6 @@ // is ambiguous. #![feature(specialization)] -//[next]~^ WARN the feature `specialization` is incomplete trait Spec { type Assoc; diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates.current.stderr b/tests/ui/specialization/source-impl-requires-constraining-predicates.current.stderr deleted file mode 100644 index 3442e5b5ca61..000000000000 --- a/tests/ui/specialization/source-impl-requires-constraining-predicates.current.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/source-impl-requires-constraining-predicates.rs:9:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates.next.stderr b/tests/ui/specialization/source-impl-requires-constraining-predicates.next.stderr deleted file mode 100644 index 3442e5b5ca61..000000000000 --- a/tests/ui/specialization/source-impl-requires-constraining-predicates.next.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/source-impl-requires-constraining-predicates.rs:9:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/source-impl-requires-constraining-predicates.rs b/tests/ui/specialization/source-impl-requires-constraining-predicates.rs index 532fc3676406..690649de0239 100644 --- a/tests/ui/specialization/source-impl-requires-constraining-predicates.rs +++ b/tests/ui/specialization/source-impl-requires-constraining-predicates.rs @@ -7,7 +7,6 @@ // `[u32; 0]: IntoIterator` predicate to constrain the `?U` impl arg. #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete trait Spec { type Assoc; diff --git a/tests/ui/specialization/specialization-allowed-cross-crate.rs b/tests/ui/specialization/specialization-allowed-cross-crate.rs index 697a62ca547f..1a6c3832b16d 100644 --- a/tests/ui/specialization/specialization-allowed-cross-crate.rs +++ b/tests/ui/specialization/specialization-allowed-cross-crate.rs @@ -5,7 +5,7 @@ //@ aux-build:go_trait.rs -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] extern crate go_trait; diff --git a/tests/ui/specialization/specialization-allowed-cross-crate.stderr b/tests/ui/specialization/specialization-allowed-cross-crate.stderr deleted file mode 100644 index 3eea4a53bf5f..000000000000 --- a/tests/ui/specialization/specialization-allowed-cross-crate.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-allowed-cross-crate.rs:8:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-assoc-fns.rs b/tests/ui/specialization/specialization-assoc-fns.rs index 75f0b0d24850..596b1c925962 100644 --- a/tests/ui/specialization/specialization-assoc-fns.rs +++ b/tests/ui/specialization/specialization-assoc-fns.rs @@ -2,7 +2,7 @@ // Test that non-method associated functions can be specialized -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo { fn mk() -> Self; diff --git a/tests/ui/specialization/specialization-assoc-fns.stderr b/tests/ui/specialization/specialization-assoc-fns.stderr deleted file mode 100644 index 69f7cece79de..000000000000 --- a/tests/ui/specialization/specialization-assoc-fns.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-assoc-fns.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-basics.rs b/tests/ui/specialization/specialization-basics.rs index dc320b2b91fc..76cba35c7fd5 100644 --- a/tests/ui/specialization/specialization-basics.rs +++ b/tests/ui/specialization/specialization-basics.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Tests a variety of basic specialization scenarios and method // dispatch for them. diff --git a/tests/ui/specialization/specialization-basics.stderr b/tests/ui/specialization/specialization-basics.stderr deleted file mode 100644 index 7714d4af4c63..000000000000 --- a/tests/ui/specialization/specialization-basics.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-basics.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-cross-crate.rs b/tests/ui/specialization/specialization-cross-crate.rs index 6daf48b6d9b5..39001819ed95 100644 --- a/tests/ui/specialization/specialization-cross-crate.rs +++ b/tests/ui/specialization/specialization-cross-crate.rs @@ -2,7 +2,7 @@ //@ aux-build:specialization_cross_crate.rs -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] extern crate specialization_cross_crate; diff --git a/tests/ui/specialization/specialization-cross-crate.stderr b/tests/ui/specialization/specialization-cross-crate.stderr deleted file mode 100644 index 06818bb5627d..000000000000 --- a/tests/ui/specialization/specialization-cross-crate.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-cross-crate.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-default-methods.rs b/tests/ui/specialization/specialization-default-methods.rs index 7058c039e465..1699fad2a9c7 100644 --- a/tests/ui/specialization/specialization-default-methods.rs +++ b/tests/ui/specialization/specialization-default-methods.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Test that default methods are cascaded correctly diff --git a/tests/ui/specialization/specialization-default-methods.stderr b/tests/ui/specialization/specialization-default-methods.stderr deleted file mode 100644 index d78d30bd802f..000000000000 --- a/tests/ui/specialization/specialization-default-methods.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-default-methods.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-default-projection.current.stderr b/tests/ui/specialization/specialization-default-projection.current.stderr index b88c1a94baf9..859f83e2314e 100644 --- a/tests/ui/specialization/specialization-default-projection.current.stderr +++ b/tests/ui/specialization/specialization-default-projection.current.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-default-projection.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/specialization-default-projection.rs:25:5 | @@ -42,6 +32,6 @@ LL | generic::<()>() = note: the associated type `<() as Foo>::Assoc` is defined as `()` in the implementation, but the where-bound `()` shadows this definition see issue #152409 for more information -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/specialization-default-projection.next.stderr b/tests/ui/specialization/specialization-default-projection.next.stderr index a385b16a2d8b..1a5869f2d0a5 100644 --- a/tests/ui/specialization/specialization-default-projection.next.stderr +++ b/tests/ui/specialization/specialization-default-projection.next.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-default-projection.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/specialization-default-projection.rs:25:5 | @@ -42,6 +32,6 @@ LL | generic::<()>() = note: the associated type `<() as Foo>::Assoc` is defined as `()` in the implementation, but the where-bound `()` shadows this definition see issue #152409 for more information -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/specialization-default-projection.rs b/tests/ui/specialization/specialization-default-projection.rs index 4f69ccb59746..36f20b63eff0 100644 --- a/tests/ui/specialization/specialization-default-projection.rs +++ b/tests/ui/specialization/specialization-default-projection.rs @@ -2,7 +2,7 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Make sure we can't project defaulted associated types diff --git a/tests/ui/specialization/specialization-default-types.current.stderr b/tests/ui/specialization/specialization-default-types.current.stderr index 8df170cbb767..2447669a8398 100644 --- a/tests/ui/specialization/specialization-default-types.current.stderr +++ b/tests/ui/specialization/specialization-default-types.current.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-default-types.rs:9:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:19:9 | @@ -38,6 +28,6 @@ LL | Example::generate(t) = note: the associated type `::Output` is defined as `Box` in the implementation, but the where-bound `T` shadows this definition see issue #152409 for more information -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/specialization-default-types.next.stderr b/tests/ui/specialization/specialization-default-types.next.stderr index 4ea9b996c86a..b6f61b40ccb2 100644 --- a/tests/ui/specialization/specialization-default-types.next.stderr +++ b/tests/ui/specialization/specialization-default-types.next.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-default-types.rs:9:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:19:9 | @@ -38,6 +28,6 @@ LL | Example::generate(t) = note: the associated type `::Output` is defined as `Box` in the implementation, but the where-bound `T` shadows this definition see issue #152409 for more information -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/specialization-default-types.rs b/tests/ui/specialization/specialization-default-types.rs index 77817abea127..ffbe8568b97d 100644 --- a/tests/ui/specialization/specialization-default-types.rs +++ b/tests/ui/specialization/specialization-default-types.rs @@ -6,7 +6,7 @@ // associated type in the impl defining it -- otherwise, what happens // if it's overridden? -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Example { type Output; diff --git a/tests/ui/specialization/specialization-no-default.rs b/tests/ui/specialization/specialization-no-default.rs index ae739b2358d5..57346b26d24e 100644 --- a/tests/ui/specialization/specialization-no-default.rs +++ b/tests/ui/specialization/specialization-no-default.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Check a number of scenarios in which one impl tries to override another, // without correctly using `default`. diff --git a/tests/ui/specialization/specialization-no-default.stderr b/tests/ui/specialization/specialization-no-default.stderr index 695a3f6cc45d..07c352995842 100644 --- a/tests/ui/specialization/specialization-no-default.stderr +++ b/tests/ui/specialization/specialization-no-default.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-no-default.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 | @@ -63,6 +53,6 @@ LL | default fn redundant(&self) {} | = note: to specialize, `redundant` in the parent `impl` must be marked `default` -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0520`. diff --git a/tests/ui/specialization/specialization-on-projection.rs b/tests/ui/specialization/specialization-on-projection.rs index 876439ca0a7d..f5fc13185a76 100644 --- a/tests/ui/specialization/specialization-on-projection.rs +++ b/tests/ui/specialization/specialization-on-projection.rs @@ -1,7 +1,7 @@ //@ run-pass #![allow(dead_code)] -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Ensure that specialization works for impls defined directly on a projection diff --git a/tests/ui/specialization/specialization-on-projection.stderr b/tests/ui/specialization/specialization-on-projection.stderr deleted file mode 100644 index 00fc7ffc5471..000000000000 --- a/tests/ui/specialization/specialization-on-projection.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-on-projection.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-out-of-order.rs b/tests/ui/specialization/specialization-out-of-order.rs index 4f4d40f43d4b..72b2856999ab 100644 --- a/tests/ui/specialization/specialization-out-of-order.rs +++ b/tests/ui/specialization/specialization-out-of-order.rs @@ -2,7 +2,7 @@ // Test that you can list the more specific impl before the more general one. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo { type Out; diff --git a/tests/ui/specialization/specialization-out-of-order.stderr b/tests/ui/specialization/specialization-out-of-order.stderr deleted file mode 100644 index b524e00f01c8..000000000000 --- a/tests/ui/specialization/specialization-out-of-order.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-out-of-order.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-overlap-negative.rs b/tests/ui/specialization/specialization-overlap-negative.rs index 244f21c7ba90..d5cf51ef98f6 100644 --- a/tests/ui/specialization/specialization-overlap-negative.rs +++ b/tests/ui/specialization/specialization-overlap-negative.rs @@ -1,5 +1,5 @@ #![feature(negative_impls)] -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait MyTrait {} diff --git a/tests/ui/specialization/specialization-overlap-negative.stderr b/tests/ui/specialization/specialization-overlap-negative.stderr index 4874e897726f..3e1cf4006a65 100644 --- a/tests/ui/specialization/specialization-overlap-negative.stderr +++ b/tests/ui/specialization/specialization-overlap-negative.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-overlap-negative.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`: --> $DIR/specialization-overlap-negative.rs:9:1 | @@ -28,7 +18,7 @@ note: the implementor must specify the same requirement LL | struct TestType(::std::marker::PhantomData); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0367, E0751. For more information about an error, try `rustc --explain E0367`. diff --git a/tests/ui/specialization/specialization-overlap-projection.rs b/tests/ui/specialization/specialization-overlap-projection.rs index f7a2a7922432..504e5d1c57f8 100644 --- a/tests/ui/specialization/specialization-overlap-projection.rs +++ b/tests/ui/specialization/specialization-overlap-projection.rs @@ -2,7 +2,6 @@ // projections involve specialization, so long as the associated type is // provided by the most specialized impl. #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes trait Assoc { type Output; diff --git a/tests/ui/specialization/specialization-overlap-projection.stderr b/tests/ui/specialization/specialization-overlap-projection.stderr index 5f3cd9c66cfe..270a498e5c7d 100644 --- a/tests/ui/specialization/specialization-overlap-projection.stderr +++ b/tests/ui/specialization/specialization-overlap-projection.stderr @@ -1,15 +1,5 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-overlap-projection.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0119]: conflicting implementations of trait `Foo` for type `u32` - --> $DIR/specialization-overlap-projection.rs:20:1 + --> $DIR/specialization-overlap-projection.rs:19:1 | LL | impl Foo for u32 {} | ---------------- first implementation here @@ -17,7 +7,7 @@ LL | impl Foo for ::Output {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` error[E0119]: conflicting implementations of trait `Foo` for type `u32` - --> $DIR/specialization-overlap-projection.rs:22:1 + --> $DIR/specialization-overlap-projection.rs:21:1 | LL | impl Foo for u32 {} | ---------------- first implementation here @@ -25,6 +15,6 @@ LL | impl Foo for u32 {} LL | impl Foo for ::Output {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-overlap.rs b/tests/ui/specialization/specialization-overlap.rs index 6bee22ceb8b6..c8ef8d61c1e8 100644 --- a/tests/ui/specialization/specialization-overlap.rs +++ b/tests/ui/specialization/specialization-overlap.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Foo { fn foo() {} } impl Foo for T {} diff --git a/tests/ui/specialization/specialization-overlap.stderr b/tests/ui/specialization/specialization-overlap.stderr index 098bf4a70ab4..ca32c173a32c 100644 --- a/tests/ui/specialization/specialization-overlap.stderr +++ b/tests/ui/specialization/specialization-overlap.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-overlap.rs:1:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0119]: conflicting implementations of trait `Foo` for type `Vec<_>` --> $DIR/specialization-overlap.rs:5:1 | @@ -40,6 +30,6 @@ LL | impl Qux for T {} LL | impl Qux for T {} | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-polarity.rs b/tests/ui/specialization/specialization-polarity.rs index b3cd8255bb9b..7427246eb467 100644 --- a/tests/ui/specialization/specialization-polarity.rs +++ b/tests/ui/specialization/specialization-polarity.rs @@ -2,7 +2,7 @@ #![feature(auto_traits)] #![feature(negative_impls)] -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] auto trait Foo {} diff --git a/tests/ui/specialization/specialization-polarity.stderr b/tests/ui/specialization/specialization-polarity.stderr index f287018ba7f7..44e60cad67aa 100644 --- a/tests/ui/specialization/specialization-polarity.stderr +++ b/tests/ui/specialization/specialization-polarity.stderr @@ -1,13 +1,3 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-polarity.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - error[E0751]: found both positive and negative implementation of trait `Foo` for type `u8`: --> $DIR/specialization-polarity.rs:10:1 | @@ -24,6 +14,6 @@ LL | impl !Bar for T {} LL | impl Bar for u8 {} | ^^^^^^^^^^^^^^^ positive implementation here -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/specialization/specialization-projection-alias.rs b/tests/ui/specialization/specialization-projection-alias.rs index 73d6115af00b..92368b17b98b 100644 --- a/tests/ui/specialization/specialization-projection-alias.rs +++ b/tests/ui/specialization/specialization-projection-alias.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Regression test for ICE when combining specialized associated types and type // aliases diff --git a/tests/ui/specialization/specialization-projection-alias.stderr b/tests/ui/specialization/specialization-projection-alias.stderr deleted file mode 100644 index c94d9ed07b19..000000000000 --- a/tests/ui/specialization/specialization-projection-alias.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-projection-alias.rs:5:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-projection.rs b/tests/ui/specialization/specialization-projection.rs index b3efa6f39ddd..20105fb9fdb1 100644 --- a/tests/ui/specialization/specialization-projection.rs +++ b/tests/ui/specialization/specialization-projection.rs @@ -1,7 +1,7 @@ //@ run-pass #![allow(dead_code)] -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Make sure we *can* project non-defaulted associated types // cf ui/specialization/specialization-default-projection.rs diff --git a/tests/ui/specialization/specialization-projection.stderr b/tests/ui/specialization/specialization-projection.stderr deleted file mode 100644 index bfc4e0a0f5d7..000000000000 --- a/tests/ui/specialization/specialization-projection.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-projection.rs:4:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-supertraits.rs b/tests/ui/specialization/specialization-supertraits.rs index cb4cfef4bdd1..ffb20fe6d1a2 100644 --- a/tests/ui/specialization/specialization-supertraits.rs +++ b/tests/ui/specialization/specialization-supertraits.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] // Test that you can specialize via an explicit trait hierarchy diff --git a/tests/ui/specialization/specialization-supertraits.stderr b/tests/ui/specialization/specialization-supertraits.stderr deleted file mode 100644 index e716bc21596b..000000000000 --- a/tests/ui/specialization/specialization-supertraits.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-supertraits.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-translate-projections-with-lifetimes.rs b/tests/ui/specialization/specialization-translate-projections-with-lifetimes.rs index 75d9a0d8ad05..06f7cdd3398a 100644 --- a/tests/ui/specialization/specialization-translate-projections-with-lifetimes.rs +++ b/tests/ui/specialization/specialization-translate-projections-with-lifetimes.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Iterator { fn next(&self); diff --git a/tests/ui/specialization/specialization-translate-projections-with-lifetimes.stderr b/tests/ui/specialization/specialization-translate-projections-with-lifetimes.stderr deleted file mode 100644 index c7aad3c0fee1..000000000000 --- a/tests/ui/specialization/specialization-translate-projections-with-lifetimes.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-translate-projections-with-lifetimes.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-translate-projections-with-params.rs b/tests/ui/specialization/specialization-translate-projections-with-params.rs index 330f51877aba..3b2f2c6a3418 100644 --- a/tests/ui/specialization/specialization-translate-projections-with-params.rs +++ b/tests/ui/specialization/specialization-translate-projections-with-params.rs @@ -4,7 +4,7 @@ // type parameters *and* rely on projections, and the type parameters are input // types on the trait. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Trait { fn convert(&self) -> T; diff --git a/tests/ui/specialization/specialization-translate-projections-with-params.stderr b/tests/ui/specialization/specialization-translate-projections-with-params.stderr deleted file mode 100644 index 1c4fd9325a68..000000000000 --- a/tests/ui/specialization/specialization-translate-projections-with-params.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-translate-projections-with-params.rs:7:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/specialization-translate-projections.rs b/tests/ui/specialization/specialization-translate-projections.rs index 01c7619b065c..c718f9329eae 100644 --- a/tests/ui/specialization/specialization-translate-projections.rs +++ b/tests/ui/specialization/specialization-translate-projections.rs @@ -3,8 +3,7 @@ // Ensure that provided items are inherited properly even when impls vary in // type parameters *and* rely on projections. -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete - +#![feature(specialization)] trait Trait { fn to_u8(&self) -> u8; diff --git a/tests/ui/specialization/specialization-translate-projections.stderr b/tests/ui/specialization/specialization-translate-projections.stderr deleted file mode 100644 index 22bbb12a09b5..000000000000 --- a/tests/ui/specialization/specialization-translate-projections.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-translate-projections.rs:6:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/trait-specialization-default-methods-55380.rs b/tests/ui/specialization/trait-specialization-default-methods-55380.rs index b3d79fb5ffb6..eeafcc16cd69 100644 --- a/tests/ui/specialization/trait-specialization-default-methods-55380.rs +++ b/tests/ui/specialization/trait-specialization-default-methods-55380.rs @@ -1,7 +1,6 @@ // https://github.com/rust-lang/rust/issues/55380 //@ run-pass #![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete pub trait Foo { fn abc() -> u32; diff --git a/tests/ui/specialization/trait-specialization-default-methods-55380.stderr b/tests/ui/specialization/trait-specialization-default-methods-55380.stderr deleted file mode 100644 index f7c1903da629..000000000000 --- a/tests/ui/specialization/trait-specialization-default-methods-55380.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/trait-specialization-default-methods-55380.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/specialization/transmute-specialization.rs b/tests/ui/specialization/transmute-specialization.rs index a896c14e6370..da0f12cf7169 100644 --- a/tests/ui/specialization/transmute-specialization.rs +++ b/tests/ui/specialization/transmute-specialization.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(specialization)] trait Specializable { type Output; } diff --git a/tests/ui/specialization/transmute-specialization.stderr b/tests/ui/specialization/transmute-specialization.stderr deleted file mode 100644 index b1c26d7dacc6..000000000000 --- a/tests/ui/specialization/transmute-specialization.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/transmute-specialization.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/static/bad-const-type.rs b/tests/ui/static/bad-const-type.rs index d4e6352d7c1c..696fa295af41 100644 --- a/tests/ui/static/bad-const-type.rs +++ b/tests/ui/static/bad-const-type.rs @@ -1,4 +1,5 @@ static i: String = 10; -//~^ ERROR mismatched types -//~| NOTE expected `String`, found integer +//~^ ERROR: mismatched types +//~| NOTE: expected `String`, found integer +//~| NOTE: expected because fn main() { println!("{}", i); } diff --git a/tests/ui/static/bad-const-type.stderr b/tests/ui/static/bad-const-type.stderr index 8573a11ef291..12ecb73d94da 100644 --- a/tests/ui/static/bad-const-type.stderr +++ b/tests/ui/static/bad-const-type.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/bad-const-type.rs:1:20 | LL | static i: String = 10; - | ^^ expected `String`, found integer + | ------ ^^ expected `String`, found integer + | | + | expected because of the type of the static | help: try using a conversion method | diff --git a/tests/ui/static/issue-5216.stderr b/tests/ui/static/issue-5216.stderr index 99c8b1aa131a..9748223e3d1d 100644 --- a/tests/ui/static/issue-5216.stderr +++ b/tests/ui/static/issue-5216.stderr @@ -18,7 +18,9 @@ error[E0308]: mismatched types --> $DIR/issue-5216.rs:8:19 | LL | pub static D: T = g; - | ^ expected `Box`, found fn item + | - ^ expected `Box`, found fn item + | | + | expected because of the type of the static | = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>` found fn item `fn() {g}` diff --git a/tests/ui/statics/mutable_memory_validation.rs b/tests/ui/statics/mutable_memory_validation.rs index 033c2bc28396..bdef949a38bb 100644 --- a/tests/ui/statics/mutable_memory_validation.rs +++ b/tests/ui/statics/mutable_memory_validation.rs @@ -11,7 +11,7 @@ struct Meh { } const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } }; -//~^ ERROR: invalid value at .x.: encountered `UnsafeCell` in read-only memory +//~^ ERROR: at .x., encountered `UnsafeCell` in read-only memory static READONLY: i32 = 0; diff --git a/tests/ui/statics/mutable_memory_validation.stderr b/tests/ui/statics/mutable_memory_validation.stderr index 1d6ba195fa28..297a96542034 100644 --- a/tests/ui/statics/mutable_memory_validation.stderr +++ b/tests/ui/statics/mutable_memory_validation.stderr @@ -1,4 +1,4 @@ -error[E0080]: constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory +error[E0080]: constructing invalid value of type Meh: at .x., encountered `UnsafeCell` in read-only memory --> $DIR/mutable_memory_validation.rs:13:1 | LL | const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } }; diff --git a/tests/ui/issues/issue-3521-2.fixed b/tests/ui/statics/static-cannot-use-local-variable.fixed similarity index 69% rename from tests/ui/issues/issue-3521-2.fixed rename to tests/ui/statics/static-cannot-use-local-variable.fixed index 2a6e0829bc0f..df9dfb7a3317 100644 --- a/tests/ui/issues/issue-3521-2.fixed +++ b/tests/ui/statics/static-cannot-use-local-variable.fixed @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3521 +//! //@ run-rustfix fn main() { let foo = 100; diff --git a/tests/ui/issues/issue-3521-2.rs b/tests/ui/statics/static-cannot-use-local-variable.rs similarity index 69% rename from tests/ui/issues/issue-3521-2.rs rename to tests/ui/statics/static-cannot-use-local-variable.rs index bd8220200654..0269f9e6e896 100644 --- a/tests/ui/issues/issue-3521-2.rs +++ b/tests/ui/statics/static-cannot-use-local-variable.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3521 +//! //@ run-rustfix fn main() { let foo = 100; diff --git a/tests/ui/issues/issue-3521-2.stderr b/tests/ui/statics/static-cannot-use-local-variable.stderr similarity index 88% rename from tests/ui/issues/issue-3521-2.stderr rename to tests/ui/statics/static-cannot-use-local-variable.stderr index ecf1ad0403d3..350c38480ed7 100644 --- a/tests/ui/issues/issue-3521-2.stderr +++ b/tests/ui/statics/static-cannot-use-local-variable.stderr @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/issue-3521-2.rs:5:23 + --> $DIR/static-cannot-use-local-variable.rs:7:23 | LL | static y: isize = foo + 1; | ^^^ non-constant value diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.fixed b/tests/ui/statics/static-in-fn-cannot-use-param.fixed similarity index 64% rename from tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.fixed rename to tests/ui/statics/static-in-fn-cannot-use-param.fixed index bf100755b906..bf6df45a2579 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.fixed +++ b/tests/ui/statics/static-in-fn-cannot-use-param.fixed @@ -1,6 +1,8 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3668 +//! //@ run-rustfix #![allow(unused_variables, dead_code)] -fn f(x:isize) { +fn f(x: isize) { let child: isize = x + 1; //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs b/tests/ui/statics/static-in-fn-cannot-use-param.rs similarity index 65% rename from tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs rename to tests/ui/statics/static-in-fn-cannot-use-param.rs index 375178172bb0..bd121a7045dd 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs +++ b/tests/ui/statics/static-in-fn-cannot-use-param.rs @@ -1,6 +1,8 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3668 +//! //@ run-rustfix #![allow(unused_variables, dead_code)] -fn f(x:isize) { +fn f(x: isize) { static child: isize = x + 1; //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr b/tests/ui/statics/static-in-fn-cannot-use-param.stderr similarity index 89% rename from tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr rename to tests/ui/statics/static-in-fn-cannot-use-param.stderr index f87514ba83b0..67890de71af6 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr +++ b/tests/ui/statics/static-in-fn-cannot-use-param.stderr @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/issue-3668-2.rs:4:27 + --> $DIR/static-in-fn-cannot-use-param.rs:6:27 | LL | static child: isize = x + 1; | ^ non-constant value diff --git a/tests/ui/statics/static-in-method-cannot-use-self.rs b/tests/ui/statics/static-in-method-cannot-use-self.rs new file mode 100644 index 000000000000..a5d6feae7e91 --- /dev/null +++ b/tests/ui/statics/static-in-method-cannot-use-self.rs @@ -0,0 +1,18 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3668 +//! +struct P { + child: Option>, +} +trait PTrait { + fn getChildOption(&self) -> Option>; +} + +impl PTrait for P { + fn getChildOption(&self) -> Option> { + static childVal: Box