diff options
| author | bors <bors@rust-lang.org> | 2024-10-14 15:11:07 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-10-14 15:11:07 +0000 |
| commit | bd8f2afc449999aa6310cc9f42029d9bfdd5e910 (patch) | |
| tree | 6eebb25d13a6ace45d712257d931527662949fdc | |
| parent | 15f0242c74c91cce4a8fd8b17ccfbaf46b03ec62 (diff) | |
| parent | 543d226589d152a27a5c150e415b451e50986c79 (diff) | |
| download | rust-bd8f2afc449999aa6310cc9f42029d9bfdd5e910.tar.gz rust-bd8f2afc449999aa6310cc9f42029d9bfdd5e910.zip | |
Auto merge of #3970 - RalfJung:rustup, r=RalfJung
Rustup
1488 files changed, 20941 insertions, 14762 deletions
diff --git a/.github/ISSUE_TEMPLATE/blank_issue.md b/.github/ISSUE_TEMPLATE/blank_issue.md deleted file mode 100644 index 9aef3ebe637..00000000000 --- a/.github/ISSUE_TEMPLATE/blank_issue.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: Blank Issue -about: Create a blank issue. ---- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6dc27f1234..003c1e5d7eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -122,6 +122,9 @@ jobs: # which then uses log commands to actually set them. EXTRA_VARIABLES: ${{ toJson(matrix.env) }} + - name: setup upstream remote + run: src/ci/scripts/setup-upstream-remote.sh + - name: ensure the channel matches the target branch run: src/ci/scripts/verify-channel.sh diff --git a/.mailmap b/.mailmap index 9ac7f1a9b49..dc5bfe6d5fc 100644 --- a/.mailmap +++ b/.mailmap @@ -74,6 +74,7 @@ Ben Striegel <ben.striegel@gmail.com> Benjamin Jackman <ben@jackman.biz> Benoît Cortier <benoit.cortier@fried-world.eu> Bheesham Persaud <bheesham123@hotmail.com> Bheesham Persaud <bheesham.persaud@live.ca> +bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3@users.noreply.github.com> Björn Steinbrink <bsteinbr@gmail.com> <B.Steinbrink@gmx.de> blake2-ppc <ulrik.sverdrup@gmail.com> <blake2-ppc> blyxyas <blyxyas@gmail.com> Alejandra González <blyxyas@gmail.com> @@ -311,6 +312,7 @@ Josh Driver <keeperofdakeys@gmail.com> Josh Holmer <jholmer.in@gmail.com> Josh Stone <cuviper@gmail.com> <jistone@redhat.com> Josh Stone <cuviper@gmail.com> <jistone@fedoraproject.org> +Julia Ryan <juliaryan3.14@gmail.com> <josephryan3.14@gmail.com> Julian Knodt <julianknodt@gmail.com> jumbatm <jumbatm@gmail.com> <30644300+jumbatm@users.noreply.github.com> Junyoung Cho <june0.cho@samsung.com> diff --git a/Cargo.lock b/Cargo.lock index 502920350d5..b50b44bd077 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,7 +96,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" dependencies = [ - "unicode-width", + "unicode-width 0.1.14", "yansi-term", ] @@ -107,7 +107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" dependencies = [ "anstyle", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -168,7 +168,7 @@ dependencies = [ "anstyle", "anstyle-lossy", "html-escape", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -737,7 +737,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", - "unicode-width", + "unicode-width 0.1.14", "windows-sys 0.52.0", ] @@ -1425,7 +1425,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -1788,7 +1788,7 @@ dependencies = [ "instant", "number_prefix", "portable-atomic", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -2590,7 +2590,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" dependencies = [ - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -2601,7 +2601,7 @@ checksum = "9ad43c07024ef767f9160710b3a6773976194758c7919b17e63b863db0bdf7fb" dependencies = [ "bytecount", "fnv", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -3416,6 +3416,7 @@ dependencies = [ "measureme", "object 0.36.4", "rustc-demangle", + "rustc_abi", "rustc_ast", "rustc_attr", "rustc_codegen_ssa", @@ -3456,6 +3457,7 @@ dependencies = [ "object 0.36.4", "pathdiff", "regex", + "rustc_abi", "rustc_arena", "rustc_ast", "rustc_attr", @@ -3493,6 +3495,7 @@ name = "rustc_const_eval" version = "0.0.0" dependencies = [ "either", + "rustc_abi", "rustc_apfloat", "rustc_ast", "rustc_attr", @@ -3772,6 +3775,7 @@ name = "rustc_hir_typeck" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_ast", "rustc_ast_ir", "rustc_attr", @@ -4027,6 +4031,7 @@ dependencies = [ "gsgdt", "polonius-engine", "rustc-rayon-core", + "rustc_abi", "rustc_apfloat", "rustc_arena", "rustc_ast", @@ -4183,7 +4188,7 @@ dependencies = [ "thin-vec", "tracing", "unicode-normalization", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -4417,7 +4422,7 @@ dependencies = [ "sha1", "sha2", "tracing", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -4522,6 +4527,7 @@ name = "rustc_ty_utils" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_ast_ir", "rustc_data_structures", "rustc_errors", @@ -4681,7 +4687,7 @@ dependencies = [ "tracing-subscriber", "unicode-properties", "unicode-segmentation", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -5091,7 +5097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c998b0c8b921495196a48aabaf1901ff28be0760136e31604f7967b0792050e" dependencies = [ "papergrid", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -5641,6 +5647,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5798,16 +5810,16 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-component-ld" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde17bc96539700198e12516230c76095cc215c84ef39ad206e1af3f84243e0f" +checksum = "4d4aa6bd7fbe7cffbed29fe3e236fda74419def1bdef6f80f989ec51137edf44" dependencies = [ "anyhow", "clap", "lexopt", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.218.0", + "wasmparser 0.219.0", "wat", "wit-component", "wit-parser", @@ -5831,19 +5843,19 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.218.0" +version = "0.219.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a" +checksum = "e2b1b95711b3ad655656a341e301cc64e33cbee94de9a99a1c5a2ab88efab79d" dependencies = [ "leb128", - "wasmparser 0.218.0", + "wasmparser 0.219.0", ] [[package]] name = "wasm-metadata" -version = "0.218.0" +version = "0.219.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa5eeb071abe8a2132fdd5565dabffee70775ee8c24fc7e300ac43f51f4a8a91" +checksum = "96132fe00dd17d092d2be289eeed5a0a68ad3cf30b68e8875bc953b96f55f0be" dependencies = [ "anyhow", "indexmap", @@ -5851,8 +5863,8 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.218.0", - "wasmparser 0.218.0", + "wasm-encoder 0.219.0", + "wasmparser 0.219.0", ] [[package]] @@ -5867,9 +5879,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.218.0" +version = "0.219.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc" +checksum = "324b4e56d24439495b88cd81439dad5e97f3c7b1eedc3c7e10455ed1e045e9a2" dependencies = [ "ahash", "bitflags 2.6.0", @@ -5881,22 +5893,22 @@ dependencies = [ [[package]] name = "wast" -version = "218.0.0" +version = "219.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a53cd1f0fa505df97557e36a58bddb8296e2fcdcd089529545ebfdb18a1b9d7" +checksum = "06880ecb25662bc21db6a83f4fcc27c41f71fbcba4f1980b650c88ada92728e1" dependencies = [ "bumpalo", "leb128", "memchr", - "unicode-width", - "wasm-encoder 0.218.0", + "unicode-width 0.1.14", + "wasm-encoder 0.219.0", ] [[package]] name = "wat" -version = "1.218.0" +version = "1.219.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f87f8e14e776762e07927c27c2054d2cf678aab9aae2d431a79b3e31e4dd391" +checksum = "11e56dbf9fc89111b0d97c91e683d7895b1a6e5633a729f2ccad2303724005b6" dependencies = [ "wast", ] @@ -6173,9 +6185,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.218.0" +version = "0.219.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa53aa7e6bf2b3e8ccaffbcc963fbdb672a603dc0af393a481b6cec24c266406" +checksum = "99a76111c20444a814019de20499d30940ecd219b9512ee296f034a5edb18a2d" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -6184,17 +6196,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.218.0", + "wasm-encoder 0.219.0", "wasm-metadata", - "wasmparser 0.218.0", + "wasmparser 0.219.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.218.0" +version = "0.219.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d3d1066ab761b115f97fef2b191090faabcb0f37b555b758d3caf42d4ed9e55" +checksum = "23102e180c0c464f36e293d31a27b524e3ece930d7b5527d2f33f9d2c963de64" dependencies = [ "anyhow", "id-arena", @@ -6205,7 +6217,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.218.0", + "wasmparser 0.219.0", ] [[package]] diff --git a/INSTALL.md b/INSTALL.md index ded0b59fc6c..74fcc58348b 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -79,9 +79,23 @@ See [the rustc-dev-guide for more info][sysllvm]. ./configure ``` - If you plan to use `x.py install` to create an installation, it is - recommended that you set the `prefix` value in the `[install]` section to a - directory: `./configure --set install.prefix=<path>` + If you plan to use `x.py install` to create an installation, you can either + set `DESTDIR` environment variable to your custom directory path: + + ```bash + export DESTDIR=<path> + ``` + + or set `prefix` and `sysconfdir` in the `[install]` section to your custom + directory path: + + ```sh + ./configure --set install.prefix=<path> --set install.sysconfdir=<path> + ``` + + When the `DESTDIR` environment variable is present, the `prefix` and + `sysconfdir` values are combined with the path from the `DESTDIR` + environment variable. 3. Build and install: diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs new file mode 100644 index 00000000000..2ecac8a9df1 --- /dev/null +++ b/compiler/rustc_abi/src/callconv.rs @@ -0,0 +1,254 @@ +mod abi { + pub(crate) use crate::Primitive::*; + pub(crate) use crate::Variants; +} + +use rustc_macros::HashStable_Generic; + +use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +pub enum RegKind { + Integer, + Float, + Vector, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +pub struct Reg { + pub kind: RegKind, + pub size: Size, +} + +macro_rules! reg_ctor { + ($name:ident, $kind:ident, $bits:expr) => { + pub fn $name() -> Reg { + Reg { kind: RegKind::$kind, size: Size::from_bits($bits) } + } + }; +} + +impl Reg { + reg_ctor!(i8, Integer, 8); + reg_ctor!(i16, Integer, 16); + reg_ctor!(i32, Integer, 32); + reg_ctor!(i64, Integer, 64); + reg_ctor!(i128, Integer, 128); + + reg_ctor!(f32, Float, 32); + reg_ctor!(f64, Float, 64); +} + +impl Reg { + pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { + let dl = cx.data_layout(); + match self.kind { + RegKind::Integer => match self.size.bits() { + 1 => dl.i1_align.abi, + 2..=8 => dl.i8_align.abi, + 9..=16 => dl.i16_align.abi, + 17..=32 => dl.i32_align.abi, + 33..=64 => dl.i64_align.abi, + 65..=128 => dl.i128_align.abi, + _ => panic!("unsupported integer: {self:?}"), + }, + RegKind::Float => match self.size.bits() { + 16 => dl.f16_align.abi, + 32 => dl.f32_align.abi, + 64 => dl.f64_align.abi, + 128 => dl.f128_align.abi, + _ => panic!("unsupported float: {self:?}"), + }, + RegKind::Vector => dl.vector_align(self.size).abi, + } + } +} + +/// Return value from the `homogeneous_aggregate` test function. +#[derive(Copy, Clone, Debug)] +pub enum HomogeneousAggregate { + /// Yes, all the "leaf fields" of this struct are passed in the + /// same way (specified in the `Reg` value). + Homogeneous(Reg), + + /// There are no leaf fields at all. + NoData, +} + +/// Error from the `homogeneous_aggregate` test function, indicating +/// there are distinct leaf fields passed in different ways, +/// or this is uninhabited. +#[derive(Copy, Clone, Debug)] +pub struct Heterogeneous; + +impl HomogeneousAggregate { + /// If this is a homogeneous aggregate, returns the homogeneous + /// unit, else `None`. + pub fn unit(self) -> Option<Reg> { + match self { + HomogeneousAggregate::Homogeneous(reg) => Some(reg), + HomogeneousAggregate::NoData => None, + } + } + + /// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in + /// the same `struct`. Only succeeds if only one of them has any data, + /// or both units are identical. + fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> { + match (self, other) { + (x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x), + + (HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => { + if a != b { + return Err(Heterogeneous); + } + Ok(self) + } + } + } +} + +impl<'a, Ty> TyAndLayout<'a, Ty> { + /// Returns `true` if this is an aggregate type (including a ScalarPair!) + pub fn is_aggregate(&self) -> bool { + match self.abi { + Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, + Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, + } + } + + /// Returns `Homogeneous` if this layout is an aggregate containing fields of + /// only a single type (e.g., `(u32, u32)`). Such aggregates are often + /// special-cased in ABIs. + /// + /// Note: We generally ignore 1-ZST fields when computing this value (see #56877). + /// + /// This is public so that it can be used in unit tests, but + /// should generally only be relevant to the ABI details of + /// specific targets. + pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous> + where + Ty: TyAbiInterface<'a, C> + Copy, + { + match self.abi { + Abi::Uninhabited => Err(Heterogeneous), + + // The primitive for this algorithm. + Abi::Scalar(scalar) => { + let kind = match scalar.primitive() { + abi::Int(..) | abi::Pointer(_) => RegKind::Integer, + abi::Float(_) => RegKind::Float, + }; + Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) + } + + Abi::Vector { .. } => { + assert!(!self.is_zst()); + Ok(HomogeneousAggregate::Homogeneous(Reg { + kind: RegKind::Vector, + size: self.size, + })) + } + + Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => { + // Helper for computing `homogeneous_aggregate`, allowing a custom + // starting offset (used below for handling variants). + let from_fields_at = + |layout: Self, + start: Size| + -> Result<(HomogeneousAggregate, Size), Heterogeneous> { + let is_union = match layout.fields { + FieldsShape::Primitive => { + unreachable!("aggregates can't have `FieldsShape::Primitive`") + } + FieldsShape::Array { count, .. } => { + assert_eq!(start, Size::ZERO); + + let result = if count > 0 { + layout.field(cx, 0).homogeneous_aggregate(cx)? + } else { + HomogeneousAggregate::NoData + }; + return Ok((result, layout.size)); + } + FieldsShape::Union(_) => true, + FieldsShape::Arbitrary { .. } => false, + }; + + let mut result = HomogeneousAggregate::NoData; + let mut total = start; + + for i in 0..layout.fields.count() { + let field = layout.field(cx, i); + if field.is_1zst() { + // No data here and no impact on layout, can be ignored. + // (We might be able to also ignore all aligned ZST but that's less clear.) + continue; + } + + if !is_union && total != layout.fields.offset(i) { + // This field isn't just after the previous one we considered, abort. + return Err(Heterogeneous); + } + + result = result.merge(field.homogeneous_aggregate(cx)?)?; + + // Keep track of the offset (without padding). + let size = field.size; + if is_union { + total = total.max(size); + } else { + total += size; + } + } + + Ok((result, total)) + }; + + let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; + + match &self.variants { + abi::Variants::Single { .. } => {} + abi::Variants::Multiple { variants, .. } => { + // Treat enum variants like union members. + // HACK(eddyb) pretend the `enum` field (discriminant) + // is at the start of every variant (otherwise the gap + // at the start of all variants would disqualify them). + // + // NB: for all tagged `enum`s (which include all non-C-like + // `enum`s with defined FFI representation), this will + // match the homogeneous computation on the equivalent + // `struct { tag; union { variant1; ... } }` and/or + // `union { struct { tag; variant1; } ... }` + // (the offsets of variant fields should be identical + // between the two for either to be a homogeneous aggregate). + let variant_start = total; + for variant_idx in variants.indices() { + let (variant_result, variant_total) = + from_fields_at(self.for_variant(cx, variant_idx), variant_start)?; + + result = result.merge(variant_result)?; + total = total.max(variant_total); + } + } + } + + // There needs to be no padding. + if total != self.size { + Err(Heterogeneous) + } else { + match result { + HomogeneousAggregate::Homogeneous(_) => { + assert_ne!(total, Size::ZERO); + } + HomogeneousAggregate::NoData => { + assert_eq!(total, Size::ZERO); + } + } + Ok(result) + } + } + Abi::Aggregate { sized: false } => Err(Heterogeneous), + } + } +} diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 620a051eeb7..6e1299944a0 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -11,6 +11,10 @@ use crate::{ Variants, WrappingRange, }; +mod ty; + +pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; + // A variant is absent if it's uninhabited and only has ZST fields. // Present uninhabited variants only require space for their fields, // but *not* an encoding of the discriminant (e.g., a tag value). diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_abi/src/layout/ty.rs index 3eaff652618..c6812c4d4c0 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -1,24 +1,13 @@ use std::fmt; use std::ops::Deref; -pub use Float::*; -pub use Integer::*; -pub use Primitive::*; +use Float::*; +use Primitive::*; use rustc_data_structures::intern::Interned; use rustc_macros::HashStable_Generic; -use crate::json::{Json, ToJson}; - -pub mod call; - // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`. -pub use rustc_abi::{Float, *}; - -impl ToJson for Endian { - fn to_json(&self) -> Json { - self.as_str().to_json() - } -} +use crate::{Float, *}; rustc_index::newtype_index! { /// The *source-order* index of a field in a variant. @@ -135,7 +124,7 @@ impl<'a> Layout<'a> { /// Note that the layout is NOT guaranteed to always be identical /// to that obtained from `layout_of(ty)`, as we need to produce /// layouts for which Rust types do not exist, such as enum variants -/// or synthetic fields of enums (i.e., discriminants) and fat pointers. +/// or synthetic fields of enums (i.e., discriminants) and wide pointers. #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] pub struct TyAndLayout<'a, Ty> { pub ty: Ty, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index fa7c98a7fa0..84d756b6d51 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", doc(rust_logo))] +#![cfg_attr(feature = "nightly", feature(rustc_attrs))] #![cfg_attr(feature = "nightly", feature(rustdoc_internals))] #![cfg_attr(feature = "nightly", feature(step_trait))] #![warn(unreachable_pub)] @@ -22,11 +23,16 @@ use rustc_macros::HashStable_Generic; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_Generic, Encodable_Generic}; +mod callconv; mod layout; #[cfg(test)] mod tests; -pub use layout::{LayoutCalculator, LayoutCalculatorError}; +pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; +pub use layout::{ + FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface, + TyAndLayout, VariantIdx, +}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 37f429cce44..937031324f5 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -511,7 +511,7 @@ pub enum MetaItemKind { /// List meta item. /// /// E.g., `#[derive(..)]`, where the field represents the `..`. - List(ThinVec<NestedMetaItem>), + List(ThinVec<MetaItemInner>), /// Name value meta item. /// @@ -523,7 +523,7 @@ pub enum MetaItemKind { /// /// E.g., each of `Clone`, `Copy` in `#[derive(Clone, Copy)]`. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum NestedMetaItem { +pub enum MetaItemInner { /// A full MetaItem, for recursive meta items. MetaItem(MetaItem), @@ -2167,10 +2167,6 @@ pub enum TyKind { Never, /// A tuple (`(A, B, C, D,...)`). Tup(ThinVec<P<Ty>>), - /// An anonymous struct type i.e. `struct { foo: Type }`. - AnonStruct(NodeId, ThinVec<FieldDef>), - /// An anonymous union type i.e. `union { bar: Type }`. - AnonUnion(NodeId, ThinVec<FieldDef>), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`. /// @@ -2227,10 +2223,6 @@ impl TyKind { None } } - - pub fn is_anon_adt(&self) -> bool { - matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..)) - } } /// Syntax used to declare a trait object. @@ -2278,7 +2270,7 @@ impl InlineAsmOptions { pub const COUNT: usize = Self::all().bits().count_ones() as usize; pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW); - pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN); + pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW); pub fn human_readable_names(&self) -> Vec<&'static str> { let mut options = vec![]; @@ -2434,6 +2426,32 @@ pub enum AsmMacro { NakedAsm, } +impl AsmMacro { + pub const fn macro_name(self) -> &'static str { + match self { + AsmMacro::Asm => "asm", + AsmMacro::GlobalAsm => "global_asm", + AsmMacro::NakedAsm => "naked_asm", + } + } + + pub const fn is_supported_option(self, option: InlineAsmOptions) -> bool { + match self { + AsmMacro::Asm => true, + AsmMacro::GlobalAsm => InlineAsmOptions::GLOBAL_OPTIONS.contains(option), + AsmMacro::NakedAsm => InlineAsmOptions::NAKED_OPTIONS.contains(option), + } + } + + pub const fn diverges(self, options: InlineAsmOptions) -> bool { + match self { + AsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), + AsmMacro::GlobalAsm => true, + AsmMacro::NakedAsm => true, + } + } +} + /// Inline assembly. /// /// E.g., `asm!("NOP");`. diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 124d0acfa49..b73412a4b1d 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -11,7 +11,7 @@ use thin_vec::{ThinVec, thin_vec}; use crate::ast::{ AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, + DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path, PathSegment, Safety, }; use crate::ptr::P; @@ -136,7 +136,7 @@ impl Attribute { } } - pub fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> { + pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { match &self.kind { AttrKind::Normal(normal) => normal.item.meta_item_list(), AttrKind::DocComment(..) => None, @@ -223,7 +223,7 @@ impl AttrItem { self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) } - fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> { + fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { match &self.args { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) @@ -285,7 +285,7 @@ impl MetaItem { matches!(self.kind, MetaItemKind::Word) } - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> { match &self.kind { MetaItemKind::List(l) => Some(&**l), _ => None, @@ -393,11 +393,11 @@ impl MetaItem { } impl MetaItemKind { - fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<NestedMetaItem>> { + fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> { let mut tokens = tokens.trees().peekable(); let mut result = ThinVec::new(); while tokens.peek().is_some() { - let item = NestedMetaItem::from_tokens(&mut tokens)?; + let item = MetaItemInner::from_tokens(&mut tokens)?; result.push(item); match tokens.next() { None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {} @@ -460,11 +460,11 @@ impl MetaItemKind { } } -impl NestedMetaItem { +impl MetaItemInner { pub fn span(&self) -> Span { match self { - NestedMetaItem::MetaItem(item) => item.span, - NestedMetaItem::Lit(lit) => lit.span, + MetaItemInner::MetaItem(item) => item.span, + MetaItemInner::Lit(lit) => lit.span, } } @@ -488,7 +488,7 @@ impl NestedMetaItem { } /// Gets a list of inner meta items from a list `MetaItem` type. - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> { self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) } @@ -519,18 +519,28 @@ impl NestedMetaItem { self.meta_item().and_then(|meta_item| meta_item.value_str()) } - /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s. + /// Returns the `MetaItemLit` if `self` is a `MetaItemInner::Literal`s. pub fn lit(&self) -> Option<&MetaItemLit> { match self { - NestedMetaItem::Lit(lit) => Some(lit), + MetaItemInner::Lit(lit) => Some(lit), _ => None, } } - /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. + /// Returns the `MetaItem` if `self` is a `MetaItemInner::MetaItem` or if it's + /// `MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`. + pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> { + match self { + MetaItemInner::MetaItem(_item) => Some(self), + MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self), + _ => None, + } + } + + /// Returns the `MetaItem` if `self` is a `MetaItemInner::MetaItem`. pub fn meta_item(&self) -> Option<&MetaItem> { match self { - NestedMetaItem::MetaItem(item) => Some(item), + MetaItemInner::MetaItem(item) => Some(item), _ => None, } } @@ -540,22 +550,22 @@ impl NestedMetaItem { self.meta_item().is_some() } - fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem> + fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemInner> where I: Iterator<Item = &'a TokenTree>, { match tokens.peek() { Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => { tokens.next(); - return Some(NestedMetaItem::Lit(lit)); + return Some(MetaItemInner::Lit(lit)); } Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => { tokens.next(); - return NestedMetaItem::from_tokens(&mut inner_tokens.trees().peekable()); + return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable()); } _ => {} } - MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem) + MetaItem::from_tokens(tokens).map(MetaItemInner::MetaItem) } } @@ -666,6 +676,6 @@ pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { find_by_name(attrs, name).is_some() } -pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { +pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool { items.iter().any(|item| item.has_name(name)) } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 104f84f26e0..1a7da46913d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -83,7 +83,7 @@ pub trait MutVisitor: Sized { walk_crate(self, c) } - fn visit_meta_list_item(&mut self, list_item: &mut NestedMetaItem) { + fn visit_meta_list_item(&mut self, list_item: &mut MetaItemInner) { walk_meta_list_item(self, list_item); } @@ -519,10 +519,6 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) { visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Impl)); } TyKind::MacCall(mac) => vis.visit_mac_call(mac), - TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { - vis.visit_id(id); - fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); - } } visit_lazy_tts(vis, tokens); vis.visit_span(span); @@ -659,10 +655,10 @@ fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) { visit_delim_args(vis, body); } -fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut NestedMetaItem) { +fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut MetaItemInner) { match li { - NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi), - NestedMetaItem::Lit(_lit) => {} + MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi), + MetaItemInner::Lit(_lit) => {} } } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 1a80a9ccdbf..a517f17c82c 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -287,12 +287,6 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { | ast::TyKind::Pat(..) | ast::TyKind::Dummy | ast::TyKind::Err(..) => break None, - - // These end in brace, but cannot occur in a let-else statement. - // They are only parsed as fields of a data structure. For the - // purpose of denying trailing braces in the expression of a - // let-else, we can disregard these. - ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None, } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 9f9c3d8c392..4dcadb8517e 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -535,9 +535,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { TyKind::Err(_guar) => {} TyKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), TyKind::Never | TyKind::CVarArgs => {} - TyKind::AnonStruct(_id, ref fields) | TyKind::AnonUnion(_id, ref fields) => { - walk_list!(visitor, visit_field_def, fields); - } } V::Result::output() } diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index e77c0fb3a3e..6289966561f 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -226,6 +226,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_opaque_ty(&mut self, opaq: &'hir OpaqueTy<'hir>) { + self.insert(opaq.span, opaq.hir_id, Node::OpaqueTy(opaq)); + + self.with_parent(opaq.hir_id, |this| { + intravisit::walk_opaque_ty(this, opaq); + }); + } + fn visit_anon_const(&mut self, constant: &'hir AnonConst) { // FIXME: use real span? self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9275308cccb..365924ef782 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1259,46 +1259,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, TyKind::Err(guar) => hir::TyKind::Err(*guar), - // Lower the anonymous structs or unions in a nested lowering context. - // - // ``` - // struct Foo { - // _: union { - // // ^__________________ <-- within the nested lowering context, - // /* fields */ // | we lower all fields defined into an - // } // | owner node of struct or union item - // // ^_____________________| - // } - // ``` - TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => { - // Here its `def_id` is created in `build_reduced_graph`. - let def_id = self.local_def_id(*node_id); - debug!(?def_id); - let owner_id = hir::OwnerId { def_id }; - self.with_hir_id_owner(*node_id, |this| { - let fields = this.arena.alloc_from_iter( - fields.iter().enumerate().map(|f| this.lower_field_def(f)), - ); - let span = t.span; - let variant_data = - hir::VariantData::Struct { fields, recovered: ast::Recovered::No }; - // FIXME: capture the generics from the outer adt. - let generics = hir::Generics::empty(); - let kind = match t.kind { - TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics), - TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics), - _ => unreachable!(), - }; - hir::OwnerNode::Item(this.arena.alloc(hir::Item { - ident: Ident::new(kw::Empty, span), - owner_id, - kind, - span: this.lower_span(span), - vis_span: this.lower_span(span.shrink_to_lo()), - })) - }); - hir::TyKind::AnonAdt(hir::ItemId { owner_id }) - } TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ref(region, mt) => { @@ -1367,14 +1327,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // takes care of rejecting invalid modifier combinations and // const trait bounds in trait object types. GenericBound::Trait(ty, modifiers) => { - // Still, don't pass along the constness here; we don't want to - // synthesize any host effect args, it'd only cause problems. - let modifiers = TraitBoundModifiers { - constness: BoundConstness::Never, - ..*modifiers - }; - let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers); - let polarity = this.lower_trait_bound_modifiers(modifiers); + let trait_ref = this.lower_poly_trait_ref(ty, itctx, *modifiers); + let polarity = this.lower_trait_bound_modifiers(*modifiers); Some((trait_ref, polarity)) } GenericBound::Outlives(lifetime) => { @@ -1573,11 +1527,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Feature gate for RPITIT + use<..> match origin { rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { - if let Some(span) = bounds.iter().find_map(|bound| match *bound { - ast::GenericBound::Use(_, span) => Some(span), - _ => None, - }) { - self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span }); + if !self.tcx.features().precise_capturing_in_traits + && let Some(span) = bounds.iter().find_map(|bound| match *bound { + ast::GenericBound::Use(_, span) => Some(span), + _ => None, + }) + { + let mut diag = + self.tcx.dcx().create_err(errors::NoPreciseCapturesOnRpitit { span }); + add_feature_diagnostics( + &mut diag, + self.tcx.sess, + sym::precise_capturing_in_traits, + ); + diag.emit(); } } _ => {} @@ -1603,7 +1566,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id); - debug!(?opaque_ty_def_id); + let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id); + debug!(?opaque_ty_def_id, ?opaque_ty_hir_id); // Map from captured (old) lifetime to synthetic (new) lifetime. // Used to resolve lifetimes in the bounds of the opaque. @@ -1676,7 +1640,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - self.with_hir_id_owner(opaque_ty_node_id, |this| { + let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| { // Install the remapping from old to new (if any). This makes sure that // any lifetimes that would have resolved to the def-id of captured // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. @@ -1714,7 +1678,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args); - let opaque_ty_item = hir::OpaqueTy { + trace!("registering opaque type with id {:#?}", opaque_ty_def_id); + let opaque_ty_def = hir::OpaqueTy { + hir_id: opaque_ty_hir_id, + def_id: opaque_ty_def_id, generics: this.arena.alloc(hir::Generics { params: generic_params, predicates: &[], @@ -1725,19 +1692,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, origin, lifetime_mapping, - }; - - // Generate an `type Foo = impl Trait;` declaration. - trace!("registering opaque type with id {:#?}", opaque_ty_def_id); - let opaque_ty_item = hir::Item { - owner_id: hir::OwnerId { def_id: opaque_ty_def_id }, - ident: Ident::empty(), - kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)), - vis_span: this.lower_span(span.shrink_to_lo()), span: this.lower_span(opaque_ty_span), }; - - hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item)) + this.arena.alloc(opaque_ty_def) }); let generic_args = self.arena.alloc_from_iter( @@ -1750,10 +1707,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Foo = impl Trait` is, internally, created as a child of the // async fn, so the *type parameters* are inherited. It's // only the lifetime parameters that we must supply. - hir::TyKind::OpaqueDef( - hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, - generic_args, - ) + hir::TyKind::OpaqueDef(opaque_ty_def, generic_args) } fn lower_precise_capturing_args( diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index c361c35b723..7cfbd6c6c6c 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -1,7 +1,3 @@ -ast_passes_anon_struct_or_union_not_allowed = - anonymous {$struct_or_union}s are not allowed outside of unnamed struct or union fields - .label = anonymous {$struct_or_union} declared here - ast_passes_assoc_const_without_body = associated constant in `impl` without body .suggestion = provide a definition for the constant @@ -160,14 +156,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} .type = inherent impl for this type .only_trait = only trait implementations may be annotated with {$annotation} -ast_passes_invalid_unnamed_field = - unnamed fields are not allowed outside of structs or unions - .label = unnamed field declared here - -ast_passes_invalid_unnamed_field_ty = - unnamed fields can only have struct or union types - .label = not a struct or union - ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier .suggestion = remove safe from this item diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 5bdd9b6eda8..87e3a6871b9 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -244,9 +244,6 @@ impl<'a> AstValidator<'a> { } } } - TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { - walk_list!(self, visit_struct_field_def, fields) - } _ => visit::walk_ty(self, t), } } @@ -255,7 +252,6 @@ impl<'a> AstValidator<'a> { if let Some(ident) = field.ident && ident.name == kw::Underscore { - self.check_unnamed_field_ty(&field.ty, ident.span); self.visit_vis(&field.vis); self.visit_ident(ident); self.visit_ty_common(&field.ty); @@ -294,39 +290,6 @@ impl<'a> AstValidator<'a> { } } - fn check_unnamed_field_ty(&self, ty: &Ty, span: Span) { - if matches!( - &ty.kind, - // We already checked for `kw::Underscore` before calling this function, - // so skip the check - TyKind::AnonStruct(..) | TyKind::AnonUnion(..) - // If the anonymous field contains a Path as type, we can't determine - // if the path is a valid struct or union, so skip the check - | TyKind::Path(..) - ) { - return; - } - self.dcx().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span }); - } - - fn deny_anon_struct_or_union(&self, ty: &Ty) { - let struct_or_union = match &ty.kind { - TyKind::AnonStruct(..) => "struct", - TyKind::AnonUnion(..) => "union", - _ => return, - }; - self.dcx().emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span }); - } - - fn deny_unnamed_field(&self, field: &FieldDef) { - if let Some(ident) = field.ident - && ident.name == kw::Underscore - { - self.dcx() - .emit_err(errors::InvalidUnnamedField { span: field.span, ident_span: ident.span }); - } - } - fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) { let Const::Yes(span) = constness else { return; @@ -890,15 +853,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_ty(&mut self, ty: &'a Ty) { self.visit_ty_common(ty); - self.deny_anon_struct_or_union(ty); self.walk_ty(ty) } - fn visit_field_def(&mut self, field: &'a FieldDef) { - self.deny_unnamed_field(field); - visit::walk_field_def(self, field) - } - fn visit_item(&mut self, item: &'a Item) { if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) { self.has_proc_macro_decls = true; diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 5cce47ce7bd..c60925b3049 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -815,33 +815,6 @@ pub(crate) struct NegativeBoundWithParentheticalNotation { } #[derive(Diagnostic)] -#[diag(ast_passes_invalid_unnamed_field_ty)] -pub(crate) struct InvalidUnnamedFieldTy { - #[primary_span] - pub span: Span, - #[label] - pub ty_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_invalid_unnamed_field)] -pub(crate) struct InvalidUnnamedField { - #[primary_span] - pub span: Span, - #[label] - pub ident_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_anon_struct_or_union_not_allowed)] -pub(crate) struct AnonStructOrUnionNotAllowed { - #[primary_span] - #[label] - pub span: Span, - pub struct_or_union: &'static str, -} - -#[derive(Diagnostic)] #[diag(ast_passes_match_arm_with_no_body)] pub(crate) struct MatchArmWithNoBody { #[primary_span] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 83931a8c1a9..82de83f8da4 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -186,9 +186,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } // Check unstable flavors of the `#[doc]` attribute. if attr.has_name(sym::doc) { - for nested_meta in attr.meta_item_list().unwrap_or_default() { + for meta_item_inner in attr.meta_item_list().unwrap_or_default() { macro_rules! gate_doc { ($($s:literal { $($name:ident => $feature:ident)* })*) => { - $($(if nested_meta.has_name(sym::$name) { + $($(if meta_item_inner.has_name(sym::$name) { let msg = concat!("`#[doc(", stringify!($name), ")]` is ", $s); gate!(self, $feature, attr.span, msg); })*)* @@ -541,7 +541,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); gate_all!(explicit_tail_calls, "`become` expression is experimental"); gate_all!(generic_const_items, "generic const items are experimental"); - gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented"); gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 726ceebe3c5..97cb6e52d56 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -67,7 +67,7 @@ pub fn vis_to_string(v: &ast::Visibility) -> String { State::new().vis_to_string(v) } -pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { +pub fn meta_list_item_to_string(li: &ast::MetaItemInner) -> String { State::new().meta_list_item_to_string(li) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 7e07ccf28a0..44a5a2d0baf 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1174,14 +1174,6 @@ impl<'a> State<'a> { } self.pclose(); } - ast::TyKind::AnonStruct(_, fields) => { - self.head("struct"); - self.print_record_struct_body(fields, ty.span); - } - ast::TyKind::AnonUnion(_, fields) => { - self.head("union"); - self.print_record_struct_body(fields, ty.span); - } ast::TyKind::Paren(typ) => { self.popen(); self.print_type(typ); @@ -2006,10 +1998,10 @@ impl<'a> State<'a> { self.print_attribute_inline(attr, false) } - fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { + fn print_meta_list_item(&mut self, item: &ast::MetaItemInner) { match item { - ast::NestedMetaItem::MetaItem(mi) => self.print_meta_item(mi), - ast::NestedMetaItem::Lit(lit) => self.print_meta_item_lit(lit), + ast::MetaItemInner::MetaItem(mi) => self.print_meta_item(mi), + ast::MetaItemInner::Lit(lit) => self.print_meta_item_lit(lit), } } @@ -2054,7 +2046,7 @@ impl<'a> State<'a> { Self::to_string(|s| s.print_path_segment(p, false)) } - pub(crate) fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { + pub(crate) fn meta_list_item_to_string(&self, li: &ast::MetaItemInner) -> String { Self::to_string(|s| s.print_meta_list_item(li)) } diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index 5d9ac23ec49..adabf18ca85 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -107,6 +107,8 @@ attr_unknown_version_literal = attr_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change +attr_unsupported_literal_cfg_boolean = + literal in `cfg` predicate value must be a boolean attr_unsupported_literal_cfg_string = literal in `cfg` predicate value must be a string attr_unsupported_literal_deprecated_kv_pair = diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 28d73fbe9f3..c1db4d07dfc 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use rustc_abi::Align; use rustc_ast::{ - self as ast, Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId, + self as ast, Attribute, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId, attr, }; use rustc_ast_pretty::pprust; @@ -18,7 +18,7 @@ use rustc_session::parse::feature_err; use rustc_session::{RustcVersion, Session}; use rustc_span::Span; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{Symbol, sym}; +use rustc_span::symbol::{Symbol, kw, sym}; use crate::fluent_generated; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool { pub(crate) enum UnsupportedLiteralReason { Generic, CfgString, + CfgBoolean, DeprecatedString, DeprecatedKvPair, } @@ -533,7 +534,7 @@ pub struct Condition { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches( - cfg: &ast::MetaItem, + cfg: &ast::MetaItemInner, sess: &Session, lint_node_id: NodeId, features: Option<&Features>, @@ -604,22 +605,53 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> { /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// evaluate individual items. pub fn eval_condition( - cfg: &ast::MetaItem, + cfg: &ast::MetaItemInner, sess: &Session, features: Option<&Features>, eval: &mut impl FnMut(Condition) -> bool, ) -> bool { let dcx = sess.dcx(); + + let cfg = match cfg { + ast::MetaItemInner::MetaItem(meta_item) => meta_item, + ast::MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { + if let Some(features) = features { + // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true` + // and `true`, and we want to keep the former working without feature gate + gate_cfg( + &(( + if *b { kw::True } else { kw::False }, + sym::cfg_boolean_literals, + |features: &Features| features.cfg_boolean_literals, + )), + cfg.span(), + sess, + features, + ); + } + return *b; + } + _ => { + dcx.emit_err(session_diagnostics::UnsupportedLiteral { + span: cfg.span(), + reason: UnsupportedLiteralReason::CfgBoolean, + is_bytestr: false, + start_point_span: sess.source_map().start_point(cfg.span()), + }); + return false; + } + }; + match &cfg.kind { ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { - [NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { + [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { (sym, span) } [ - NestedMetaItem::Lit(MetaItemLit { span, .. }) - | NestedMetaItem::MetaItem(MetaItem { span, .. }), + MetaItemInner::Lit(MetaItemLit { span, .. }) + | MetaItemInner::MetaItem(MetaItem { span, .. }), ] => { dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); return false; @@ -645,7 +677,7 @@ pub fn eval_condition( } ast::MetaItemKind::List(mis) => { for mi in mis.iter() { - if !mi.is_meta_item() { + if mi.meta_item_or_bool().is_none() { dcx.emit_err(session_diagnostics::UnsupportedLiteral { span: mi.span(), reason: UnsupportedLiteralReason::Generic, @@ -663,23 +695,19 @@ pub fn eval_condition( .iter() // We don't use any() here, because we want to evaluate all cfg condition // as eval_condition can (and does) extra checks - .fold(false, |res, mi| { - res | eval_condition(mi.meta_item().unwrap(), sess, features, eval) - }), + .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), sym::all => mis .iter() // We don't use all() here, because we want to evaluate all cfg condition // as eval_condition can (and does) extra checks - .fold(true, |res, mi| { - res & eval_condition(mi.meta_item().unwrap(), sess, features, eval) - }), + .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), sym::not => { let [mi] = mis.as_slice() else { dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); return false; }; - !eval_condition(mi.meta_item().unwrap(), sess, features, eval) + !eval_condition(mi, sess, features, eval) } sym::target => { if let Some(features) = features @@ -700,7 +728,12 @@ pub fn eval_condition( seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); } - res & eval_condition(&mi, sess, features, eval) + res & eval_condition( + &ast::MetaItemInner::MetaItem(mi), + sess, + features, + eval, + ) }) } _ => { @@ -840,7 +873,7 @@ pub fn find_deprecation( for meta in list { match meta { - NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() { + MetaItemInner::MetaItem(mi) => match mi.name_or_empty() { sym::since => { if !get(mi, &mut since) { continue 'outer; @@ -879,7 +912,7 @@ pub fn find_deprecation( continue 'outer; } }, - NestedMetaItem::Lit(lit) => { + MetaItemInner::Lit(lit) => { sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { span: lit.span, reason: UnsupportedLiteralReason::DeprecatedKvPair, @@ -1244,7 +1277,7 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> { let mut candidates = Vec::new(); for meta in metas { - let NestedMetaItem::Lit(meta_lit) = meta else { + let MetaItemInner::Lit(meta_lit) = meta else { return None; }; candidates.push(meta_lit.symbol); diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 959a5a4bba7..626840aa6a3 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { let mut diag = Diag::new(dcx, level, match self.reason { UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic, UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string, + UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean, UnsupportedLiteralReason::DeprecatedString => { fluent::attr_unsupported_literal_deprecated_string } diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index c994c4dc1e4..7ace38c3e85 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -1,7 +1,5 @@ //! This file provides API for compiler consumers. -use std::rc::Rc; - use rustc_hir::def_id::LocalDefId; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::{Body, Promoted}; @@ -65,10 +63,10 @@ pub struct BodyWithBorrowckFacts<'tcx> { /// The mir bodies of promoteds. pub promoted: IndexVec<Promoted, Body<'tcx>>, /// The set of borrows occurring in `body` with data about them. - pub borrow_set: Rc<BorrowSet<'tcx>>, + pub borrow_set: BorrowSet<'tcx>, /// Context generated during borrowck, intended to be passed to /// [`calculate_borrows_out_of_scope_at_location`]. - pub region_inference_context: Rc<RegionInferenceContext<'tcx>>, + pub region_inference_context: RegionInferenceContext<'tcx>, /// The table that maps Polonius points to locations in the table. /// Populated when using [`ConsumerOptions::PoloniusInputFacts`] /// or [`ConsumerOptions::PoloniusOutputFacts`]. @@ -79,7 +77,7 @@ pub struct BodyWithBorrowckFacts<'tcx> { pub input_facts: Option<Box<PoloniusInput>>, /// Polonius output facts. Populated when using /// [`ConsumerOptions::PoloniusOutputFacts`]. - pub output_facts: Option<Rc<PoloniusOutput>>, + pub output_facts: Option<Box<PoloniusOutput>>, } /// This function computes borrowck facts for the given body. The [`ConsumerOptions`] diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 60ea0d1edbf..c687be69b1a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -708,9 +708,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // for the branching codepaths that aren't covered, to point at them. let map = self.infcx.tcx.hir(); let body = map.body_owned_by(self.mir_def_id()); - let mut visitor = - ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] }; + let mut visitor = ConditionVisitor { tcx: self.infcx.tcx, spans, name, errors: vec![] }; visitor.visit_body(&body); + let spans = visitor.spans; let mut show_assign_sugg = false; let isnt_initialized = if let InitializationRequiringAction::PartialAssignment @@ -4465,20 +4465,20 @@ impl<'hir> Visitor<'hir> for BreakFinder { /// Given a set of spans representing statements initializing the relevant binding, visit all the /// function expressions looking for branching code paths that *do not* initialize the binding. -struct ConditionVisitor<'b, 'tcx> { +struct ConditionVisitor<'tcx> { tcx: TyCtxt<'tcx>, - spans: &'b [Span], - name: &'b str, + spans: Vec<Span>, + name: String, errors: Vec<(Span, String)>, } -impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { +impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { match ex.kind { hir::ExprKind::If(cond, body, None) => { // `if` expressions with no `else` that initialize the binding might be missing an // `else` arm. - if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() { + if ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break() { self.errors.push(( cond.span, format!( @@ -4495,8 +4495,8 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { hir::ExprKind::If(cond, body, Some(other)) => { // `if` expressions where the binding is only initialized in one of the two arms // might be missing a binding initialization. - let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break(); - let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break(); + let a = ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break(); + let b = ReferencedStatementsVisitor(&self.spans).visit_expr(other).is_break(); match (a, b) { (true, true) | (false, false) => {} (true, false) => { @@ -4536,7 +4536,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { // arms might be missing an initialization. let results: Vec<bool> = arms .iter() - .map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break()) + .map(|arm| ReferencedStatementsVisitor(&self.spans).visit_arm(arm).is_break()) .collect(); if results.iter().any(|x| *x) && !results.iter().all(|x| *x) { for (arm, seen) in arms.iter().zip(results) { diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index d8fa5506a99..26a090f5579 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -1,5 +1,4 @@ use std::collections::VecDeque; -use std::rc::Rc; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; @@ -11,7 +10,7 @@ use crate::region_infer::{Cause, RegionInferenceContext}; pub(crate) fn find<'tcx>( body: &Body<'tcx>, - regioncx: &Rc<RegionInferenceContext<'tcx>>, + regioncx: &RegionInferenceContext<'tcx>, tcx: TyCtxt<'tcx>, region_vid: RegionVid, start_point: Location, @@ -23,7 +22,7 @@ pub(crate) fn find<'tcx>( struct UseFinder<'a, 'tcx> { body: &'a Body<'tcx>, - regioncx: &'a Rc<RegionInferenceContext<'tcx>>, + regioncx: &'a RegionInferenceContext<'tcx>, tcx: TyCtxt<'tcx>, region_vid: RegionVid, start_point: Location, diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 98417e8c7a3..3871816777c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -706,7 +706,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { suggestions.push(( pat_span, format!("consider removing the {to_remove}"), - suggestion.to_string(), + suggestion, )); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index d4598a1f582..1a5f9bdb154 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -830,20 +830,14 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// /// [`OpaqueDef`]: hir::TyKind::OpaqueDef fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { - let hir = self.infcx.tcx.hir(); - - let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else { + let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else { span_bug!( hir_ty.span, "lowered return type of async fn is not OpaqueDef: {:?}", hir_ty ); }; - let opaque_ty = hir.item(id); - if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { - bounds: [hir::GenericBound::Trait(trait_ref, _)], - .. - }) = opaque_ty.kind + if let hir::OpaqueTy { bounds: [hir::GenericBound::Trait(trait_ref, _)], .. } = opaque_ty && let Some(segment) = trait_ref.trait_ref.path.segments.last() && let Some(args) = segment.args && let [constraint] = args.constraints diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a11eca0b9c7..cbf8aa313c5 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -5,7 +5,6 @@ #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(file_buffered)] #![feature(let_chains)] #![feature(never_type)] @@ -20,7 +19,6 @@ use std::cell::RefCell; use std::collections::BTreeMap; use std::marker::PhantomData; use std::ops::Deref; -use std::rc::Rc; use consumers::{BodyWithBorrowckFacts, ConsumerOptions}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -201,8 +199,7 @@ fn do_mir_borrowck<'tcx>( .into_results_cursor(body); let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure(); - let borrow_set = - Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data)); + let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data); // Compute non-lexical lifetimes. let nll::NllOutput { @@ -246,8 +243,6 @@ fn do_mir_borrowck<'tcx>( // usage significantly on some benchmarks. drop(flow_inits); - let regioncx = Rc::new(regioncx); - let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set) .into_engine(tcx, body) .pass_name("borrowck") @@ -289,10 +284,10 @@ fn do_mir_borrowck<'tcx>( access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), uninitialized_error_reported: Default::default(), - regioncx: regioncx.clone(), + regioncx: ®ioncx, used_mut: Default::default(), used_mut_upvars: SmallVec::new(), - borrow_set: Rc::clone(&borrow_set), + borrow_set: &borrow_set, upvars: &[], local_names: IndexVec::from_elem(None, &promoted_body.local_decls), region_names: RefCell::default(), @@ -330,10 +325,10 @@ fn do_mir_borrowck<'tcx>( access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), uninitialized_error_reported: Default::default(), - regioncx: Rc::clone(®ioncx), + regioncx: ®ioncx, used_mut: Default::default(), used_mut_upvars: SmallVec::new(), - borrow_set: Rc::clone(&borrow_set), + borrow_set: &borrow_set, upvars: tcx.closure_captures(def), local_names, region_names: RefCell::default(), @@ -570,10 +565,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { used_mut_upvars: SmallVec<[FieldIdx; 8]>, /// Region inference context. This contains the results from region inference and lets us e.g. /// find out which CFG points are contained in each borrow region. - regioncx: Rc<RegionInferenceContext<'tcx>>, + regioncx: &'a RegionInferenceContext<'tcx>, /// The set of borrows extracted from the MIR - borrow_set: Rc<BorrowSet<'tcx>>, + borrow_set: &'a BorrowSet<'tcx>, /// Information about upvars not necessarily preserved in types or MIR upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>], @@ -589,7 +584,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { next_region_name: RefCell<usize>, /// Results of Polonius analysis. - polonius_output: Option<Rc<PoloniusOutput>>, + polonius_output: Option<Box<PoloniusOutput>>, diags: diags::BorrowckDiags<'infcx, 'tcx>, move_errors: Vec<MoveError<'tcx>>, @@ -743,6 +738,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> } TerminatorKind::InlineAsm { + asm_macro: _, template: _, operands, options: _, @@ -800,9 +796,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => { if self.movable_coroutine { // Look for any active borrows to locals - let borrow_set = self.borrow_set.clone(); for i in state.borrows.iter() { - let borrow = &borrow_set[i]; + let borrow = &self.borrow_set[i]; self.check_for_local_borrow(borrow, span); } } @@ -816,9 +811,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> // Often, the storage will already have been killed by an explicit // StorageDead, but we don't always emit those (notably on unwind paths), // so this "extra check" serves as a kind of backup. - let borrow_set = self.borrow_set.clone(); for i in state.borrows.iter() { - let borrow = &borrow_set[i]; + let borrow = &self.borrow_set[i]; self.check_for_invalidation_at_exit(loc, borrow, span); } } @@ -1037,13 +1031,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { state: &BorrowckDomain<'a, 'tcx>, ) -> bool { let mut error_reported = false; - let borrow_set = Rc::clone(&self.borrow_set); // Use polonius output if it has been enabled. let mut polonius_output; let borrows_in_scope = if let Some(polonius) = &self.polonius_output { let location = self.location_table.start_index(location); - polonius_output = BitSet::new_empty(borrow_set.len()); + polonius_output = BitSet::new_empty(self.borrow_set.len()); for &idx in polonius.errors_at(location) { polonius_output.insert(idx); } @@ -1057,7 +1050,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { self.infcx.tcx, self.body, (sd, place_span.0), - &borrow_set, + self.borrow_set, |borrow_index| borrows_in_scope.contains(borrow_index), |this, borrow_index, borrow| match (rw, borrow.kind) { // Obviously an activation is compatible with its own @@ -1580,9 +1573,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with // another borrow. - let borrow_set = self.borrow_set.clone(); - for &borrow_index in borrow_set.activations_at_location(location) { - let borrow = &borrow_set[borrow_index]; + for &borrow_index in self.borrow_set.activations_at_location(location) { + let borrow = &self.borrow_set[borrow_index]; // only mutable borrows should be 2-phase assert!(match borrow.kind { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index d85af52b01e..3674053409b 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -42,7 +42,7 @@ pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub polonius_input: Option<Box<AllFacts>>, - pub polonius_output: Option<Rc<PoloniusOutput>>, + pub polonius_output: Option<Box<PoloniusOutput>>, pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>, pub nll_errors: RegionErrors<'tcx>, } @@ -98,7 +98,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( let universal_regions = Rc::new(universal_regions); - let elements = &Rc::new(DenseLocationMap::new(body)); + let elements = Rc::new(DenseLocationMap::new(body)); // Run the MIR type-checker. let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = @@ -107,13 +107,13 @@ pub(crate) fn compute_regions<'a, 'tcx>( param_env, body, promoted, - &universal_regions, + universal_regions.clone(), location_table, borrow_set, &mut all_facts, flow_inits, move_data, - elements, + elements.clone(), upvars, ); @@ -184,7 +184,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( let algorithm = Algorithm::from_str(&algorithm).unwrap(); debug!("compute_regions: using polonius algorithm {:?}", algorithm); let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis"); - Some(Rc::new(Output::compute(all_facts, algorithm, false))) + Some(Box::new(Output::compute(all_facts, algorithm, false))) } else { None } diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 519ba0b9e0c..679e111caa9 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -3,7 +3,7 @@ //! we can prove overlap one way or another. Essentially, we treat `Overlap` as //! a monoid and report a conflict if the product ends up not being `Disjoint`. //! -//! At each step, if we didn't run out of borrow or place, we know that our elements +//! On each step, if we didn't run out of borrow or place, we know that our elements //! have the same type, and that they only overlap if they are the identical. //! //! For example, if we are comparing these: diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index afd811a0efb..d1b65943199 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -169,6 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { } } TerminatorKind::InlineAsm { + asm_macro: _, template: _, operands, options: _, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index c62ea870acf..e85f529bf0e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -407,7 +407,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>, type_tests: Vec<TypeTest<'tcx>>, liveness_constraints: LivenessValues, - elements: &Rc<DenseLocationMap>, + elements: Rc<DenseLocationMap>, ) -> Self { debug!("universal_regions: {:#?}", universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); @@ -430,7 +430,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let mut scc_values = - RegionValues::new(elements, universal_regions.len(), &placeholder_indices); + RegionValues::new(elements, universal_regions.len(), placeholder_indices); for region in liveness_constraints.regions() { let scc = constraint_sccs.scc(region); @@ -637,7 +637,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &mut self, infcx: &InferCtxt<'tcx>, body: &Body<'tcx>, - polonius_output: Option<Rc<PoloniusOutput>>, + polonius_output: Option<Box<PoloniusOutput>>, ) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) { let mir_def_id = body.source.def_id(); self.propagate_constraints(); @@ -663,7 +663,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_polonius_subset_errors( outlives_requirements.as_mut(), &mut errors_buffer, - polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), + polonius_output + .as_ref() + .expect("Polonius output is unavailable despite `-Z polonius`"), ); } else { self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer); @@ -1411,7 +1413,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, errors_buffer: &mut RegionErrors<'tcx>, - polonius_output: Rc<PoloniusOutput>, + polonius_output: &PoloniusOutput, ) { debug!( "check_polonius_subset_errors: {} subset_errors", diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 2f90e916281..a16c1931a55 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -329,8 +329,8 @@ fn check_opaque_type_well_formed<'tcx>( ) -> Result<Ty<'tcx>, ErrorGuaranteed> { // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. - let opaque_ty_hir = tcx.hir().expect_item(def_id); - let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else { + let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id); + let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else { return Ok(definition_ty); }; let param_env = tcx.param_env(def_id); diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index b95fe5b5028..662e6fa46b5 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -275,15 +275,16 @@ impl<N: Idx> RegionValues<N> { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. pub(crate) fn new( - elements: &Rc<DenseLocationMap>, + elements: Rc<DenseLocationMap>, num_universal_regions: usize, - placeholder_indices: &Rc<PlaceholderIndices>, + placeholder_indices: Rc<PlaceholderIndices>, ) -> Self { + let num_points = elements.num_points(); let num_placeholders = placeholder_indices.len(); Self { - elements: elements.clone(), - points: SparseIntervalMatrix::new(elements.num_points()), - placeholder_indices: placeholder_indices.clone(), + elements, + points: SparseIntervalMatrix::new(num_points), + placeholder_indices, free_regions: SparseBitMatrix::new(num_universal_regions), placeholders: SparseBitMatrix::new(num_placeholders), } diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 0a375c7fae8..b7aef71eb54 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -11,7 +11,7 @@ use crate::BorrowckInferCtxt; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. #[instrument(skip(infcx, body, promoted), level = "debug")] -pub fn renumber_mir<'tcx>( +pub(crate) fn renumber_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexSlice<Promoted, Body<'tcx>>, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index fc1600ea4a6..6c86968389a 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -97,7 +97,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { /// that we computed for the closure. This has the effect of adding new outlives obligations /// to existing region variables in `closure_args`. #[instrument(skip(self), level = "debug")] - pub fn apply_closure_requirements( + pub(crate) fn apply_closure_requirements( &mut self, closure_requirements: &ClosureRegionRequirements<'tcx>, closure_def_id: DefId, diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 6977fed59ed..cded9935f97 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -54,7 +54,7 @@ pub(crate) fn create<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: ty::Region<'tcx>, - universal_regions: &Rc<UniversalRegions<'tcx>>, + universal_regions: Rc<UniversalRegions<'tcx>>, constraints: &mut MirTypeckRegionConstraints<'tcx>, ) -> CreateResult<'tcx> { UniversalRegionRelationsBuilder { @@ -62,7 +62,7 @@ pub(crate) fn create<'tcx>( param_env, implicit_region_bound, constraints, - universal_regions: universal_regions.clone(), + universal_regions, region_bound_pairs: Default::default(), outlives: Default::default(), inverse_outlives: Default::default(), diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index d4900d21f8f..b8e35f882ec 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use itertools::{Either, Itertools}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::visit::{TyContext, Visitor}; @@ -33,7 +31,7 @@ mod trace; pub(super) fn generate<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc<DenseLocationMap>, + elements: &DenseLocationMap, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, ) { diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 8cbe3ac6701..a5175e653d8 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_index::bit_set::BitSet; use rustc_index::interval::IntervalSet; @@ -40,7 +38,7 @@ use crate::type_check::{NormalizeLocation, TypeChecker}; pub(super) fn trace<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc<DenseLocationMap>, + elements: &DenseLocationMap, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec<Local>, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6b17879de26..82aeca66693 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -121,13 +121,13 @@ pub(crate) fn type_check<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice<Promoted, Body<'tcx>>, - universal_regions: &Rc<UniversalRegions<'tcx>>, + universal_regions: Rc<UniversalRegions<'tcx>>, location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option<AllFacts>, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, - elements: &Rc<DenseLocationMap>, + elements: Rc<DenseLocationMap>, upvars: &[&ty::CapturedPlace<'tcx>], ) -> MirTypeckResults<'tcx> { let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); @@ -150,14 +150,14 @@ pub(crate) fn type_check<'a, 'tcx>( infcx, param_env, implicit_region_bound, - universal_regions, + universal_regions.clone(), &mut constraints, ); debug!(?normalized_inputs_and_output); let mut borrowck_context = BorrowCheckContext { - universal_regions, + universal_regions: &universal_regions, location_table, borrow_set, all_facts, @@ -181,10 +181,10 @@ pub(crate) fn type_check<'a, 'tcx>( verifier.visit_body(body); checker.typeck_mir(body); - checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output); + checker.equate_inputs_and_outputs(body, &universal_regions, &normalized_inputs_and_output); checker.check_signature_annotation(body); - liveness::generate(&mut checker, body, elements, flow_inits, move_data); + liveness::generate(&mut checker, body, &elements, flow_inits, move_data); translate_outlives_facts(&mut checker); let opaque_type_values = infcx.take_opaque_types(); diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index bf079e813f1..cfc14d146bd 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -11,6 +11,7 @@ use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::fold::FnMutDelegate; +use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -362,7 +363,7 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> { &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), ) if a_def_id == b_def_id || infcx.next_trait_solver() => { - infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| { + super_combine_tys(&infcx.infcx, self, a, b).map(|_| ()).or_else(|err| { // This behavior is only there for the old solver, the new solver // shouldn't ever fail. Instead, it unconditionally emits an // alias-relate goal. @@ -385,7 +386,7 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> { debug!(?a, ?b, ?self.ambient_variance); // Will also handle unification of `IntVar` and `FloatVar`. - self.type_checker.infcx.super_combine_tys(self, a, b)?; + super_combine_tys(&self.type_checker.infcx.infcx, self, a, b)?; } } @@ -422,7 +423,7 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> { assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a); assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); - self.type_checker.infcx.super_combine_consts(self, a, b) + super_combine_consts(&self.type_checker.infcx.infcx, self, a, b) } #[instrument(skip(self), level = "trace")] diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 9695df9c87e..77cb8dc63c4 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -12,9 +12,9 @@ builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}` builtin_macros_asm_expected_comma = expected token: `,` .label = expected `,` -builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> - [true] options - *[false] clobber_abi, options +builtin_macros_asm_expected_other = expected operand, {$is_inline_asm -> + [false] options + *[true] clobber_abi, options }, or additional template string builtin_macros_asm_expected_string_literal = expected string literal @@ -51,6 +51,15 @@ builtin_macros_asm_sym_no_path = expected a path for argument to `sym` builtin_macros_asm_underscore_input = _ cannot be used for input operands +builtin_macros_asm_unsupported_clobber_abi = `clobber_abi` cannot be used with `{$macro_name}!` + +builtin_macros_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `{$macro_name}!` + .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it + +builtin_macros_asm_unsupported_option = the `{$symbol}` option cannot be used with `{$macro_name}!` + .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly + .suggestion = remove this option + builtin_macros_assert_missing_comma = unexpected string literal .suggestion = try adding a comma @@ -194,15 +203,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments builtin_macros_format_use_positional = consider using a positional formatting argument instead -builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` - -builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!` - .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it - -builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!` - .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly - .suggestion = remove this option - builtin_macros_invalid_crate_attribute = invalid crate attribute builtin_macros_multiple_default_attrs = multiple `#[default]` attributes @@ -235,6 +235,8 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive .label = declared `#[non_exhaustive]` here .help = consider a manual implementation of `Default` +builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters + builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants .help = consider a manual implementation of `Default` diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 75dbb3d8e6a..9ae48024f44 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -37,15 +37,23 @@ pub struct AsmArgs { /// - `Ok(true)` if the current token matches the keyword, and was expected /// - `Ok(false)` if the current token does not match the keyword /// - `Err(_)` if the current token matches the keyword, but was not expected -fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> { - if expect { +fn eat_operand_keyword<'a>( + p: &mut Parser<'a>, + symbol: Symbol, + asm_macro: AsmMacro, +) -> PResult<'a, bool> { + if matches!(asm_macro, AsmMacro::Asm) { Ok(p.eat_keyword(symbol)) } else { let span = p.token.span; if p.eat_keyword_noexpect(symbol) { // in gets printed as `r#in` otherwise let symbol = if symbol == kw::In { "in" } else { symbol.as_str() }; - Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol })) + Err(p.dcx().create_err(errors::AsmUnsupportedOperand { + span, + symbol, + macro_name: asm_macro.macro_name(), + })) } else { Ok(false) } @@ -56,10 +64,10 @@ fn parse_args<'a>( ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream, - is_global_asm: bool, + asm_macro: AsmMacro, ) -> PResult<'a, AsmArgs> { let mut p = ecx.new_parser_from_tts(tts); - parse_asm_args(&mut p, sp, is_global_asm) + parse_asm_args(&mut p, sp, asm_macro) } // Primarily public for rustfmt consumption. @@ -67,7 +75,7 @@ fn parse_args<'a>( pub fn parse_asm_args<'a>( p: &mut Parser<'a>, sp: Span, - is_global_asm: bool, + asm_macro: AsmMacro, ) -> PResult<'a, AsmArgs> { let dcx = p.dcx(); @@ -110,7 +118,7 @@ pub fn parse_asm_args<'a>( // Parse options if p.eat_keyword(sym::options) { - parse_options(p, &mut args, is_global_asm)?; + parse_options(p, &mut args, asm_macro)?; allow_templates = false; continue; } @@ -129,7 +137,7 @@ pub fn parse_asm_args<'a>( }; let mut explicit_reg = false; - let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? { + let op = if eat_operand_keyword(p, kw::In, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -137,15 +145,15 @@ pub fn parse_asm_args<'a>( } let expr = p.parse_expr()?; ast::InlineAsmOperand::In { reg, expr } - } else if eat_operand_keyword(p, sym::out, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::out, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: false } - } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::lateout, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: true } - } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::inout, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -159,7 +167,7 @@ pub fn parse_asm_args<'a>( } else { ast::InlineAsmOperand::InOut { reg, expr, late: false } } - } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::inlateout, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -173,7 +181,7 @@ pub fn parse_asm_args<'a>( } else { ast::InlineAsmOperand::InOut { reg, expr, late: true } } - } else if eat_operand_keyword(p, sym::label, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::label, asm_macro)? { let block = p.parse_block()?; ast::InlineAsmOperand::Label { block } } else if p.eat_keyword(kw::Const) { @@ -205,7 +213,7 @@ pub fn parse_asm_args<'a>( _ => { let err = dcx.create_err(errors::AsmExpectedOther { span: template.span, - is_global_asm, + is_inline_asm: matches!(asm_macro, AsmMacro::Asm), }); return Err(err); } @@ -301,20 +309,25 @@ pub fn parse_asm_args<'a>( dcx.emit_err(errors::AsmMayUnwind { labels_sp }); } - if args.clobber_abis.len() > 0 { - if is_global_asm { - let err = dcx.create_err(errors::GlobalAsmClobberAbi { - spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), - }); + if !args.clobber_abis.is_empty() { + match asm_macro { + AsmMacro::GlobalAsm | AsmMacro::NakedAsm => { + let err = dcx.create_err(errors::AsmUnsupportedClobberAbi { + spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + macro_name: asm_macro.macro_name(), + }); - // Bail out now since this is likely to confuse later stages - return Err(err); - } - if !regclass_outputs.is_empty() { - dcx.emit_err(errors::AsmClobberNoReg { - spans: regclass_outputs, - clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(), - }); + // Bail out now since this is likely to confuse later stages + return Err(err); + } + AsmMacro::Asm => { + if !regclass_outputs.is_empty() { + dcx.emit_err(errors::AsmClobberNoReg { + spans: regclass_outputs, + clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + }); + } + } } } @@ -335,10 +348,15 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { /// /// This function must be called immediately after the option token is parsed. /// Otherwise, the suggestion will be incorrect. -fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) { +fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) { // Tool-only output let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span }; - p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span }); + p.dcx().emit_err(errors::AsmUnsupportedOption { + span, + symbol, + full_span, + macro_name: asm_macro.macro_name(), + }); } /// Try to set the provided option in the provided `AsmArgs`. @@ -349,12 +367,12 @@ fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) { fn try_set_option<'a>( p: &Parser<'a>, args: &mut AsmArgs, - is_global_asm: bool, + asm_macro: AsmMacro, symbol: Symbol, option: ast::InlineAsmOptions, ) { - if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { - err_unsupported_option(p, symbol, p.prev_token.span); + if !asm_macro.is_supported_option(option) { + err_unsupported_option(p, asm_macro, symbol, p.prev_token.span); } else if args.options.contains(option) { err_duplicate_option(p, symbol, p.prev_token.span); } else { @@ -365,7 +383,7 @@ fn try_set_option<'a>( fn parse_options<'a>( p: &mut Parser<'a>, args: &mut AsmArgs, - is_global_asm: bool, + asm_macro: AsmMacro, ) -> PResult<'a, ()> { let span_start = p.prev_token.span; @@ -386,15 +404,14 @@ fn parse_options<'a>( 'blk: { for (symbol, option) in OPTIONS { - let kw_matched = - if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { - p.eat_keyword(symbol) - } else { - p.eat_keyword_noexpect(symbol) - }; + let kw_matched = if asm_macro.is_supported_option(option) { + p.eat_keyword(symbol) + } else { + p.eat_keyword_noexpect(symbol) + }; if kw_matched { - try_set_option(p, args, is_global_asm, symbol, option); + try_set_option(p, args, asm_macro, symbol, option); break 'blk; } } @@ -483,7 +500,7 @@ fn parse_reg<'a>( fn expand_preparsed_asm( ecx: &mut ExtCtxt<'_>, - asm_macro: ast::AsmMacro, + asm_macro: AsmMacro, args: AsmArgs, ) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> { let mut template = vec![]; @@ -797,7 +814,7 @@ pub(super) fn expand_asm<'cx>( sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { + ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) { Ok(args) => { let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else { return ExpandResult::Retry(()); @@ -826,29 +843,20 @@ pub(super) fn expand_naked_asm<'cx>( sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { + ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) { Ok(args) => { let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args) else { return ExpandResult::Retry(()); }; let expr = match mac { - Ok(mut inline_asm) => { - // for future compatibility, we always set the NORETURN option. - // - // When we turn `asm!` into `naked_asm!` with this implementation, we can drop - // the `options(noreturn)`, which makes the upgrade smooth when `naked_asm!` - // starts disallowing the `noreturn` option in the future - inline_asm.options |= ast::InlineAsmOptions::NORETURN; - - P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::InlineAsm(P(inline_asm)), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }) - } + Ok(inline_asm) => P(ast::Expr { + id: ast::DUMMY_NODE_ID, + kind: ast::ExprKind::InlineAsm(P(inline_asm)), + span: sp, + attrs: ast::AttrVec::new(), + tokens: None, + }), Err(guar) => DummyResult::raw_expr(sp, Some(guar)), }; MacEager::expr(expr) @@ -865,7 +873,7 @@ pub(super) fn expand_global_asm<'cx>( sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, true) { + ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) { Ok(args) => { let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args) else { diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index cf1d5c68ead..15993dbf5ec 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -6,7 +6,6 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_span::Span; use {rustc_ast as ast, rustc_attr as attr}; @@ -36,14 +35,18 @@ pub(crate) fn expand_cfg( }) } -fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { +fn parse_cfg<'a>( + cx: &ExtCtxt<'a>, + span: Span, + tts: TokenStream, +) -> PResult<'a, ast::MetaItemInner> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); } - let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?; + let cfg = p.parse_meta_item_inner()?; let _ = p.eat(&token::Comma); diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 4be2d209ae7..60450d085f6 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,5 +1,5 @@ use rustc_ast as ast; -use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast::{GenericParamKind, ItemKind, MetaItemInner, MetaItemKind, StmtKind}; use rustc_expand::base::{ Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, }; @@ -49,9 +49,9 @@ impl MultiItemModifier for Expander { let mut resolutions = match &meta_item.kind { MetaItemKind::List(list) => { list.iter() - .filter_map(|nested_meta| match nested_meta { - NestedMetaItem::MetaItem(meta) => Some(meta), - NestedMetaItem::Lit(lit) => { + .filter_map(|meta_item_inner| match meta_item_inner { + MetaItemInner::MetaItem(meta) => Some(meta), + MetaItemInner::Lit(lit) => { // Reject `#[derive("Debug")]`. report_unexpected_meta_item_lit(sess, lit); None diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index dde696fca61..f79227d52a8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -113,7 +113,7 @@ fn cs_clone_simple( // Already produced an assertion for this type. // Anonymous structs or unions must be eliminated as they cannot be // type parameters. - } else if !field.ty.kind.is_anon_adt() { + } else { // let _: AssertParamIsClone<FieldTy>; super::assert_ty_bounds(cx, &mut stmts, field.ty.clone(), field.span, &[ sym::clone, diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index d5ee5e430d5..e884c0ec718 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -124,8 +124,6 @@ fn assert_ty_bounds( span: Span, assert_path: &[Symbol], ) { - // Deny anonymous structs or unions to avoid weird errors. - assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters"); // Generate statement `let _: assert_path<ty>;`. let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]); diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index 78028df2aa0..e3878d90e41 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -13,6 +13,8 @@ use rustc_span::symbol::{Ident, sym}; use rustc_span::{Span, Symbol}; use thin_vec::{ThinVec, thin_vec}; +use crate::errors; + macro_rules! path { ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } } @@ -25,6 +27,8 @@ pub(crate) fn expand_deriving_smart_ptr( push: &mut dyn FnMut(Annotatable), _is_const: bool, ) { + item.visit_with(&mut DetectNonGenericPointeeAttr { cx }); + let (name_ident, generics) = if let Annotatable::Item(aitem) = item && let ItemKind::Struct(struct_data, g) = &aitem.kind { @@ -308,7 +312,7 @@ pub(crate) fn expand_deriving_smart_ptr( impl_generics.params.insert(pointee_param_idx + 1, extra_param); // Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`. - let gen_args = vec![GenericArg::Type(alt_self_type.clone())]; + let gen_args = vec![GenericArg::Type(alt_self_type)]; add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone()); add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args); } @@ -396,3 +400,63 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> { } } } + +struct DetectNonGenericPointeeAttr<'a, 'b> { + cx: &'a ExtCtxt<'b>, +} + +impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonGenericPointeeAttr<'a, 'b> { + fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result { + if attr.has_name(sym::pointee) { + self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span }); + } + } + + fn visit_generic_param(&mut self, param: &'a rustc_ast::GenericParam) -> Self::Result { + let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx }; + + match ¶m.kind { + GenericParamKind::Type { default } => { + // The `default` may end up containing a block expression. + // The problem is block expressions may define structs with generics. + // A user may attach a #[pointee] attribute to one of these generics + // We want to catch that. The simple solution is to just + // always raise a `NonGenericPointee` error when this happens. + // + // This solution does reject valid rust programs but, + // such a code would have to, in order: + // - Define a smart pointer struct. + // - Somewhere in this struct definition use a type with a const generic argument. + // - Calculate this const generic in a expression block. + // - Define a new smart pointer type in this block. + // - Have this smart pointer type have more than 1 generic type. + // In this case, the inner smart pointer derive would be complaining that it + // needs a pointer attribute. Meanwhile, the outer macro would be complaining + // that we attached a #[pointee] to a generic type argument while helpfully + // informing the user that #[pointee] can only be attached to generic pointer arguments + rustc_ast::visit::visit_opt!(error_on_pointee, visit_ty, default); + } + + GenericParamKind::Const { .. } | GenericParamKind::Lifetime => { + rustc_ast::visit::walk_generic_param(&mut error_on_pointee, param); + } + } + } + + fn visit_ty(&mut self, t: &'a rustc_ast::Ty) -> Self::Result { + let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx }; + error_on_pointee.visit_ty(t) + } +} + +struct AlwaysErrorOnGenericParam<'a, 'b> { + cx: &'a ExtCtxt<'b>, +} + +impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> { + fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result { + if attr.has_name(sym::pointee) { + self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span }); + } + } +} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 4fffffb91c8..639c2aa231c 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -751,7 +751,7 @@ pub(crate) struct AsmExpectedOther { #[primary_span] #[label(builtin_macros_asm_expected_other)] pub(crate) span: Span, - pub(crate) is_global_asm: bool, + pub(crate) is_inline_asm: bool, } #[derive(Diagnostic)] @@ -799,13 +799,6 @@ pub(crate) struct AsmMayUnwind { pub(crate) labels_sp: Vec<Span>, } -#[derive(Diagnostic)] -#[diag(builtin_macros_global_asm_clobber_abi)] -pub(crate) struct GlobalAsmClobberAbi { - #[primary_span] - pub(crate) spans: Vec<Span>, -} - pub(crate) struct AsmClobberNoReg { pub(crate) spans: Vec<Span>, pub(crate) clobbers: Vec<Span>, @@ -841,23 +834,33 @@ pub(crate) struct AsmOptAlreadyprovided { } #[derive(Diagnostic)] -#[diag(builtin_macros_global_asm_unsupported_option)] -pub(crate) struct GlobalAsmUnsupportedOption { +#[diag(builtin_macros_asm_unsupported_option)] +pub(crate) struct AsmUnsupportedOption { #[primary_span] #[label] pub(crate) span: Span, pub(crate) symbol: Symbol, #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub(crate) full_span: Span, + pub(crate) macro_name: &'static str, } #[derive(Diagnostic)] -#[diag(builtin_macros_global_asm_unsupported_operand)] -pub(crate) struct GlobalAsmUnsupportedOperand<'a> { +#[diag(builtin_macros_asm_unsupported_operand)] +pub(crate) struct AsmUnsupportedOperand<'a> { #[primary_span] #[label] pub(crate) span: Span, pub(crate) symbol: &'a str, + pub(crate) macro_name: &'static str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_unsupported_clobber_abi)] +pub(crate) struct AsmUnsupportedClobberAbi { + #[primary_span] + pub(crate) spans: Vec<Span>, + pub(crate) macro_name: &'static str, } #[derive(Diagnostic)] @@ -937,3 +940,10 @@ pub(crate) struct NakedFunctionTestingAttribute { #[label] pub testing_span: Span, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_non_generic_pointee)] +pub(crate) struct NonGenericPointee { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 5e535ff62e1..9fc0318df5d 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -726,6 +726,12 @@ pub macro global_asm() { /* compiler built-in */ } +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro naked_asm() { + /* compiler built-in */ +} + pub static A_STATIC: u8 = 42; #[lang = "panic_location"] 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 ccbd5a78485..e47431e0f87 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -390,7 +390,7 @@ global_asm! { #[naked] extern "C" fn naked_test() { unsafe { - asm!("ret", options(noreturn)); + naked_asm!("ret"); } } diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index ebaa9c69c81..3078288c286 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -168,7 +168,7 @@ fn main() { foo(I64X2([0, 0])); - transmute_fat_pointer(); + transmute_wide_pointer(); rust_call_abi(); @@ -192,7 +192,7 @@ type TwoPtrs = i64; #[cfg(target_pointer_width = "64")] type TwoPtrs = i128; -fn transmute_fat_pointer() -> TwoPtrs { +fn transmute_wide_pointer() -> TwoPtrs { unsafe { transmute::<_, TwoPtrs>("true !") } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 1ce0aacab49..a681e6d9f3c 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -8,6 +8,7 @@ use rustc_ast::InlineAsmOptions; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::InlineAsmMacro; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; @@ -57,6 +58,7 @@ pub(crate) fn codegen_fn<'tcx>( match &mir.basic_blocks[START_BLOCK].terminator().kind { TerminatorKind::InlineAsm { + asm_macro: InlineAsmMacro::NakedAsm, template, operands, options, @@ -498,6 +500,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { "tail calls are not yet supported in `rustc_codegen_cranelift` backend" ), TerminatorKind::InlineAsm { + asm_macro: _, template, operands, options, @@ -713,17 +716,17 @@ fn codegen_stmt<'tcx>( let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); - fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { + fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { ty.builtin_deref(true) .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty)) } - if is_fat_ptr(fx, from_ty) { - if is_fat_ptr(fx, to_ty) { - // fat-ptr -> fat-ptr + if is_wide_ptr(fx, from_ty) { + if is_wide_ptr(fx, to_ty) { + // wide-ptr -> wide-ptr lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout)); } else { - // fat-ptr -> thin-ptr + // wide-ptr -> thin-ptr let (ptr, _extra) = operand.load_scalar_pair(fx); lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout)) } diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index e78ba5a3415..69a32cc3d43 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -101,7 +101,7 @@ fn clif_pair_type_from_ty<'tcx>( }) } -/// Is a pointer to this type a fat ptr? +/// Is a pointer to this type a wide ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { if ty.is_sized(tcx, ParamEnv::reveal_all()) { return false; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs index a710701e72c..714742aeaff 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs @@ -139,7 +139,7 @@ impl DebugContext { pointer_type_id } else { - // FIXME implement debuginfo for fat pointers + // FIXME implement debuginfo for wide pointers self.placeholder_for_type(tcx, type_dbg, ptr_type) } } diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index e7ac084558a..d462dcd63a9 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -3,7 +3,8 @@ //! Adapted from <https://github.com/rust-lang/rust/blob/31c0645b9d2539f47eecb096142474b29dc542f7/compiler/rustc_codegen_ssa/src/mir/place.rs> //! (<https://github.com/rust-lang/rust/pull/104535>) -use rustc_target::abi::{Int, TagEncoding, Variants}; +use rustc_abi::Primitive::Int; +use rustc_abi::{TagEncoding, Variants}; use crate::prelude::*; diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 19e5adc2538..35f0ccff3f9 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -328,6 +328,9 @@ fn codegen_float_intrinsic_call<'tcx>( sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64), sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64), + // FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation + 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::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32), sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64), sym::floorf32 => ("floorf", 1, fx.tcx.types.f32, types::F32), @@ -381,7 +384,7 @@ fn codegen_float_intrinsic_call<'tcx>( let layout = fx.layout_of(ty); let res = match intrinsic { - sym::fmaf32 | sym::fmaf64 => { + sym::fmaf32 | sym::fmaf64 | sym::fmuladdf32 | sym::fmuladdf64 => { CValue::by_val(fx.bcx.ins().fma(args[0], args[1], args[2]), layout) } sym::copysignf32 | sym::copysignf64 => { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index f6b7981395a..b6f9ce8fc29 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -15,6 +15,7 @@ extern crate jobserver; #[macro_use] extern crate rustc_middle; +extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index 0235384445e..bbae59ea7a5 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -8,9 +8,6 @@ codegen_gcc_invalid_minimum_alignment = codegen_gcc_lto_not_supported = LTO is not supported. You may get a linker error. -codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together - .help = add the missing features in a `target_feature` attribute - codegen_gcc_unwinding_inline_asm = GCC backend does not support unwinding from inline asm diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index 5fdf2680aac..d20e13e15b9 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -7,11 +7,9 @@ use rustc_attr::InstructionSetAttr; #[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty; -use rustc_span::symbol::sym; use crate::context::CodegenCx; -use crate::errors::TiedTargetFeatures; -use crate::gcc_util::{check_tied_features, to_gcc_features}; +use crate::gcc_util::to_gcc_features; /// Get GCC attribute for the provided inline heuristic. #[cfg(feature = "master")] @@ -72,26 +70,10 @@ pub fn from_fn_attrs<'gcc, 'tcx>( } } - let function_features = codegen_fn_attrs + let mut function_features = codegen_fn_attrs .target_features .iter() .map(|features| features.name.as_str()) - .collect::<Vec<&str>>(); - - if let Some(features) = check_tied_features( - cx.tcx.sess, - &function_features.iter().map(|features| (*features, true)).collect(), - ) { - let span = cx - .tcx - .get_attr(instance.def_id(), sym::target_feature) - .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); - cx.tcx.dcx().create_err(TiedTargetFeatures { features: features.join(", "), span }).emit(); - return; - } - - let mut function_features = function_features - .iter() .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. diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index acd53588831..b611f9ba8bc 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -7,6 +7,8 @@ use gccjit::{ BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type, UnaryOp, }; +use rustc_abi as abi; +use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout, WrappingRange}; use rustc_apfloat::{Float, Round, Status, ieee}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{ @@ -28,7 +30,6 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::def_id::DefId; use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange}; use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi}; use crate::common::{SignType, TypeReflection, type_is_pointer}; @@ -998,12 +999,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { ) { let vr = scalar.valid_range(bx); match scalar.primitive() { - abi::Int(..) => { + abi::Primitive::Int(..) => { if !scalar.is_always_valid(bx) { bx.range_metadata(load, vr); } } - abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => { + abi::Primitive::Pointer(_) if vr.start < vr.end && !vr.contains(0) => { bx.nonnull_metadata(load); } _ => {} diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 726b126e727..0d3e7083d56 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,11 +1,13 @@ use gccjit::{LValue, RValue, ToRValue, Type}; +use rustc_abi as abi; +use rustc_abi::HasDataLayout; +use rustc_abi::Primitive::Pointer; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, }; use rustc_middle::mir::Mutability; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::LayoutOf; -use rustc_target::abi::{self, HasDataLayout, Pointer}; use crate::consts::const_alloc_to_gcc; use crate::context::CodegenCx; diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 6bada3d334c..dc1895f437b 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -1,9 +1,6 @@ -use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; -use crate::fluent_generated as fluent; - #[derive(Diagnostic)] #[diag(codegen_gcc_unknown_ctarget_feature_prefix)] #[note] @@ -46,15 +43,6 @@ pub(crate) struct InvalidMinimumAlignment { } #[derive(Diagnostic)] -#[diag(codegen_gcc_tied_target_features)] -#[help] -pub(crate) struct TiedTargetFeatures { - #[primary_span] - pub span: Span, - pub features: String, -} - -#[derive(Diagnostic)] #[diag(codegen_gcc_copy_bitcode)] pub(crate) struct CopyBitcode { pub err: std::io::Error, @@ -78,27 +66,3 @@ pub(crate) struct LtoDylib; pub(crate) struct LtoBitcodeFromRlib { pub gcc_err: String, } - -pub(crate) struct TargetFeatureDisableOrEnable<'a> { - pub features: &'a [&'a str], - pub span: Option<Span>, - pub missing_features: Option<MissingFeatures>, -} - -#[derive(Subdiagnostic)] -#[help(codegen_gcc_missing_features)] -pub(crate) struct MissingFeatures; - -impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { - let mut diag = Diag::new(dcx, level, fluent::codegen_gcc_target_feature_disable_or_enable); - if let Some(span) = self.span { - diag.span(span); - }; - if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(missing_features); - } - diag.arg("features", self.features.join(", ")); - diag - } -} diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 01dd1a8856a..3104088e0d5 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -1,15 +1,14 @@ #[cfg(feature = "master")] use gccjit::Context; +use rustc_codegen_ssa::codegen_attrs::check_tied_features; +use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable; use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; use rustc_session::Session; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; -use crate::errors::{ - PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, - UnknownCTargetFeaturePrefix, -}; +use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). @@ -185,23 +184,6 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> } } -// Given a map from target_features to whether they are enabled or disabled, -// ensure only valid combinations are allowed. -pub fn check_tied_features( - sess: &Session, - features: &FxHashMap<&str, bool>, -) -> Option<&'static [&'static str]> { - for tied in sess.target.tied_target_features() { - // Tied features must be set to the same value, or not set at all - let mut tied_iter = tied.iter(); - let enabled = features.get(tied_iter.next().unwrap()); - if tied_iter.any(|feature| enabled != features.get(feature)) { - return Some(tied); - } - } - None -} - fn arch_to_gcc(name: &str) -> &str { match name { "M68020" => "68020", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 945eedf5556..972d6632140 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -66,6 +66,9 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::log2f64 => "log2", sym::fmaf32 => "fmaf", sym::fmaf64 => "fma", + // FIXME: calling `fma` from libc without FMA target feature uses expensive sofware 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", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index eeab2a5f155..4e1b99fdebf 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -478,7 +478,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, name, ty: in_elem @@ -493,7 +493,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, name, ty: out_elem diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a7a32e285d8..7486eefeb85 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -32,6 +32,7 @@ extern crate tempfile; extern crate tracing; // The rustc crates we need +extern crate rustc_abi; extern crate rustc_apfloat; extern crate rustc_ast; extern crate rustc_attr; diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index cb45bbde2c2..183e9ddf8bf 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -1,6 +1,9 @@ use std::fmt::Write; use gccjit::{Struct, Type}; +use rustc_abi as abi; +use rustc_abi::Primitive::*; +use rustc_abi::{Abi, FieldsShape, Integer, PointeeInfo, Size, Variants}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, DerivedTypeCodegenMethods, LayoutTypeCodegenMethods, }; @@ -8,11 +11,8 @@ use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt}; +use rustc_target::abi::TyAbiInterface; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; -use rustc_target::abi::{ - self, Abi, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface, - Variants, -}; use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType}; use crate::context::CodegenCx; @@ -207,7 +207,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // layout. if let Abi::Scalar(ref scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs - // can be either fat or thin (data pointers of fat pointers). + // can be either wide or thin (data pointers of wide pointers). if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { return ty; } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index a93baf88413..03a871297c4 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -14,6 +14,7 @@ libc = "0.2" measureme = "11" object = { version = "0.36.3", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index df2198df14b..0950e4bb26b 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -33,9 +33,6 @@ codegen_llvm_lto_proc_macro = lto cannot be used for `proc-macro` crate type wit codegen_llvm_mismatch_data_layout = data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}` -codegen_llvm_missing_features = - add the missing features in a `target_feature` attribute - codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err} @@ -63,9 +60,6 @@ codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name} codegen_llvm_symbol_already_defined = symbol `{$symbol_name}` is already defined -codegen_llvm_target_feature_disable_or_enable = - the target features {$features} must all be either enabled or disabled together - codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple} codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err} diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 3d75393bf06..2fe5ed32daa 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -1,17 +1,19 @@ use std::cmp; use libc::c_uint; +use rustc_abi as abi; +use rustc_abi::Primitive::Int; +use rustc_abi::{HasDataLayout, Size}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; -pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; +pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA}; use rustc_middle::{bug, ty}; use rustc_session::config; pub(crate) use rustc_target::abi::call::*; -use rustc_target::abi::{self, HasDataLayout, Int, Size}; use rustc_target::spec::SanitizerSet; pub(crate) use rustc_target::spec::abi::Abi; use smallvec::SmallVec; diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 82ca3f519f7..298cac2fd6e 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -154,7 +154,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // We prefer the latter because it matches the behavior of // Clang. if late && matches!(reg, InlineAsmRegOrRegClass::Reg(_)) { - constraints.push(reg_to_llvm(reg, Some(&in_value.layout)).to_string()); + constraints.push(reg_to_llvm(reg, Some(&in_value.layout))); } else { constraints.push(format!("{}", op_idx[&idx])); } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 489259da856..2c5ec9dad59 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -6,12 +6,11 @@ use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet}; -use rustc_span::symbol::sym; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use smallvec::SmallVec; use crate::context::CodegenCx; -use crate::errors::{MissingFeatures, SanitizerMemtagRequiresMte, TargetFeatureDisableOrEnable}; +use crate::errors::SanitizerMemtagRequiresMte; use crate::llvm::AttributePlace::Function; use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects}; use crate::value::Value; @@ -502,26 +501,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let function_features = codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>(); - if let Some(f) = llvm_util::check_tied_features( - cx.tcx.sess, - &function_features.iter().map(|f| (*f, true)).collect(), - ) { - let span = cx - .tcx - .get_attrs(instance.def_id(), sym::target_feature) - .next() - .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); - cx.tcx - .dcx() - .create_err(TargetFeatureDisableOrEnable { - features: f, - span: Some(span), - missing_features: Some(MissingFeatures), - }) - .emit(); - return; - } - let function_features = function_features .iter() // Convert to LLVMFeatures and filter out unavailable ones diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4e0c62c8bf8..dbf5298d64b 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -3,6 +3,8 @@ use std::ops::Deref; use std::{iter, ptr}; use libc::{c_char, c_uint}; +use rustc_abi as abi; +use rustc_abi::{Align, Size, WrappingRange}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; @@ -20,7 +22,6 @@ use rustc_sanitizers::{cfi, kcfi}; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{self, Align, Size, WrappingRange}; use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -505,12 +506,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } match scalar.primitive() { - abi::Int(..) => { + abi::Primitive::Int(..) => { if !scalar.is_always_valid(bx) { bx.range_metadata(load, scalar.valid_range(bx)); } } - abi::Pointer(_) => { + abi::Primitive::Pointer(_) => { if !scalar.valid_range(bx).contains(0) { bx.nonnull_metadata(load); } @@ -521,7 +522,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } } - abi::Float(_) => {} + abi::Primitive::Float(_) => {} } } @@ -1679,16 +1680,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { &mut self, fn_name: &'ll Value, hash: &'ll Value, - bitmap_bytes: &'ll Value, + bitmap_bits: &'ll Value, ) { - debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes); + debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bits); + + assert!( + crate::llvm_util::get_version() >= (19, 0, 0), + "MCDC intrinsics require LLVM 19 or later" + ); let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) }; let llty = self.cx.type_func( &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()], self.cx.type_void(), ); - let args = &[fn_name, hash, bitmap_bytes]; + let args = &[fn_name, hash, bitmap_bits]; let args = self.check_call("call", llty, llfn, args); unsafe { @@ -1708,28 +1714,25 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { &mut self, fn_name: &'ll Value, hash: &'ll Value, - bitmap_bytes: &'ll Value, bitmap_index: &'ll Value, mcdc_temp: &'ll Value, ) { debug!( - "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})", - fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp + "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?})", + fn_name, hash, bitmap_index, mcdc_temp + ); + assert!( + crate::llvm_util::get_version() >= (19, 0, 0), + "MCDC intrinsics require LLVM 19 or later" ); let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) }; let llty = self.cx.type_func( - &[ - self.cx.type_ptr(), - self.cx.type_i64(), - self.cx.type_i32(), - self.cx.type_i32(), - self.cx.type_ptr(), - ], + &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_ptr()], self.cx.type_void(), ); - let args = &[fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp]; + let args = &[fn_name, hash, bitmap_index, mcdc_temp]; let args = self.check_call("call", llty, llfn, args); unsafe { let _ = llvm::LLVMRustBuildCall( @@ -1745,41 +1748,15 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi); } - pub(crate) fn mcdc_condbitmap_update( - &mut self, - fn_name: &'ll Value, - hash: &'ll Value, - cond_loc: &'ll Value, - mcdc_temp: &'ll Value, - bool_value: &'ll Value, - ) { - debug!( - "mcdc_condbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})", - fn_name, hash, cond_loc, mcdc_temp, bool_value - ); - let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(self.cx().llmod) }; - let llty = self.cx.type_func( - &[ - self.cx.type_ptr(), - self.cx.type_i64(), - self.cx.type_i32(), - self.cx.type_ptr(), - self.cx.type_i1(), - ], - self.cx.type_void(), + pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) { + debug!("mcdc_condbitmap_update() with args ({:?}, {:?})", cond_index, mcdc_temp); + assert!( + crate::llvm_util::get_version() >= (19, 0, 0), + "MCDC intrinsics require LLVM 19 or later" ); - let args = &[fn_name, hash, cond_loc, mcdc_temp, bool_value]; - self.check_call("call", llty, llfn, args); - unsafe { - let _ = llvm::LLVMRustBuildCall( - self.llbuilder, - llty, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - ); - } + let align = self.tcx.data_layout.i32_align.abi; + let current_tv_index = self.load(self.cx.type_i32(), mcdc_temp, align); + let new_tv_index = self.add(current_tv_index, cond_index); + self.store(new_tv_index, mcdc_temp, align); } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 31d59905446..0ced37b53a8 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,7 +1,11 @@ //! Code that is useful in various codegen modules. use libc::{c_char, c_uint}; +use rustc_abi as abi; +use rustc_abi::Primitive::Pointer; +use rustc_abi::{AddressSpace, HasDataLayout}; use rustc_ast::Mutability; +use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::DefId; @@ -9,7 +13,6 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::DllImport; -use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer}; use tracing::debug; use crate::consts::const_alloc_to_llvm; @@ -144,6 +147,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value { + debug_assert!( + self.type_kind(t) == TypeKind::Integer, + "only allows integer types in const_int" + ); unsafe { llvm::LLVMConstInt(t, i as u64, True) } } @@ -174,10 +181,18 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn const_uint(&self, t: &'ll Type, i: u64) -> &'ll Value { + debug_assert!( + self.type_kind(t) == TypeKind::Integer, + "only allows integer types in const_uint" + ); unsafe { llvm::LLVMConstInt(t, i, False) } } fn const_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value { + debug_assert!( + self.type_kind(t) == TypeKind::Integer, + "only allows integer types in const_uint_big" + ); unsafe { let words = [u as u64, (u >> 64) as u64]; llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr()) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 2b8912d1db2..c836dd5473f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::Session; use rustc_session::config::{ - BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, PAuthKey, PacRet, + BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span}; @@ -378,6 +378,18 @@ pub(crate) unsafe fn create_module<'ll>( } } + match sess.opts.unstable_opts.function_return { + FunctionReturn::Keep => {} + FunctionReturn::ThunkExtern => unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + c"function_return_thunk_extern".as_ptr(), + 1, + ) + }, + } + match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support()) { // Set up the small-data optimization limit for architectures that use @@ -872,6 +884,11 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); ifn!("llvm.fma.f128", fn(t_f128, t_f128, t_f128) -> t_f128); + ifn!("llvm.fmuladd.f16", fn(t_f16, t_f16, t_f16) -> t_f16); + ifn!("llvm.fmuladd.f32", fn(t_f32, t_f32, t_f32) -> t_f32); + ifn!("llvm.fmuladd.f64", fn(t_f64, t_f64, t_f64) -> t_f64); + ifn!("llvm.fmuladd.f128", fn(t_f128, t_f128, t_f128) -> t_f128); + ifn!("llvm.fabs.f16", fn(t_f16) -> t_f16); ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); @@ -1175,10 +1192,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { span: Span, fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { - if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { - self.tcx.dcx().emit_fatal(Spanned { span, node: err }) - } else { - match fn_abi_request { + match err { + FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::Cycle(_)) => { + self.tcx.dcx().emit_fatal(Spanned { span, node: err }); + } + _ => match fn_abi_request { FnAbiRequest::OfFnPtr { sig, extra_args } => { span_bug!(span, "`fn_abi_of_fn_ptr({sig}, {extra_args:?})` failed: {err:?}",); } @@ -1188,7 +1206,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { "`fn_abi_of_instance({instance}, {extra_args:?})` failed: {err:?}", ); } - } + }, } } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index 77821ca89bc..90f7dd733ca 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -111,7 +111,7 @@ enum RegionKind { } mod mcdc { - use rustc_middle::mir::coverage::{ConditionInfo, DecisionInfo}; + use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo}; /// Must match the layout of `LLVMRustMCDCDecisionParameters`. #[repr(C)] @@ -167,12 +167,13 @@ mod mcdc { impl From<ConditionInfo> for BranchParameters { fn from(value: ConditionInfo) -> Self { + let to_llvm_cond_id = |cond_id: Option<ConditionId>| { + cond_id.and_then(|id| LLVMConditionId::try_from(id.as_usize()).ok()).unwrap_or(-1) + }; + let ConditionInfo { condition_id, true_next_id, false_next_id } = value; Self { - condition_id: value.condition_id.as_u32() as LLVMConditionId, - condition_ids: [ - value.false_next_id.as_u32() as LLVMConditionId, - value.true_next_id.as_u32() as LLVMConditionId, - ], + condition_id: to_llvm_cond_id(Some(condition_id)), + condition_ids: [to_llvm_cond_id(false_next_id), to_llvm_cond_id(true_next_id)], } } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 267a2244916..c2c261da79b 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -14,29 +14,20 @@ use crate::coverageinfo::ffi::CounterMappingRegion; use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector}; use crate::{coverageinfo, llvm}; -/// Generates and exports the Coverage Map. +/// Generates and exports the coverage map, which is embedded in special +/// linker sections in the final binary. /// -/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions -/// 6 and 7 (encoded as 5 and 6 respectively), as described at -/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/18.0-2024-02-13/llvm/docs/CoverageMappingFormat.rst). -/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`) -/// distributed in the `llvm-tools-preview` rustup component. -/// -/// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with -/// the same version. Clang's implementation of Coverage Map generation was referenced when -/// implementing this Rust version, and though the format documentation is very explicit and -/// detailed, some undocumented details in Clang's implementation (that may or may not be important) -/// were also replicated for Rust's Coverage Map. +/// Those sections are then read and understood by LLVM's `llvm-cov` tool, +/// which is distributed in the `llvm-tools` rustup component. pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { let tcx = cx.tcx; // Ensure that LLVM is using a version of the coverage mapping format that // agrees with our Rust-side code. Expected versions (encoded as n-1) are: - // - `CovMapVersion::Version6` (5) used by LLVM 13-17 - // - `CovMapVersion::Version7` (6) used by LLVM 18 + // - `CovMapVersion::Version7` (6) used by LLVM 18-19 let covmap_version = { let llvm_covmap_version = coverageinfo::mapping_version(); - let expected_versions = 5..=6; + let expected_versions = 6..=6; assert!( expected_versions.contains(&llvm_covmap_version), "Coverage mapping version exposed by `llvm-wrapper` is out of sync; \ diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 3a80d216f47..d7d29eebf85 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -98,14 +98,14 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { }; // If there are no MC/DC bitmaps to set up, return immediately. - if function_coverage_info.mcdc_bitmap_bytes == 0 { + if function_coverage_info.mcdc_bitmap_bits == 0 { return; } let fn_name = self.get_pgo_func_name_var(instance); let hash = self.const_u64(function_coverage_info.function_source_hash); - let bitmap_bytes = self.const_u32(function_coverage_info.mcdc_bitmap_bytes); - self.mcdc_parameters(fn_name, hash, bitmap_bytes); + let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32); + self.mcdc_parameters(fn_name, hash, bitmap_bits); // Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps. let mut cond_bitmaps = vec![]; @@ -185,35 +185,28 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { CoverageKind::ExpressionUsed { id } => { func_coverage.mark_expression_id_seen(id); } - CoverageKind::CondBitmapUpdate { id, value, decision_depth } => { + CoverageKind::CondBitmapUpdate { index, decision_depth } => { drop(coverage_map); - assert_ne!( - id.as_u32(), - 0, - "ConditionId of evaluated conditions should never be zero" - ); let cond_bitmap = coverage_context .try_get_mcdc_condition_bitmap(&instance, decision_depth) .expect("mcdc cond bitmap should have been allocated for updating"); - let cond_loc = bx.const_i32(id.as_u32() as i32 - 1); - let bool_value = bx.const_bool(value); - let fn_name = bx.get_pgo_func_name_var(instance); - let hash = bx.const_u64(function_coverage_info.function_source_hash); - bx.mcdc_condbitmap_update(fn_name, hash, cond_loc, cond_bitmap, bool_value); + let cond_index = bx.const_i32(index as i32); + bx.mcdc_condbitmap_update(cond_index, cond_bitmap); } CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { drop(coverage_map); let cond_bitmap = coverage_context .try_get_mcdc_condition_bitmap(&instance, decision_depth) .expect("mcdc cond bitmap should have been allocated for merging into the global bitmap"); - let bitmap_bytes = function_coverage_info.mcdc_bitmap_bytes; - assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range"); + assert!( + bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits, + "bitmap index of the decision out of range" + ); let fn_name = bx.get_pgo_func_name_var(instance); let hash = bx.const_u64(function_coverage_info.function_source_hash); - let bitmap_bytes = bx.const_u32(bitmap_bytes); let bitmap_index = bx.const_u32(bitmap_idx); - bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_bytes, bitmap_index, cond_bitmap); + bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap); } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index b7a6f80956d..15d441a986d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -34,7 +34,7 @@ use super::utils::{ }; use crate::common::CodegenCx; use crate::debuginfo::metadata::type_map::build_type_with_children; -use crate::debuginfo::utils::{FatPtrKind, fat_pointer_kind}; +use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind}; use crate::llvm::debuginfo::{ DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind, DebugNameTableKind, @@ -161,7 +161,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( unique_type_id: UniqueTypeId<'tcx>, ) -> DINodeCreationResult<'ll> { // The debuginfo generated by this function is only valid if `ptr_type` is really just - // a (fat) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`. + // a (wide) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`. assert_eq!( cx.size_and_align_of(ptr_type), cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type)) @@ -174,7 +174,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( let data_layout = &cx.tcx.data_layout; let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true); - match fat_pointer_kind(cx, pointee_type) { + match wide_pointer_kind(cx, pointee_type) { None => { // This is a thin pointer. Create a regular pointer type and give it the correct name. assert_eq!( @@ -197,7 +197,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( DINodeCreationResult { di_node, already_stored_in_typemap: false } } - Some(fat_pointer_kind) => { + Some(wide_pointer_kind) => { type_map::build_type_with_children( cx, type_map::stub( @@ -210,7 +210,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( DIFlags::FlagZero, ), |cx, owner| { - // FIXME: If this fat pointer is a `Box` then we don't want to use its + // FIXME: If this wide pointer is a `Box` then we don't want to use its // type layout and instead use the layout of the raw pointer inside // of it. // The proper way to handle this is to not treat Box as a pointer @@ -227,16 +227,16 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( }; let layout = cx.layout_of(layout_type); - let addr_field = layout.field(cx, abi::FAT_PTR_ADDR); - let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA); + let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR); + let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA); - let (addr_field_name, extra_field_name) = match fat_pointer_kind { - FatPtrKind::Dyn => ("pointer", "vtable"), - FatPtrKind::Slice => ("data_ptr", "length"), + let (addr_field_name, extra_field_name) = match wide_pointer_kind { + WidePtrKind::Dyn => ("pointer", "vtable"), + WidePtrKind::Slice => ("data_ptr", "length"), }; - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); + assert_eq!(abi::WIDE_PTR_ADDR, 0); + assert_eq!(abi::WIDE_PTR_EXTRA, 1); // The data pointer type is a regular, thin pointer, regardless of whether this // is a slice or a trait object. @@ -258,7 +258,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( owner, addr_field_name, (addr_field.size, addr_field.align.abi), - layout.fields.offset(abi::FAT_PTR_ADDR), + layout.fields.offset(abi::WIDE_PTR_ADDR), DIFlags::FlagZero, data_ptr_type_di_node, ), @@ -267,7 +267,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( owner, extra_field_name, (extra_field.size, extra_field.align.abi), - layout.fields.offset(abi::FAT_PTR_EXTRA), + layout.fields.offset(abi::WIDE_PTR_EXTRA), DIFlags::FlagZero, type_di_node(cx, extra_field.ty), ), @@ -391,7 +391,7 @@ fn build_dyn_type_di_node<'ll, 'tcx>( /// /// NOTE: We currently emit just emit the debuginfo for the element type here /// (i.e. `T` for slices and `u8` for `str`), so that we end up with -/// `*const T` for the `data_ptr` field of the corresponding fat-pointer +/// `*const T` for the `data_ptr` field of the corresponding wide-pointer /// debuginfo of `&[T]`. /// /// It would be preferable and more accurate if we emitted a DIArray of T diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index acb15449ce3..960487ada16 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -49,23 +49,23 @@ pub(crate) fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId } #[derive(Debug, PartialEq, Eq)] -pub(crate) enum FatPtrKind { +pub(crate) enum WidePtrKind { Slice, Dyn, } /// Determines if `pointee_ty` is slice-like or trait-object-like, i.e. -/// if the second field of the fat pointer is a length or a vtable-pointer. -/// If `pointee_ty` does not require a fat pointer (because it is Sized) then +/// if the second field of the wide pointer is a length or a vtable-pointer. +/// If `pointee_ty` does not require a wide pointer (because it is Sized) then /// the function returns `None`. -pub(crate) fn fat_pointer_kind<'ll, 'tcx>( +pub(crate) fn wide_pointer_kind<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, pointee_ty: Ty<'tcx>, -) -> Option<FatPtrKind> { +) -> Option<WidePtrKind> { let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env()); let layout = cx.layout_of(pointee_tail_ty); trace!( - "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})", + "wide_pointer_kind: {:?} has layout {:?} (is_unsized? {})", pointee_tail_ty, layout, layout.is_unsized() @@ -76,8 +76,8 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( } match *pointee_tail_ty.kind() { - ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice), - ty::Dynamic(..) => Some(FatPtrKind::Dyn), + ty::Str | ty::Slice(_) => Some(WidePtrKind::Slice), + ty::Dynamic(..) => Some(WidePtrKind::Dyn), ty::Foreign(_) => { // Assert that pointers to foreign types really are thin: assert_eq!( @@ -90,7 +90,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( // For all other pointee types we should already have returned None // at the beginning of the function. panic!( - "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}" + "wide_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}" ) } } diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 7be44dd51b5..33258cb46fa 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -84,10 +84,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { unnamed: llvm::UnnamedAddr, fn_type: &'ll Type, ) -> &'ll Value { - // Declare C ABI functions with the visibility used by C by default. - let visibility = Visibility::from_generic(self.tcx.sess.default_visibility()); - - declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type) + // Visibility should always be default for declarations, otherwise the linker may report an + // error. + declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type) } /// Declare an entry Function diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index bb481d2a308..0d436e1891e 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -80,30 +80,6 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { } } -pub(crate) struct TargetFeatureDisableOrEnable<'a> { - pub features: &'a [&'a str], - pub span: Option<Span>, - pub missing_features: Option<MissingFeatures>, -} - -#[derive(Subdiagnostic)] -#[help(codegen_llvm_missing_features)] -pub(crate) struct MissingFeatures; - -impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { - let mut diag = Diag::new(dcx, level, fluent::codegen_llvm_target_feature_disable_or_enable); - if let Some(span) = self.span { - diag.span(span); - }; - if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(missing_features); - } - diag.arg("features", self.features.join(", ")); - diag - } -} - #[derive(Diagnostic)] #[diag(codegen_llvm_lto_disallowed)] pub(crate) struct LtoDisallowed; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c66c80da9fc..bfe623e7fc3 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -86,6 +86,11 @@ fn get_simple_intrinsic<'ll>( sym::fmaf64 => "llvm.fma.f64", sym::fmaf128 => "llvm.fma.f128", + sym::fmuladdf16 => "llvm.fmuladd.f16", + sym::fmuladdf32 => "llvm.fmuladd.f32", + sym::fmuladdf64 => "llvm.fmuladd.f64", + sym::fmuladdf128 => "llvm.fmuladd.f128", + sym::fabsf16 => "llvm.fabs.f16", sym::fabsf32 => "llvm.fabs.f32", sym::fabsf64 => "llvm.fabs.f64", @@ -2185,7 +2190,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, name, ty: in_elem @@ -2200,7 +2205,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, name, ty: out_elem diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d3950df91fb..661debbb9f1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1614,7 +1614,6 @@ unsafe extern "C" { pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value; pub fn LLVMRustGetInstrProfMCDCParametersIntrinsic(M: &Module) -> &Value; pub fn LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(M: &Module) -> &Value; pub fn LLVMRustBuildCall<'a>( B: &Builder<'a>, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index bd847cd0068..57936215ff1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,6 +6,7 @@ use std::{ptr, slice, str}; use libc::c_int; use rustc_codegen_ssa::base::wants_wasm_eh; +use rustc_codegen_ssa::codegen_attrs::check_tied_features; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::unord::UnordSet; @@ -19,8 +20,8 @@ use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATU use crate::back::write::create_informational_target_machine; use crate::errors::{ - FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable, - UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature, + FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, UnknownCTargetFeature, + UnknownCTargetFeaturePrefix, UnstableCTargetFeature, }; use crate::llvm; @@ -247,7 +248,9 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea ("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")), ("aarch64", "paca") => Some(LLVMFeature::new("pauth")), ("aarch64", "pacg") => Some(LLVMFeature::new("pauth")), - ("aarch64", "sve-b16b16") => Some(LLVMFeature::new("b16b16")), + // Before LLVM 20 those two features were packaged together as b16b16 + ("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")), + ("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")), ("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")), // Rust ties fp and neon together. ("aarch64", "neon") => { @@ -276,25 +279,6 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea } } -/// Given a map from target_features to whether they are enabled or disabled, -/// ensure only valid combinations are allowed. -pub(crate) fn check_tied_features( - sess: &Session, - features: &FxHashMap<&str, bool>, -) -> Option<&'static [&'static str]> { - if !features.is_empty() { - for tied in sess.target.tied_target_features() { - // Tied features must be set to the same value, or not set at all - let mut tied_iter = tied.iter(); - let enabled = features.get(tied_iter.next().unwrap()); - if tied_iter.any(|f| enabled != features.get(f)) { - return Some(tied); - } - } - } - None -} - /// Used to generate cfg variables and apply features /// Must express features in the way Rust understands them pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { @@ -685,7 +669,7 @@ pub(crate) fn global_llvm_features( features.extend(feats); if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { - sess.dcx().emit_err(TargetFeatureDisableOrEnable { + sess.dcx().emit_err(rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable { features: f, span: None, missing_features: None, diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 6e429a1674a..1af666f818b 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -1,11 +1,12 @@ use std::fmt::Write; +use rustc_abi::Primitive::{Float, Int, Pointer}; +use rustc_abi::{Abi, Align, FieldsShape, Scalar, Size, Variants}; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt}; -use rustc_target::abi::{Abi, Align, FieldsShape, Float, Int, Pointer, Scalar, Size, Variants}; use tracing::debug; use crate::common::*; @@ -199,7 +200,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // layout. if let Abi::Scalar(scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs - // can be either fat or thin (data pointers of fat pointers). + // can be either wide or thin (data pointers of wide pointers). if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { return llty; } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 58baf40b581..dffb7a7271e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -14,6 +14,7 @@ itertools = "0.12" jobserver = "0.1.28" pathdiff = "0.2.0" regex = "1.4" +rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 9091602d75b..d07274920fe 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -82,7 +82,7 @@ codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphizati codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` -codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}` +codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}` codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}` @@ -183,6 +183,8 @@ codegen_ssa_metadata_object_file_write = error writing metadata object file: {$e codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload +codegen_ssa_missing_features = add the missing features in a `target_feature` attribute + codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering codegen_ssa_missing_query_depgraph = @@ -238,6 +240,9 @@ codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` fa codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error} +codegen_ssa_target_feature_disable_or_enable = + the target features {$features} must all be either enabled or disabled together + codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method .label = cannot be applied to safe trait method .label_def = not an `unsafe` function diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e7b1c63a822..34dc599e4fd 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1087,7 +1087,9 @@ fn link_natively( let strip = sess.opts.cg.strip; if sess.target.is_like_osx { - let stripcmd = "/usr/bin/strip"; + // Use system `strip` when running on host macOS. + // <https://github.com/rust-lang/rust/pull/130781> + let stripcmd = if cfg!(target_os = "macos") { "/usr/bin/strip" } else { "strip" }; match (strip, crate_type) { (Strip::Debuginfo, _) => { strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S")) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3f3d305da01..c4bb82d0dd7 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -404,12 +404,14 @@ impl<'a> GccLinker<'a> { fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { - if !self.is_ld { + if self.is_cc() { + // `-dynamiclib` makes `cc` pass `-dylib` to the linker. self.cc_arg("-dynamiclib"); + } else { + self.link_arg("-dylib"); + // Clang also sets `-dynamic`, but that's implied by `-dylib`, so unnecessary. } - self.link_arg("-dylib"); - // Note that the `osx_rpath_install_name` option here is a hack // purely to support bootstrap right now, we should get a more // principled solution at some point to force the compiler to pass diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 4d81ff933dd..e3d11cfaf4f 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -11,7 +11,6 @@ use rustc_ast::attr; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; -use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::translation::Translate; use rustc_errors::{ @@ -1889,7 +1888,7 @@ impl SharedEmitter { } impl Translate for SharedEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } @@ -1924,7 +1923,7 @@ impl Emitter for SharedEmitter { ); } - fn source_map(&self) -> Option<&Lrc<SourceMap>> { + fn source_map(&self) -> Option<&SourceMap> { None } } @@ -2165,8 +2164,14 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { && tcx.sess.opts.cg.prefer_dynamic) ); + // We need to generate _imp__ symbol if we are generating an rlib or we include one + // indirectly from ThinLTO. In theory these are not needed as ThinLTO could resolve + // these, but it currently does not do so. + let can_have_static_objects = + tcx.sess.lto() == Lto::Thin || tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib); + tcx.sess.target.is_like_windows && - tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib) && + can_have_static_objects && // ThinLTO can't handle this workaround in all cases, so we don't // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing // dynamic linking when linker plugin LTO is enabled. diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e99c3a46271..d536419ab3c 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,5 +1,6 @@ -use rustc_ast::{MetaItemKind, NestedMetaItem, ast, attr}; +use rustc_ast::{MetaItemInner, MetaItemKind, ast, attr}; use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; use rustc_hir as hir; @@ -13,13 +14,13 @@ use rustc_middle::middle::codegen_fn_attrs::{ use rustc_middle::mir::mono::Linkage; use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; -use rustc_session::lint; use rustc_session::parse::feature_err; +use rustc_session::{Session, lint}; use rustc_span::symbol::Ident; use rustc_span::{Span, sym}; use rustc_target::spec::{SanitizerSet, abi}; -use crate::errors; +use crate::errors::{self, MissingFeatures, TargetFeatureDisableOrEnable}; use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature}; fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { @@ -357,7 +358,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::instruction_set => { codegen_fn_attrs.instruction_set = attr.meta_item_list().and_then(|l| match &l[..] { - [NestedMetaItem::MetaItem(set)] => { + [MetaItemInner::MetaItem(set)] => { let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); match segments.as_slice() { @@ -662,9 +663,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } + if let Some(features) = check_tied_features( + tcx.sess, + &codegen_fn_attrs + .target_features + .iter() + .map(|features| (features.name.as_str(), true)) + .collect(), + ) { + let span = tcx + .get_attrs(did, sym::target_feature) + .next() + .map_or_else(|| tcx.def_span(did), |a| a.span); + tcx.dcx() + .create_err(TargetFeatureDisableOrEnable { + features, + span: Some(span), + missing_features: Some(MissingFeatures), + }) + .emit(); + } + codegen_fn_attrs } +/// Given a map from target_features to whether they are enabled or disabled, ensure only valid +/// combinations are allowed. +pub fn check_tied_features( + sess: &Session, + features: &FxHashMap<&str, bool>, +) -> Option<&'static [&'static str]> { + if !features.is_empty() { + for tied in sess.target.tied_target_features() { + // Tied features must be set to the same value, or not set at all + let mut tied_iter = tied.iter(); + let enabled = features.get(tied_iter.next().unwrap()); + if tied_iter.any(|f| enabled != features.get(f)) { + return Some(tied); + } + } + } + None +} + /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 08b326e3ac3..d67cf0e3a6d 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -9,7 +9,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; -use rustc_macros::Diagnostic; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutError; use rustc_span::{Span, Symbol}; @@ -916,8 +916,8 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)] - CastFatPointer { + #[diag(codegen_ssa_invalid_monomorphization_cast_wide_pointer, code = E0511)] + CastWidePointer { #[primary_span] span: Span, name: Symbol, @@ -1068,3 +1068,27 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> { pub lib_name: &'a str, pub error: String, } + +pub struct TargetFeatureDisableOrEnable<'a> { + pub features: &'a [&'a str], + pub span: Option<Span>, + pub missing_features: Option<MissingFeatures>, +} + +#[derive(Subdiagnostic)] +#[help(codegen_ssa_missing_features)] +pub struct MissingFeatures; + +impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { + let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable); + if let Some(span) = self.span { + diag.span(span); + }; + if let Some(missing_features) = self.missing_features { + diag.subdiagnostic(missing_features); + } + diag.arg("features", self.features.join(", ")); + diag + } +} diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 162d14272a5..cbd95146294 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -156,7 +156,7 @@ pub struct NativeLib { pub kind: NativeLibKind, pub name: Symbol, pub filename: Option<Symbol>, - pub cfg: Option<ast::MetaItem>, + pub cfg: Option<ast::MetaItemInner>, pub verbatim: bool, pub dll_imports: Vec<cstore::DllImport>, } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 125d3b908c7..be9a6d9a90e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -3,7 +3,9 @@ use std::cmp; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; -use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTerminateReason}; +use rustc_middle::mir::{ + self, AssertKind, BasicBlock, InlineAsmMacro, SwitchTargets, UnwindTerminateReason, +}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty}; @@ -1133,6 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, helper: TerminatorCodegenHelper<'tcx>, bx: &mut Bx, + asm_macro: InlineAsmMacro, terminator: &mir::Terminator<'tcx>, template: &[ast::InlineAsmTemplatePiece], operands: &[mir::InlineAsmOperand<'tcx>], @@ -1203,11 +1206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &operands, options, line_spans, - if options.contains(InlineAsmOptions::NORETURN) { - None - } else { - targets.get(0).copied() - }, + if asm_macro.diverges(options) { None } else { targets.get(0).copied() }, unwind, instance, mergeable_succ, @@ -1381,6 +1380,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::InlineAsm { + asm_macro, template, ref operands, options, @@ -1390,6 +1390,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } => self.codegen_asm_terminator( helper, bx, + asm_macro, terminator, template, operands, diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index c4fb24aa625..8bd172a9ce6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -133,9 +133,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { enum LocalRef<'tcx, V> { Place(PlaceRef<'tcx, V>), /// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place). - /// `*p` is the fat pointer that references the actual unsized place. + /// `*p` is the wide pointer that references the actual unsized place. /// Every time it is initialized, we have to reallocate the place - /// and update the fat pointer. That's the reason why it is indirect. + /// and update the wide pointer. That's the reason why it is indirect. UnsizedPlace(PlaceRef<'tcx, V>), /// The backend [`OperandValue`] has already been generated. Operand(OperandRef<'tcx, V>), @@ -429,7 +429,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Unsized indirect qrguments PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { // As the storage for the indirect argument lives during - // the whole function call, we just copy the fat pointer. + // the whole function call, we just copy the wide pointer. let llarg = bx.get_param(llarg_idx); llarg_idx += 1; let llextra = bx.get_param(llarg_idx); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 17f66c12a03..88ceff327d0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -3,12 +3,13 @@ use std::fmt; use arrayvec::ArrayVec; use either::Either; +use rustc_abi as abi; +use rustc_abi::{Abi, Align, Size}; use rustc_middle::bug; use rustc_middle::mir::interpret::{Pointer, Scalar, alloc_range}; use rustc_middle::mir::{self, ConstValue}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_target::abi::{self, Abi, Align, Size}; use tracing::debug; use super::place::{PlaceRef, PlaceValue}; @@ -41,7 +42,7 @@ pub enum OperandValue<V> { /// The backend value in this variant must be the *immediate* backend type, /// as returned by [`LayoutTypeCodegenMethods::immediate_backend_type`]. Immediate(V), - /// A pair of immediate LLVM values. Used by fat pointers too. + /// A pair of immediate LLVM values. Used by wide pointers too. /// /// An `OperandValue` *must* be this variant for any type for which /// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`. @@ -207,7 +208,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { match alloc.0.read_scalar( bx, alloc_range(start, size), - /*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)), + /*read_provenance*/ matches!(s.primitive(), abi::Primitive::Pointer(_)), ) { Ok(val) => bx.scalar_to_backend(val, s, ty), Err(_) => bx.const_poison(ty), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 0b764ae7747..a7d5541481a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -1,10 +1,10 @@ +use rustc_abi::Primitive::{Int, Pointer}; +use rustc_abi::{Align, FieldsShape, Size, TagEncoding, Variants}; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, mir}; -use rustc_target::abi::{ - Align, FieldsShape, Int, Pointer, Size, TagEncoding, VariantIdx, Variants, -}; +use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; use super::operand::OperandValue; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index f9c0f3ce941..a132ca69540 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -38,10 +38,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ref source, _, ) => { - // The destination necessarily contains a fat pointer, so if - // it's a scalar pair, it's a fat pointer or newtype thereof. + // The destination necessarily contains a wide pointer, so if + // it's a scalar pair, it's a wide pointer or newtype thereof. if bx.cx().is_backend_scalar_pair(dest.layout) { - // Into-coerce of a thin pointer to a fat pointer -- just + // Into-coerce of a thin pointer to a wide pointer -- just // use the operand path. let temp = self.codegen_rvalue_operand(bx, rvalue); temp.val.store(bx, dest); @@ -519,7 +519,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if bx.cx().is_backend_scalar_pair(cast) { OperandValue::Pair(data_ptr, meta) } else { - // Cast of fat-ptr to thin-ptr is an extraction of data-ptr. + // Cast of wide-ptr to thin-ptr is an extraction of data-ptr. OperandValue::Immediate(data_ptr) } } else { @@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ( OperandValue::Pair(lhs_addr, lhs_extra), OperandValue::Pair(rhs_addr, rhs_extra), - ) => self.codegen_fat_ptr_binop( + ) => self.codegen_wide_ptr_binop( bx, op, lhs_addr, @@ -984,7 +984,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn codegen_fat_ptr_binop( + fn codegen_wide_ptr_binop( &mut self, bx: &mut Bx, op: mir::BinOp, @@ -1021,7 +1021,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.or(lhs, rhs) } _ => { - bug!("unexpected fat ptr binop"); + bug!("unexpected wide ptr binop"); } } } diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index c4f8841d71c..41136019a88 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start either = "1" +rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 73a9a1569f6..24dbe688f36 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -134,14 +134,16 @@ const_eval_incompatible_return_types = const_eval_incompatible_types = calling a function with argument of type {$callee_ty} passing data of type {$caller_ty} -const_eval_interior_mutable_data_refer = +const_eval_interior_mutable_ref_escaping = {const_eval_const_context}s cannot refer to interior mutable data .label = this borrow of an interior mutable value may end up in the final value .help = to fix this, the value can be extracted to a separate `static` item and then referenced .teach_note = - A constant containing interior mutable data behind a reference can allow you to modify that data. - This would make multiple uses of a constant to be able to see different values and allow circumventing - the `Send` and `Sync` requirements for shared mutable data, which is unsound. + References that escape into the final value of a constant or static must be immutable. + This is to avoid accidentally creating shared mutable state. + + + If you really want global mutable state, try using an interior mutable `static` or a `static mut`. const_eval_intern_kind = {$kind -> [static] static @@ -229,6 +231,24 @@ const_eval_modified_global = const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} +const_eval_mutable_raw_escaping = + raw mutable pointers are not allowed in the final value of {const_eval_const_context}s + .teach_note = + Pointers that escape into the final value of a constant or static must be immutable. + This is to avoid accidentally creating shared mutable state. + + + If you really want global mutable state, try using an interior mutable `static` or a `static mut`. + +const_eval_mutable_ref_escaping = + mutable references are not allowed in the final value of {const_eval_const_context}s + .teach_note = + References that escape into the final value of a constant or static must be immutable. + This is to avoid accidentally creating shared mutable state. + + + If you really want global mutable state, try using an interior mutable `static` or a `static mut`. + const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead const_eval_non_const_fmt_macro_call = cannot call non-const formatting macro in {const_eval_const_context}s @@ -364,30 +384,11 @@ const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in const_eval_unallowed_heap_allocations = allocations are not allowed in {const_eval_const_context}s .label = allocation not allowed in {const_eval_const_context}s - .teach_note = The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + .teach_note = + The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created. const_eval_unallowed_inline_asm = inline assembly is not allowed in {const_eval_const_context}s -const_eval_unallowed_mutable_raw = - raw mutable pointers are not allowed in the final value of {const_eval_const_context}s - .teach_note = - References in statics and constants may only refer to immutable values. - - - Statics are shared everywhere, and if they refer to mutable data one might violate memory - safety since holding multiple mutable references to shared data is not allowed. - - - If you really want global mutable state, try using static mut or a global UnsafeCell. - -const_eval_unallowed_mutable_refs = - mutable references are not allowed in the final value of {const_eval_const_context}s - .teach_note = - Statics are shared everywhere, and if they refer to mutable data one might violate memory - safety since holding multiple mutable references to shared data is not allowed. - - - If you really want global mutable state, try using static mut or a global UnsafeCell. const_eval_unallowed_op_in_const_context = {$msg} diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 2cbf242fcf2..463a66d4e2e 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -666,6 +666,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } + // This can be called on stable via the `vec!` macro. if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) { self.check_op(ops::HeapAllocation); return; diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 6eb33c29e1d..5c4a899f28a 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -402,7 +402,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow { DiagImportance::Secondary } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::InteriorMutableDataRefer { + ccx.dcx().create_err(errors::InteriorMutableRefEscaping { span, opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)), kind: ccx.const_kind(), @@ -430,12 +430,12 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { match self.0 { - hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw { + hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::MutableRawEscaping { span, kind: ccx.const_kind(), teach: ccx.tcx.sess.teach(E0764), }), - hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs { + hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping { span, kind: ccx.const_kind(), teach: ccx.tcx.sess.teach(E0764), diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4aec74595bc..2db43a0f787 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -140,7 +140,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> { #[inline(always)] fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> { - self.iter().filter_map(move |(k, v)| f(k, &*v)).collect() + self.iter().filter_map(move |(k, v)| f(k, v)).collect() } #[inline(always)] diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index c60bacb8506..c943236affc 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -118,8 +118,8 @@ pub(crate) struct UnstableConstFn { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_refs, code = E0764)] -pub(crate) struct UnallowedMutableRefs { +#[diag(const_eval_mutable_ref_escaping, code = E0764)] +pub(crate) struct MutableRefEscaping { #[primary_span] pub span: Span, pub kind: ConstContext, @@ -128,8 +128,8 @@ pub(crate) struct UnallowedMutableRefs { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_raw, code = E0764)] -pub(crate) struct UnallowedMutableRaw { +#[diag(const_eval_mutable_raw_escaping, code = E0764)] +pub(crate) struct MutableRawEscaping { #[primary_span] pub span: Span, pub kind: ConstContext, @@ -181,8 +181,8 @@ pub(crate) struct UnallowedInlineAsm { } #[derive(Diagnostic)] -#[diag(const_eval_interior_mutable_data_refer, code = E0492)] -pub(crate) struct InteriorMutableDataRefer { +#[diag(const_eval_interior_mutable_ref_escaping, code = E0492)] +pub(crate) struct InteriorMutableRefEscaping { #[primary_span] #[label] pub span: Span, diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 565a7d16242..30b5a8d70bc 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -204,12 +204,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_any_ptr()); assert!(cast_to.ty.is_unsafe_ptr()); - // Handle casting any ptr to raw ptr (might be a fat ptr). + // Handle casting any ptr to raw ptr (might be a wide ptr). if cast_to.size == src.layout.size { - // Thin or fat pointer that just has the ptr kind of target type changed. + // Thin or wide pointer that just has the ptr kind of target type changed. return interp_ok(ImmTy::from_immediate(**src, cast_to)); } else { - // Casting the metadata away from a fat ptr. + // Casting the metadata away from a wide ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); assert_eq!(cast_to.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 0f796c31222..89d49ba046e 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -395,7 +395,7 @@ pub trait Machine<'tcx>: Sized { /// /// This should take care of jumping to the next block (one of `targets`) when asm goto /// is triggered, `targets[0]` when the assembly falls through, or diverge in case of - /// `InlineAsmOptions::NORETURN` being set. + /// naked_asm! or `InlineAsmOptions::NORETURN` being set. fn eval_inline_asm( _ecx: &mut InterpCx<'tcx, Self>, _template: &'tcx [InlineAsmTemplatePiece], diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index e6ab8ca12a8..7700eb792ef 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -993,11 +993,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { bytes } - /// Find leaked allocations. Allocations reachable from `static_roots` or a `Global` allocation - /// are not considered leaked, as well as leaks whose kind's `may_leak()` returns true. - pub fn find_leaked_allocations( - &self, - static_roots: &[AllocId], + /// Find leaked allocations, remove them from memory and return them. Allocations reachable from + /// `static_roots` or a `Global` allocation are not considered leaked, as well as leaks whose + /// kind's `may_leak()` returns true. + /// + /// This is highly destructive, no more execution can happen after this! + pub fn take_leaked_allocations( + &mut self, + static_roots: impl FnOnce(&Self) -> &[AllocId], ) -> Vec<(AllocId, MemoryKind<M::MemoryKind>, Allocation<M::Provenance, M::AllocExtra, M::Bytes>)> { // Collect the set of allocations that are *reachable* from `Global` allocations. @@ -1008,7 +1011,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.memory.alloc_map.filter_map_collect(move |&id, &(kind, _)| { if Some(kind) == global_kind { Some(id) } else { None } }); - todo.extend(static_roots); + todo.extend(static_roots(self)); while let Some(id) = todo.pop() { if reachable.insert(id) { // This is a new allocation, add the allocation it points to `todo`. @@ -1023,13 +1026,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; // All allocations that are *not* `reachable` and *not* `may_leak` are considered leaking. - self.memory.alloc_map.filter_map_collect(|id, (kind, alloc)| { - if kind.may_leak() || reachable.contains(id) { - None - } else { - Some((*id, *kind, alloc.clone())) - } - }) + let leaked: Vec<_> = self.memory.alloc_map.filter_map_collect(|&id, &(kind, _)| { + if kind.may_leak() || reachable.contains(&id) { None } else { Some(id) } + }); + let mut result = Vec::new(); + for &id in leaked.iter() { + let (kind, alloc) = self.memory.alloc_map.remove(&id).unwrap(); + result.push((id, kind, alloc)); + } + result } /// Runs the closure in "validation" mode, which means the machine's memory read hooks will be diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 291664d556a..cd5e2aeca85 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -4,13 +4,14 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; +use rustc_abi as abi; +use rustc_abi::{Abi, HasDataLayout, Size}; use rustc_hir::def::Namespace; use rustc_middle::mir::interpret::ScalarSizeMismatch; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug, ty}; -use rustc_target::abi::{self, Abi, HasDataLayout, Size}; use tracing::trace; use super::{ @@ -113,28 +114,47 @@ impl<Prov: Provenance> Immediate<Prov> { } /// Assert that this immediate is a valid value for the given ABI. - pub fn assert_matches_abi(self, abi: Abi, cx: &impl HasDataLayout) { + pub fn assert_matches_abi(self, abi: Abi, msg: &str, cx: &impl HasDataLayout) { match (self, abi) { (Immediate::Scalar(scalar), Abi::Scalar(s)) => { - assert_eq!(scalar.size(), s.size(cx)); - if !matches!(s.primitive(), abi::Pointer(..)) { + assert_eq!(scalar.size(), s.size(cx), "{msg}: scalar value has wrong size"); + if !matches!(s.primitive(), abi::Primitive::Pointer(..)) { // This is not a pointer, it should not carry provenance. - assert!(matches!(scalar, Scalar::Int(..))); + assert!( + matches!(scalar, Scalar::Int(..)), + "{msg}: scalar value should be an integer, but has provenance" + ); } } (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { - assert_eq!(a_val.size(), a.size(cx)); - if !matches!(a.primitive(), abi::Pointer(..)) { - assert!(matches!(a_val, Scalar::Int(..))); + assert_eq!( + a_val.size(), + a.size(cx), + "{msg}: first component of scalar pair has wrong size" + ); + if !matches!(a.primitive(), abi::Primitive::Pointer(..)) { + assert!( + matches!(a_val, Scalar::Int(..)), + "{msg}: first component of scalar pair should be an integer, but has provenance" + ); } - assert_eq!(b_val.size(), b.size(cx)); - if !matches!(b.primitive(), abi::Pointer(..)) { - assert!(matches!(b_val, Scalar::Int(..))); + assert_eq!( + b_val.size(), + b.size(cx), + "{msg}: second component of scalar pair has wrong size" + ); + if !matches!(b.primitive(), abi::Primitive::Pointer(..)) { + assert!( + matches!(b_val, Scalar::Int(..)), + "{msg}: second component of scalar pair should be an integer, but has provenance" + ); } } - (Immediate::Uninit, _) => {} + (Immediate::Uninit, _) => { + assert!(abi.is_sized(), "{msg}: unsized immediates are not a thing"); + } _ => { - bug!("value {self:?} does not match ABI {abi:?})",) + bug!("{msg}: value {self:?} does not match ABI {abi:?})",) } } } @@ -241,6 +261,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline(always)] pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self { + // Without a `cx` we cannot call `assert_matches_abi`. debug_assert!( match (imm, layout.abi) { (Immediate::Scalar(..), Abi::Scalar(..)) => true, @@ -261,7 +282,6 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_scalar_int(s: ScalarInt, layout: TyAndLayout<'tcx>) -> Self { - assert_eq!(s.size(), layout.size); Self::from_scalar(Scalar::from(s), layout) } @@ -334,7 +354,10 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { /// given layout. // Not called `offset` to avoid confusion with the trait method. fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self { - debug_assert!(layout.is_sized(), "unsized immediates are not a thing"); + // Verify that the input matches its type. + if cfg!(debug_assertions) { + self.assert_matches_abi(self.layout.abi, "invalid input to Immediate::offset", cx); + } // `ImmTy` have already been checked to be in-bounds, so we can just check directly if this // remains in-bounds. This cannot actually be violated since projections are type-checked // and bounds-checked. @@ -368,32 +391,14 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { // the field covers the entire type _ if layout.size == self.layout.size => { assert_eq!(offset.bytes(), 0); - assert!( - match (self.layout.abi, layout.abi) { - (Abi::Scalar(l), Abi::Scalar(r)) => l.size(cx) == r.size(cx), - (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => - l1.size(cx) == r1.size(cx) && l2.size(cx) == r2.size(cx), - _ => false, - }, - "cannot project into {} immediate with equally-sized field {}\nouter ABI: {:#?}\nfield ABI: {:#?}", - self.layout.ty, - layout.ty, - self.layout.abi, - layout.abi, - ); **self } // extract fields from types with `ScalarPair` ABI (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { - assert_matches!(layout.abi, Abi::Scalar(..)); Immediate::from(if offset.bytes() == 0 { - // It is "okay" to transmute from `usize` to a pointer (GVN relies on that). - // So only compare the size. - assert_eq!(layout.size, a.size(cx)); a_val } else { assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi)); - assert_eq!(layout.size, b.size(cx)); b_val }) } @@ -405,6 +410,8 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { self.layout ), }; + // Ensure the new layout matches the new value. + inner_val.assert_matches_abi(layout.abi, "invalid field type in Immediate::offset", cx); ImmTy::from_immediate(inner_val, layout) } @@ -566,7 +573,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); let scalar = alloc.read_scalar( alloc_range(Size::ZERO, size), - /*read_provenance*/ matches!(s, abi::Pointer(_)), + /*read_provenance*/ matches!(s, abi::Primitive::Pointer(_)), )?; Some(ImmTy::from_scalar(scalar, mplace.layout)) } @@ -582,11 +589,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields let a_val = alloc.read_scalar( alloc_range(Size::ZERO, a_size), - /*read_provenance*/ matches!(a, abi::Pointer(_)), + /*read_provenance*/ matches!(a, abi::Primitive::Pointer(_)), )?; let b_val = alloc.read_scalar( alloc_range(b_offset, b_size), - /*read_provenance*/ matches!(b, abi::Pointer(_)), + /*read_provenance*/ matches!(b, abi::Primitive::Pointer(_)), )?; Some(ImmTy::from_immediate(Immediate::ScalarPair(a_val, b_val), mplace.layout)) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 49656e10f2a..81b926a1b65 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -658,7 +658,11 @@ where // Things can ge wrong in quite weird ways when this is violated. // Unfortunately this is too expensive to do in release builds. if cfg!(debug_assertions) { - src.assert_matches_abi(local_layout.abi, self); + src.assert_matches_abi( + local_layout.abi, + "invalid immediate for given destination place", + self, + ); } } Left(mplace) => { @@ -679,7 +683,7 @@ where ) -> InterpResult<'tcx> { // We use the sizes from `value` below. // Ensure that matches the type of the place it is written to. - value.assert_matches_abi(layout.abi, self); + value.assert_matches_abi(layout.abi, "invalid immediate for given destination place", self); // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here // to handle padding properly, which is only correct if we never look at this data with the diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index cc49d7cebf4..e636090a324 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -82,6 +82,10 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx) } + /// This does an offset-by-zero, which is effectively a transmute. Note however that + /// not all transmutes are supported by all projectables -- specifically, if this is an + /// `OpTy` or `ImmTy`, the new layout must have almost the same ABI as the old one + /// (only changing the `valid_range` is allowed and turning integers into pointers). fn transmute<M: Machine<'tcx, Provenance = Prov>>( &self, layout: TyAndLayout<'tcx>, diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 7ff1339c5ab..3d6d0003483 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -5,7 +5,11 @@ const RED_ZONE: usize = 100 * 1024; // 100k // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then // on. This flag has performance relevant characteristics. Don't set it too high. +#[cfg(not(target_os = "aix"))] const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB +// LLVM for AIX doesn't feature TCO, increase recursion size for workaround. +#[cfg(target_os = "aix")] +const STACK_PER_RECURSION: usize = 16 * 1024 * 1024; // 16MB /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations /// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit diff --git a/compiler/rustc_data_structures/src/unhash.rs b/compiler/rustc_data_structures/src/unhash.rs index 48e21a9dab1..0617ef83aad 100644 --- a/compiler/rustc_data_structures/src/unhash.rs +++ b/compiler/rustc_data_structures/src/unhash.rs @@ -3,6 +3,7 @@ use std::hash::{BuildHasherDefault, Hasher}; pub type UnhashMap<K, V> = HashMap<K, V, BuildHasherDefault<Unhasher>>; pub type UnhashSet<V> = HashSet<V, BuildHasherDefault<Unhasher>>; +pub type UnindexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<Unhasher>>; /// This no-op hasher expects only a single `write_u64` call. It's intended for /// map keys that already have hash-like quality, like `Fingerprint`. diff --git a/compiler/rustc_driver_impl/README.md b/compiler/rustc_driver_impl/README.md index 6d7fba36fb3..9fa4242de3c 100644 --- a/compiler/rustc_driver_impl/README.md +++ b/compiler/rustc_driver_impl/README.md @@ -7,4 +7,4 @@ options). For more information about how the driver works, see the [rustc dev guide]. -[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver.html +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver/intro.html diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 76b7270d4b8..a59dea557bb 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -29,13 +29,12 @@ use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; -use std::time::{Duration, Instant, SystemTime}; +use std::time::{Instant, SystemTime}; use std::{env, str}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenErrors, CodegenResults}; -use rustc_const_eval::CTRL_C_RECEIVED; use rustc_data_structures::profiling::{ TimePassesFormat, get_resident_set_size, print_time_passes_entry, }; @@ -1577,8 +1576,8 @@ pub fn install_ctrlc_handler() { // time to check CTRL_C_RECEIVED and run its own shutdown logic, but after a short amount // of time exit the process. This sleep+exit ensures that even if nobody is checking // CTRL_C_RECEIVED, the compiler exits reasonably promptly. - CTRL_C_RECEIVED.store(true, Ordering::Relaxed); - std::thread::sleep(Duration::from_millis(100)); + rustc_const_eval::CTRL_C_RECEIVED.store(true, Ordering::Relaxed); + std::thread::sleep(std::time::Duration::from_millis(100)); std::process::exit(1); }) .expect("Unable to install ctrlc handler"); diff --git a/compiler/rustc_error_codes/src/error_codes/E0607.md b/compiler/rustc_error_codes/src/error_codes/E0607.md index 0545246929f..8ebc227114d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0607.md +++ b/compiler/rustc_error_codes/src/error_codes/E0607.md @@ -1,4 +1,4 @@ -A cast between a thin and a fat pointer was attempted. +A cast between a thin and a wide pointer was attempted. Erroneous code example: @@ -7,18 +7,18 @@ let v = core::ptr::null::<u8>(); v as *const [u8]; ``` -First: what are thin and fat pointers? +First: what are thin and wide pointers? Thin pointers are "simple" pointers: they are purely a reference to a memory address. -Fat pointers are pointers referencing Dynamically Sized Types (also called +Wide pointers are pointers referencing Dynamically Sized Types (also called DSTs). DSTs don't have a statically known size, therefore they can only exist behind some kind of pointer that contains additional information. For example, slices and trait objects are DSTs. In the case of slices, the additional -information the fat pointer holds is their size. +information the wide pointer holds is their size. -To fix this error, don't try to cast directly between thin and fat pointers. +To fix this error, don't try to cast directly between thin and wide pointers. For more information about type casts, take a look at the section of the [The Rust Reference][1] on type cast expressions. diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md index cee50829270..f5c5faa066b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0787.md +++ b/compiler/rustc_error_codes/src/error_codes/E0787.md @@ -11,11 +11,10 @@ pub extern "C" fn f() -> u32 { } ``` -The naked functions must be defined using a single inline assembly -block. +The naked function must be defined using a single `naked_asm!` assembly block. The execution must never fall through past the end of the assembly -code so the block must use `noreturn` option. The asm block can also +code, so it must either return or diverge. The asm block can also use `att_syntax` and `raw` options, but others options are not allowed. The asm block must not contain any operands other than `const` and diff --git a/compiler/rustc_error_codes/src/error_codes/E0793.md b/compiler/rustc_error_codes/src/error_codes/E0793.md index b2e51e24e14..ccd1b43bd19 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0793.md +++ b/compiler/rustc_error_codes/src/error_codes/E0793.md @@ -1,4 +1,4 @@ -An unaligned references to a field of a [packed] struct got created. +An unaligned reference to a field of a [packed] struct got created. Erroneous code example: diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index f468fbf4497..335432c9cfe 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -34,8 +34,8 @@ pub struct AnnotateSnippetEmitter { } impl Translate for AnnotateSnippetEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { - self.fluent_bundle.as_ref() + fn fluent_bundle(&self) -> Option<&FluentBundle> { + self.fluent_bundle.as_deref() } fn fallback_fluent_bundle(&self) -> &FluentBundle { @@ -69,8 +69,8 @@ impl Emitter for AnnotateSnippetEmitter { ); } - fn source_map(&self) -> Option<&Lrc<SourceMap>> { - self.source_map.as_ref() + fn source_map(&self) -> Option<&SourceMap> { + self.source_map.as_deref() } fn should_show_explain(&self) -> bool { diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 1dc52c4d0a4..1adb6b9dcfe 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -205,7 +205,7 @@ pub trait Emitter: Translate { false } - fn source_map(&self) -> Option<&Lrc<SourceMap>>; + fn source_map(&self) -> Option<&SourceMap>; /// Formats the substitutions of the primary_span /// @@ -481,8 +481,8 @@ pub trait Emitter: Translate { } impl Translate for HumanEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { - self.fluent_bundle.as_ref() + fn fluent_bundle(&self) -> Option<&FluentBundle> { + self.fluent_bundle.as_deref() } fn fallback_fluent_bundle(&self) -> &FluentBundle { @@ -491,8 +491,8 @@ impl Translate for HumanEmitter { } impl Emitter for HumanEmitter { - fn source_map(&self) -> Option<&Lrc<SourceMap>> { - self.sm.as_ref() + fn source_map(&self) -> Option<&SourceMap> { + self.sm.as_deref() } fn emit_diagnostic(&mut self, mut diag: DiagInner) { @@ -540,7 +540,7 @@ pub struct SilentEmitter { } impl Translate for SilentEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } @@ -552,7 +552,7 @@ impl Translate for SilentEmitter { } impl Emitter for SilentEmitter { - fn source_map(&self) -> Option<&Lrc<SourceMap>> { + fn source_map(&self) -> Option<&SourceMap> { None } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 1972a522e39..1534e256520 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -111,8 +111,8 @@ enum EmitTyped<'a> { } impl Translate for JsonEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { - self.fluent_bundle.as_ref() + fn fluent_bundle(&self) -> Option<&FluentBundle> { + self.fluent_bundle.as_deref() } fn fallback_fluent_bundle(&self) -> &FluentBundle { @@ -172,7 +172,7 @@ impl Emitter for JsonEmitter { } } - fn source_map(&self) -> Option<&Lrc<SourceMap>> { + fn source_map(&self) -> Option<&SourceMap> { Some(&self.sm) } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 39acacfbe59..94365a89adc 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -59,7 +59,7 @@ use registry::Registry; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::{Lock, Lrc}; +use rustc_data_structures::sync::Lock; pub use rustc_error_messages::{ DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, fallback_fluent_bundle, fluent_bundle, @@ -685,13 +685,13 @@ impl DiagCtxt { unimplemented!("false emitter must only used during `wrap_emitter`") } - fn source_map(&self) -> Option<&Lrc<SourceMap>> { + fn source_map(&self) -> Option<&SourceMap> { unimplemented!("false emitter must only used during `wrap_emitter`") } } impl translation::Translate for FalseEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { unimplemented!("false emitter must only used during `wrap_emitter`") } @@ -925,18 +925,6 @@ impl<'a> DiagCtxtHandle<'a> { self.inner.borrow_mut().emit_stashed_diagnostics() } - /// This excludes lint errors, and delayed bugs. - #[inline] - pub fn err_count_excluding_lint_errs(&self) -> usize { - let inner = self.inner.borrow(); - inner.err_guars.len() - + inner - .stashed_diagnostics - .values() - .filter(|(diag, guar)| guar.is_some() && diag.is_lint.is_none()) - .count() - } - /// This excludes delayed bugs. #[inline] pub fn err_count(&self) -> usize { diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 17a1635bd11..70179237e5d 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; +use rustc_data_structures::sync::IntoDynSyncSend; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::{DiagMessage, langid}; @@ -12,7 +12,7 @@ struct Dummy { } impl Translate for Dummy { - fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index e0b64b276eb..156f5e5d26e 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use std::env; use std::error::Report; -use rustc_data_structures::sync::Lrc; pub use rustc_error_messages::FluentArgs; use tracing::{debug, trace}; @@ -33,7 +32,7 @@ pub trait Translate { /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no /// language was requested by the user then this will be `None` and `fallback_fluent_bundle` /// should be used. - fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>>; + fn fluent_bundle(&self) -> Option<&FluentBundle>; /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler. /// Used when the user has not requested a specific language or when a localized diagnostic is diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 766d96e268f..57bac9d09d5 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -27,6 +27,12 @@ expand_collapse_debuginfo_illegal = expand_count_repetition_misplaced = `count` can not be placed inside the inner-most repetition +expand_crate_name_in_cfg_attr = + `crate_name` within an `#![cfg_attr]` attribute is forbidden + +expand_crate_type_in_cfg_attr = + `crate_type` within an `#![cfg_attr]` attribute is forbidden + expand_custom_attribute_panicked = custom attribute panicked .help = message: {$message} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index d0552a754fe..f0cfe133a49 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -29,7 +29,7 @@ use rustc_span::{DUMMY_SP, FileName, Span}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; -use crate::base::ast::NestedMetaItem; +use crate::base::ast::MetaItemInner; use crate::errors; use crate::expand::{self, AstFragment, Invocation}; use crate::module::DirOwnership; @@ -783,7 +783,7 @@ impl SyntaxExtension { fn collapse_debuginfo_by_name(attr: &Attribute) -> Result<CollapseMacroDebuginfo, Span> { let list = attr.meta_item_list(); - let Some([NestedMetaItem::MetaItem(item)]) = list.as_deref() else { + let Some([MetaItemInner::MetaItem(item)]) = list.as_deref() else { return Err(attr.span); }; if !item.is_word() { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 32088374277..ea06415801f 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, }; -use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId}; +use rustc_ast::{ + self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, +}; use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ @@ -21,8 +23,9 @@ use thin_vec::ThinVec; use tracing::instrument; use crate::errors::{ - FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, - MalformedFeatureAttributeHelp, RemoveExprNotSupported, + CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved, + FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp, + RemoveExprNotSupported, }; /// A folder that strips out items that do not belong in the current configuration. @@ -37,7 +40,7 @@ pub struct StripUnconfigured<'a> { } pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features { - fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> { + fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> { if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() { @@ -358,20 +361,10 @@ impl<'a> StripUnconfigured<'a> { item_span, ); if attr.has_name(sym::crate_type) { - self.sess.psess.buffer_lint( - rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - attr.span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::CrateTypeInCfgAttr, - ); + self.sess.dcx().emit_err(CrateTypeInCfgAttr { span: attr.span }); } if attr.has_name(sym::crate_name) { - self.sess.psess.buffer_lint( - rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - attr.span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::CrateNameInCfgAttr, - ); + self.sess.dcx().emit_err(CrateNameInCfgAttr { span: attr.span }); } attr } @@ -449,7 +442,7 @@ impl<'a> StripUnconfigured<'a> { } } -pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> { +pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> { let span = meta_item.span; match meta_item.meta_item_list() { None => { @@ -464,7 +457,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() }); None } - Some([single]) => match single.meta_item() { + Some([single]) => match single.meta_item_or_bool() { Some(meta_item) => Some(meta_item), None => { sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() }); diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 0fdccb08918..5682c574552 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -468,6 +468,20 @@ pub(crate) struct GlobDelegationOutsideImpls { } #[derive(Diagnostic)] +#[diag(expand_crate_name_in_cfg_attr)] +pub(crate) struct CrateNameInCfgAttr { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(expand_crate_type_in_cfg_attr)] +pub(crate) struct CrateTypeInCfgAttr { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(expand_glob_delegation_traitless_qpath)] pub(crate) struct GlobDelegationTraitlessQpath { #[primary_span] diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 079dcee99d3..a872b12e744 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -11,7 +11,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind, - HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem, + HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, }; use rustc_ast_pretty::pprust; @@ -1863,8 +1863,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .iter() .filter(|a| a.has_name(sym::derive)) .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .filter_map(|nested_meta| match nested_meta { - NestedMetaItem::MetaItem(ast::MetaItem { + .filter_map(|meta_item_inner| match meta_item_inner { + MetaItemInner::MetaItem(ast::MetaItem { kind: MetaItemKind::Word, path, .. diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 0cd0963d4e3..cba4535156b 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -154,6 +154,10 @@ declare_features! ( /// then removed. But there was no utility storing it separately, so now /// it's in this list. (removed, no_stack_check, "1.0.0", None, None), + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible (object safe). + /// Renamed to `dyn_compatible_for_dispatch`. + (removed, object_safe_for_dispatch, "CURRENT_RUSTC_VERSION", Some(43561), + Some("renamed to `dyn_compatible_for_dispatch`")), /// Allows using `#[on_unimplemented(..)]` on traits. /// (Moved to `rustc_attrs`.) (removed, on_unimplemented, "1.40.0", None, None), @@ -216,6 +220,8 @@ declare_features! ( (removed, test_removed_feature, "1.0.0", None, None), /// Allows using items which are missing stability attributes (removed, unmarked_api, "1.0.0", None, None), + /// Allows unnamed fields of struct and union type + (removed, unnamed_fields, "CURRENT_RUSTC_VERSION", Some(49804), Some("feature needs redesign")), (removed, unsafe_no_drop_flag, "1.0.0", None, None), /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue. (removed, untagged_unions, "1.13.0", Some(55149), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c5530097e96..c0398db9c10 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -259,6 +259,14 @@ declare_features! ( (unstable, doc_notable_trait, "1.52.0", Some(45040)), /// Allows using the `may_dangle` attribute (RFC 1327). (unstable, dropck_eyepatch, "1.10.0", Some(34761)), + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1]. + /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and + /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. + /// + /// Renamed from `object_safe_for_dispatch`. + /// + /// [^1]: Formerly known as "object safe". + (unstable, dyn_compatible_for_dispatch, "CURRENT_RUSTC_VERSION", Some(43561)), /// Allows using the `#[fundamental]` attribute. (unstable, fundamental, "1.0.0", Some(29635)), /// Allows using `#[link_name="llvm.*"]`. @@ -371,6 +379,8 @@ declare_features! ( (unstable, async_for_loop, "1.77.0", Some(118898)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), + /// Allows the use of `#[cfg(<true/false>)]`. + (unstable, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. (unstable, cfg_overflow_checks, "1.71.0", Some(111466)), /// Provides the relocation model information as cfg entry @@ -544,13 +554,6 @@ declare_features! ( (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)), /// Allows `for<T>` binders in where-clauses (incomplete, non_lifetime_binders, "1.69.0", Some(108185)), - /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1]. - /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and - /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. - /// - /// [^1]: Formerly known as "object safe". - // FIXME(dyn_compat_renaming): Rename feature. - (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)), /// Allows using enums in offset_of! (unstable, offset_of_enum, "1.75.0", Some(120141)), /// Allows using fields with slice type in offset_of! @@ -563,6 +566,8 @@ declare_features! ( (incomplete, pin_ergonomics, "CURRENT_RUSTC_VERSION", Some(130494)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), + /// Allows `use<..>` precise capturign on impl Trait in traits. + (unstable, precise_capturing_in_traits, "CURRENT_RUSTC_VERSION", Some(130044)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. @@ -618,8 +623,6 @@ declare_features! ( /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), - /// Allows unnamed fields of struct and union type - (incomplete, unnamed_fields, "1.74.0", Some(49804)), /// Allows const generic parameters to be defined with types that /// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`. (incomplete, unsized_const_params, "1.82.0", Some(95174)), diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 80813af3864..4e9d21c900d 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -76,10 +76,14 @@ pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<Li } } -#[cfg(unix)] +#[cfg(any(unix, all(target_os = "wasi", target_env = "p1")))] pub fn path_to_c_string(p: &Path) -> CString { use std::ffi::OsStr; + #[cfg(unix)] use std::os::unix::ffi::OsStrExt; + #[cfg(all(target_os = "wasi", target_env = "p1"))] + use std::os::wasi::ffi::OsStrExt; + let p: &OsStr = p.as_ref(); CString::new(p.as_bytes()).unwrap() } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f58ec22aea9..2ef6fa53f4e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2749,6 +2749,8 @@ pub struct BareFnTy<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct OpaqueTy<'hir> { + pub hir_id: HirId, + pub def_id: LocalDefId, pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, pub origin: OpaqueTyOrigin, @@ -2762,6 +2764,7 @@ pub struct OpaqueTy<'hir> { /// This mapping associated a captured lifetime (first parameter) with the new /// early-bound lifetime that was generated for the opaque. pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)], + pub span: Span, } #[derive(Debug, Clone, Copy, HashStable_Generic)] @@ -2868,7 +2871,7 @@ pub enum TyKind<'hir> { /// possibly parameters) that are actually bound on the `impl Trait`. /// /// The last parameter specifies whether this opaque appears in a trait definition. - OpaqueDef(ItemId, &'hir [GenericArg<'hir>]), + OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject( @@ -3337,8 +3340,6 @@ impl<'hir> Item<'hir> { expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>), ItemKind::TyAlias(ty, generics), (ty, generics); - expect_opaque_ty, &OpaqueTy<'hir>, ItemKind::OpaqueTy(ty), ty; - expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics); expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>), @@ -3451,8 +3452,6 @@ pub enum ItemKind<'hir> { GlobalAsm(&'hir InlineAsm<'hir>), /// A type alias, e.g., `type Foo = Bar<u8>`. TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>), - /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. - OpaqueTy(&'hir OpaqueTy<'hir>), /// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`. Enum(EnumDef<'hir>, &'hir Generics<'hir>), /// A struct definition, e.g., `struct Foo<A> {x: A}`. @@ -3496,7 +3495,6 @@ impl ItemKind<'_> { ItemKind::Fn(_, ref generics, _) | ItemKind::TyAlias(_, ref generics) | ItemKind::Const(_, ref generics, _) - | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) @@ -3519,7 +3517,6 @@ impl ItemKind<'_> { ItemKind::ForeignMod { .. } => "extern block", ItemKind::GlobalAsm(..) => "global asm item", ItemKind::TyAlias(..) => "type alias", - ItemKind::OpaqueTy(..) => "opaque type", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", @@ -3806,6 +3803,7 @@ pub enum Node<'hir> { Ty(&'hir Ty<'hir>), AssocItemConstraint(&'hir AssocItemConstraint<'hir>), TraitRef(&'hir TraitRef<'hir>), + OpaqueTy(&'hir OpaqueTy<'hir>), Pat(&'hir Pat<'hir>), PatField(&'hir PatField<'hir>), Arm(&'hir Arm<'hir>), @@ -3871,6 +3869,7 @@ impl<'hir> Node<'hir> { | Node::Crate(..) | Node::Ty(..) | Node::TraitRef(..) + | Node::OpaqueTy(..) | Node::Infer(..) | Node::WhereBoundPredicate(..) | Node::ArrayLenInfer(..) @@ -3996,6 +3995,7 @@ impl<'hir> Node<'hir> { | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), Node::Item(item) => item.kind.generics(), + Node::OpaqueTy(opaque) => Some(opaque.generics), _ => None, } } @@ -4055,6 +4055,7 @@ impl<'hir> Node<'hir> { expect_ty, &'hir Ty<'hir>, Node::Ty(n), n; expect_assoc_item_constraint, &'hir AssocItemConstraint<'hir>, Node::AssocItemConstraint(n), n; expect_trait_ref, &'hir TraitRef<'hir>, Node::TraitRef(n), n; + expect_opaque_ty, &'hir OpaqueTy<'hir>, Node::OpaqueTy(n), n; expect_pat, &'hir Pat<'hir>, Node::Pat(n), n; expect_pat_field, &'hir PatField<'hir>, Node::PatField(n), n; expect_arm, &'hir Arm<'hir>, Node::Arm(n), n; diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index d0a8aaa85bb..58916d05865 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -111,6 +111,7 @@ impl<'a> FnKind<'a> { pub trait Map<'hir> { /// Retrieves the `Node` corresponding to `id`. fn hir_node(&self, hir_id: HirId) -> Node<'hir>; + fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir>; fn body(&self, id: BodyId) -> &'hir Body<'hir>; fn item(&self, id: ItemId) -> &'hir Item<'hir>; fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>; @@ -123,6 +124,9 @@ impl<'hir> Map<'hir> for ! { fn hir_node(&self, _: HirId) -> Node<'hir> { *self; } + fn hir_node_by_def_id(&self, _: LocalDefId) -> Node<'hir> { + *self; + } fn body(&self, _: BodyId) -> &'hir Body<'hir> { *self; } @@ -423,6 +427,9 @@ pub trait Visitor<'v>: Sized { fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result { walk_poly_trait_ref(self, t) } + fn visit_opaque_ty(&mut self, opaque: &'v OpaqueTy<'v>) -> Self::Result { + walk_opaque_ty(self, opaque) + } fn visit_variant_data(&mut self, s: &'v VariantData<'v>) -> Self::Result { walk_struct_def(self, s) } @@ -536,11 +543,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_generics(generics)); } - ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => { - try_visit!(visitor.visit_id(item.hir_id())); - try_visit!(walk_generics(visitor, generics)); - walk_list!(visitor, visit_param_bound, bounds); - } ItemKind::Enum(ref enum_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`. @@ -894,8 +896,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul TyKind::Path(ref qpath) => { try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); } - TyKind::OpaqueDef(item_id, lifetimes) => { - try_visit!(visitor.visit_nested_item(item_id)); + TyKind::OpaqueDef(opaque, lifetimes) => { + try_visit!(visitor.visit_opaque_ty(opaque)); walk_list!(visitor, visit_generic_arg, lifetimes); } TyKind::Array(ref ty, ref length) => { @@ -1185,6 +1187,15 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( visitor.visit_trait_ref(&trait_ref.trait_ref) } +pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result { + let &OpaqueTy { hir_id, def_id: _, generics, bounds, origin: _, lifetime_mapping: _, span: _ } = + opaque; + try_visit!(visitor.visit_id(hir_id)); + try_visit!(walk_generics(visitor, generics)); + walk_list!(visitor, visit_param_bound, bounds); + V::Result::output() +} + pub fn walk_struct_def<'v, V: Visitor<'v>>( visitor: &mut V, struct_definition: &'v VariantData<'v>, diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index c1a4a4497c7..381062b1429 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -33,6 +33,7 @@ pub mod weak_lang_items; #[cfg(test)] mod tests; +#[doc(no_inline)] pub use hir::*; pub use hir_id::*; pub use lang_items::{LangItem, LanguageItems}; diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 155270ca6a7..6ff57396b4a 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -34,7 +34,6 @@ pub enum Target { ForeignMod, GlobalAsm, TyAlias, - OpaqueTy, Enum, Variant, Struct, @@ -79,7 +78,6 @@ impl Target { | Target::ForeignMod | Target::GlobalAsm | Target::TyAlias - | Target::OpaqueTy | Target::Enum | Target::Variant | Target::Struct @@ -114,7 +112,6 @@ impl Target { ItemKind::ForeignMod { .. } => Target::ForeignMod, ItemKind::GlobalAsm(..) => Target::GlobalAsm, ItemKind::TyAlias(..) => Target::TyAlias, - ItemKind::OpaqueTy(..) => Target::OpaqueTy, ItemKind::Enum(..) => Target::Enum, ItemKind::Struct(..) => Target::Struct, ItemKind::Union(..) => Target::Union, @@ -137,7 +134,6 @@ impl Target { DefKind::ForeignMod => Target::ForeignMod, DefKind::GlobalAsm => Target::GlobalAsm, DefKind::TyAlias => Target::TyAlias, - DefKind::OpaqueTy => Target::OpaqueTy, DefKind::Enum => Target::Enum, DefKind::Struct => Target::Struct, DefKind::Union => Target::Union, @@ -191,7 +187,6 @@ impl Target { Target::ForeignMod => "foreign module", Target::GlobalAsm => "global asm", Target::TyAlias => "type alias", - Target::OpaqueTy => "opaque type", Target::Enum => "enum", Target::Variant => "enum variant", Target::Struct => "struct", diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index c73826c489f..da814cd2d69 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -248,8 +248,6 @@ hir_analysis_invalid_union_field = hir_analysis_invalid_union_field_sugg = wrap the field type in `ManuallyDrop<...>` -hir_analysis_invalid_unnamed_field_ty = unnamed fields can only have struct or union types - hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl .label = const parameter declared here @@ -259,6 +257,9 @@ hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetim hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl .label = type parameter declared here +hir_analysis_lifetime_implicitly_captured = `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list + .param_label = all lifetime parameters originating from a trait are captured implicitly + hir_analysis_lifetime_must_be_first = lifetime parameter `{$name}` must be listed before non-lifetime parameters .label = move the lifetime before this parameter @@ -535,19 +536,6 @@ hir_analysis_unconstrained_generic_parameter = the {$param_def_kind} `{$param_na hir_analysis_unconstrained_opaque_type = unconstrained opaque type .note = `{$name}` must be used in combination with a concrete type within the same {$what} -hir_analysis_unnamed_fields_repr_field_defined = unnamed field defined here - -hir_analysis_unnamed_fields_repr_field_missing_repr_c = - named type of unnamed field must have `#[repr(C)]` representation - .label = unnamed field defined here - .field_ty_label = `{$field_ty}` defined here - .suggestion = add `#[repr(C)]` to this {$field_adt_kind} - -hir_analysis_unnamed_fields_repr_missing_repr_c = - {$adt_kind} with unnamed fields must have `#[repr(C)]` representation - .label = {$adt_kind} `{$adt_name}` defined here - .suggestion = add `#[repr(C)]` to this {$adt_kind} - hir_analysis_unrecognized_atomic_operation = unrecognized atomic operation function: `{$op}` .label = unrecognized atomic operation diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 312212232bc..4429f6346e8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -8,7 +8,9 @@ use rustc_hir::Node; use rustc_hir::def::{CtorKind, DefKind}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; -use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; +use rustc_lint_defs::builtin::{ + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, +}; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; @@ -52,16 +54,18 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { }); } } +} - // This ABI is only allowed on function pointers - if abi == Abi::CCmseNonSecureCall { - struct_span_code_err!( - tcx.dcx(), - span, - E0781, - "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" - ) - .emit(); +pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { + match tcx.sess.target.is_abi_supported(abi) { + Some(true) => (), + Some(false) | None => { + tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| { + lint.primary_message( + "use of calling convention not supported on this target on function pointer", + ); + }); + } } } @@ -76,7 +80,6 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_transparent(tcx, def); check_packed(tcx, span, def); - check_unnamed_fields(tcx, def); } fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { @@ -86,61 +89,6 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_transparent(tcx, def); check_union_fields(tcx, span, def_id); check_packed(tcx, span, def); - check_unnamed_fields(tcx, def); -} - -/// Check the representation of adts with unnamed fields. -fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) { - if def.is_enum() { - return; - } - let variant = def.non_enum_variant(); - if !variant.has_unnamed_fields() { - return; - } - if !def.is_anonymous() { - let adt_kind = def.descr(); - let span = tcx.def_span(def.did()); - let unnamed_fields = variant - .fields - .iter() - .filter(|f| f.is_unnamed()) - .map(|f| { - let span = tcx.def_span(f.did); - errors::UnnamedFieldsReprFieldDefined { span } - }) - .collect::<Vec<_>>(); - debug_assert_ne!(unnamed_fields.len(), 0, "expect unnamed fields in this adt"); - let adt_name = tcx.item_name(def.did()); - if !def.repr().c() { - tcx.dcx().emit_err(errors::UnnamedFieldsRepr::MissingReprC { - span, - adt_kind, - adt_name, - unnamed_fields, - sugg_span: span.shrink_to_lo(), - }); - } - } - for field in variant.fields.iter().filter(|f| f.is_unnamed()) { - let field_ty = tcx.type_of(field.did).instantiate_identity(); - if let Some(adt) = field_ty.ty_adt_def() - && !adt.is_enum() - { - if !adt.is_anonymous() && !adt.repr().c() { - let field_ty_span = tcx.def_span(adt.did()); - tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC { - span: tcx.def_span(field.did), - field_ty_span, - field_ty, - field_adt_kind: adt.descr(), - sugg_span: field_ty_span.shrink_to_lo(), - }); - } - } else { - tcx.dcx().emit_err(errors::InvalidUnnamedFieldTy { span: tcx.def_span(field.did) }); - } - } } /// Check that the fields of the `union` do not need dropping. @@ -252,10 +200,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` /// projections that would result in "inheriting lifetimes". fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else { - tcx.dcx().span_bug(item.span, "expected opaque item"); - }; + let hir::OpaqueTy { origin, .. } = tcx.hir().expect_opaque_ty(def_id); // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting // `async-std` (and `pub async fn` in general). @@ -265,16 +210,16 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } - let span = tcx.def_span(item.owner_id.def_id); + let span = tcx.def_span(def_id); - if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() { + if tcx.type_of(def_id).instantiate_identity().references_error() { return; } - if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() { + if check_opaque_for_cycles(tcx, def_id, span).is_err() { return; } - let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, origin); + let _ = check_opaque_meets_bounds(tcx, def_id, span, origin); } /// Checks that an opaque type does not contain cycles. @@ -481,8 +426,7 @@ fn sanity_check_found_hidden_type<'tcx>( /// 2. Checking that all lifetimes that are implicitly captured are mentioned. /// 3. Asserting that all parameters mentioned in the captures list are invariant. fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) { - let hir::OpaqueTy { bounds, .. } = - *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty(); let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound { hir::GenericBound::Use(bounds, ..) => Some(bounds), _ => None, @@ -593,15 +537,22 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe param_span: tcx.def_span(def_id), }); } else { - // If the `use_span` is actually just the param itself, then we must - // have not duplicated the lifetime but captured the original. - // The "effective" `use_span` will be the span of the opaque itself, - // and the param span will be the def span of the param. - tcx.dcx().emit_err(errors::LifetimeNotCaptured { - opaque_span, - use_span: opaque_span, - param_span: use_span, - }); + if tcx.def_kind(tcx.parent(param.def_id)) == DefKind::Trait { + tcx.dcx().emit_err(errors::LifetimeImplicitlyCaptured { + opaque_span, + param_span: tcx.def_span(param.def_id), + }); + } else { + // If the `use_span` is actually just the param itself, then we must + // have not duplicated the lifetime but captured the original. + // The "effective" `use_span` will be the span of the opaque itself, + // and the param span will be the def span of the param. + tcx.dcx().emit_err(errors::LifetimeNotCaptured { + opaque_span, + use_span: opaque_span, + param_span: use_span, + }); + } } continue; } @@ -1105,7 +1056,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { // Check that we use types valid for use in the lanes of a SIMD "vector register" // These are scalar types which directly match a "machine" type // Yes: Integers, floats, "thin" pointers - // No: char, "fat" pointers, compound types + // No: char, "wide" pointers, compound types match element_ty.kind() { ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 35c2b7e7ce2..2d6b9813271 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -64,6 +64,10 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( return; }; + if hidden_tys.items().any(|(_, &ty)| ty.skip_binder().references_error()) { + return; + } + let mut collector = ImplTraitInTraitCollector { tcx, types: FxIndexSet::default() }; trait_m_sig.visit_with(&mut collector); @@ -93,7 +97,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( // it's a refinement to a TAIT. if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| { matches!( - node.expect_item().expect_opaque_ty().origin, + node.expect_opaque_ty().origin, hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::FnReturn { parent, .. } if parent == impl_m.def_id.expect_local() ) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 25e219ef3f2..06317a3b304 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -357,6 +357,19 @@ pub fn check_intrinsic_type( (0, 0, vec![tcx.types.f128, tcx.types.f128, tcx.types.f128], tcx.types.f128) } + sym::fmuladdf16 => { + (0, 0, vec![tcx.types.f16, tcx.types.f16, tcx.types.f16], tcx.types.f16) + } + sym::fmuladdf32 => { + (0, 0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32) + } + sym::fmuladdf64 => { + (0, 0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64) + } + sym::fmuladdf128 => { + (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), diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index d3d88919d87..004540b2643 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -73,7 +73,7 @@ pub mod wfcheck; use std::num::NonZero; -pub use check::check_abi; +pub use check::{check_abi, check_abi_fn_ptr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 02d23b95d46..3a9d2640eee 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -185,15 +185,16 @@ where } } -fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> { - let node = tcx.hir_owner_node(def_id); +fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { + let node = tcx.hir_node_by_def_id(def_id); let mut res = match node { - hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), - hir::OwnerNode::Item(item) => check_item(tcx, item), - hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item), - hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item), - hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item), - hir::OwnerNode::Synthetic => unreachable!(), + hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), + hir::Node::Item(item) => check_item(tcx, item), + hir::Node::TraitItem(item) => check_trait_item(tcx, item), + hir::Node::ImplItem(item) => check_impl_item(tcx, item), + hir::Node::ForeignItem(item) => check_foreign_item(tcx, item), + hir::Node::OpaqueTy(_) => Ok(crate::check::check::check_item_type(tcx, def_id)), + _ => unreachable!(), }; if let Some(generics) = node.generics() { @@ -201,6 +202,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorG res = res.and(check_param_wf(tcx, param)); } } + res } @@ -2172,10 +2174,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_module_items(module); - let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id))); - res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id))); - res = res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)); + res = + res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); + res = + res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); + res = res + .and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); + res = res.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item))); if module == LocalModDefId::CRATE_DEF_ID { super::entry::check_for_entry_fn(tcx); } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index bea8d28a9f7..76c75d976ee 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -424,7 +424,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( // Here `U = [i32; 3]` and `V = [i32]`. At runtime, // when this coercion occurs, we would be changing the // field `ptr` from a thin pointer of type `*mut [i32; - // 3]` to a fat pointer of type `*mut [i32]` (with + // 3]` to a wide pointer of type `*mut [i32]` (with // extra data `3`). **The purpose of this check is to // make sure that we know how to do this conversion.** // diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 69d36426447..eea5a16ac6f 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -199,7 +199,7 @@ fn check_object_overlap<'tcx>( for component_def_id in component_def_ids { if !tcx.is_dyn_compatible(component_def_id) { // FIXME(dyn_compat_renaming): Rename test and update comment. - // Without the 'object_safe_for_dispatch' feature this is an error + // Without the 'dyn_compatible_for_dispatch' feature this is an error // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. // With the feature enabled, the trait is not implemented automatically, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 93b021be245..f63e2d40e39 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -260,8 +260,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( | hir::ItemKind::Trait(_, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Struct(_, generics) => (generics, true), - hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }) - | hir::ItemKind::TyAlias(_, generics) => (generics, false), + hir::ItemKind::TyAlias(_, generics) => (generics, false), // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type. _ => return, }; @@ -328,6 +327,19 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { intravisit::walk_expr(self, expr); } + /// Don't call `type_of` on opaque types, since that depends on type checking function bodies. + /// `check_item_type` ensures that it's called instead. + fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) { + let def_id = opaque.def_id; + self.tcx.ensure().generics_of(def_id); + self.tcx.ensure().predicates_of(def_id); + self.tcx.ensure().explicit_item_bounds(def_id); + self.tcx.ensure().explicit_item_super_predicates(def_id); + self.tcx.ensure().item_bounds(def_id); + self.tcx.ensure().item_super_predicates(def_id); + intravisit::walk_opaque_ty(self, opaque); + } + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { lower_trait_item(self.tcx, trait_item.trait_item_id()); intravisit::walk_trait_item(self, trait_item); @@ -731,18 +743,6 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } } - // Don't call `type_of` on opaque types, since that depends on type - // checking function bodies. `check_item_type` ensures that it's called - // instead. - hir::ItemKind::OpaqueTy(..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().predicates_of(def_id); - tcx.ensure().explicit_item_bounds(def_id); - tcx.ensure().explicit_item_super_predicates(def_id); - tcx.ensure().item_bounds(def_id); - tcx.ensure().item_super_predicates(def_id); - } - hir::ItemKind::TyAlias(..) => { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); @@ -1007,79 +1007,6 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> { } } } - - /// Check the uniqueness of fields across adt where there are - /// nested fields imported from an unnamed field. - fn check_field_in_nested_adt(&mut self, adt_def: ty::AdtDef<'_>, unnamed_field_span: Span) { - for field in adt_def.all_fields() { - if field.is_unnamed() { - // Here we don't care about the generic parameters, so `instantiate_identity` is enough. - match self.tcx.type_of(field.did).instantiate_identity().kind() { - ty::Adt(adt_def, _) => { - self.check_field_in_nested_adt(*adt_def, unnamed_field_span); - } - ty_kind => span_bug!( - self.tcx.def_span(field.did), - "Unexpected TyKind in FieldUniquenessCheckContext::check_field_in_nested_adt(): {ty_kind:?}" - ), - } - } else { - self.check_field_decl( - field.ident(self.tcx), - NestedSpan { - span: unnamed_field_span, - nested_field_span: self.tcx.def_span(field.did), - } - .into(), - ); - } - } - } - - /// Check the uniqueness of fields in a struct variant, and recursively - /// check the nested fields if it is an unnamed field with type of an - /// anonymous adt. - fn check_field(&mut self, field: &hir::FieldDef<'_>) { - if field.ident.name != kw::Underscore { - self.check_field_decl(field.ident, field.span.into()); - return; - } - match &field.ty.kind { - hir::TyKind::AnonAdt(item_id) => { - match &self.tcx.hir_node(item_id.hir_id()).expect_item().kind { - hir::ItemKind::Struct(variant_data, ..) - | hir::ItemKind::Union(variant_data, ..) => { - variant_data.fields().iter().for_each(|f| self.check_field(f)); - } - item_kind => span_bug!( - field.ty.span, - "Unexpected ItemKind in FieldUniquenessCheckContext::check_field(): {item_kind:?}" - ), - } - } - hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => { - // If this is a direct path to an ADT, we can check it - // If this is a type alias or non-ADT, `check_unnamed_fields` should verify it - if let Some(def_id) = res.opt_def_id() - && let Some(local) = def_id.as_local() - && let Node::Item(item) = self.tcx.hir_node_by_def_id(local) - && item.is_adt() - { - self.check_field_in_nested_adt(self.tcx.adt_def(def_id), field.span); - } - } - // Abort due to errors (there must be an error if an unnamed field - // has any type kind other than an anonymous adt or a named adt) - ty_kind => { - self.tcx.dcx().span_delayed_bug( - field.ty.span, - format!("Unexpected TyKind in FieldUniquenessCheckContext::check_field(): {ty_kind:?}"), - ); - // FIXME: errors during AST validation should abort the compilation before reaching here. - self.tcx.dcx().abort_if_errors(); - } - } - } } fn lower_variant( @@ -1090,20 +1017,13 @@ fn lower_variant( def: &hir::VariantData<'_>, adt_kind: ty::AdtKind, parent_did: LocalDefId, - is_anonymous: bool, ) -> ty::VariantDef { - let mut has_unnamed_fields = false; let mut field_uniqueness_check_ctx = FieldUniquenessCheckContext::new(tcx); let fields = def .fields() .iter() - .inspect(|f| { - has_unnamed_fields |= f.ident.name == kw::Underscore; - // We only check named ADT here because anonymous ADTs are checked inside - // the named ADT in which they are defined. - if !is_anonymous { - field_uniqueness_check_ctx.check_field(f); - } + .inspect(|field| { + field_uniqueness_check_ctx.check_field_decl(field.ident, field.span.into()); }) .map(|f| ty::FieldDef { did: f.def_id.to_def_id(), @@ -1127,7 +1047,6 @@ fn lower_variant( adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive) || variant_did .is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)), - has_unnamed_fields, ) } @@ -1138,20 +1057,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { bug!("expected ADT to be an item"); }; - let is_anonymous = item.ident.name == kw::Empty; - let repr = if is_anonymous { - let parent = tcx.local_parent(def_id); - if let Node::Item(item) = tcx.hir_node_by_def_id(parent) - && item.is_struct_or_union() - { - tcx.adt_def(parent).repr() - } else { - tcx.dcx().span_delayed_bug(item.span, "anonymous field inside non struct/union"); - ty::ReprOptions::default() - } - } else { - tcx.repr_options_of_def(def_id) - }; + let repr = tcx.repr_options_of_def(def_id); let (kind, variants) = match &item.kind { ItemKind::Enum(def, _) => { let mut distance_from_explicit = 0; @@ -1175,7 +1081,6 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { &v.data, AdtKind::Enum, def_id, - is_anonymous, ) }) .collect(); @@ -1195,7 +1100,6 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { def, adt_kind, def_id, - is_anonymous, )) .collect(); @@ -1203,7 +1107,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { } _ => bug!("{:?} is not an ADT", item.owner_id.def_id), }; - tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous) + tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr) } fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { @@ -1852,12 +1756,8 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId { } fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { - match tcx.hir_node_by_def_id(def_id) { - Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => { - matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }) - } - _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), - } + let opaque = tcx.hir().expect_opaque_ty(def_id); + matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }) } fn rendered_precise_capturing_args<'tcx>( @@ -1870,12 +1770,10 @@ fn rendered_precise_capturing_args<'tcx>( return tcx.rendered_precise_capturing_args(opaque_def_id); } - tcx.hir_node_by_def_id(def_id).expect_item().expect_opaque_ty().bounds.iter().find_map( - |bound| match bound { - hir::GenericBound::Use(args, ..) => { - Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name()))) - } - _ => None, - }, - ) + tcx.hir_node_by_def_id(def_id).expect_opaque_ty().bounds.iter().find_map(|bound| match bound { + hir::GenericBound::Use(args, ..) => { + Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name()))) + } + _ => None, + }) } diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index d76d9213129..8648a7d1e32 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,4 +1,3 @@ -use rustc_hir::def::DefKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::intravisit; use rustc_middle::hir::nested_filter::OnlyBodies; @@ -10,12 +9,10 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { return; } - for id in tcx.hir().items() { - let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; - - let ty = tcx.type_of(id.owner_id).instantiate_identity(); - - tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty }); + for id in tcx.hir_crate_items(()).opaques() { + let ty = tcx.type_of(id).instantiate_identity(); + let span = tcx.def_span(id); + tcx.dcx().emit_err(crate::errors::TypeOf { span, ty }); } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 8ff9640a874..14b6b17ed18 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -24,6 +24,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = tcx.opt_rpitit_info(def_id.to_def_id()) { + debug!("RPITIT fn_def_id={fn_def_id:?} opaque_def_id={opaque_def_id:?}"); let trait_def_id = tcx.parent(fn_def_id); let opaque_ty_generics = tcx.generics_of(opaque_def_id); let opaque_ty_parent_count = opaque_ty_generics.parent_count; @@ -207,36 +208,33 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { Some(tcx.typeck_root_def_id(def_id.to_def_id())) } - Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(&hir::OpaqueTy { - origin: - hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl } - | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, - .. - }) => { - if in_trait_or_impl.is_some() { - assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn); - } else { - assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn); - } - Some(fn_def_id.to_def_id()) + Node::OpaqueTy(&hir::OpaqueTy { + origin: + hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, + .. + }) => { + if in_trait_or_impl.is_some() { + assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn); + } else { + assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn); } - ItemKind::OpaqueTy(&hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty }, - .. - }) => { - if in_assoc_ty { - assert_matches!(tcx.def_kind(parent), DefKind::AssocTy); - } else { - assert_matches!(tcx.def_kind(parent), DefKind::TyAlias); - } - 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(fn_def_id.to_def_id()) + } + Node::OpaqueTy(&hir::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty }, + .. + }) => { + if in_assoc_ty { + assert_matches!(tcx.def_kind(parent), DefKind::AssocTy); + } else { + assert_matches!(tcx.def_kind(parent), DefKind::TyAlias); } - _ => None, - }, + 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()) + } _ => None, }; @@ -272,13 +270,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) - | ItemKind::OpaqueTy(..) | ItemKind::Union(..) => (None, Defaults::Allowed), ItemKind::Const(..) => (None, Defaults::Deny), _ => (None, Defaults::FutureCompatDisallowed), } } + Node::OpaqueTy(..) => (None, Defaults::Allowed), + // GATs Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => { (None, Defaults::Deny) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 2418037ae96..4346504450d 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -335,8 +335,7 @@ pub(super) fn explicit_item_bounds_with_filter( // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { - let item = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_item(); - let opaque_ty = item.expect_opaque_ty(); + let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty(); let item_ty = Ty::new_projection_from_args( tcx, def_id.to_def_id(), @@ -347,7 +346,7 @@ pub(super) fn explicit_item_bounds_with_filter( opaque_def_id.expect_local(), opaque_ty.bounds, item_ty, - item.span, + opaque_ty.span, filter, ); assert_only_contains_predicates_from(filter, bounds, item_ty); @@ -369,11 +368,7 @@ pub(super) fn explicit_item_bounds_with_filter( span, .. }) => associated_type_bounds(tcx, def_id, bounds, *span, filter), - hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, origin, .. }), - span, - .. - }) => match origin { + hir::Node::OpaqueTy(hir::OpaqueTy { bounds, origin, span, .. }) => match origin { // Since RPITITs are lowered as projections in `<dyn HirTyLowerer>::lower_ty`, // when we're asking for the item bounds of the *opaques* in a trait's default // method signature, we need to map these projections back to opaques. @@ -412,7 +407,7 @@ pub(super) fn explicit_item_bounds_with_filter( } }, hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], - _ => bug!("item_bounds called on {:?}", def_id), + node => bug!("item_bounds called on {def_id:?} => {node:?}"), }; ty::EarlyBinder::bind(bounds) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 33f6623edfd..6d30f7c7b9d 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -330,7 +330,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // Opaque types duplicate some of their generic parameters. // We create bi-directional Outlives predicates between the original // and the duplicated parameter, to ensure that they do not get out of sync. - if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node { + if let Node::OpaqueTy(..) = node { let opaque_ty_node = tcx.parent_hir_node(hir_id); let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node else { 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 a15621bf28b..c8852a3a369 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -11,10 +11,13 @@ use std::fmt; use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node}; +use rustc_hir::{ + GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node, +}; use rustc_macros::extension; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::*; @@ -74,7 +77,7 @@ impl ResolvedArg { struct NamedVarMap { // maps from every use of a named (not anonymous) bound var to a // `ResolvedArg` describing how that variable is bound - defs: HirIdMap<ResolvedArg>, + defs: ItemLocalMap<ResolvedArg>, // Maps relevant hir items to the bound vars on them. These include: // - function defs @@ -82,7 +85,7 @@ struct NamedVarMap { // - closures // - trait refs // - bound types (like `T` in `for<'a> T<'a>: Foo`) - late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>, + late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>, } struct BoundVarContext<'a, 'tcx> { @@ -225,10 +228,10 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { resolve_bound_vars, - named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id), + named_variable_map: |tcx, id| &tcx.resolve_bound_vars(id).defs, is_late_bound_map, object_lifetime_default, - late_bound_vars_map: |tcx, id| tcx.resolve_bound_vars(id).late_bound_vars.get(&id), + late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars, ..*providers }; @@ -265,16 +268,12 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou hir::OwnerNode::Synthetic => unreachable!(), } - let mut rl = ResolveBoundVars::default(); - - for (hir_id, v) in named_variable_map.defs { - let map = rl.defs.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, v); - } - for (hir_id, v) in named_variable_map.late_bound_vars { - let map = rl.late_bound_vars.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, v); - } + let defs = named_variable_map.defs.into_sorted_stable_ord(); + let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord(); + let rl = ResolveBoundVars { + defs: SortedMap::from_presorted_elements(defs), + late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars), + }; debug!(?rl.defs); debug!(?rl.late_bound_vars); @@ -340,7 +339,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Binder { hir_id, .. } => { // Nested poly trait refs have the binders concatenated let mut full_binders = - self.map.late_bound_vars.entry(*hir_id).or_default().clone(); + self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone(); full_binders.extend(supertrait_bound_vars); break (full_binders, BinderScopeType::Concatenating); } @@ -487,6 +486,31 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] + fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { + // We want to start our early-bound indices at the end of the parent scope, + // not including any parent `impl Trait`s. + let mut bound_vars = FxIndexMap::default(); + debug!(?opaque.generics.params); + for param in opaque.generics.params { + let (def_id, reg) = ResolvedArg::early(param); + bound_vars.insert(def_id, reg); + } + + let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id); + let scope = Scope::Binder { + hir_id, + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: None, + }; + self.with(scope, |this| { + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) + }) + } + + #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { match &item.kind { hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { @@ -513,38 +537,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } - hir::ItemKind::OpaqueTy(&hir::OpaqueTy { - origin: - hir::OpaqueTyOrigin::FnReturn { parent, .. } - | hir::OpaqueTyOrigin::AsyncFn { parent, .. } - | hir::OpaqueTyOrigin::TyAlias { parent, .. }, - generics, - .. - }) => { - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut bound_vars = FxIndexMap::default(); - debug!(?generics.params); - for param in generics.params { - let (def_id, reg) = ResolvedArg::early(param); - bound_vars.insert(def_id, reg); - } - - let scope = Scope::Root { opt_parent_item: Some(parent) }; - self.with(scope, |this| { - let scope = Scope::Binder { - hir_id: item.hir_id(), - bound_vars, - s: this.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: None, - }; - this.with(scope, |this| { - let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| intravisit::walk_item(this, item)) - }); - }) - } hir::ItemKind::TyAlias(_, generics) | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::Enum(_, generics) @@ -684,22 +676,19 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { hir::TyKind::Ref(lifetime_ref, ref mt) => { self.visit_lifetime(lifetime_ref); let scope = Scope::ObjectLifetimeDefault { - lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), + lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(), s: self.scope, }; self.with(scope, |this| this.visit_ty(mt.ty)); } - hir::TyKind::OpaqueDef(item_id, lifetimes) => { + hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { + self.visit_opaque_ty(opaque_ty); + // Resolve the lifetimes in the bounds to the lifetime defs in the generics. // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to // `type MyAnonTy<'b> = impl MyTrait<'b>;` // ^ ^ this gets resolved in the scope of // the opaque_ty generics - let opaque_ty = self.tcx.hir().item(item_id); - match &opaque_ty.kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: _, .. }) => {} - i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), - }; // Resolve the lifetimes that are applied to the opaque type. // These are resolved in the current scope. @@ -714,7 +703,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // and ban them. Type variables instantiated inside binders aren't // well-supported at the moment, so this doesn't work. // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.hir_id).copied(); + let def = self.map.defs.get(&lifetime.hir_id.local_id).copied(); let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue }; let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); @@ -722,9 +711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { { // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque // it must be a reified late-bound lifetime from a trait goal. - hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy { .. }, .. - }) => "higher-ranked lifetime from outer `impl Trait`", + hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`", // Other items are fine. hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => { continue; @@ -740,8 +727,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id) { - let opaque_span = self.tcx.def_span(item_id.owner_id); - (opaque_span, Some(opaque_span)) + (opaque_ty.span, Some(opaque_ty.span)) } else { (lifetime.ident.span, None) }; @@ -854,7 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let bound_vars: Vec<_> = self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect(); let hir_id = self.tcx.local_def_id_to_hir_id(def_id); - self.map.late_bound_vars.insert(hir_id, bound_vars); + self.map.late_bound_vars.insert(hir_id.local_id, bound_vars); } self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure)); intravisit::walk_fn_kind(self, fk); @@ -1032,10 +1018,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) { - if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) { + if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) { bug!( "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}", - self.map.late_bound_vars[&hir_id] + self.map.late_bound_vars[&hir_id.local_id] ) } } @@ -1394,9 +1380,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind.descr(param_def_id.to_def_id()) ), }; - self.map.defs.insert(hir_id, ResolvedArg::Error(guar)); + self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar)); } else { - self.map.defs.insert(hir_id, def); + self.map.defs.insert(hir_id.local_id, def); } return; } @@ -1429,7 +1415,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id())) } }); - self.map.defs.insert(hir_id, ResolvedArg::Error(guar)); + self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar)); return; } Scope::Root { .. } => break, @@ -1539,7 +1525,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // This index can be used with `generic_args` since `parent_count == 0`. let index = generics.param_def_id_to_index[¶m_def_id] as usize; generic_args.args.get(index).and_then(|arg| match arg { - GenericArg::Lifetime(lt) => map.defs.get(<.hir_id).copied(), + GenericArg::Lifetime(lt) => map.defs.get(<.hir_id.local_id).copied(), _ => None, }) } @@ -1829,7 +1815,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) { debug!(span = ?lifetime_ref.ident.span); - self.map.defs.insert(lifetime_ref.hir_id, def); + self.map.defs.insert(lifetime_ref.hir_id.local_id, def); } /// Sometimes we resolve a lifetime, but later find that it is an @@ -1840,8 +1826,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { lifetime_ref: &'tcx hir::Lifetime, bad_def: ResolvedArg, ) { - // FIXME(#120456) - is `swap_remove` correct? - let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id); + let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id); assert_eq!(old_value, Some(bad_def)); } @@ -2011,7 +1996,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`. // And this is exercised in: // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`. - let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap(); + let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap(); let existing_bound_vars_saved = existing_bound_vars.clone(); existing_bound_vars.extend(bound_vars); self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 3af4d1f5eda..470bcaeded1 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -529,10 +529,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_adt(tcx, def, args) } - ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else( - |CyclePlaceholder(guar)| Ty::new_error(tcx, guar), - |ty| ty.instantiate_identity(), - ), ItemKind::Trait(..) | ItemKind::TraitAlias(..) | ItemKind::Macro(..) @@ -545,6 +541,11 @@ 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::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { let args = ty::GenericArgs::identity_for_item(tcx, def_id); @@ -603,42 +604,25 @@ pub(super) fn type_of_opaque( def_id: DefId, ) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> { if let Some(def_id) = def_id.as_local() { - use rustc_hir::*; - - Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) { - Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. }, - .. - }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), - ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. }, - .. - }) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id), - // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(&OpaqueTy { - origin: - hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl } - | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl }, - .. - }) => { - if in_trait_or_impl == Some(hir::RpitContext::Trait) - && !tcx.defaultness(owner).has_value() - { - span_bug!( - tcx.def_span(def_id), - "tried to get type of this RPITIT with no definition" - ); - } - opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) - } - _ => { - span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind); + Ok(ty::EarlyBinder::bind(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, def_id) + } + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => { + opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id) + } + // Opaque types desugared from `impl Trait`. + hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl } + | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => { + if in_trait_or_impl == Some(hir::RpitContext::Trait) + && !tcx.defaultness(owner).has_value() + { + span_bug!( + tcx.def_span(def_id), + "tried to get type of this RPITIT with no definition" + ); } - }, - - x => { - bug!("unexpected sort of node in type_of_opaque(): {:?}", x); + opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) } })) } else { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 4edb68e6199..9099703e812 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -735,13 +735,6 @@ pub(crate) struct InvalidUnionField { } #[derive(Diagnostic)] -#[diag(hir_analysis_invalid_unnamed_field_ty)] -pub(crate) struct InvalidUnnamedFieldTy { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(hir_analysis_return_type_notation_on_non_rpitit)] pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> { #[primary_span] @@ -1599,41 +1592,6 @@ pub(crate) struct UnconstrainedGenericParameter { } #[derive(Diagnostic)] -pub(crate) enum UnnamedFieldsRepr<'a> { - #[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)] - MissingReprC { - #[primary_span] - #[label] - span: Span, - adt_kind: &'static str, - adt_name: Symbol, - #[subdiagnostic] - unnamed_fields: Vec<UnnamedFieldsReprFieldDefined>, - #[suggestion(code = "#[repr(C)]\n")] - sugg_span: Span, - }, - #[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)] - FieldMissingReprC { - #[primary_span] - #[label] - span: Span, - #[label(hir_analysis_field_ty_label)] - field_ty_span: Span, - field_ty: Ty<'a>, - field_adt_kind: &'static str, - #[suggestion(code = "#[repr(C)]\n")] - sugg_span: Span, - }, -} - -#[derive(Subdiagnostic)] -#[note(hir_analysis_unnamed_fields_repr_field_defined)] -pub(crate) struct UnnamedFieldsReprFieldDefined { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(hir_analysis_opaque_captures_higher_ranked_lifetime, code = E0657)] pub(crate) struct OpaqueCapturesHigherRankedLifetime { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs index b6cffb90805..8a83866b7fa 100644 --- a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs +++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs @@ -35,6 +35,15 @@ pub(crate) struct LifetimeNotCaptured { } #[derive(Diagnostic)] +#[diag(hir_analysis_lifetime_implicitly_captured)] +pub(crate) struct LifetimeImplicitlyCaptured { + #[primary_span] + pub opaque_span: Span, + #[label(hir_analysis_param_label)] + pub param_span: Span, +} + +#[derive(Diagnostic)] #[diag(hir_analysis_bad_precise_capture)] pub(crate) struct BadPreciseCapture { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 5150db7f51b..a562759da11 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -1,6 +1,5 @@ -use rustc_errors::DiagCtxtHandle; -use rustc_hir as hir; -use rustc_hir::HirId; +use rustc_errors::{DiagCtxtHandle, E0781, struct_span_code_err}; +use rustc_hir::{self as hir, HirId}; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{self, ParamEnv, TyCtxt}; use rustc_span::Span; @@ -26,7 +25,19 @@ pub(crate) fn validate_cmse_abi<'tcx>( .. }) = hir_node else { - // might happen when this ABI is used incorrectly. That will be handled elsewhere + let span = match tcx.parent_hir_node(hir_id) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::ForeignMod { .. }, span, .. + }) => *span, + _ => tcx.hir().span(hir_id), + }; + struct_span_code_err!( + tcx.dcx(), + span, + E0781, + "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" + ) + .emit(); return; }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index e7b8e6e69b0..394a263fbb5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{ use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations}; +use rustc_type_ir::elaborate::ClauseWithSupertraitSpan; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -124,16 +125,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into_iter() .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); - for (base_trait_ref, span) in regular_traits_refs_spans { + for (base_trait_ref, original_span) in regular_traits_refs_spans { let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx); - for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() { + for ClauseWithSupertraitSpan { pred, original_span, supertrait_span } in + traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)]) + .filter_only_self() + { debug!("observing object predicate `{pred:?}`"); let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { let pred = bound_predicate.rebind(pred); - associated_types.entry(span).or_default().extend( + associated_types.entry(original_span).or_default().extend( tcx.associated_items(pred.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) @@ -172,8 +176,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // the discussion in #56288 for alternatives. if !references_self { // Include projections defined on supertraits. - projection_bounds.push((pred, span)); + projection_bounds.push((pred, original_span)); } + + self.check_elaborated_projection_mentions_input_lifetimes( + pred, + original_span, + supertrait_span, + ); } _ => (), } @@ -360,6 +370,56 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_dynamic(tcx, existential_predicates, region_bound, representation) } + + /// Check that elaborating the principal of a trait ref doesn't lead to projections + /// that are unconstrained. This can happen because an otherwise unconstrained + /// *type variable* can be substituted with a type that has late-bound regions. See + /// `elaborated-predicates-unconstrained-late-bound.rs` for a test. + fn check_elaborated_projection_mentions_input_lifetimes( + &self, + pred: ty::PolyProjectionPredicate<'tcx>, + span: Span, + supertrait_span: Span, + ) { + let tcx = self.tcx(); + + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref or assoc_item. These are not well-formed. + // + // Example: + // + // for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad + // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok + let late_bound_in_projection_term = + tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term)); + let late_bound_in_term = + tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term)); + debug!(?late_bound_in_projection_term); + debug!(?late_bound_in_term); + + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ + // NOTE(associated_const_equality): This error should be impossible to trigger + // with associated const equality constraints. + self.validate_late_bound_regions( + late_bound_in_projection_term, + late_bound_in_term, + |br_name| { + let item_name = tcx.item_name(pred.projection_def_id()); + struct_span_code_err!( + self.dcx(), + span, + E0582, + "binding for associated type `{}` references {}, \ + which does not appear in the trait input types", + item_name, + br_name + ) + .with_span_label(supertrait_span, "due to this supertrait") + }, + ); + } } fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index a70f881f5fe..11c0450bfe2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -1,6 +1,6 @@ use rustc_ast::TraitObjectSyntax; use rustc_errors::codes::*; -use rustc_errors::{Diag, EmissionGuarantee, StashKey}; +use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::Applicability; @@ -15,13 +15,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`. /// In edition 2021 and onward we emit a hard error for them. - pub(super) fn prohibit_or_lint_bare_trait_object_ty(&self, self_ty: &hir::Ty<'_>) { + pub(super) fn prohibit_or_lint_bare_trait_object_ty( + &self, + self_ty: &hir::Ty<'_>, + ) -> Option<ErrorGuaranteed> { let tcx = self.tcx(); let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = self_ty.kind else { - return; + return None; }; let in_path = match tcx.parent_hir_node(self_ty.hir_id) { @@ -70,8 +73,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } if self_ty.span.edition().at_least_rust_2021() { - let msg = "trait objects must include the `dyn` keyword"; - let label = "add `dyn` keyword before this trait"; + let msg = "expected a type, found a trait"; + let label = "you can add the `dyn` keyword if you want a trait object"; let mut diag = rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg); if self_ty.span.can_be_used_for_suggestions() @@ -83,7 +86,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Check if the impl trait that we are considering is an impl of a local trait. self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag); self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag); - diag.stash(self_ty.span, StashKey::TraitMissingMethod); + // In case there is an associate type with the same name + // Add the suggestion to this error + if let Some(mut sugg) = + tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion) + && let Suggestions::Enabled(ref mut s1) = diag.suggestions + && let Suggestions::Enabled(ref mut s2) = sugg.suggestions + { + s1.append(s2); + sugg.cancel(); + } + diag.stash(self_ty.span, StashKey::TraitMissingMethod) } else { tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, |lint| { lint.primary_message("trait objects without an explicit `dyn` are deprecated"); @@ -96,6 +109,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } self.maybe_suggest_blanket_trait_impl(self_ty, lint); }); + None } } @@ -108,17 +122,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; if let hir::Node::Item(hir::Item { - kind: - hir::ItemKind::Impl(hir::Impl { - self_ty: impl_self_ty, - of_trait: Some(of_trait_ref), - generics, - .. - }), + kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }), .. }) = tcx.hir_node_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id { + let Some(of_trait_ref) = of_trait else { + diag.span_suggestion_verbose( + impl_self_ty.span.shrink_to_hi(), + "you might have intended to implement this trait for a given type", + format!(" for /* Type */"), + Applicability::HasPlaceholders, + ); + return; + }; if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { return; } @@ -171,41 +188,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // 1. Independent functions // 2. Functions inside trait blocks // 3. Functions inside impl blocks - let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) { + let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => { - (sig, generics, None) + (sig, generics) } hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(sig, _), generics, - owner_id, .. - }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))), + }) => (sig, generics), hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(sig, _), generics, - owner_id, .. - }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))), + }) => (sig, generics), _ => return false, }; let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return false; }; let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())]; - let mut is_downgradable = true; - // Check if trait object is safe for suggesting dynamic dispatch. let is_dyn_compatible = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { objects.iter().all(|(o, _)| match o.trait_ref.path.res { - Res::Def(DefKind::Trait, id) => { - if Some(id) == owner { - // For recursive traits, don't downgrade the error. (#119652) - is_downgradable = false; - } - tcx.is_dyn_compatible(id) - } + Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id), _ => false, }) } @@ -252,9 +259,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { suggestion, Applicability::MachineApplicable, ); - } else if is_downgradable { - // We'll emit the dyn-compatibility error already, with a structured suggestion. - diag.downgrade_to_delayed_bug(); } return true; } @@ -278,10 +282,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); if !is_dyn_compatible { diag.note(format!("`{trait_name}` it is dyn-incompatible, so it can't be `dyn`")); - if is_downgradable { - // We'll emit the dyn-compatibility error already, with a structured suggestion. - diag.downgrade_to_delayed_bug(); - } } else { // No ampersand in suggestion if it's borrowed already let (dyn_str, paren_dyn_str) = 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 95f83836d75..d760acf53bd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -53,6 +53,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::{debug, debug_span, instrument}; use crate::bounds::Bounds; +use crate::check::check_abi_fn_ptr; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; @@ -2063,13 +2064,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) } hir::TyKind::TraitObject(bounds, lifetime, repr) => { - self.prohibit_or_lint_bare_trait_object_ty(hir_ty); - - let repr = match repr { - TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, - TraitObjectSyntax::DynStar => ty::DynStar, - }; - self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr) + if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) { + // Don't continue with type analysis if the `dyn` keyword is missing + // It generates confusing errors, especially if the user meant to use another + // keyword like `impl` + Ty::new_error(tcx, guar) + } else { + let repr = match repr { + TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, + TraitObjectSyntax::DynStar => ty::DynStar, + }; + self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr) + } } // If we encounter a fully qualified path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore @@ -2087,43 +2093,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_path(opt_self_ty, path, hir_ty.hir_id, false) } - &hir::TyKind::OpaqueDef(item_id, lifetimes) => { - let opaque_ty = tcx.hir().item(item_id); - - match opaque_ty.kind { - hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => { - let local_def_id = item_id.owner_id.def_id; - // If this is an RPITIT and we are using the new RPITIT lowering scheme, we - // generate the def_id of an associated type for the trait and return as - // type a projection. - match origin { - hir::OpaqueTyOrigin::FnReturn { - in_trait_or_impl: Some(hir::RpitContext::Trait), - .. - } - | hir::OpaqueTyOrigin::AsyncFn { - in_trait_or_impl: Some(hir::RpitContext::Trait), - .. - } => self.lower_opaque_ty( - tcx.associated_type_for_impl_trait_in_trait(local_def_id) - .to_def_id(), - lifetimes, - true, - ), - hir::OpaqueTyOrigin::FnReturn { - in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), - .. - } - | hir::OpaqueTyOrigin::AsyncFn { - in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), - .. - } - | hir::OpaqueTyOrigin::TyAlias { .. } => { - self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false) - } - } + &hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { + let local_def_id = opaque_ty.def_id; + + // If this is an RPITIT and we are using the new RPITIT lowering scheme, we + // generate the def_id of an associated type for the trait and return as + // type a projection. + match opaque_ty.origin { + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: Some(hir::RpitContext::Trait), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: Some(hir::RpitContext::Trait), + .. + } => self.lower_opaque_ty( + tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(), + lifetimes, + true, + ), + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::TyAlias { .. } => { + self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false) } - ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } } // If we encounter a type relative path with RTN generics, then it must have @@ -2289,7 +2288,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span_bug!( tcx.def_span(param.def_id), "only expected lifetime for opaque's own generics, got {:?}", - param.kind + param ); }; let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { @@ -2344,6 +2343,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi); let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); + if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(bare_fn_ty), span, .. }) = + tcx.hir_node(hir_id) + { + check_abi_fn_ptr(tcx, hir_id, *span, bare_fn_ty.abi); + } + // reject function types that violate cmse ABI requirements cmse::validate_cmse_abi(self.tcx(), self.dcx(), hir_id, abi, bare_fn_ty); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 7d40a7746b9..71ee77f8f61 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -62,7 +62,6 @@ This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index dbaf9c2c6f0..a0fdf95a831 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -1,6 +1,5 @@ use std::fmt::Write; -use rustc_hir::def::DefKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_middle::ty::{GenericArgs, TyCtxt}; use rustc_span::symbol::sym; @@ -24,18 +23,18 @@ fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { } pub(crate) fn variances(tcx: TyCtxt<'_>) { - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { - for id in tcx.hir().items() { - let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; + let crate_items = tcx.hir_crate_items(()); + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { + for id in crate_items.opaques() { tcx.dcx().emit_err(crate::errors::VariancesOf { - span: tcx.def_span(id.owner_id), - variances: format_variances(tcx, id.owner_id.def_id), + span: tcx.def_span(id), + variances: format_variances(tcx, id), }); } } - for id in tcx.hir().items() { + for id in crate_items.free_items() { if !tcx.has_attr(id.owner_id, sym::rustc_variance) { continue; } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 12bb9a3f9e0..02cfb57b836 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -5,6 +5,7 @@ use itertools::Itertools; use rustc_arena::DroplessArena; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; @@ -63,8 +64,29 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { let crate_map = tcx.crate_variances(()); return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); } + DefKind::AssocTy => match tcx.opt_rpitit_info(item_def_id.to_def_id()) { + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + return variance_of_opaque( + tcx, + opaque_def_id.expect_local(), + ForceCaptureTraitArgs::Yes, + ); + } + None | Some(ty::ImplTraitInTraitData::Impl { .. }) => {} + }, DefKind::OpaqueTy => { - return variance_of_opaque(tcx, item_def_id); + let force_capture_trait_args = if let hir::OpaqueTyOrigin::FnReturn { + parent: _, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } = + tcx.hir_node_by_def_id(item_def_id).expect_opaque_ty().origin + { + ForceCaptureTraitArgs::Yes + } else { + ForceCaptureTraitArgs::No + }; + + return variance_of_opaque(tcx, item_def_id, force_capture_trait_args); } _ => {} } @@ -73,8 +95,18 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item"); } +#[derive(Debug, Copy, Clone)] +enum ForceCaptureTraitArgs { + Yes, + No, +} + #[instrument(level = "trace", skip(tcx), ret)] -fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { +fn variance_of_opaque( + tcx: TyCtxt<'_>, + item_def_id: LocalDefId, + force_capture_trait_args: ForceCaptureTraitArgs, +) -> &[ty::Variance] { let generics = tcx.generics_of(item_def_id); // Opaque types may only use regions that are bound. So for @@ -115,9 +147,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc #[instrument(level = "trace", skip(self), ret)] fn visit_ty(&mut self, t: Ty<'tcx>) { match t.kind() { - ty::Alias(_, ty::AliasTy { def_id, args, .. }) - if matches!(self.tcx.def_kind(*def_id), DefKind::OpaqueTy) => - { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { self.visit_opaque(*def_id, args); } _ => t.super_visit_with(self), @@ -135,6 +165,15 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc let mut generics = generics; while let Some(def_id) = generics.parent { generics = tcx.generics_of(def_id); + + // Don't mark trait params generic if we're in an RPITIT. + if matches!(force_capture_trait_args, ForceCaptureTraitArgs::Yes) + && generics.parent.is_none() + { + debug_assert_eq!(tcx.def_kind(def_id), DefKind::Trait); + break; + } + for param in &generics.own_params { match param.kind { ty::GenericParamDefKind::Lifetime => { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1c52283d537..9fe6a8ee342 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -96,6 +96,7 @@ impl<'a> State<'a> { Node::Ty(a) => self.print_type(a), Node::AssocItemConstraint(a) => self.print_assoc_item_constraint(a), Node::TraitRef(a) => self.print_trait_ref(a), + Node::OpaqueTy(o) => self.print_opaque_ty(o), Node::Pat(a) => self.print_pat(a), Node::PatField(a) => self.print_patfield(a), Node::Arm(a) => self.print_arm(a), @@ -568,11 +569,6 @@ impl<'a> State<'a> { state.print_type(ty); }); } - hir::ItemKind::OpaqueTy(opaque_ty) => { - self.print_item_type(item, opaque_ty.generics, |state| { - state.print_bounds("= impl", opaque_ty.bounds) - }); - } hir::ItemKind::Enum(ref enum_definition, params) => { self.print_enum_def(enum_definition, params, item.ident.name, item.span); } @@ -665,6 +661,15 @@ impl<'a> State<'a> { self.print_path(t.path, false); } + fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) { + self.head("opaque"); + self.print_generic_params(o.generics.params); + self.print_where_clause(o.generics); + self.word("{"); + self.print_bounds("impl", o.bounds); + self.word("}"); + } + fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) { if !generic_params.is_empty() { self.word("for"); diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 73a775690d6..894402a8c2e 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start itertools = "0.12" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 39d430cf73b..3669100ed91 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -23,17 +23,17 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop` -hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}` +hir_typeck_cast_thin_pointer_to_wide_pointer = cannot cast thin pointer `{$expr_ty}` to wide pointer `{$cast_ty}` .teach_help = Thin pointers are "simple" pointers: they are purely a reference to a memory address. - Fat pointers are pointers referencing "Dynamically Sized Types" (also + Wide pointers are pointers referencing "Dynamically Sized Types" (also called DST). DST don't have a statically known size, therefore they can only exist behind some kind of pointers that contain additional information. Slices and trait objects are DSTs. In the case of slices, - the additional information the fat pointer holds is their size. + the additional information the wide pointer holds is their size. - To fix this error, don't try to cast directly between thin and fat + To fix this error, don't try to cast directly between thin and wide pointers. For more information about casts, take a look at The Book: diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 2dbadf8198b..0d9d1910ae0 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug", ret)] - pub fn check_match( + pub(crate) fn check_match( &self, expr: &'tcx hir::Expr<'tcx>, scrut: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index fcd2940b83a..407191661a4 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -66,7 +66,7 @@ pub(crate) struct CastCheck<'tcx> { } /// The kind of pointer and associated metadata (thin, length or vtable) - we -/// only allow casts between fat pointers if their metadata have the same +/// only allow casts between wide pointers if their metadata have the same /// kind. #[derive(Debug, Copy, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)] enum PointerKind<'tcx> { @@ -162,7 +162,7 @@ enum CastError<'tcx> { src_kind: PointerKind<'tcx>, dst_kind: PointerKind<'tcx>, }, - /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`). + /// Cast of thin to wide raw ptr (e.g., `*const () as *const [u8]`). SizedUnsizedCast, IllegalCast, NeedDeref, @@ -172,12 +172,12 @@ enum CastError<'tcx> { NonScalar, UnknownExprPtrKind, UnknownCastPtrKind, - /// Cast of int to (possibly) fat raw pointer. + /// Cast of int to (possibly) wide raw pointer. /// /// Argument is the specific name of the metadata in plain words, such as "a vtable" /// or "a length". If this argument is None, then the metadata is unknown, for example, /// when we're typechecking a type parameter with a ?Sized bound. - IntToFatCast(Option<&'static str>), + IntToWideCast(Option<&'static str>), ForeignNonExhaustiveAdt, } @@ -545,14 +545,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::SizedUnsizedCast => { - fcx.dcx().emit_err(errors::CastThinPointerToFatPointer { + fcx.dcx().emit_err(errors::CastThinPointerToWidePointer { span: self.span, expr_ty: self.expr_ty, cast_ty: fcx.ty_to_string(self.cast_ty), teach: fcx.tcx.sess.teach(E0607), }); } - CastError::IntToFatCast(known_metadata) => { + CastError::IntToWideCast(known_metadata) => { let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); let expr_ty = fcx.ty_to_string(self.expr_ty); @@ -671,7 +671,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } #[instrument(skip(fcx), level = "debug")] - pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { + pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty); self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty); @@ -861,7 +861,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { return Ok(CastKind::PtrPtrCast); } - // We can't cast to fat pointer if source pointer kind is unknown + // We can't cast to wide pointer if source pointer kind is unknown let Some(src_kind) = src_kind else { return Err(CastError::UnknownCastPtrKind); }; @@ -1054,10 +1054,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast), - Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), - Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))), + Some(PointerKind::VTable(_)) => Err(CastError::IntToWideCast(Some("a vtable"))), + Some(PointerKind::Length) => Err(CastError::IntToWideCast(Some("a length"))), Some(PointerKind::OfAlias(_) | PointerKind::OfParam(_)) => { - Err(CastError::IntToFatCast(None)) + Err(CastError::IntToWideCast(None)) } } } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 3e7ce2955fc..fcaa5751152 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -44,7 +44,7 @@ struct ClosureSignatures<'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self, closure), level = "debug")] - pub fn check_expr_closure( + pub(crate) fn check_expr_closure( &self, closure: &hir::Closure<'tcx>, expr_span: Span, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index fb462eec1b9..bd0b9870298 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -82,6 +82,11 @@ struct Coerce<'a, 'tcx> { /// See #47489 and #48598 /// See docs on the "AllowTwoPhase" type for a more detailed discussion allow_two_phase: AllowTwoPhase, + /// Whether we allow `NeverToAny` coercions. This is unsound if we're + /// coercing a place expression without it counting as a read in the MIR. + /// This is a side-effect of HIR not really having a great distinction + /// between places and values. + coerce_never: bool, } impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { @@ -125,8 +130,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fcx: &'f FnCtxt<'f, 'tcx>, cause: ObligationCause<'tcx>, allow_two_phase: AllowTwoPhase, + coerce_never: bool, ) -> Self { - Coerce { fcx, cause, allow_two_phase, use_lub: false } + Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never } } fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { @@ -135,7 +141,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let at = self.at(&self.cause, self.fcx.param_env); let res = if self.use_lub { - at.lub(DefineOpaqueTypes::Yes, b, a) + at.lub(b, a) } else { at.sup(DefineOpaqueTypes::Yes, b, a) .map(|InferOk { value: (), obligations }| InferOk { value: b, obligations }) @@ -177,7 +183,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Coercing from `!` to any type is allowed: if a.is_never() { - return success(simple(Adjust::NeverToAny)(b), b, vec![]); + if self.coerce_never { + return success(simple(Adjust::NeverToAny)(b), b, vec![]); + } else { + // Otherwise the only coercion we can do is unification. + return self.unify_and(a, b, identity); + } } // Coercing *from* an unresolved inference variable means that @@ -1038,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// The expressions *must not* have any preexisting adjustments. pub(crate) fn coerce( &self, - expr: &hir::Expr<'_>, + expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, mut target: Ty<'tcx>, allow_two_phase: AllowTwoPhase, @@ -1055,7 +1066,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable)); - let coerce = Coerce::new(self, cause, allow_two_phase); + let coerce = Coerce::new( + self, + cause, + allow_two_phase, + self.expr_guaranteed_to_constitute_read_for_never(expr), + ); let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; let (adjustments, _) = self.register_infer_ok_obligations(ok); @@ -1077,8 +1093,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("coercion::can_with_predicates({:?} -> {:?})", source, target); let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); - // We don't ever need two-phase here since we throw out the result of the coercion - let coerce = Coerce::new(self, cause, AllowTwoPhase::No); + // We don't ever need two-phase here since we throw out the result of the coercion. + // We also just always set `coerce_never` to true, since this is a heuristic. + let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); self.probe(|_| { let Ok(ok) = coerce.coerce(source, target) else { return false; @@ -1090,12 +1107,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Given a type and a target type, this function will calculate and return - /// how many dereference steps needed to achieve `expr_ty <: target`. If + /// how many dereference steps needed to coerce `expr_ty` to `target`. If /// it's not possible, return `None`. - pub(crate) fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize> { + pub(crate) fn deref_steps_for_suggestion( + &self, + expr_ty: Ty<'tcx>, + target: Ty<'tcx>, + ) -> Option<usize> { let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); - // We don't ever need two-phase here since we throw out the result of the coercion - let coerce = Coerce::new(self, cause, AllowTwoPhase::No); + // We don't ever need two-phase here since we throw out the result of the coercion. + let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); coerce .autoderef(DUMMY_SP, expr_ty) .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps)) @@ -1169,13 +1190,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (ty::FnDef(..), ty::FnDef(..)) => { // Don't reify if the function types have a LUB, i.e., they // are the same function and their parameters have a LUB. - match self.commit_if_ok(|_| { - self.at(cause, self.param_env).lub( - DefineOpaqueTypes::Yes, - prev_ty, - new_ty, - ) - }) { + match self + .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) + { // We have a LUB of prev_ty and new_ty, just return it. Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), Err(_) => { @@ -1218,7 +1235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig)); let sig = self .at(cause, self.param_env) - .lub(DefineOpaqueTypes::Yes, a_sig, b_sig) + .lub(a_sig, b_sig) .map(|ok| self.register_infer_ok_obligations(ok))?; // Reify both sides and return the reified fn pointer type. @@ -1252,7 +1269,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // probably aren't processing function arguments here and even if we were, // they're going to get autorefed again anyway and we can apply 2-phase borrows // at that time. - let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No); + // + // NOTE: we set `coerce_never` to `true` here because coercion LUBs only + // operate on values and not places, so a never coercion is valid. + let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true); coerce.use_lub = true; // First try to coerce the new expression to the type of the previous ones, @@ -1306,9 +1326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return Err(self - .commit_if_ok(|_| { - self.at(cause, self.param_env).lub(DefineOpaqueTypes::Yes, prev_ty, new_ty) - }) + .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) .unwrap_err()); } } @@ -1320,13 +1338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(e) } else { Err(self - .commit_if_ok(|_| { - self.at(cause, self.param_env).lub( - DefineOpaqueTypes::Yes, - prev_ty, - new_ty, - ) - }) + .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) .unwrap_err()) } } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index cfa8fc4bbf2..777248ff873 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - pub fn demand_suptype_with_origin( + pub(crate) fn demand_suptype_with_origin( &'a self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, @@ -247,7 +247,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!` /// will be permitted if the diverges flag is currently "always". #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))] - pub fn demand_coerce_diag( + pub(crate) fn demand_coerce_diag( &'a self, mut expr: &'tcx hir::Expr<'tcx>, checked_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index a692642ccfc..cceaabaff65 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -699,8 +699,8 @@ pub(crate) struct ReplaceWithName { } #[derive(Diagnostic)] -#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)] -pub(crate) struct CastThinPointerToFatPointer<'tcx> { +#[diag(hir_typeck_cast_thin_pointer_to_wide_pointer, code = E0607)] +pub(crate) struct CastThinPointerToWidePointer<'tcx> { #[primary_span] pub span: Span, pub expr_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 67f4dbee3cb..4653458b5dd 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Expectation<'tcx> { /// be checked higher up, as is the case with `&expr` and `box expr`), but /// is useful in determining the concrete type. /// - /// The primary use case is where the expected type is a fat pointer, + /// The primary use case is where the expected type is a wide pointer, /// like `&[isize]`. For example, consider the following statement: /// /// let x: &[isize] = &[1, 2, 3]; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b34ed4640db..b310398a0f1 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1,3 +1,6 @@ +// ignore-tidy-filelength +// FIXME: we should move the field error reporting code somewhere else. + //! Type checking expressions. //! //! See [`rustc_hir_analysis::check`] for more context on type checking in general. @@ -33,7 +36,6 @@ use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_target::abi::{FIRST_VARIANT, FieldIdx}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; -use smallvec::SmallVec; use tracing::{debug, instrument, trace}; use {rustc_ast as ast, rustc_hir as hir}; @@ -62,7 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. - if ty.is_never() { + if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) { if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { let reported = self.dcx().span_delayed_bug( expr.span, @@ -238,8 +240,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"), } - // Any expression that produces a value of type `!` must have diverged - if ty.is_never() { + // Any expression that produces a value of type `!` must have diverged, + // unless it's a place expression that isn't being read from, in which case + // diverging would be unsound since we may never actually read the `!`. + // e.g. `let _ = *never_ptr;` with `never_ptr: *const !`. + if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) { self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); } @@ -257,6 +262,185 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + /// Whether this expression constitutes a read of value of the type that + /// it evaluates to. + /// + /// This is used to determine if we should consider the block to diverge + /// if the expression evaluates to `!`, and if we should insert a `NeverToAny` + /// coercion for values of type `!`. + /// + /// This function generally returns `false` if the expression is a place + /// expression and the *parent* expression is the scrutinee of a match or + /// the pointee of an `&` addr-of expression, since both of those parent + /// expressions take a *place* and not a value. + pub(super) fn expr_guaranteed_to_constitute_read_for_never( + &self, + expr: &'tcx hir::Expr<'tcx>, + ) -> bool { + // We only care about place exprs. Anything else returns an immediate + // which would constitute a read. We don't care about distinguishing + // "syntactic" place exprs since if the base of a field projection is + // not a place then it would've been UB to read from it anyways since + // that constitutes a read. + if !expr.is_syntactic_place_expr() { + return true; + } + + let parent_node = self.tcx.parent_hir_node(expr.hir_id); + match parent_node { + hir::Node::Expr(parent_expr) => { + match parent_expr.kind { + // Addr-of, field projections, and LHS of assignment don't constitute reads. + // Assignment does call `drop_in_place`, though, but its safety + // requirements are not the same. + ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false, + ExprKind::Assign(lhs, _, _) => { + // Only the LHS does not constitute a read + expr.hir_id != lhs.hir_id + } + + // See note on `PatKind::Or` below for why this is `all`. + ExprKind::Match(scrutinee, arms, _) => { + assert_eq!(scrutinee.hir_id, expr.hir_id); + arms.iter() + .all(|arm| self.pat_guaranteed_to_constitute_read_for_never(arm.pat)) + } + ExprKind::Let(hir::LetExpr { init, pat, .. }) => { + assert_eq!(init.hir_id, expr.hir_id); + self.pat_guaranteed_to_constitute_read_for_never(*pat) + } + + // Any expression child of these expressions constitute reads. + ExprKind::Array(_) + | ExprKind::Call(_, _) + | ExprKind::MethodCall(_, _, _, _) + | ExprKind::Tup(_) + | ExprKind::Binary(_, _, _) + | ExprKind::Unary(_, _) + | ExprKind::Cast(_, _) + | ExprKind::Type(_, _) + | ExprKind::DropTemps(_) + | ExprKind::If(_, _, _) + | ExprKind::Closure(_) + | ExprKind::Block(_, _) + | ExprKind::AssignOp(_, _, _) + | ExprKind::Index(_, _, _) + | ExprKind::Break(_, _) + | ExprKind::Ret(_) + | ExprKind::Become(_) + | ExprKind::InlineAsm(_) + | ExprKind::Struct(_, _, _) + | ExprKind::Repeat(_, _) + | ExprKind::Yield(_, _) => true, + + // These expressions have no (direct) sub-exprs. + ExprKind::ConstBlock(_) + | ExprKind::Loop(_, _, _, _) + | ExprKind::Lit(_) + | ExprKind::Path(_) + | ExprKind::Continue(_) + | ExprKind::OffsetOf(_, _) + | ExprKind::Err(_) => unreachable!("no sub-expr expected for {:?}", expr.kind), + } + } + + // If we have a subpattern that performs a read, we want to consider this + // to diverge for compatibility to support something like `let x: () = *never_ptr;`. + hir::Node::LetStmt(hir::LetStmt { init: Some(target), pat, .. }) => { + assert_eq!(target.hir_id, expr.hir_id); + self.pat_guaranteed_to_constitute_read_for_never(*pat) + } + + // These nodes (if they have a sub-expr) do constitute a read. + hir::Node::Block(_) + | hir::Node::Arm(_) + | hir::Node::ExprField(_) + | hir::Node::AnonConst(_) + | hir::Node::ConstBlock(_) + | hir::Node::ConstArg(_) + | hir::Node::Stmt(_) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(..), .. + }) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => true, + + // These nodes do not have direct sub-exprs. + hir::Node::Param(_) + | hir::Node::Item(_) + | hir::Node::ForeignItem(_) + | hir::Node::TraitItem(_) + | hir::Node::ImplItem(_) + | hir::Node::Variant(_) + | hir::Node::Field(_) + | hir::Node::PathSegment(_) + | hir::Node::Ty(_) + | hir::Node::AssocItemConstraint(_) + | hir::Node::TraitRef(_) + | hir::Node::Pat(_) + | hir::Node::PatField(_) + | hir::Node::LetStmt(_) + | hir::Node::Synthetic + | hir::Node::Err(_) + | hir::Node::Ctor(_) + | hir::Node::Lifetime(_) + | hir::Node::GenericParam(_) + | hir::Node::Crate(_) + | hir::Node::Infer(_) + | hir::Node::WhereBoundPredicate(_) + | hir::Node::ArrayLenInfer(_) + | hir::Node::PreciseCapturingNonLifetimeArg(_) + | hir::Node::OpaqueTy(_) => { + unreachable!("no sub-expr expected for {parent_node:?}") + } + } + } + + /// Whether this pattern constitutes a read of value of the scrutinee that + /// it is matching against. This is used to determine whether we should + /// perform `NeverToAny` coercions. + /// + /// See above for the nuances of what happens when this returns true. + pub(super) fn pat_guaranteed_to_constitute_read_for_never(&self, pat: &hir::Pat<'_>) -> bool { + match pat.kind { + // Does not constitute a read. + hir::PatKind::Wild => false, + + // This is unnecessarily restrictive when the pattern that doesn't + // constitute a read is unreachable. + // + // For example `match *never_ptr { value => {}, _ => {} }` or + // `match *never_ptr { _ if false => {}, value => {} }`. + // + // It is however fine to be restrictive here; only returning `true` + // can lead to unsoundness. + hir::PatKind::Or(subpats) => { + subpats.iter().all(|pat| self.pat_guaranteed_to_constitute_read_for_never(pat)) + } + + // Does constitute a read, since it is equivalent to a discriminant read. + hir::PatKind::Never => true, + + // All of these constitute a read, or match on something that isn't `!`, + // which would require a `NeverToAny` coercion. + hir::PatKind::Binding(_, _, _, _) + | hir::PatKind::Struct(_, _, _) + | hir::PatKind::TupleStruct(_, _, _) + | hir::PatKind::Path(_) + | hir::PatKind::Tuple(_, _) + | hir::PatKind::Box(_) + | hir::PatKind::Ref(_, _) + | hir::PatKind::Deref(_) + | hir::PatKind::Lit(_) + | hir::PatKind::Range(_, _, _) + | hir::PatKind::Slice(_, _, _) + | hir::PatKind::Err(_) => true, + } + } + #[instrument(skip(self, expr), level = "debug")] fn check_expr_kind( &self, @@ -413,7 +597,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => { if oprnd.is_syntactic_place_expr() { // Places may legitimately have unsized types. - // For example, dereferences of a fat pointer and + // For example, dereferences of a wide pointer and // the last field of a struct can be unsized. ExpectHasType(*ty) } else { @@ -1598,7 +1782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let flds = expected.only_has_type(self).and_then(|ty| { - let ty = self.resolve_vars_with_obligations(ty); + let ty = self.try_structurally_resolve_type(expr.span, ty); match ty.kind() { ty::Tuple(flds) => Some(&flds[..]), _ => None, @@ -1676,7 +1860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let tcx = self.tcx; - let adt_ty = self.resolve_vars_with_obligations(adt_ty); + let adt_ty = self.try_structurally_resolve_type(span, adt_ty); let adt_ty_hint = expected.only_has_type(self).and_then(|expected| { self.fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); @@ -1722,8 +1906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ident = tcx.adjust_ident(field.ident, variant.def_id); let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { seen_fields.insert(ident, field.span); - // FIXME: handle nested fields - self.write_field_index(field.hir_id, i, Vec::new()); + self.write_field_index(field.hir_id, i); // We don't look at stability attributes on // struct-like enums (yet...), but it's definitely not @@ -2367,35 +2550,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, base_def: ty::AdtDef<'tcx>, ident: Ident, - nested_fields: &mut SmallVec<[(FieldIdx, &'tcx ty::FieldDef); 1]>, - ) -> bool { + ) -> Option<(FieldIdx, &'tcx ty::FieldDef)> { // No way to find a field in an enum. if base_def.is_enum() { - return false; + return None; } for (field_idx, field) in base_def.non_enum_variant().fields.iter_enumerated() { - if field.is_unnamed() { - // We have an unnamed field, recurse into the nested ADT to find `ident`. - // If we find it there, return immediately, and `nested_fields` will contain the - // correct path. - nested_fields.push((field_idx, field)); - - let field_ty = self.tcx.type_of(field.did).instantiate_identity(); - let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); - if self.find_adt_field(adt_def, ident, &mut *nested_fields) { - return true; - } - - nested_fields.pop(); - } else if field.ident(self.tcx).normalize_to_macros_2_0() == ident { + if field.ident(self.tcx).normalize_to_macros_2_0() == ident { // We found the field we wanted. - nested_fields.push((field_idx, field)); - return true; + return Some((field_idx, field)); } } - false + None } // Check field access expressions @@ -2425,34 +2593,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(self.tcx(), guar); } - let mut field_path = SmallVec::new(); - if self.find_adt_field(*base_def, ident, &mut field_path) { - let (first_idx, _) = field_path[0]; - let (_, last_field) = field_path.last().unwrap(); - - // Save the index of all fields regardless of their visibility in case - // of error recovery. - let nested_fields = field_path[..] - .array_windows() - .map(|[(_, outer), (inner_idx, _)]| { - let outer_ty = self.field_ty(expr.span, outer, args); - (outer_ty, *inner_idx) - }) - .collect(); - self.write_field_index(expr.hir_id, first_idx, nested_fields); + if let Some((idx, field)) = self.find_adt_field(*base_def, ident) { + self.write_field_index(expr.hir_id, idx); let adjustments = self.adjust_steps(&autoderef); - if last_field.vis.is_accessible_from(def_scope, self.tcx) { + if field.vis.is_accessible_from(def_scope, self.tcx) { self.apply_adjustments(base, adjustments); self.register_predicates(autoderef.into_obligations()); - self.tcx.check_stability( - last_field.did, - Some(expr.hir_id), - expr.span, - None, - ); - return self.field_ty(expr.span, last_field, args); + self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); + return self.field_ty(expr.span, field, args); } // The field is not accessible, fall through to error reporting. @@ -2467,11 +2617,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.apply_adjustments(base, adjustments); self.register_predicates(autoderef.into_obligations()); - self.write_field_index( - expr.hir_id, - FieldIdx::from_usize(index), - Vec::new(), - ); + self.write_field_index(expr.hir_id, FieldIdx::from_usize(index)); return field_ty; } } @@ -3322,7 +3468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { - let mut diverge = asm.options.contains(ast::InlineAsmOptions::NORETURN); + let mut diverge = asm.asm_macro.diverges(asm.options); for (op, _op_sp) in asm.operands { match op { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 62107877283..eccb18ad6c4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -165,16 +165,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(crate) fn write_field_index( - &self, - hir_id: HirId, - index: FieldIdx, - nested_fields: Vec<(Ty<'tcx>, FieldIdx)>, - ) { + pub(crate) fn write_field_index(&self, hir_id: HirId, index: FieldIdx) { self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); - if !nested_fields.is_empty() { - self.typeck_results.borrow_mut().nested_fields_mut().insert(hir_id, nested_fields); - } } #[instrument(level = "debug", skip(self))] @@ -187,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn write_method_call_and_enforce_effects( + pub(crate) fn write_method_call_and_enforce_effects( &self, hir_id: HirId, span: Span, @@ -214,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. #[instrument(skip(self), level = "debug")] - pub fn write_user_type_annotation_from_args( + pub(crate) fn write_user_type_annotation_from_args( &self, hir_id: HirId, def_id: DefId, @@ -235,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - pub fn write_user_type_annotation( + pub(crate) fn write_user_type_annotation( &self, hir_id: HirId, canonical_user_type_annotation: CanonicalUserType<'tcx>, @@ -254,7 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(skip(self, expr), level = "debug")] - pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) { + pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) { debug!("expr = {:#?}", expr); if adj.is_empty() { @@ -448,7 +440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip_all)] - pub fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + pub(crate) fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let ty = self.lower_ty(hir_ty); debug!(?ty); @@ -736,7 +728,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Resolves an associated value path into a base type and associated constant, or method /// resolution. The newly resolved definition is written into `type_dependent_defs`. #[instrument(level = "trace", skip(self), ret)] - pub fn resolve_ty_and_res_fully_qualified_call( + pub(crate) fn resolve_ty_and_res_fully_qualified_call( &self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, @@ -995,7 +987,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. #[instrument(skip(self, span), level = "debug")] - pub fn instantiate_value_path( + pub(crate) fn instantiate_value_path( &self, segments: &'tcx [hir::PathSegment<'tcx>], self_ty: Option<LoweredTy<'tcx>>, @@ -1446,7 +1438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// variable. This is different from `structurally_resolve_type` which errors /// in this case. #[instrument(level = "debug", skip(self, sp), ret)] - pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + pub(crate) fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let ty = self.resolve_vars_with_obligations(ty); if self.next_trait_solver() @@ -1471,7 +1463,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self, sp), ret)] - pub fn try_structurally_resolve_const(&self, sp: Span, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + pub(crate) fn try_structurally_resolve_const( + &self, + sp: Span, + ct: ty::Const<'tcx>, + ) -> ty::Const<'tcx> { // FIXME(min_const_generic_exprs): We could process obligations here if `ct` is a var. if self.next_trait_solver() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 550c58b5a17..fa471647d02 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -984,7 +984,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_deref_unwrap_or( &mut err, - error_span, callee_ty, call_ident, expected_ty, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 487cc7e55cd..1df4d32f3cb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -847,11 +847,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } hir::FnRetTy::Return(hir_ty) => { - if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind + if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind // FIXME: account for RPITIT. - && let hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(op_ty), .. - }) = self.tcx.hir_node(item_id.hir_id()) && let [hir::GenericBound::Trait(trait_ref, _)] = op_ty.bounds && let Some(hir::PathSegment { args: Some(generic_args), .. }) = trait_ref.trait_ref.path.segments.last() @@ -1462,7 +1459,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_deref_unwrap_or( &self, err: &mut Diag<'_>, - error_span: Span, callee_ty: Option<Ty<'tcx>>, call_ident: Option<Ident>, expected_ty: Ty<'tcx>, @@ -2612,7 +2608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind - && let Some(1) = self.deref_steps(expected, checked_ty) + && let Some(1) = self.deref_steps_for_suggestion(expected, checked_ty) { // We have `*&T`, check if what was expected was `&T`. // If so, we may want to suggest removing a `*`. @@ -2742,7 +2738,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } (_, &ty::RawPtr(ty_b, mutbl_b), &ty::Ref(_, ty_a, mutbl_a)) => { - if let Some(steps) = self.deref_steps(ty_a, ty_b) + if let Some(steps) = self.deref_steps_for_suggestion(ty_a, ty_b) // Only suggest valid if dereferencing needed. && steps > 0 // The pointer type implements `Copy` trait so the suggestion is always valid. @@ -2786,7 +2782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } _ if sp == expr.span => { - if let Some(mut steps) = self.deref_steps(checked_ty, expected) { + if let Some(mut steps) = self.deref_steps_for_suggestion(checked_ty, expected) { let mut expr = expr.peel_blocks(); let mut prefix_span = expr.span.shrink_to_lo(); let mut remove = String::new(); diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index a4121adf628..8a7005ac328 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -1,4 +1,5 @@ use hir::HirId; +use rustc_abi::Primitive::Pointer; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; @@ -6,7 +7,7 @@ use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_target::abi::{Pointer, VariantIdx}; +use rustc_target::abi::VariantIdx; use tracing::trace; use super::FnCtxt; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index f8352d9d44a..6b0a897faba 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -3,7 +3,6 @@ #![allow(rustc::untranslatable_diagnostic)] #![feature(array_windows)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(never_type)] diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 72842075fec..1d7b3433fe5 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -235,6 +235,23 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { target, }); } + + Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => { + let region = self.next_region_var(infer::Autoref(self.span)); + + target = match target.kind() { + ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { + let inner_ty = match args[0].expect_ty().kind() { + ty::Ref(_, ty, _) => *ty, + _ => bug!("Expected a reference type for argument to Pin"), + }; + Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl) + } + _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"), + }; + + adjustments.push(Adjustment { kind: Adjust::ReborrowPin(region, mutbl), target }); + } None => {} } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 3e9cb0ac2c8..cb8b1df2c6e 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -94,7 +94,7 @@ pub(crate) enum CandidateSource { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Determines whether the type `self_ty` supports a visible method named `method_name` or not. #[instrument(level = "debug", skip(self))] - pub fn method_exists_for_diagnostic( + pub(crate) fn method_exists_for_diagnostic( &self, method_name: Ident, self_ty: Ty<'tcx>, @@ -178,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `self_expr`: the self expression (`foo`) /// * `args`: the expressions of the arguments (`a, b + 1, ...`) #[instrument(level = "debug", skip(self))] - pub fn lookup_method( + pub(crate) fn lookup_method( &self, self_ty: Ty<'tcx>, segment: &'tcx hir::PathSegment<'tcx>, @@ -281,7 +281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self, call_expr))] - pub fn lookup_probe( + pub(crate) fn lookup_probe( &self, method_name: Ident, self_ty: Ty<'tcx>, @@ -498,7 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `self_ty_span` the span for the type being searched within (span of `Foo`) /// * `expr_id`: the [`hir::HirId`] of the expression composing the entire call #[instrument(level = "debug", skip(self), ret)] - pub fn resolve_fully_qualified_call( + pub(crate) fn resolve_fully_qualified_call( &self, span: Span, method_name: Ident, diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index a8b5b6165db..b20592c85d2 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -121,16 +121,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mutbl.ref_prefix_str() } Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", + Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl { + hir::Mutability::Mut => "Pin<&mut ", + hir::Mutability::Not => "Pin<&", + }, }; if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) { - let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + let mut self_adjusted = + if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{derefs}{self_expr} as *const _") + } else { + format!("{autoref}{derefs}{self_expr}") + }; + + if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment { - format!("{derefs}{self_expr} as *const _") - } else { - format!("{autoref}{derefs}{self_expr}") - }; + self_adjusted.push('>'); + } lint.span_suggestion( sp, @@ -400,6 +411,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let autoref = match pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(), Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", + Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl { + hir::Mutability::Mut => "Pin<&mut ", + hir::Mutability::Not => "Pin<&", + }, }; let (expr_text, precise) = if let Some(expr_text) = expr @@ -412,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ("(..)".to_string(), false) }; - let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + let mut adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment { format!("{derefs}{expr_text} as *const _") @@ -420,6 +435,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{autoref}{derefs}{expr_text}") }; + if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment + { + adjusted_text.push('>'); + } + (adjusted_text, precise) } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3bb7070d61d..ba6bfd3a5e9 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -136,7 +136,7 @@ enum ProbeResult { /// `mut`), or it has type `*mut T` and we convert it to `*const T`. #[derive(Debug, PartialEq, Copy, Clone)] pub(crate) enum AutorefOrPtrAdjustment { - /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it. + /// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it. /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing. Autoref { mutbl: hir::Mutability, @@ -147,6 +147,9 @@ pub(crate) enum AutorefOrPtrAdjustment { }, /// Receiver has type `*mut T`, convert to `*const T` ToConstPtr, + + /// Reborrow a `Pin<&mut T>` or `Pin<&T>`. + ReborrowPin(hir::Mutability), } impl AutorefOrPtrAdjustment { @@ -154,6 +157,7 @@ impl AutorefOrPtrAdjustment { match self { AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize, AutorefOrPtrAdjustment::ToConstPtr => false, + AutorefOrPtrAdjustment::ReborrowPin(_) => false, } } } @@ -224,7 +228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// would use to decide if a method is a plausible fit for /// ambiguity purposes). #[instrument(level = "debug", skip(self, candidate_filter))] - pub fn probe_for_return_type_for_diagnostic( + pub(crate) fn probe_for_return_type_for_diagnostic( &self, span: Span, mode: Mode, @@ -267,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn probe_for_name( + pub(crate) fn probe_for_name( &self, mode: Mode, item_name: Ident, @@ -1103,6 +1107,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { unstable_candidates.as_deref_mut(), ) }) + .or_else(|| { + self.pick_reborrow_pin_method( + step, + self_ty, + unstable_candidates.as_deref_mut(), + ) + }) }) }) } @@ -1127,13 +1138,28 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { r.map(|mut pick| { pick.autoderefs = step.autoderefs; - // Insert a `&*` or `&mut *` if this is a reference type: - if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() { - pick.autoderefs += 1; - pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref { - mutbl, - unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()), - }) + match *step.self_ty.value.value.kind() { + // Insert a `&*` or `&mut *` if this is a reference type: + ty::Ref(_, _, mutbl) => { + pick.autoderefs += 1; + pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref { + mutbl, + unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()), + }) + } + + ty::Adt(def, args) + if self.tcx.features().pin_ergonomics + && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => + { + // make sure this is a pinned reference (and not a `Pin<Box>` or something) + if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() { + pick.autoref_or_ptr_adjustment = + Some(AutorefOrPtrAdjustment::ReborrowPin(*mutbl)); + } + } + + _ => (), } pick @@ -1164,6 +1190,43 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }) } + /// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`. + #[instrument(level = "debug", skip(self, step, unstable_candidates))] + fn pick_reborrow_pin_method( + &self, + step: &CandidateStep<'tcx>, + self_ty: Ty<'tcx>, + unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, + ) -> Option<PickResult<'tcx>> { + if !self.tcx.features().pin_ergonomics { + return None; + } + + // make sure self is a Pin<&mut T> + let inner_ty = match self_ty.kind() { + ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => { + match args[0].expect_ty().kind() { + ty::Ref(_, ty, hir::Mutability::Mut) => *ty, + _ => { + return None; + } + } + } + _ => return None, + }; + + let region = self.tcx.lifetimes.re_erased; + let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not); + self.pick_method(autopin_ty, unstable_candidates).map(|r| { + r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref_or_ptr_adjustment = + Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not)); + pick + }) + }) + } + /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a /// special case for this is because going from `*mut T` to `*const T` with autoderefs and /// autorefs would require dereferencing the pointer, which is not safe. diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a37e9744293..4f726f3ed38 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -183,7 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn report_method_error( + pub(crate) fn report_method_error( &self, call_id: HirId, rcvr_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 49c5a7d8a65..fb78da0a86c 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1513,8 +1513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_map .get(&ident) .map(|(i, f)| { - // FIXME: handle nested fields - self.write_field_index(field.hir_id, *i, Vec::new()); + self.write_field_index(field.hir_id, *i); self.tcx.check_stability(f.did, Some(pat.hir_id), span, None); self.field_ty(span, f, args) }) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 3254dddaee9..b193b81f6de 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -588,11 +588,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { { self.typeck_results.field_indices_mut().insert(hir_id, index); } - if let Some(nested_fields) = - self.fcx.typeck_results.borrow_mut().nested_fields_mut().remove(hir_id) - { - self.typeck_results.nested_fields_mut().insert(hir_id, nested_fields); - } } #[instrument(skip(self, span), level = "debug")] diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 9dc5cbaafce..d25fe4219b5 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -19,7 +19,7 @@ //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. -use rustc_ast::{self as ast, Attribute, NestedMetaItem}; +use rustc_ast::{self as ast, Attribute, MetaItemInner}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::LocalDefId; @@ -307,7 +307,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { (name, labels) } - fn resolve_labels(&self, item: &NestedMetaItem, value: Symbol) -> Labels { + fn resolve_labels(&self, item: &MetaItemInner, value: Symbol) -> Labels { let mut out = Labels::default(); for label in value.as_str().split(',') { let label = label.trim(); @@ -415,7 +415,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { } } -fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol { +fn expect_associated_value(tcx: TyCtxt<'_>, item: &MetaItemInner) -> Symbol { if let Some(value) = item.value_str() { value } else if let Some(ident) = item.ident() { diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 52f354b8eca..cae55230b06 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -17,6 +17,7 @@ mod vec; pub use idx::Idx; pub use rustc_index_macros::newtype_index; pub use slice::IndexSlice; +#[doc(no_inline)] pub use vec::IndexVec; /// Type size assertion. The first argument is a type and the second argument is its expected size. diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors.rs index 76ea9c3433d..76ea9c3433d 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors.rs diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 6ce47db8b9b..8c943a961e7 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -25,12 +25,16 @@ //! sometimes useful when the types of `c` and `d` are not traceable //! things. (That system should probably be refactored.) +use relate::lattice::{LatticeOp, LatticeOpKind}; use rustc_middle::bug; +use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate; use rustc_middle::ty::{Const, ImplSubject}; use super::*; -use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation}; +use crate::infer::relate::type_relating::TypeRelating; +use crate::infer::relate::{Relate, TypeRelation}; use crate::traits::Obligation; +use crate::traits::solve::Goal; /// Whether we should define opaque types or just treat them opaquely. /// @@ -82,7 +86,6 @@ impl<'tcx> InferCtxt<'tcx> { reported_trait_errors: self.reported_trait_errors.clone(), reported_signature_mismatch: self.reported_signature_mismatch.clone(), tainted_by_errors: self.tainted_by_errors.clone(), - err_count_on_creation: self.err_count_on_creation, universe: self.universe.clone(), intercrate, next_trait_solver: self.next_trait_solver, @@ -109,14 +112,26 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( - self.infcx, - ToTrace::to_trace(self.cause, expected, actual), - self.param_env, - define_opaque_types, - ); - fields.sup().relate(expected, actual)?; - Ok(InferOk { value: (), obligations: fields.into_obligations() }) + if self.infcx.next_trait_solver { + NextSolverRelate::relate( + self.infcx, + self.param_env, + expected, + ty::Contravariant, + actual, + ) + .map(|goals| self.goals_to_obligations(goals)) + } else { + let mut op = TypeRelating::new( + self.infcx, + ToTrace::to_trace(self.cause, expected, actual), + self.param_env, + define_opaque_types, + ty::Contravariant, + ); + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) + } } /// Makes `expected <: actual`. @@ -129,14 +144,20 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( - self.infcx, - ToTrace::to_trace(self.cause, expected, actual), - self.param_env, - define_opaque_types, - ); - fields.sub().relate(expected, actual)?; - Ok(InferOk { value: (), obligations: fields.into_obligations() }) + if self.infcx.next_trait_solver { + NextSolverRelate::relate(self.infcx, self.param_env, expected, ty::Covariant, actual) + .map(|goals| self.goals_to_obligations(goals)) + } else { + let mut op = TypeRelating::new( + self.infcx, + ToTrace::to_trace(self.cause, expected, actual), + self.param_env, + define_opaque_types, + ty::Covariant, + ); + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) + } } /// Makes `expected == actual`. @@ -168,45 +189,20 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: Relate<TyCtxt<'tcx>>, { - let mut fields = CombineFields::new(self.infcx, trace, self.param_env, define_opaque_types); - fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?; - Ok(InferOk { - value: (), - obligations: fields - .goals - .into_iter() - .map(|goal| { - Obligation::new( - self.infcx.tcx, - fields.trace.cause.clone(), - goal.param_env, - goal.predicate, - ) - }) - .collect(), - }) - } - - /// Equates `expected` and `found` while structurally relating aliases. - /// This should only be used inside of the next generation trait solver - /// when relating rigid aliases. - pub fn eq_structurally_relating_aliases<T>( - self, - expected: T, - actual: T, - ) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - assert!(self.infcx.next_trait_solver()); - let mut fields = CombineFields::new( - self.infcx, - ToTrace::to_trace(self.cause, expected, actual), - self.param_env, - DefineOpaqueTypes::Yes, - ); - fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; - Ok(InferOk { value: (), obligations: fields.into_obligations() }) + if self.infcx.next_trait_solver { + NextSolverRelate::relate(self.infcx, self.param_env, expected, ty::Invariant, actual) + .map(|goals| self.goals_to_obligations(goals)) + } else { + let mut op = TypeRelating::new( + self.infcx, + trace, + self.param_env, + define_opaque_types, + ty::Invariant, + ); + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) + } } pub fn relate<T>( @@ -233,94 +229,43 @@ impl<'a, 'tcx> At<'a, 'tcx> { } } - /// Used in the new solver since we don't care about tracking an `ObligationCause`. - pub fn relate_no_trace<T>( - self, - expected: T, - variance: ty::Variance, - actual: T, - ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> - where - T: Relate<TyCtxt<'tcx>>, - { - let mut fields = CombineFields::new( - self.infcx, - TypeTrace::dummy(self.cause), - self.param_env, - DefineOpaqueTypes::Yes, - ); - fields.sub().relate_with_variance( - variance, - ty::VarianceDiagInfo::default(), - expected, - actual, - )?; - Ok(fields.goals) - } - - /// Used in the new solver since we don't care about tracking an `ObligationCause`. - pub fn eq_structurally_relating_aliases_no_trace<T>( - self, - expected: T, - actual: T, - ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> - where - T: Relate<TyCtxt<'tcx>>, - { - let mut fields = CombineFields::new( - self.infcx, - TypeTrace::dummy(self.cause), - self.param_env, - DefineOpaqueTypes::Yes, - ); - fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; - Ok(fields.goals) - } - /// Computes the least-upper-bound, or mutual supertype, of two /// values. The order of the arguments doesn't matter, but since /// this can result in an error (e.g., if asked to compute LUB of /// u32 and i32), it is meaningful to call one of them the /// "expected type". - pub fn lub<T>( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'tcx, T> + pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( + let mut op = LatticeOp::new( self.infcx, ToTrace::to_trace(self.cause, expected, actual), self.param_env, - define_opaque_types, + LatticeOpKind::Lub, ); - let value = fields.lub().relate(expected, actual)?; - Ok(InferOk { value, obligations: fields.into_obligations() }) + let value = op.relate(expected, actual)?; + Ok(InferOk { value, obligations: op.into_obligations() }) } - /// Computes the greatest-lower-bound, or mutual subtype, of two - /// values. As with `lub` order doesn't matter, except for error - /// cases. - pub fn glb<T>( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'tcx, T> - where - T: ToTrace<'tcx>, - { - let mut fields = CombineFields::new( - self.infcx, - ToTrace::to_trace(self.cause, expected, actual), - self.param_env, - define_opaque_types, - ); - let value = fields.glb().relate(expected, actual)?; - Ok(InferOk { value, obligations: fields.into_obligations() }) + fn goals_to_obligations( + &self, + goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + ) -> InferOk<'tcx, ()> { + InferOk { + value: (), + obligations: goals + .into_iter() + .map(|goal| { + Obligation::new( + self.infcx.tcx, + self.cause.clone(), + goal.param_env, + goal.predicate, + ) + }) + .collect(), + } } } @@ -382,21 +327,7 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())) } - - ( - GenericArgKind::Lifetime(_), - GenericArgKind::Type(_) | GenericArgKind::Const(_), - ) - | ( - GenericArgKind::Type(_), - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_), - ) - | ( - GenericArgKind::Const(_), - GenericArgKind::Lifetime(_) | GenericArgKind::Type(_), - ) => { - bug!("relating different kinds: {a:?} {b:?}") - } + _ => bug!("relating different kinds: {a:?} {b:?}"), }, } } diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index c06836edcfb..57007752cad 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,22 +1,27 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::traits::ObligationCause; -use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode}; +use rustc_middle::traits::solve::SolverMode; use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::relate::RelateResult; +use rustc_middle::ty::relate::combine::PredicateEmittingRelation; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; -use rustc_type_ir::InferCtxtLike; -use rustc_type_ir::relate::Relate; +use rustc_span::{DUMMY_SP, ErrorGuaranteed}; use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin}; -impl<'tcx> InferCtxtLike for InferCtxt<'tcx> { +impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { type Interner = TyCtxt<'tcx>; fn cx(&self) -> TyCtxt<'tcx> { self.tcx } + fn next_trait_solver(&self) -> bool { + self.next_trait_solver + } + fn solver_mode(&self) -> ty::solve::SolverMode { match self.intercrate { true => SolverMode::Coherence, @@ -131,29 +136,86 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> { self.enter_forall(value, f) } - fn relate<T: Relate<TyCtxt<'tcx>>>( + fn equate_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) { + self.inner.borrow_mut().type_variables().equate(a, b); + } + + fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) { + self.inner.borrow_mut().int_unification_table().union(a, b); + } + + fn equate_float_vids_raw(&self, a: rustc_type_ir::FloatVid, b: rustc_type_ir::FloatVid) { + self.inner.borrow_mut().float_unification_table().union(a, b); + } + + fn equate_const_vids_raw(&self, a: rustc_type_ir::ConstVid, b: rustc_type_ir::ConstVid) { + self.inner.borrow_mut().const_unification_table().union(a, b); + } + + fn equate_effect_vids_raw(&self, a: rustc_type_ir::EffectVid, b: rustc_type_ir::EffectVid) { + self.inner.borrow_mut().effect_unification_table().union(a, b); + } + + fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>( &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + relation: &mut R, + target_is_expected: bool, + target_vid: rustc_type_ir::TyVid, + instantiation_variance: rustc_type_ir::Variance, + source_ty: Ty<'tcx>, + ) -> RelateResult<'tcx, ()> { + self.instantiate_ty_var( + relation, + target_is_expected, + target_vid, + instantiation_variance, + source_ty, + ) + } + + fn instantiate_int_var_raw( + &self, + vid: rustc_type_ir::IntVid, + value: rustc_type_ir::IntVarValue, + ) { + self.inner.borrow_mut().int_unification_table().union_value(vid, value); + } + + fn instantiate_float_var_raw( + &self, + vid: rustc_type_ir::FloatVid, + value: rustc_type_ir::FloatVarValue, + ) { + self.inner.borrow_mut().float_unification_table().union_value(vid, value); + } + + fn instantiate_effect_var_raw(&self, vid: rustc_type_ir::EffectVid, value: ty::Const<'tcx>) { + self.inner + .borrow_mut() + .effect_unification_table() + .union_value(vid, EffectVarValue::Known(value)); } - fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>( + fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>( &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases_no_trace(lhs, rhs) + relation: &mut R, + target_is_expected: bool, + target_vid: rustc_type_ir::ConstVid, + source_ct: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ()> { + self.instantiate_const_var(relation, target_is_expected, target_vid, source_ct) + } + + fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { + self.set_tainted_by_errors(e) } fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> { self.shallow_resolve(ty) } + fn shallow_resolve_const(&self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + self.shallow_resolve_const(ct) + } fn resolve_vars_if_possible<T>(&self, value: T) -> T where @@ -167,7 +229,19 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> { } fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) { - self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), sub, sup) + self.inner.borrow_mut().unwrap_region_constraints().make_subregion( + SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), + sub, + sup, + ); + } + + fn equate_regions(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) { + self.inner.borrow_mut().unwrap_region_constraints().make_eqregion( + SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), + a, + b, + ); } fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 5fa1bf51634..bc813305ba4 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -14,11 +14,11 @@ use region_constraints::{ GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound, }; pub use relate::StructurallyRelateAliases; -pub use relate::combine::{CombineFields, PredicateEmittingRelation}; +pub use relate::combine::PredicateEmittingRelation; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::undo_log::Rollback; +use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify as ut; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_hir as hir; @@ -32,7 +32,6 @@ use rustc_middle::infer::unify_key::{ use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::traits::select; -use rustc_middle::traits::solve::{Goal, NoSolution}; pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{ @@ -50,24 +49,31 @@ use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; -use crate::infer::relate::RelateResult; +use crate::infer::region_constraints::UndoLog; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; pub mod at; pub mod canonical; mod context; -pub mod free_regions; +mod free_regions; mod freshen; mod lexical_region_resolve; -pub mod opaque_types; +mod opaque_types; pub mod outlives; mod projection; pub mod region_constraints; pub mod relate; pub mod resolve; pub(crate) mod snapshot; -pub mod type_variable; - +mod type_variable; + +/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper +/// around `Vec<PredicateObligation<'tcx>>`, but it has one important property: +/// because `InferOk` is marked with `#[must_use]`, if you have a method +/// `InferCtxt::f` that returns `InferResult<'tcx, ()>` and you call it with +/// `infcx.f()?;` you'll get a warning about the obligations being discarded +/// without use, which is probably unintentional and has been a source of bugs +/// in the past. #[must_use] #[derive(Debug)] pub struct InferOk<'tcx, T> { @@ -76,8 +82,7 @@ pub struct InferOk<'tcx, T> { } pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>; -pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" -pub type FixupResult<T> = Result<T, FixupError>; // "fixup result" +pub(crate) type FixupResult<T> = Result<T, FixupError>; // "fixup result" pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>, @@ -165,12 +170,12 @@ impl<'tcx> InferCtxtInner<'tcx> { undo_log: InferCtxtUndoLogs::default(), projection_cache: Default::default(), - type_variable_storage: type_variable::TypeVariableStorage::new(), - const_unification_storage: ut::UnificationTableStorage::new(), - int_unification_storage: ut::UnificationTableStorage::new(), - float_unification_storage: ut::UnificationTableStorage::new(), - effect_unification_storage: ut::UnificationTableStorage::new(), - region_constraint_storage: Some(RegionConstraintStorage::new()), + type_variable_storage: Default::default(), + const_unification_storage: Default::default(), + int_unification_storage: Default::default(), + float_unification_storage: Default::default(), + effect_unification_storage: Default::default(), + region_constraint_storage: Some(Default::default()), region_obligations: vec![], opaque_type_storage: Default::default(), } @@ -202,7 +207,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { + fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { self.opaque_type_storage.with_log(&mut self.undo_log) } @@ -280,27 +285,14 @@ pub struct InferCtxt<'tcx> { pub reported_signature_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>, /// When an error occurs, we want to avoid reporting "derived" - /// errors that are due to this original failure. Normally, we - /// handle this with the `err_count_on_creation` count, which - /// basically just tracks how many errors were reported when we - /// started type-checking a fn and checks to see if any new errors - /// have been reported since then. Not great, but it works. - /// - /// However, when errors originated in other passes -- notably - /// resolve -- this heuristic breaks down. Therefore, we have this - /// auxiliary flag that one can set whenever one creates a - /// type-error that is due to an error in a prior pass. + /// errors that are due to this original failure. We have this + /// flag that one can set whenever one creates a type-error that + /// is due to an error in a prior pass. /// /// Don't read this flag directly, call `is_tainted_by_errors()` /// and `set_tainted_by_errors()`. tainted_by_errors: Cell<Option<ErrorGuaranteed>>, - /// Track how many errors were reported when this infcx is created. - /// If the number of errors increases, that's also a sign (like - /// `tainted_by_errors`) to avoid reporting certain kinds of errors. - // FIXME(matthewjasper) Merge into `tainted_by_errors` - err_count_on_creation: usize, - /// What is the innermost universe we have created? Starts out as /// `UniverseIndex::root()` but grows from there as we enter /// universal quantifiers. @@ -347,7 +339,6 @@ pub enum ValuePairs<'tcx> { PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>), ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>), ExistentialProjection(ExpectedFound<ty::PolyExistentialProjection<'tcx>>), - Dummy, } impl<'tcx> ValuePairs<'tcx> { @@ -509,46 +500,41 @@ pub enum NllRegionVariableOrigin { }, } -// FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`. #[derive(Copy, Clone, Debug)] -pub enum FixupError { - UnresolvedIntTy(IntVid), - UnresolvedFloatTy(FloatVid), - UnresolvedTy(TyVid), - UnresolvedConst(ConstVid), - UnresolvedEffect(EffectVid), -} - -/// See the `region_obligations` field for more information. -#[derive(Clone, Debug)] -pub struct RegionObligation<'tcx> { - pub sub_region: ty::Region<'tcx>, - pub sup_type: Ty<'tcx>, - pub origin: SubregionOrigin<'tcx>, +pub struct FixupError { + unresolved: TyOrConstInferVar, } impl fmt::Display for FixupError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::FixupError::*; + use TyOrConstInferVar::*; - match *self { - UnresolvedIntTy(_) => write!( + match self.unresolved { + TyInt(_) => write!( f, "cannot determine the type of this integer; \ add a suffix to specify the type explicitly" ), - UnresolvedFloatTy(_) => write!( + TyFloat(_) => write!( f, "cannot determine the type of this number; \ add a suffix to specify the type explicitly" ), - UnresolvedTy(_) => write!(f, "unconstrained type"), - UnresolvedConst(_) => write!(f, "unconstrained const value"), - UnresolvedEffect(_) => write!(f, "unconstrained effect value"), + Ty(_) => write!(f, "unconstrained type"), + Const(_) => write!(f, "unconstrained const value"), + Effect(_) => write!(f, "unconstrained effect value"), } } } +/// See the `region_obligations` field for more information. +#[derive(Clone, Debug)] +pub struct RegionObligation<'tcx> { + pub sub_region: ty::Region<'tcx>, + pub sup_type: Ty<'tcx>, + pub origin: SubregionOrigin<'tcx>, +} + /// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, @@ -588,14 +574,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn with_defining_opaque_types( - mut self, - defining_opaque_types: &'tcx ty::List<LocalDefId>, - ) -> Self { - self.defining_opaque_types = defining_opaque_types; - self - } - pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self { self.next_trait_solver = next_trait_solver; self @@ -624,14 +602,15 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// the bound values in `C` to their instantiated values in `V` /// (in other words, `S(C) = V`). pub fn build_with_canonical<T>( - self, + mut self, span: Span, canonical: &Canonical<'tcx, T>, ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>) where T: TypeFoldable<TyCtxt<'tcx>>, { - let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build(); + self.defining_opaque_types = canonical.defining_opaque_types; + let infcx = self.build(); let (value, args) = infcx.instantiate_canonical(span, canonical); (infcx, value, args) } @@ -657,7 +636,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_trait_errors: Default::default(), reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), - err_count_on_creation: tcx.dcx().err_count_excluding_lint_errs(), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, next_trait_solver, @@ -776,7 +754,7 @@ impl<'tcx> InferCtxt<'tcx> { definition_span: Span, hidden_ty: Ty<'tcx>, region: ty::Region<'tcx>, - in_regions: &Lrc<Vec<ty::Region<'tcx>>>, + in_regions: Lrc<Vec<ty::Region<'tcx>>>, ) { self.inner.borrow_mut().unwrap_region_constraints().member_constraint( key, @@ -919,28 +897,16 @@ impl<'tcx> InferCtxt<'tcx> { ty::Const::new_var(self.tcx, vid) } - pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid { - self.inner - .borrow_mut() - .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) - .vid - } - - fn next_int_var_id(&self) -> IntVid { - self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown) - } - pub fn next_int_var(&self) -> Ty<'tcx> { - Ty::new_int_var(self.tcx, self.next_int_var_id()) - } - - fn next_float_var_id(&self) -> FloatVid { - self.inner.borrow_mut().float_unification_table().new_key(ty::FloatVarValue::Unknown) + let next_int_var_id = + self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown); + Ty::new_int_var(self.tcx, next_int_var_id) } pub fn next_float_var(&self) -> Ty<'tcx> { - Ty::new_float_var(self.tcx, self.next_float_var_id()) + let next_float_var_id = + self.inner.borrow_mut().float_unification_table().new_key(ty::FloatVarValue::Unknown); + Ty::new_float_var(self.tcx, next_float_var_id) } /// Creates a fresh region variable with the next available index. @@ -1044,8 +1010,8 @@ impl<'tcx> InferCtxt<'tcx> { ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)).into() } - /// Given a set of generics defined on a type or impl, returns the generic parameters mapping each - /// type/region parameter to a fresh inference variable. + /// Given a set of generics defined on a type or impl, returns the generic parameters mapping + /// each type/region parameter to a fresh inference variable. pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> { GenericArgs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param)) } @@ -1076,18 +1042,14 @@ impl<'tcx> InferCtxt<'tcx> { /// Clone the list of variable regions. This is used only during NLL processing /// to put the set of region variables into the NLL region context. pub fn get_region_var_origins(&self) -> VarInfos { - let mut inner = self.inner.borrow_mut(); - let (var_infos, data) = inner - .region_constraint_storage - // We clone instead of taking because borrowck still wants to use - // the inference context after calling this for diagnostics - // and the new trait solver. - .clone() - .expect("regions already resolved") - .with_log(&mut inner.undo_log) - .into_infos_and_data(); - assert!(data.is_empty()); - var_infos + let inner = self.inner.borrow(); + assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&inner.undo_log)); + let storage = inner.region_constraint_storage.as_ref().expect("regions already resolved"); + assert!(storage.data.is_empty()); + // We clone instead of taking because borrowck still wants to use the + // inference context after calling this for diagnostics and the new + // trait solver. + storage.var_infos.clone() } #[instrument(level = "debug", skip(self), ret)] @@ -1353,7 +1315,7 @@ impl<'tcx> InferCtxt<'tcx> { } /// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method. - pub fn verify_generic_bound( + pub(crate) fn verify_generic_bound( &self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, @@ -1423,10 +1385,10 @@ impl<'tcx> InferCtxt<'tcx> { /// /// The constant can be located on a trait like `<A as B>::C`, in which case the given /// generic parameters and environment are used to resolve the constant. Alternatively if the - /// constant has generic parameters in scope the instantiations are used to evaluate the value of - /// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count - /// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is still - /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is + /// constant has generic parameters in scope the instantiations are used to evaluate the value + /// of the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count + /// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is + /// still too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is /// returned. /// /// This handles inferences variables within both `param_env` and `args` by @@ -1674,10 +1636,6 @@ impl<'tcx> TypeTrace<'tcx> { values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } - - fn dummy(cause: &ObligationCause<'tcx>) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: ValuePairs::Dummy } - } } impl<'tcx> SubregionOrigin<'tcx> { diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 55c51bc856f..365ddaba138 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -13,16 +13,15 @@ use rustc_middle::ty::{ use rustc_span::Span; use tracing::{debug, instrument}; +use super::DefineOpaqueTypes; use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{InferCtxt, InferOk}; use crate::traits::{self, Obligation}; mod table; -pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; -pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; - -use super::DefineOpaqueTypes; +pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; +pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable}; /// Information about the opaque types whose values we /// are inferring in this function (these are the `impl Trait` that @@ -149,11 +148,11 @@ impl<'tcx> InferCtxt<'tcx> { } if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { - // We could accept this, but there are various ways to handle this situation, and we don't - // want to make a decision on it right now. Likely this case is so super rare anyway, that - // no one encounters it in practice. - // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, - // where it is of no concern, so we only check for TAITs. + // We could accept this, but there are various ways to handle this situation, + // and we don't want to make a decision on it right now. Likely this case is so + // super rare anyway, that no one encounters it in practice. It does occur + // however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, where + // it is of no concern, so we only check for TAITs. if self.can_define_opaque_ty(b_def_id) && self.tcx.is_type_alias_impl_trait(b_def_id) { @@ -359,7 +358,15 @@ impl<'tcx> InferCtxt<'tcx> { // not currently sound until we have existential regions. concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { tcx: self.tcx, - op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions), + op: |r| { + self.member_constraint( + opaque_type_key, + span, + concrete_ty, + r, + choice_regions.clone(), + ) + }, }); } } @@ -377,9 +384,9 @@ impl<'tcx> InferCtxt<'tcx> { /// /// We ignore any type parameters because impl trait values are assumed to /// capture all the in-scope type parameters. -pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> { - pub tcx: TyCtxt<'tcx>, - pub op: OP, +struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> { + tcx: TyCtxt<'tcx>, + op: OP, } impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> @@ -455,20 +462,6 @@ where } } -pub enum UseKind { - DefiningUse, - OpaqueUse, -} - -impl UseKind { - pub fn is_defining(self) -> bool { - match self { - UseKind::DefiningUse => true, - UseKind::OpaqueUse => false, - } - } -} - impl<'tcx> InferCtxt<'tcx> { #[instrument(skip(self), level = "debug")] fn register_hidden_type( diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 4aa2ccab0e7..047d8edad3d 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -7,7 +7,7 @@ use super::{OpaqueTypeDecl, OpaqueTypeMap}; use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; #[derive(Default, Debug, Clone)] -pub struct OpaqueTypeStorage<'tcx> { +pub(crate) struct OpaqueTypeStorage<'tcx> { /// Opaque types found in explicit return types and their /// associated fresh inference variable. Writeback resolves these /// variables to get the concrete type, which can be used to @@ -46,7 +46,7 @@ impl<'tcx> Drop for OpaqueTypeStorage<'tcx> { } } -pub struct OpaqueTypeTable<'a, 'tcx> { +pub(crate) struct OpaqueTypeTable<'a, 'tcx> { storage: &'a mut OpaqueTypeStorage<'tcx>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index a071b84a1a0..9300fc574dc 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,8 +1,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; -use rustc_middle::bug; -use rustc_middle::ty::{self, Region}; -use tracing::{debug, instrument}; +use rustc_middle::{bug, ty}; +use tracing::debug; use super::explicit_outlives_bounds; use crate::infer::GenericKind; @@ -54,37 +53,16 @@ pub struct OutlivesEnvironment<'tcx> { region_bound_pairs: RegionBoundPairs<'tcx>, } -/// Builder of OutlivesEnvironment. -#[derive(Debug)] -struct OutlivesEnvironmentBuilder<'tcx> { - param_env: ty::ParamEnv<'tcx>, - region_relation: TransitiveRelationBuilder<Region<'tcx>>, - region_bound_pairs: RegionBoundPairs<'tcx>, -} - /// "Region-bound pairs" tracks outlives relations that are known to /// be true, either because of explicit where-clauses like `T: 'a` or /// because of implied bounds. pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>; impl<'tcx> OutlivesEnvironment<'tcx> { - /// Create a builder using `ParamEnv` and add explicit outlives bounds into it. - fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> { - let mut builder = OutlivesEnvironmentBuilder { - param_env, - region_relation: Default::default(), - region_bound_pairs: Default::default(), - }; - - builder.add_outlives_bounds(explicit_outlives_bounds(param_env)); - - builder - } - - #[inline] /// Create a new `OutlivesEnvironment` without extra outlives bounds. + #[inline] pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self { - Self::builder(param_env).build() + Self::with_bounds(param_env, vec![]) } /// Create a new `OutlivesEnvironment` with extra outlives bounds. @@ -92,56 +70,27 @@ impl<'tcx> OutlivesEnvironment<'tcx> { param_env: ty::ParamEnv<'tcx>, extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>, ) -> Self { - let mut builder = Self::builder(param_env); - builder.add_outlives_bounds(extra_bounds); - builder.build() - } + let mut region_relation = TransitiveRelationBuilder::default(); + let mut region_bound_pairs = RegionBoundPairs::default(); - /// Borrows current value of the `free_region_map`. - pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> { - &self.free_region_map - } - - /// Borrows current `region_bound_pairs`. - pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> { - &self.region_bound_pairs - } -} - -impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { - #[inline] - #[instrument(level = "debug")] - fn build(self) -> OutlivesEnvironment<'tcx> { - OutlivesEnvironment { - param_env: self.param_env, - free_region_map: FreeRegionMap { relation: self.region_relation.freeze() }, - region_bound_pairs: self.region_bound_pairs, - } - } - - /// Processes outlives bounds that are known to hold, whether from implied or other sources. - fn add_outlives_bounds<I>(&mut self, outlives_bounds: I) - where - I: IntoIterator<Item = OutlivesBound<'tcx>>, - { // Record relationships such as `T:'x` that don't go into the // free-region-map but which we use here. - for outlives_bound in outlives_bounds { + for outlives_bound in explicit_outlives_bounds(param_env).chain(extra_bounds) { debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound); match outlives_bound { OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs + region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } OutlivesBound::RegionSubAlias(r_a, alias_b) => { - self.region_bound_pairs + region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) { ( ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), - ) => self.region_relation.add(r_a, r_b), + ) => region_relation.add(r_a, r_b), (ty::ReError(_), _) | (_, ty::ReError(_)) => {} // FIXME(#109628): We shouldn't have existential variables in implied bounds. // Panic here once the linked issue is resolved! @@ -150,5 +99,21 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { }, } } + + OutlivesEnvironment { + param_env, + free_region_map: FreeRegionMap { relation: region_relation.freeze() }, + region_bound_pairs, + } + } + + /// Borrows current value of the `free_region_map`. + pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> { + &self.free_region_map + } + + /// Borrows current `region_bound_pairs`. + pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> { + &self.region_bound_pairs } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index f5c873b0375..e23bb1aaa56 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,11 +1,12 @@ //! Various code related to computing outlives relations. +use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::traits::query::{NoSolution, OutlivesBound}; use rustc_middle::ty; use tracing::instrument; use self::env::OutlivesEnvironment; -use super::region_constraints::RegionConstraintData; +use super::region_constraints::{RegionConstraintData, UndoLog}; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; @@ -14,7 +15,7 @@ pub mod env; pub mod for_liveness; pub mod obligations; pub mod test_type_match; -pub mod verify; +pub(crate) mod verify; #[instrument(level = "debug", skip(param_env), ret)] pub fn explicit_outlives_bounds<'tcx>( @@ -63,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { } }; - let (var_infos, data) = { + let storage = { let mut inner = self.inner.borrow_mut(); let inner = &mut *inner; assert!( @@ -71,18 +72,14 @@ impl<'tcx> InferCtxt<'tcx> { "region_obligations not empty: {:#?}", inner.region_obligations ); - inner - .region_constraint_storage - .take() - .expect("regions already resolved") - .with_log(&mut inner.undo_log) - .into_infos_and_data() + assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&inner.undo_log)); + inner.region_constraint_storage.take().expect("regions already resolved") }; let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); let (lexical_region_resolutions, errors) = - lexical_region_resolve::resolve(region_rels, var_infos, data); + lexical_region_resolve::resolve(region_rels, storage.var_infos, storage.data); let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); assert!(old_value.is_none()); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 634cda86bc3..e0e03a29220 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -396,11 +396,12 @@ where // 'a` in the environment but `trait Foo<'b> { type Item: 'b // }` in the trait definition. approx_env_bounds.retain(|bound_outlives| { - // OK to skip binder because we only manipulate and compare against other - // values from the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a` - // in `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region. - // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait` - // will be invoked with `['b => ^1]` and so we will get `^1` returned. + // OK to skip binder because we only manipulate and compare against other values from + // the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a` in + // `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region. If the + // declaration is `trait Trait<'b> { type Item: 'b; }`, then + // `projection_declared_bounds_from_trait` will be invoked with `['b => ^1]` and so we + // will get `^1` returned. let bound = bound_outlives.skip_binder(); let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") }; self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1) diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 74a80a1b9aa..247fbc25965 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -15,7 +15,7 @@ use crate::infer::{GenericKind, VerifyBound}; /// via a "delegate" of type `D` -- this is usually the `infcx`, which /// accrues them into the `region_obligations` code, but for NLL we /// use something else. -pub struct VerifyBoundCx<'cx, 'tcx> { +pub(crate) struct VerifyBoundCx<'cx, 'tcx> { tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, /// During borrowck, if there are no outlives bounds on a generic @@ -28,7 +28,7 @@ pub struct VerifyBoundCx<'cx, 'tcx> { } impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { - pub fn new( + pub(crate) fn new( tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, implicit_region_bound: Option<ty::Region<'tcx>>, @@ -38,7 +38,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { + pub(crate) fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { // Start with anything like `T: 'a` we can scrape from the // environment. If the environment contains something like // `for<'a> T: 'a`, then we know that `T` outlives everything. @@ -92,7 +92,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// the clause from the environment only applies if `'0 = 'a`, /// which we don't know yet. But we would still include `'b` in /// this list. - pub fn approx_declared_bounds_from_env( + pub(crate) fn approx_declared_bounds_from_env( &self, alias_ty: ty::AliasTy<'tcx>, ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> { @@ -101,7 +101,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> { + pub(crate) fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> { let alias_ty_as_ty = alias_ty.to_ty(self.tcx); // Search the env for where clauses like `P: 'a`. @@ -285,7 +285,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// /// This is for simplicity, and because we are not really smart /// enough to cope with such bounds anywhere. - pub fn declared_bounds_from_definition( + pub(crate) fn declared_bounds_from_definition( &self, alias_ty: ty::AliasTy<'tcx>, ) -> impl Iterator<Item = ty::Region<'tcx>> { diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 7913f0e340e..3cfc58dea05 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -55,8 +55,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// * what placeholder they must outlive transitively /// * if they must also be equal to a placeholder, report an error because `P1: P2` /// * minimum universe U of all SCCs they must outlive - /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that - /// indicates `P: R` and `R` is in an incompatible universe + /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as + /// that indicates `P: R` and `R` is in an incompatible universe /// /// To improve performance and for the old trait solver caching to be sound, this takes /// an optional snapshot in which case we only look at region constraints added in that @@ -73,7 +73,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// * R: P1, R: P2, as above #[instrument(level = "debug", skip(self, tcx, only_consider_snapshot), ret)] pub fn leak_check( - &mut self, + self, tcx: TyCtxt<'tcx>, outer_universe: ty::UniverseIndex, max_universe: ty::UniverseIndex, @@ -83,7 +83,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { return Ok(()); } - let mini_graph = &MiniGraph::new(tcx, self, only_consider_snapshot); + let mini_graph = MiniGraph::new(tcx, &self, only_consider_snapshot); let mut leak_check = LeakCheck::new(tcx, outer_universe, max_universe, mini_graph, self); leak_check.assign_placeholder_values()?; @@ -92,11 +92,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } -struct LeakCheck<'a, 'b, 'tcx> { +struct LeakCheck<'a, 'tcx> { tcx: TyCtxt<'tcx>, outer_universe: ty::UniverseIndex, - mini_graph: &'a MiniGraph<'tcx>, - rcc: &'a mut RegionConstraintCollector<'b, 'tcx>, + mini_graph: MiniGraph<'tcx>, + rcc: RegionConstraintCollector<'a, 'tcx>, // Initially, for each SCC S, stores a placeholder `P` such that `S = P` // must hold. @@ -115,26 +115,27 @@ struct LeakCheck<'a, 'b, 'tcx> { // either the placeholder `P1` or the empty region in that same universe. // // To detect errors, we look for an SCC S where the values in - // `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`. + // `scc_placeholders[S]` (if any) cannot be stored into `scc_universes[S]`. scc_universes: IndexVec<LeakCheckScc, SccUniverse<'tcx>>, } -impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { +impl<'a, 'tcx> LeakCheck<'a, 'tcx> { fn new( tcx: TyCtxt<'tcx>, outer_universe: ty::UniverseIndex, max_universe: ty::UniverseIndex, - mini_graph: &'a MiniGraph<'tcx>, - rcc: &'a mut RegionConstraintCollector<'b, 'tcx>, + mini_graph: MiniGraph<'tcx>, + rcc: RegionConstraintCollector<'a, 'tcx>, ) -> Self { let dummy_scc_universe = SccUniverse { universe: max_universe, region: None }; + let num_sccs = mini_graph.sccs.num_sccs(); Self { tcx, outer_universe, mini_graph, rcc, - scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()), - scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()), + scc_placeholders: IndexVec::from_elem_n(None, num_sccs), + scc_universes: IndexVec::from_elem_n(dummy_scc_universe, num_sccs), } } @@ -156,7 +157,16 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { // Detect those SCCs that directly contain a placeholder if let ty::RePlaceholder(placeholder) = **region { if self.outer_universe.cannot_name(placeholder.universe) { - self.assign_scc_value(scc, placeholder)?; + // Update `scc_placeholders` to account for the fact that `P: S` must hold. + match self.scc_placeholders[scc] { + Some(p) => { + assert_ne!(p, placeholder); + return Err(self.placeholder_error(p, placeholder)); + } + None => { + self.scc_placeholders[scc] = Some(placeholder); + } + } } } } @@ -164,26 +174,6 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { Ok(()) } - // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold. - // This may create an error. - fn assign_scc_value( - &mut self, - scc: LeakCheckScc, - placeholder: ty::PlaceholderRegion, - ) -> RelateResult<'tcx, ()> { - match self.scc_placeholders[scc] { - Some(p) => { - assert_ne!(p, placeholder); - return Err(self.placeholder_error(p, placeholder)); - } - None => { - self.scc_placeholders[scc] = Some(placeholder); - } - }; - - Ok(()) - } - /// For each SCC S, iterate over each successor S1 where `S: S1`: /// /// * Compute @@ -216,8 +206,8 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { // Walk over each `scc2` such that `scc1: scc2` and compute: // // * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1` - // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple, - // we pick one arbitrarily) + // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there + // are multiple, we pick one arbitrarily) let mut scc1_universe = self.scc_universes[scc1]; let mut succ_bound = None; for &scc2 in self.mini_graph.sccs.successors(scc1) { @@ -260,7 +250,8 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { self.scc_placeholders[scc1] = succ_bound; } - // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any). + // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must + // outlive (if any). } Ok(()) } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 82f7668b2d2..270217e26b7 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -27,9 +27,9 @@ pub use rustc_middle::infer::MemberConstraint; #[derive(Clone, Default)] pub struct RegionConstraintStorage<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. - var_infos: IndexVec<RegionVid, RegionVariableInfo>, + pub(super) var_infos: IndexVec<RegionVid, RegionVariableInfo>, - data: RegionConstraintData<'tcx>, + pub(super) data: RegionConstraintData<'tcx>, /// For a given pair of regions (R1, R2), maps to a region R3 that /// is designated as their LUB (edges R1 <= R3 and R2 <= R3 @@ -61,21 +61,6 @@ pub struct RegionConstraintCollector<'a, 'tcx> { undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } -impl<'tcx> std::ops::Deref for RegionConstraintCollector<'_, 'tcx> { - type Target = RegionConstraintStorage<'tcx>; - #[inline] - fn deref(&self) -> &RegionConstraintStorage<'tcx> { - self.storage - } -} - -impl<'tcx> std::ops::DerefMut for RegionConstraintCollector<'_, 'tcx> { - #[inline] - fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> { - self.storage - } -} - pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>; /// The full set of region constraints gathered up by the collector. @@ -304,15 +289,11 @@ pub struct RegionVariableInfo { pub universe: ty::UniverseIndex, } -pub struct RegionSnapshot { +pub(crate) struct RegionSnapshot { any_unifications: bool, } impl<'tcx> RegionConstraintStorage<'tcx> { - pub fn new() -> Self { - Self::default() - } - #[inline] pub(crate) fn with_log<'a>( &'a mut self, @@ -320,46 +301,15 @@ impl<'tcx> RegionConstraintStorage<'tcx> { ) -> RegionConstraintCollector<'a, 'tcx> { RegionConstraintCollector { storage: self, undo_log } } - - fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) { - match undo_entry { - AddVar(vid) => { - self.var_infos.pop().unwrap(); - assert_eq!(self.var_infos.len(), vid.index()); - } - AddConstraint(index) => { - self.data.constraints.pop().unwrap(); - assert_eq!(self.data.constraints.len(), index); - } - AddVerify(index) => { - self.data.verifys.pop(); - assert_eq!(self.data.verifys.len(), index); - } - AddCombination(Glb, ref regions) => { - self.glbs.remove(regions); - } - AddCombination(Lub, ref regions) => { - self.lubs.remove(regions); - } - } - } } impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn num_region_vars(&self) -> usize { - self.var_infos.len() + self.storage.var_infos.len() } pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> { - &self.data - } - - /// Once all the constraints have been gathered, extract out the final data. - /// - /// Not legal during a snapshot. - pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) { - assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&self.undo_log)); - (mem::take(&mut self.storage.var_infos), mem::take(&mut self.storage.data)) + &self.storage.data } /// Takes (and clears) the current set of constraints. Note that @@ -415,17 +365,17 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } pub fn data(&self) -> &RegionConstraintData<'tcx> { - &self.data + &self.storage.data } - pub(super) fn start_snapshot(&mut self) -> RegionSnapshot { + pub(super) fn start_snapshot(&self) -> RegionSnapshot { debug!("RegionConstraintCollector: start_snapshot"); - RegionSnapshot { any_unifications: self.any_unifications } + RegionSnapshot { any_unifications: self.storage.any_unifications } } pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) { debug!("RegionConstraintCollector: rollback_to({:?})", snapshot); - self.any_unifications = snapshot.any_unifications; + self.storage.any_unifications = snapshot.any_unifications; } pub(super) fn new_region_var( @@ -433,7 +383,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { universe: ty::UniverseIndex, origin: RegionVariableOrigin, ) -> RegionVid { - let vid = self.var_infos.push(RegionVariableInfo { origin, universe }); + let vid = self.storage.var_infos.push(RegionVariableInfo { origin, universe }); let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe }); assert_eq!(vid, u_vid.vid); @@ -444,7 +394,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Returns the origin for the given variable. pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { - self.var_infos[vid].origin + self.storage.var_infos[vid].origin } fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) { @@ -467,8 +417,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { return; } - let index = self.data.verifys.len(); - self.data.verifys.push(verify); + let index = self.storage.data.verifys.len(); + self.storage.data.verifys.push(verify); self.undo_log.push(AddVerify(index)); } @@ -488,7 +438,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { (ty::ReVar(a), ty::ReVar(b)) => { debug!("make_eqregion: unifying {:?} with {:?}", a, b); if self.unification_table_mut().unify_var_var(a, b).is_ok() { - self.any_unifications = true; + self.storage.any_unifications = true; } } (ty::ReVar(vid), _) => { @@ -498,7 +448,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { .unify_var_value(vid, RegionVariableValue::Known { value: b }) .is_ok() { - self.any_unifications = true; + self.storage.any_unifications = true; }; } (_, ty::ReVar(vid)) => { @@ -508,7 +458,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { .unify_var_value(vid, RegionVariableValue::Known { value: a }) .is_ok() { - self.any_unifications = true; + self.storage.any_unifications = true; }; } (_, _) => {} @@ -522,7 +472,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { definition_span: Span, hidden_ty: Ty<'tcx>, member_region: ty::Region<'tcx>, - choice_regions: &Lrc<Vec<ty::Region<'tcx>>>, + choice_regions: Lrc<Vec<ty::Region<'tcx>>>, ) { debug!("member_constraint({:?} in {:#?})", member_region, choice_regions); @@ -530,12 +480,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { return; } - self.data.member_constraints.push(MemberConstraint { + self.storage.data.member_constraints.push(MemberConstraint { key, definition_span, hidden_ty, member_region, - choice_regions: choice_regions.clone(), + choice_regions, }); } @@ -646,8 +596,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> { match t { - Glb => &mut self.glbs, - Lub => &mut self.lubs, + Glb => &mut self.storage.glbs, + Lub => &mut self.storage.lubs, } } @@ -700,11 +650,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { &self, value_count: usize, ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) { - let range = RegionVid::from(value_count)..RegionVid::from(self.unification_table.len()); + let range = + RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len()); ( range.clone(), (range.start.index()..range.end.index()) - .map(|index| self.var_infos[ty::RegionVid::from(index)].origin) + .map(|index| self.storage.var_infos[ty::RegionVid::from(index)].origin) .collect(), ) } @@ -801,6 +752,25 @@ impl<'tcx> RegionConstraintData<'tcx> { impl<'tcx> Rollback<UndoLog<'tcx>> for RegionConstraintStorage<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { - self.rollback_undo_entry(undo) + match undo { + AddVar(vid) => { + self.var_infos.pop().unwrap(); + assert_eq!(self.var_infos.len(), vid.index()); + } + AddConstraint(index) => { + self.data.constraints.pop().unwrap(); + assert_eq!(self.data.constraints.len(), index); + } + AddVerify(index) => { + self.data.verifys.pop(); + assert_eq!(self.data.verifys.len(), index); + } + AddCombination(Glb, ref regions) => { + self.glbs.remove(regions); + } + AddCombination(Lub, ref regions) => { + self.lubs.remove(regions); + } + } } } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs deleted file mode 100644 index 4a8c7387ddc..00000000000 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ /dev/null @@ -1,330 +0,0 @@ -//! There are four type combiners: [TypeRelating], `Lub`, and `Glb`, -//! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL. -//! -//! Each implements the trait [TypeRelation] and contains methods for -//! combining two instances of various things and yielding a new instance. -//! These combiner methods always yield a `Result<T>`. To relate two -//! types, you can use `infcx.at(cause, param_env)` which then allows -//! you to use the relevant methods of [At](crate::infer::at::At). -//! -//! Combiners mostly do their specific behavior and then hand off the -//! bulk of the work to [InferCtxt::super_combine_tys] and -//! [InferCtxt::super_combine_consts]. -//! -//! Combining two types may have side-effects on the inference contexts -//! which can be undone by using snapshots. You probably want to use -//! either [InferCtxt::commit_if_ok] or [InferCtxt::probe]. -//! -//! On success, the LUB/GLB operations return the appropriate bound. The -//! return value of `Equate` or `Sub` shouldn't really be used. - -use rustc_middle::bug; -use rustc_middle::infer::unify_key::EffectVarValue; -use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, InferConst, IntType, Ty, TyCtxt, TypeVisitableExt, UintType, Upcast}; -pub use rustc_next_trait_solver::relate::combine::*; -use tracing::debug; - -use super::lattice::{LatticeOp, LatticeOpKind}; -use super::type_relating::TypeRelating; -use super::{RelateResult, StructurallyRelateAliases}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate}; -use crate::traits::{Obligation, PredicateObligation}; - -#[derive(Clone)] -pub struct CombineFields<'infcx, 'tcx> { - pub infcx: &'infcx InferCtxt<'tcx>, - // Immutable fields - pub trace: TypeTrace<'tcx>, - pub param_env: ty::ParamEnv<'tcx>, - pub define_opaque_types: DefineOpaqueTypes, - // Mutable fields - // - // Adding any additional field likely requires - // changes to the cache of `TypeRelating`. - pub goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, -} - -impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { - pub fn new( - infcx: &'infcx InferCtxt<'tcx>, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - define_opaque_types: DefineOpaqueTypes, - ) -> Self { - Self { infcx, trace, param_env, define_opaque_types, goals: vec![] } - } - - pub(crate) fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> { - self.goals - .into_iter() - .map(|goal| { - Obligation::new( - self.infcx.tcx, - self.trace.cause.clone(), - goal.param_env, - goal.predicate, - ) - }) - .collect() - } -} - -impl<'tcx> InferCtxt<'tcx> { - pub fn super_combine_tys<R>( - &self, - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - R: PredicateEmittingRelation<InferCtxt<'tcx>>, - { - debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b); - debug_assert!(!a.has_escaping_bound_vars()); - debug_assert!(!b.has_escaping_bound_vars()); - - match (a.kind(), b.kind()) { - // Relate integral variables to other types - (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { - self.inner.borrow_mut().int_unification_table().union(a_id, b_id); - Ok(a) - } - (&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => { - self.unify_integral_variable(v_id, IntType(v)); - Ok(b) - } - (&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => { - self.unify_integral_variable(v_id, IntType(v)); - Ok(a) - } - (&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => { - self.unify_integral_variable(v_id, UintType(v)); - Ok(b) - } - (&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => { - self.unify_integral_variable(v_id, UintType(v)); - Ok(a) - } - - // Relate floating-point variables to other types - (&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => { - self.inner.borrow_mut().float_unification_table().union(a_id, b_id); - Ok(a) - } - (&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => { - self.unify_float_variable(v_id, ty::FloatVarValue::Known(v)); - Ok(b) - } - (&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => { - self.unify_float_variable(v_id, ty::FloatVarValue::Known(v)); - Ok(a) - } - - // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm. - (ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..)) - if self.next_trait_solver() => - { - bug!( - "We do not expect to encounter `TyVar` this late in combine \ - -- they should have been handled earlier" - ) - } - (_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))) - | (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _) - if self.next_trait_solver() => - { - bug!("We do not expect to encounter `Fresh` variables in the new solver") - } - - (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => { - match relation.structurally_relate_aliases() { - StructurallyRelateAliases::Yes => { - relate::structurally_relate_tys(relation, a, b) - } - StructurallyRelateAliases::No => { - relation.register_alias_relate_predicate(a, b); - Ok(a) - } - } - } - - // All other cases of inference are errors - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) - } - - // During coherence, opaque types should be treated as *possibly* - // equal to any other type (except for possibly itself). This is an - // extremely heavy hammer, but can be relaxed in a forwards-compatible - // way later. - (&ty::Alias(ty::Opaque, _), _) | (_, &ty::Alias(ty::Opaque, _)) if self.intercrate => { - relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); - Ok(a) - } - - _ => relate::structurally_relate_tys(relation, a, b), - } - } - - pub fn super_combine_consts<R>( - &self, - relation: &mut R, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> - where - R: PredicateEmittingRelation<InferCtxt<'tcx>>, - { - debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b); - debug_assert!(!a.has_escaping_bound_vars()); - debug_assert!(!b.has_escaping_bound_vars()); - - if a == b { - return Ok(a); - } - - let a = self.shallow_resolve_const(a); - let b = self.shallow_resolve_const(b); - - match (a.kind(), b.kind()) { - ( - ty::ConstKind::Infer(InferConst::Var(a_vid)), - ty::ConstKind::Infer(InferConst::Var(b_vid)), - ) => { - self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid); - Ok(a) - } - - ( - ty::ConstKind::Infer(InferConst::EffectVar(a_vid)), - ty::ConstKind::Infer(InferConst::EffectVar(b_vid)), - ) => { - self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid); - Ok(a) - } - - // All other cases of inference with other variables are errors. - ( - ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)), - ty::ConstKind::Infer(_), - ) - | ( - ty::ConstKind::Infer(_), - ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)), - ) => { - bug!( - "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}" - ) - } - - (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - self.instantiate_const_var(relation, true, vid, b)?; - Ok(b) - } - - (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - self.instantiate_const_var(relation, false, vid, a)?; - Ok(a) - } - - (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => { - Ok(self.unify_effect_variable(vid, b)) - } - - (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => { - Ok(self.unify_effect_variable(vid, a)) - } - - (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) - if self.tcx.features().generic_const_exprs || self.next_trait_solver() => - { - match relation.structurally_relate_aliases() { - StructurallyRelateAliases::No => { - relation.register_predicates([if self.next_trait_solver() { - ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Equate, - ) - } else { - ty::PredicateKind::ConstEquate(a, b) - }]); - - Ok(b) - } - StructurallyRelateAliases::Yes => { - relate::structurally_relate_consts(relation, a, b) - } - } - } - _ => relate::structurally_relate_consts(relation, a, b), - } - } - - #[inline(always)] - fn unify_integral_variable(&self, vid: ty::IntVid, val: ty::IntVarValue) { - self.inner.borrow_mut().int_unification_table().union_value(vid, val); - } - - #[inline(always)] - fn unify_float_variable(&self, vid: ty::FloatVid, val: ty::FloatVarValue) { - self.inner.borrow_mut().float_unification_table().union_value(vid, val); - } - - fn unify_effect_variable(&self, vid: ty::EffectVid, val: ty::Const<'tcx>) -> ty::Const<'tcx> { - self.inner - .borrow_mut() - .effect_unification_table() - .union_value(vid, EffectVarValue::Known(val)); - val - } -} - -impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - pub fn equate<'a>( - &'a mut self, - structurally_relate_aliases: StructurallyRelateAliases, - ) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, structurally_relate_aliases, ty::Invariant) - } - - pub fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, StructurallyRelateAliases::No, ty::Covariant) - } - - pub fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant) - } - - pub(crate) fn lub<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> { - LatticeOp::new(self, LatticeOpKind::Lub) - } - - pub(crate) fn glb<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> { - LatticeOp::new(self, LatticeOpKind::Glb) - } - - pub fn register_obligations( - &mut self, - obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, - ) { - self.goals.extend(obligations); - } - - pub fn register_predicates( - &mut self, - obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, - ) { - self.goals.extend( - obligations - .into_iter() - .map(|to_pred| Goal::new(self.infcx.tcx, self.param_env, to_pred)), - ) - } -} diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index a6d10aa5968..7049444db9b 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -50,7 +50,8 @@ impl<'tcx> InferCtxt<'tcx> { // 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`. + // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and + // `?1 <: ?3`. let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self .generalize( relation.span(), @@ -104,7 +105,8 @@ impl<'tcx> InferCtxt<'tcx> { &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`. + // `Projection(normalized_source, ?ty_normalized)` and + // `?normalized_source <: generalized_ty`. relation.register_predicates([ty::ProjectionPredicate { projection_term: data.into(), term: generalized_ty.into(), @@ -181,7 +183,7 @@ impl<'tcx> InferCtxt<'tcx> { /// /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. #[instrument(level = "debug", skip(self, relation))] - pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>( + pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>( &self, relation: &mut R, target_is_expected: bool, diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 9564baa6ab2..7eb61abfbc1 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -18,14 +18,16 @@ //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) use rustc_middle::traits::solve::Goal; +use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt}; use rustc_span::Span; use tracing::{debug, instrument}; use super::StructurallyRelateAliases; -use super::combine::{CombineFields, PredicateEmittingRelation}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; +use super::combine::PredicateEmittingRelation; +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace}; +use crate::traits::{Obligation, PredicateObligation}; #[derive(Clone, Copy)] pub(crate) enum LatticeOpKind { @@ -43,23 +45,34 @@ impl LatticeOpKind { } /// A greatest lower bound" (common subtype) or least upper bound (common supertype). -pub(crate) struct LatticeOp<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, +pub(crate) struct LatticeOp<'infcx, 'tcx> { + infcx: &'infcx InferCtxt<'tcx>, + // Immutable fields + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + // Mutable fields kind: LatticeOpKind, + obligations: Vec<PredicateObligation<'tcx>>, } -impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { +impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> { pub(crate) fn new( - fields: &'combine mut CombineFields<'infcx, 'tcx>, + infcx: &'infcx InferCtxt<'tcx>, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, kind: LatticeOpKind, - ) -> LatticeOp<'combine, 'infcx, 'tcx> { - LatticeOp { fields, kind } + ) -> LatticeOp<'infcx, 'tcx> { + LatticeOp { infcx, trace, param_env, kind, obligations: vec![] } + } + + pub(crate) fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> { + self.obligations } } -impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() + self.infcx.tcx } fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( @@ -70,7 +83,15 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { b: T, ) -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), + ty::Invariant => { + self.obligations.extend( + self.infcx + .at(&self.trace.cause, self.param_env) + .eq_trace(DefineOpaqueTypes::Yes, self.trace.clone(), a, b)? + .into_obligations(), + ); + Ok(a) + } ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a), @@ -90,7 +111,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { return Ok(a); } - let infcx = self.fields.infcx; + let infcx = self.infcx; let a = infcx.shallow_resolve(a); let b = infcx.shallow_resolve(b); @@ -115,12 +136,12 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { // iterate on the subtype obligations that are returned, but I // think this suffices. -nmatsakis (&ty::Infer(TyVar(..)), _) => { - let v = infcx.next_ty_var(self.fields.trace.cause.span); + let v = infcx.next_ty_var(self.trace.cause.span); self.relate_bound(v, b, a)?; Ok(v) } (_, &ty::Infer(TyVar(..))) => { - let v = infcx.next_ty_var(self.fields.trace.cause.span); + let v = infcx.next_ty_var(self.trace.cause.span); self.relate_bound(v, a, b)?; Ok(v) } @@ -128,13 +149,11 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b), + ) if a_def_id == b_def_id => super_combine_tys(infcx, self, a, b), (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if self.fields.define_opaque_types == DefineOpaqueTypes::Yes - && def_id.is_local() - && !infcx.next_trait_solver() => + if def_id.is_local() && !infcx.next_trait_solver() => { self.register_goals(infcx.handle_opaque_type( a, @@ -145,7 +164,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { Ok(a) } - _ => infcx.super_combine_tys(self, a, b), + _ => super_combine_tys(infcx, self, a, b), } } @@ -155,8 +174,8 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); - let mut inner = self.fields.infcx.inner.borrow_mut(); + let origin = SubregionOrigin::Subtype(Box::new(self.trace.clone())); + let mut inner = self.infcx.inner.borrow_mut(); let mut constraints = inner.unwrap_region_constraints(); Ok(match self.kind { // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 @@ -173,7 +192,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { a: ty::Const<'tcx>, b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) + super_combine_consts(self.infcx, self, a, b) } fn binders<T>( @@ -202,7 +221,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { } } -impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { +impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> { // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. // @@ -210,24 +229,24 @@ impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { // relates `v` to `a` first, which may help us to avoid unnecessary // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); + let at = self.infcx.at(&self.trace.cause, self.param_env); match self.kind { LatticeOpKind::Glb => { - sub.relate(v, a)?; - sub.relate(v, b)?; + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations()); + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations()); } LatticeOpKind::Lub => { - sub.relate(a, v)?; - sub.relate(b, v)?; + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations()); + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations()); } } Ok(()) } } -impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, 'tcx> { fn span(&self) -> Span { - self.fields.trace.span() + self.trace.span() } fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { @@ -235,21 +254,27 @@ impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx } fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env + self.param_env } fn register_predicates( &mut self, - obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, + preds: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, ) { - self.fields.register_predicates(obligations); + self.obligations.extend(preds.into_iter().map(|pred| { + Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, pred) + })) } - fn register_goals( - &mut self, - obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, - ) { - self.fields.register_obligations(obligations); + fn register_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) { + self.obligations.extend(goals.into_iter().map(|goal| { + Obligation::new( + self.infcx.tcx, + self.trace.cause.clone(), + goal.param_env, + goal.predicate, + ) + })) } fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index edc0c4f078a..e6d1003cab6 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -3,13 +3,10 @@ //! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). pub use rustc_middle::ty::relate::RelateResult; -pub use rustc_next_trait_solver::relate::*; +pub use rustc_type_ir::relate::combine::PredicateEmittingRelation; +pub use rustc_type_ir::relate::*; -pub use self::combine::{CombineFields, PredicateEmittingRelation}; - -#[allow(hidden_glob_reexports)] -pub(super) mod combine; mod generalize; mod higher_ranked; -mod lattice; -mod type_relating; +pub(super) mod lattice; +pub(super) mod type_relating; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 7acfea643dd..35103c070c2 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -1,4 +1,5 @@ use rustc_middle::traits::solve::Goal; +use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}; use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances, }; @@ -7,29 +8,30 @@ use rustc_span::Span; use rustc_type_ir::data_structures::DelayedSet; use tracing::{debug, instrument}; -use super::combine::CombineFields; use crate::infer::BoundRegionConversionTime::HigherRankedType; use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace}; +use crate::traits::{Obligation, PredicateObligation}; /// Enforce that `a` is equal to or a subtype of `b`. -pub struct TypeRelating<'combine, 'a, 'tcx> { - // Immutable except for the `InferCtxt` and the - // resulting nested `goals`. - fields: &'combine mut CombineFields<'a, 'tcx>, - - // Immutable field. - structurally_relate_aliases: StructurallyRelateAliases, - // Mutable field. - ambient_variance: ty::Variance, +pub(crate) struct TypeRelating<'infcx, 'tcx> { + infcx: &'infcx InferCtxt<'tcx>, + + // Immutable fields + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + // Mutable fields. + ambient_variance: ty::Variance, + obligations: Vec<PredicateObligation<'tcx>>, /// The cache only tracks the `ambient_variance` as it's the /// only field which is mutable and which meaningfully changes /// the result when relating types. /// /// The cache does not track whether the state of the /// `InferCtxt` has been changed or whether we've added any - /// obligations to `self.fields.goals`. Whether a goal is added + /// obligations to `self.goals`. Whether a goal is added /// once or multiple times is not really meaningful. /// /// Changes in the inference state may delay some type inference to @@ -48,24 +50,34 @@ pub struct TypeRelating<'combine, 'a, 'tcx> { cache: DelayedSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>, } -impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { - pub fn new( - f: &'combine mut CombineFields<'infcx, 'tcx>, - structurally_relate_aliases: StructurallyRelateAliases, +impl<'infcx, 'tcx> TypeRelating<'infcx, 'tcx> { + pub(crate) fn new( + infcx: &'infcx InferCtxt<'tcx>, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, ambient_variance: ty::Variance, - ) -> TypeRelating<'combine, 'infcx, 'tcx> { + ) -> TypeRelating<'infcx, 'tcx> { + assert!(!infcx.next_trait_solver); TypeRelating { - fields: f, - structurally_relate_aliases, + infcx, + trace, + param_env, + define_opaque_types, ambient_variance, + obligations: vec![], cache: Default::default(), } } + + pub(crate) fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> { + self.obligations + } } -impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.fields.infcx.tcx + self.infcx.tcx } fn relate_item_args( @@ -109,7 +121,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { return Ok(a); } - let infcx = self.fields.infcx; + let infcx = self.infcx; let a = infcx.shallow_resolve(a); let b = infcx.shallow_resolve(b); @@ -123,9 +135,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { ty::Covariant => { // can't make progress on `A <: B` if both A and B are // type variables, so record an obligation. - self.fields.goals.push(Goal::new( + self.obligations.push(Obligation::new( self.cx(), - self.fields.param_env, + self.trace.cause.clone(), + self.param_env, ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: true, a, @@ -136,9 +149,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { ty::Contravariant => { // can't make progress on `B <: A` if both A and B are // type variables, so record an obligation. - self.fields.goals.push(Goal::new( + self.obligations.push(Obligation::new( self.cx(), - self.fields.param_env, + self.trace.cause.clone(), + self.param_env, ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: false, a: b, @@ -168,34 +182,27 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { )?; } - (&ty::Error(e), _) | (_, &ty::Error(e)) => { - infcx.set_tainted_by_errors(e); - return Ok(Ty::new_error(self.cx(), e)); - } - ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), ) if a_def_id == b_def_id => { - infcx.super_combine_tys(self, a, b)?; + super_combine_tys(infcx, self, a, b)?; } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if self.fields.define_opaque_types == DefineOpaqueTypes::Yes - && def_id.is_local() - && !infcx.next_trait_solver() => + if self.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() => { - self.fields.goals.extend(infcx.handle_opaque_type( + self.register_goals(infcx.handle_opaque_type( a, b, - self.fields.trace.cause.span, + self.trace.cause.span, self.param_env(), )?); } _ => { - infcx.super_combine_tys(self, a, b)?; + super_combine_tys(infcx, self, a, b)?; } } @@ -210,13 +217,12 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); + let origin = SubregionOrigin::Subtype(Box::new(self.trace.clone())); match self.ambient_variance { // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) ty::Covariant => { - self.fields - .infcx + self.infcx .inner .borrow_mut() .unwrap_region_constraints() @@ -224,16 +230,14 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { } // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b) ty::Contravariant => { - self.fields - .infcx + self.infcx .inner .borrow_mut() .unwrap_region_constraints() .make_subregion(origin, a, b); } ty::Invariant => { - self.fields - .infcx + self.infcx .inner .borrow_mut() .unwrap_region_constraints() @@ -253,7 +257,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { a: ty::Const<'tcx>, b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) + super_combine_consts(self.infcx, self, a, b) } fn binders<T>( @@ -271,8 +275,8 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { { self.relate(a, b)?; } else { - let span = self.fields.trace.cause.span; - let infcx = self.fields.infcx; + let span = self.trace.cause.span; + let infcx = self.infcx; match self.ambient_variance { // Checks whether `for<..> sub <: for<..> sup` holds. @@ -335,31 +339,37 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { } } -impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, 'tcx> { fn span(&self) -> Span { - self.fields.trace.span() + self.trace.span() } fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env + self.param_env } fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - self.structurally_relate_aliases + StructurallyRelateAliases::No } fn register_predicates( &mut self, - obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, + preds: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, ) { - self.fields.register_predicates(obligations); + self.obligations.extend(preds.into_iter().map(|pred| { + Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, pred) + })) } - fn register_goals( - &mut self, - obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, - ) { - self.fields.register_obligations(obligations); + fn register_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) { + self.obligations.extend(goals.into_iter().map(|goal| { + Obligation::new( + self.infcx.tcx, + self.trace.cause.clone(), + goal.param_env, + goal.predicate, + ) + })) } fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 671a66d504f..64cc76f827e 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> { if !t.has_non_region_infer() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else if let Some(&ty) = self.cache.get(&t) { - return ty; + ty } else { let shallow = self.infcx.shallow_resolve(t); let res = shallow.super_fold_with(self); @@ -121,8 +121,6 @@ where value.try_fold_with(&mut FullTypeResolver { infcx }) } -// N.B. This type is not public because the protocol around checking the -// `err` field is not enforceable otherwise. struct FullTypeResolver<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, } @@ -138,11 +136,13 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { if !t.has_infer() { Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects... } else { + use super::TyOrConstInferVar::*; + let t = self.infcx.shallow_resolve(t); match *t.kind() { - ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)), - ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)), - ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)), + ty::Infer(ty::TyVar(vid)) => Err(FixupError { unresolved: Ty(vid) }), + ty::Infer(ty::IntVar(vid)) => Err(FixupError { unresolved: TyInt(vid) }), + ty::Infer(ty::FloatVar(vid)) => Err(FixupError { unresolved: TyFloat(vid) }), ty::Infer(_) => { bug!("Unexpected type in full type resolver: {:?}", t); } @@ -171,13 +171,13 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { let c = self.infcx.shallow_resolve_const(c); match c.kind() { ty::ConstKind::Infer(InferConst::Var(vid)) => { - return Err(FixupError::UnresolvedConst(vid)); + return Err(FixupError { unresolved: super::TyOrConstInferVar::Const(vid) }); } ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("Unexpected const in full const resolver: {:?}", c); } ty::ConstKind::Infer(InferConst::EffectVar(evid)) => { - return Err(FixupError::UnresolvedEffect(evid)); + return Err(FixupError { unresolved: super::TyOrConstInferVar::Effect(evid) }); } _ => {} } diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs index 964fb1f6819..07a482c2f9a 100644 --- a/compiler/rustc_infer/src/infer/snapshot/mod.rs +++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs @@ -5,7 +5,7 @@ use tracing::{debug, instrument}; use super::InferCtxt; use super::region_constraints::RegionSnapshot; -mod fudge; +pub(crate) mod fudge; pub(crate) mod undo_log; use undo_log::{Snapshot, UndoLog}; diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 7eb2c20e0d8..779ce976bec 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -19,8 +19,8 @@ impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariabl } } -#[derive(Clone)] -pub struct TypeVariableStorage<'tcx> { +#[derive(Clone, Default)] +pub(crate) struct TypeVariableStorage<'tcx> { /// The origins of each type variable. values: IndexVec<TyVid, TypeVariableData>, /// Two variables are unified in `eq_relations` when we have a @@ -29,7 +29,7 @@ pub struct TypeVariableStorage<'tcx> { eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>, } -pub struct TypeVariableTable<'a, 'tcx> { +pub(crate) struct TypeVariableTable<'a, 'tcx> { storage: &'a mut TypeVariableStorage<'tcx>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, @@ -50,7 +50,7 @@ pub(crate) struct TypeVariableData { } #[derive(Copy, Clone, Debug)] -pub enum TypeVariableValue<'tcx> { +pub(crate) enum TypeVariableValue<'tcx> { Known { value: Ty<'tcx> }, Unknown { universe: ty::UniverseIndex }, } @@ -58,14 +58,14 @@ pub enum TypeVariableValue<'tcx> { impl<'tcx> TypeVariableValue<'tcx> { /// If this value is known, returns the type it is known to be. /// Otherwise, `None`. - pub fn known(&self) -> Option<Ty<'tcx>> { + pub(crate) fn known(&self) -> Option<Ty<'tcx>> { match *self { TypeVariableValue::Unknown { .. } => None, TypeVariableValue::Known { value } => Some(value), } } - pub fn is_unknown(&self) -> bool { + pub(crate) fn is_unknown(&self) -> bool { match *self { TypeVariableValue::Unknown { .. } => true, TypeVariableValue::Known { .. } => false, @@ -74,13 +74,6 @@ impl<'tcx> TypeVariableValue<'tcx> { } impl<'tcx> TypeVariableStorage<'tcx> { - pub fn new() -> TypeVariableStorage<'tcx> { - TypeVariableStorage { - values: Default::default(), - eq_relations: ut::UnificationTableStorage::new(), - } - } - #[inline] pub(crate) fn with_log<'a>( &'a mut self, @@ -105,14 +98,14 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// /// Note that this function does not return care whether /// `vid` has been unified with something else or not. - pub fn var_origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { + pub(crate) fn var_origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { self.storage.values[vid].origin } /// Records that `a == b`, depending on `dir`. /// /// Precondition: neither `a` nor `b` are known. - pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { + pub(crate) fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { debug_assert!(self.probe(a).is_unknown()); debug_assert!(self.probe(b).is_unknown()); self.eq_relations().union(a, b); @@ -121,7 +114,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Instantiates `vid` with the type `ty`. /// /// Precondition: `vid` must not have been previously instantiated. - pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { + pub(crate) fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { let vid = self.root_var(vid); debug_assert!(!ty.is_ty_var(), "instantiating ty var with var: {vid:?} {ty:?}"); debug_assert!(self.probe(vid).is_unknown()); @@ -143,7 +136,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// - `origin`: indicates *why* the type variable was created. /// The code in this module doesn't care, but it can be useful /// for improving error messages. - pub fn new_var( + pub(crate) fn new_var( &mut self, universe: ty::UniverseIndex, origin: TypeVariableOrigin, @@ -158,7 +151,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { } /// Returns the number of type variables created thus far. - pub fn num_vars(&self) -> usize { + pub(crate) fn num_vars(&self) -> usize { self.storage.values.len() } @@ -167,42 +160,29 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// will yield the same root variable (per the union-find /// algorithm), so `root_var(a) == root_var(b)` implies that `a == /// b` (transitively). - pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { + pub(crate) fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { self.eq_relations().find(vid).vid } /// Retrieves the type to which `vid` has been instantiated, if /// any. - pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { + pub(crate) fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { self.inlined_probe(vid) } /// An always-inlined variant of `probe`, for very hot call sites. #[inline(always)] - pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { + pub(crate) fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { self.eq_relations().inlined_probe_value(vid) } - /// If `t` is a type-inference variable, and it has been - /// instantiated, then return the with which it was - /// instantiated. Otherwise, returns `t`. - pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match *t.kind() { - ty::Infer(ty::TyVar(v)) => match self.probe(v) { - TypeVariableValue::Unknown { .. } => t, - TypeVariableValue::Known { value } => value, - }, - _ => t, - } - } - #[inline] fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> { self.storage.eq_relations.with_log(self.undo_log) } /// Returns a range of the type variables created during the snapshot. - pub fn vars_since_snapshot( + pub(crate) fn vars_since_snapshot( &mut self, value_count: usize, ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) { @@ -215,7 +195,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Returns indices of all variables that are not yet /// instantiated. - pub fn unresolved_variables(&mut self) -> Vec<ty::TyVid> { + pub(crate) fn unresolved_variables(&mut self) -> Vec<ty::TyVid> { (0..self.num_vars()) .filter_map(|i| { let vid = ty::TyVid::from_usize(i); diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 051bba58518..a04b2bb2b08 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -19,11 +19,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(extend_one)] -#![feature(if_let_guard)] -#![feature(iter_intersperse)] #![feature(iterator_try_collect)] #![feature(let_chains)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index fa813d0f90c..64b72de3986 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -92,38 +92,31 @@ pub enum ProjectionCacheEntry<'tcx> { Error, NormalizedTerm { ty: NormalizedTerm<'tcx>, - /// If we were able to successfully evaluate the - /// corresponding cache entry key during predicate - /// evaluation, then this field stores the final - /// result obtained from evaluating all of the projection - /// sub-obligations. During evaluation, we will skip - /// evaluating the cached sub-obligations in `ty` - /// if this field is set. Evaluation only - /// cares about the final result, so we don't - /// care about any region constraint side-effects - /// produced by evaluating the sub-obligations. + /// If we were able to successfully evaluate the corresponding cache + /// entry key during predicate evaluation, then this field stores the + /// final result obtained from evaluating all of the projection + /// sub-obligations. During evaluation, we will skip evaluating the + /// cached sub-obligations in `ty` if this field is set. Evaluation + /// only cares about the final result, so we don't care about any + /// region constraint side-effects produced by evaluating the + /// sub-obligations. /// - /// Additionally, we will clear out the sub-obligations - /// entirely if we ever evaluate the cache entry (along - /// with all its sub obligations) to `EvaluatedToOk`. - /// This affects all users of the cache, not just evaluation. - /// Since a result of `EvaluatedToOk` means that there were - /// no region obligations that need to be tracked, it's - /// fine to forget about the sub-obligations - they - /// don't provide any additional information. However, - /// we do *not* discard any obligations when we see - /// `EvaluatedToOkModuloRegions` - we don't know - /// which sub-obligations may introduce region constraints, - /// so we keep them all to be safe. + /// Additionally, we will clear out the sub-obligations entirely if we + /// ever evaluate the cache entry (along with all its sub obligations) + /// to `EvaluatedToOk`. This affects all users of the cache, not just + /// evaluation. Since a result of `EvaluatedToOk` means that there were + /// no region obligations that need to be tracked, it's fine to forget + /// about the sub-obligations - they don't provide any additional + /// information. However, we do *not* discard any obligations when we + /// see `EvaluatedToOkModuloRegions` - we don't know which + /// sub-obligations may introduce region constraints, so we keep them + /// all to be safe. /// - /// When we are not performing evaluation - /// (e.g. in `FulfillmentContext`), we ignore this field, - /// and always re-process the cached sub-obligations - /// (which may have been cleared out - see the above - /// paragraph). - /// This ensures that we do not lose any regions - /// constraints that arise from processing the - /// sub-obligations. + /// When we are not performing evaluation (e.g. in + /// `FulfillmentContext`), we ignore this field, and always re-process + /// the cached sub-obligations (which may have been cleared out - see + /// the above paragraph). This ensures that we do not lose any regions + /// constraints that arise from processing the sub-obligations. complete: Option<EvaluationResult>, }, } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 204ae437a3e..fd850d2f39a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -470,7 +470,6 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P }) } - #[allow(rustc::potential_query_instability)] let extra_tracked_files = hash_iter_files( file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))), checksum_hash_algo, diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 60aab668cba..b0ab50dd773 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -104,6 +104,12 @@ pub enum TokenKind { /// for emoji identifier recovery, as those are not meant to be ever accepted. InvalidPrefix, + /// Guarded string literal prefix: `#"` or `##`. + /// + /// Used for reserving "guarded strings" (RFC 3598) in edition 2024. + /// Split into the component tokens on older editions. + GuardedStrPrefix, + /// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid /// suffix, but may be present here on string and float literals. Users of /// this type will need to check for and reject that case. @@ -191,30 +197,41 @@ pub enum DocStyle { /// `rustc_ast::ast::LitKind`). #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum LiteralKind { - /// "12_u8", "0o100", "0b120i99", "1f32". + /// `12_u8`, `0o100`, `0b120i99`, `1f32`. Int { base: Base, empty_int: bool }, - /// "12.34f32", "1e3", but not "1f32". + /// `12.34f32`, `1e3`, but not `1f32`. Float { base: Base, empty_exponent: bool }, - /// "'a'", "'\\'", "'''", "';" + /// `'a'`, `'\\'`, `'''`, `';` Char { terminated: bool }, - /// "b'a'", "b'\\'", "b'''", "b';" + /// `b'a'`, `b'\\'`, `b'''`, `b';` Byte { terminated: bool }, - /// ""abc"", ""abc" + /// `"abc"`, `"abc` Str { terminated: bool }, - /// "b"abc"", "b"abc" + /// `b"abc"`, `b"abc` ByteStr { terminated: bool }, /// `c"abc"`, `c"abc` CStr { terminated: bool }, - /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates + /// `r"abc"`, `r#"abc"#`, `r####"ab"###"c"####`, `r#"a`. `None` indicates /// an invalid literal. RawStr { n_hashes: Option<u8> }, - /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None` + /// `br"abc"`, `br#"abc"#`, `br####"ab"###"c"####`, `br#"a`. `None` /// indicates an invalid literal. RawByteStr { n_hashes: Option<u8> }, /// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal. RawCStr { n_hashes: Option<u8> }, } +/// `#"abc"#`, `##"a"` (fewer closing), or even `#"a` (unterminated). +/// +/// Can capture fewer closing hashes than starting hashes, +/// for more efficient lexing and better backwards diagnostics. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct GuardedStr { + pub n_hashes: u32, + pub terminated: bool, + pub token_len: u32, +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum RawStrError { /// Non `#` characters exist between `r` and `"`, e.g. `r##~"abcde"##` @@ -403,6 +420,12 @@ impl Cursor<'_> { TokenKind::Literal { kind: literal_kind, suffix_start } } + // Guarded string literal prefix: `#"` or `##` + '#' if matches!(self.first(), '"' | '#') => { + self.bump(); + TokenKind::GuardedStrPrefix + } + // One-symbol tokens. ';' => Semi, ',' => Comma, @@ -780,6 +803,60 @@ impl Cursor<'_> { false } + /// Attempt to lex for a guarded string literal. + /// + /// Used by `rustc_parse::lexer` to lex for guarded strings + /// conditionally based on edition. + /// + /// Note: this will not reset the `Cursor` when a + /// guarded string is not found. It is the caller's + /// responsibility to do so. + pub fn guarded_double_quoted_string(&mut self) -> Option<GuardedStr> { + debug_assert!(self.prev() != '#'); + + let mut n_start_hashes: u32 = 0; + while self.first() == '#' { + n_start_hashes += 1; + self.bump(); + } + + if self.first() != '"' { + return None; + } + self.bump(); + debug_assert!(self.prev() == '"'); + + // Lex the string itself as a normal string literal + // so we can recover that for older editions later. + let terminated = self.double_quoted_string(); + if !terminated { + let token_len = self.pos_within_token(); + self.reset_pos_within_token(); + + return Some(GuardedStr { n_hashes: n_start_hashes, terminated: false, token_len }); + } + + // Consume closing '#' symbols. + // Note that this will not consume extra trailing `#` characters: + // `###"abcde"####` is lexed as a `GuardedStr { n_end_hashes: 3, .. }` + // followed by a `#` token. + let mut n_end_hashes = 0; + while self.first() == '#' && n_end_hashes < n_start_hashes { + n_end_hashes += 1; + self.bump(); + } + + // Reserved syntax, always an error, so it doesn't matter if + // `n_start_hashes != n_end_hashes`. + + self.eat_literal_suffix(); + + let token_len = self.pos_within_token(); + self.reset_pos_within_token(); + + Some(GuardedStr { n_hashes: n_start_hashes, terminated: true, token_len }) + } + /// Eats the double-quoted string and returns `n_hashes` and an error if encountered. fn raw_double_quoted_string(&mut self, prefix_len: u32) -> Result<u8, RawStrError> { // Wrap the actual function to handle the error with too many hashes. diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 8acb986bfc9..c4d709aa1f9 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -203,12 +203,6 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i .current_use = this identifier can be confused with `{$existing_sym}` .other_use = other identifier used here -lint_crate_name_in_cfg_attr_deprecated = - `crate_name` within an `#![cfg_attr]` attribute is deprecated - -lint_crate_type_in_cfg_attr_deprecated = - `crate_type` within an `#![cfg_attr]` attribute is deprecated - lint_cstring_ptr = getting the inner pointer of a temporary `CString` .as_ptr_label = this pointer will be invalid .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime @@ -587,8 +581,6 @@ lint_non_glob_import_type_ir_inherent = non-glob import of `rustc_type_ir::inher lint_non_local_definitions_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` -lint_non_local_definitions_deprecation = this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> - lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks should be written at the same level as their item .non_local = an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` .doctest = make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}` @@ -746,6 +738,9 @@ lint_reserved_prefix = prefix `{$prefix}` is unknown .label = unknown prefix .suggestion = insert whitespace here to avoid this being parsed as a prefix in Rust 2021 +lint_reserved_string = will be parsed as a guarded string in Rust 2024 + .suggestion = insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + lint_shadowed_into_iter = this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<{$target} as IntoIterator>::into_iter` in Rust {$edition} .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index d9040207300..63a8a949e96 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -104,8 +104,9 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { return; } - let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = - sig.decl.output + let hir::FnRetTy::Return(hir::Ty { + kind: hir::TyKind::OpaqueDef(opaq_def, ..), .. + }) = sig.decl.output else { // This should never happen, but let's not ICE. return; @@ -114,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { cx.tcx, sig, body, - def.owner_id.def_id, + opaq_def.def_id, " + Send", ); cx.tcx.emit_node_span_lint( diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 168e3a8e92c..565c3c04252 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -176,6 +176,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() } .decorate_lint(diag); } + BuiltinLintDiag::ReservedString(suggestion) => { + lints::ReservedString { suggestion }.decorate_lint(diag); + } BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => { lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag); } @@ -400,12 +403,6 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::CfgAttrNoAttributes => { lints::CfgAttrNoAttributes.decorate_lint(diag); } - BuiltinLintDiag::CrateTypeInCfgAttr => { - lints::CrateTypeInCfgAttr.decorate_lint(diag); - } - BuiltinLintDiag::CrateNameInCfgAttr => { - lints::CrateNameInCfgAttr.decorate_lint(diag); - } BuiltinLintDiag::MissingFragmentSpecifier => { lints::MissingFragmentSpecifier.decorate_lint(diag); } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 5aeaad42069..d029ad93407 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -258,7 +258,7 @@ where && self.seen.insert(opaque_def_id) // If it's owned by this function && let opaque = - self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty() + self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty() && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin && parent == self.parent_def_id { diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index de401397150..6d5903ac467 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -18,7 +18,7 @@ use std::any::Any; use std::cell::Cell; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::{Lrc, join}; +use rustc_data_structures::sync::join; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::{HirId, intravisit as hir_visit}; @@ -36,8 +36,7 @@ use crate::{LateContext, LateLintPass, LintStore}; /// /// This function exists because [`Session::lint_store`] is type-erased. pub fn unerased_lint_store(sess: &Session) -> &LintStore { - let store: &Lrc<_> = sess.lint_store.as_ref().unwrap(); - let store: &dyn Any = &**store; + let store: &dyn Any = sess.lint_store.as_deref().unwrap(); store.downcast_ref().unwrap() } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 007e86ae0d2..89a67fc0d89 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -669,7 +669,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let sp = li.span(); let meta_item = match li { - ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item, + ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => meta_item, _ => { let sub = if let Some(item) = li.meta_item() && let ast::MetaItemKind::NameValue(_) = item.kind diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c74cb866f21..81352af3d48 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -32,7 +32,6 @@ #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(extract_if)] #![feature(if_let_guard)] #![feature(iter_order_by)] @@ -571,6 +570,11 @@ fn register_builtins(store: &mut LintStore) { <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information", ); store.register_removed( + "deprecated_cfg_attr_crate_type_name", + "converted into hard error, see issue #91632 \ + <https://github.com/rust-lang/rust/issues/91632> for more information", + ); + store.register_removed( "pointer_structural_match", "converted into hard error, see RFC #3535 \ <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information", diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0045cfcaa56..16cfae17d40 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1430,8 +1430,6 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { ); } } - - diag.note(fluent::lint_non_local_definitions_deprecation); } NonLocalDefinitionsDiag::MacroRules { depth, @@ -1452,7 +1450,6 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { } diag.note(fluent::lint_non_local); - diag.note(fluent::lint_non_local_definitions_deprecation); if let Some(cargo_update) = cargo_update { diag.subdiagnostic(cargo_update); @@ -1703,7 +1700,7 @@ pub(crate) enum InvalidNanComparisons { #[diag(lint_invalid_nan_comparisons_eq_ne)] EqNe { #[subdiagnostic] - suggestion: Option<InvalidNanComparisonsSuggestion>, + suggestion: InvalidNanComparisonsSuggestion, }, #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)] LtLeGtGe, @@ -2442,14 +2439,6 @@ pub(crate) struct DuplicateMacroAttribute; pub(crate) struct CfgAttrNoAttributes; #[derive(LintDiagnostic)] -#[diag(lint_crate_type_in_cfg_attr_deprecated)] -pub(crate) struct CrateTypeInCfgAttr; - -#[derive(LintDiagnostic)] -#[diag(lint_crate_name_in_cfg_attr_deprecated)] -pub(crate) struct CrateNameInCfgAttr; - -#[derive(LintDiagnostic)] #[diag(lint_missing_fragment_specifier)] pub(crate) struct MissingFragmentSpecifier; @@ -3061,3 +3050,10 @@ pub(crate) enum MutRefSugg { #[derive(LintDiagnostic)] #[diag(lint_unqualified_local_imports)] pub(crate) struct UnqualifiedLocalImportsDiag {} + +#[derive(LintDiagnostic)] +#[diag(lint_reserved_string)] +pub(crate) struct ReservedString { + #[suggestion(code = " ", applicability = "machine-applicable")] + pub suggestion: Span, +} diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 56f930ea7f6..3c31b879bd6 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -124,16 +124,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { // If that's the case this means that this impl block declaration // is using local items and so we don't lint on it. - // We also ignore anon-const in item by including the anon-const - // parent as well. - let parent_parent = if parent_def_kind == DefKind::Const - && parent_opt_item_name == Some(kw::Underscore) - { - Some(cx.tcx.parent(parent)) - } else { - None - }; - // 1. We collect all the `hir::Path` from the `Self` type and `Trait` ref // of the `impl` definition let mut collector = PathCollector { paths: Vec::new() }; @@ -148,13 +138,33 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { |p| matches!(p.res, Res::Def(def_kind, _) if def_kind != DefKind::TyParam), ); - // 2. We check if any of path reference a "local" parent and if that the case - // we bail out as asked by T-lang, even though this isn't correct from a - // type-system point of view, as inference exists and could still leak the impl. + // 1.9. We retrieve the parent def id of the impl item, ... + // + // ... modulo const-anons items, for enhanced compatibility with the ecosystem + // as that pattern is common with `serde`, `bevy`, ... + // + // For this example we want the `DefId` parent of the outermost const-anon items. + // ``` + // const _: () = { // the parent of this const-anon + // const _: () = { + // impl Foo {} + // }; + // }; + // ``` + let outermost_impl_parent = peel_parent_while(cx.tcx, parent, |tcx, did| { + tcx.def_kind(did) == DefKind::Const + && tcx.opt_item_name(did) == Some(kw::Underscore) + }); + + // 2. We check if any of the paths reference a the `impl`-parent. + // + // If that the case we bail out, as was asked by T-lang, even though this isn't + // correct from a type-system point of view, as inference exists and one-impl-rule + // make its so that we could still leak the impl. if collector .paths .iter() - .any(|path| path_has_local_parent(path, cx, parent, parent_parent)) + .any(|path| path_has_local_parent(path, cx, parent, outermost_impl_parent)) { return; } @@ -253,8 +263,8 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> { } } -/// Given a path and a parent impl def id, this checks if the if parent resolution -/// def id correspond to the def id of the parent impl definition. +/// Given a path, this checks if the if the parent resolution def id corresponds to +/// the def id of the parent impl definition (the direct one and the outermost one). /// /// Given this path, we will look at the path (and ignore any generic args): /// @@ -267,32 +277,54 @@ fn path_has_local_parent( path: &Path<'_>, cx: &LateContext<'_>, impl_parent: DefId, - impl_parent_parent: Option<DefId>, + outermost_impl_parent: Option<DefId>, ) -> bool { path.res .opt_def_id() - .is_some_and(|did| did_has_local_parent(did, cx.tcx, impl_parent, impl_parent_parent)) + .is_some_and(|did| did_has_local_parent(did, cx.tcx, impl_parent, outermost_impl_parent)) } -/// Given a def id and a parent impl def id, this checks if the parent -/// def id (modulo modules) correspond to the def id of the parent impl definition. +/// Given a def id this checks if the parent def id (modulo modules) correspond to +/// the def id of the parent impl definition (the direct one and the outermost one). #[inline] fn did_has_local_parent( did: DefId, tcx: TyCtxt<'_>, impl_parent: DefId, - impl_parent_parent: Option<DefId>, + outermost_impl_parent: Option<DefId>, ) -> bool { - did.is_local() - && if let Some(did_parent) = tcx.opt_parent(did) { - did_parent == impl_parent - || Some(did_parent) == impl_parent_parent - || !did_parent.is_crate_root() - && tcx.def_kind(did_parent) == DefKind::Mod - && did_has_local_parent(did_parent, tcx, impl_parent, impl_parent_parent) - } else { - false - } + if !did.is_local() { + return false; + } + + let Some(parent_did) = tcx.opt_parent(did) else { + return false; + }; + + peel_parent_while(tcx, parent_did, |tcx, did| { + tcx.def_kind(did) == DefKind::Mod + || (tcx.def_kind(did) == DefKind::Const + && tcx.opt_item_name(did) == Some(kw::Underscore)) + }) + .map(|parent_did| parent_did == impl_parent || Some(parent_did) == outermost_impl_parent) + .unwrap_or(false) +} + +/// Given a `DefId` checks if it satisfies `f` if it does check with it's parent and continue +/// until it doesn't satisfies `f` and return the last `DefId` checked. +/// +/// In other word this method return the first `DefId` that doesn't satisfies `f`. +#[inline] +fn peel_parent_while( + tcx: TyCtxt<'_>, + mut did: DefId, + mut f: impl FnMut(TyCtxt<'_>, DefId) -> bool, +) -> Option<DefId> { + while !did.is_crate_root() && f(tcx, did) { + did = tcx.opt_parent(did).filter(|parent_did| parent_did.is_local())?; + } + + Some(did) } /// Return for a given `Path` the span until the last args diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 342ebfa0b06..ffbcf7f808e 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -68,8 +68,8 @@ declare_lint! { declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) { + let hir::TyKind::OpaqueDef(opaque, _) = &ty.kind else { return; }; @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { return; } - let def_id = item.owner_id.def_id.to_def_id(); + let def_id = opaque.def_id.to_def_id(); let infcx = &cx.tcx.infer_ctxt().build(); // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 15fe18adbfb..db4413149a4 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -209,36 +209,32 @@ fn lint_nan<'tcx>( } fn eq_ne( - cx: &LateContext<'_>, e: &hir::Expr<'_>, l: &hir::Expr<'_>, r: &hir::Expr<'_>, f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion, ) -> InvalidNanComparisons { - // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const. - let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| { - if let Some(l_span) = l.span.find_ancestor_inside(e.span) - && let Some(r_span) = r.span.find_ancestor_inside(e.span) - { - f(l_span, r_span) - } else { - InvalidNanComparisonsSuggestion::Spanless - } - }); + let suggestion = if let Some(l_span) = l.span.find_ancestor_inside(e.span) + && let Some(r_span) = r.span.find_ancestor_inside(e.span) + { + f(l_span, r_span) + } else { + InvalidNanComparisonsSuggestion::Spanless + }; InvalidNanComparisons::EqNe { suggestion } } let lint = match binop.node { hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => { - eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { + eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { nan_plus_binop: l_span.until(r_span), float: r_span.shrink_to_hi(), neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()), }) } hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => { - eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { + eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { nan_plus_binop: l_span.shrink_to_hi().to(r_span), float: l_span.shrink_to_hi(), neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()), @@ -1423,7 +1419,6 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { hir::ItemKind::Impl(..) | hir::ItemKind::TraitAlias(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Mod(..) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 12d5b5cf979..1a007250961 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -804,7 +804,15 @@ trait UnusedDelimLint { .find_ancestor_inside(value.span) .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))), ast::ExprKind::Paren(ref expr) => { - expr.span.find_ancestor_inside(value.span).map(|expr_span| { + // For the expr with attributes, like `let _ = (#[inline] || println!("Hello!"));`, + // the span should contains the attributes, or the suggestion will remove them. + let expr_span_with_attrs = + if let Some(attr_lo) = expr.attrs.iter().map(|attr| attr.span.lo()).min() { + expr.span.with_lo(attr_lo) + } else { + expr.span + }; + expr_span_with_attrs.find_ancestor_inside(value.span).map(|expr_span| { (value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())) }) } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 549dc64a562..23dc5214fe2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -34,7 +34,6 @@ declare_lint_pass! { DEAD_CODE, DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, DEPRECATED, - DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DEPRECATED_IN_FUTURE, DEPRECATED_SAFE_2024, DEPRECATED_WHERE_CLAUSE_LOCATION, @@ -81,6 +80,7 @@ declare_lint_pass! { PRIVATE_INTERFACES, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PTR_CAST_ADD_AUTO_TO_OBJECT, + PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, REDUNDANT_LIFETIMES, @@ -92,6 +92,7 @@ declare_lint_pass! { RUST_2021_INCOMPATIBLE_OR_PATTERNS, RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2021_PRELUDE_COLLISIONS, + RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, RUST_2024_INCOMPATIBLE_PAT, RUST_2024_PRELUDE_COLLISIONS, SELF_CONSTRUCTOR_FROM_OUTER_ITEM, @@ -123,6 +124,7 @@ declare_lint_pass! { UNSTABLE_NAME_COLLISIONS, UNSTABLE_SYNTAX_PRE_EXPANSION, UNSUPPORTED_CALLING_CONVENTIONS, + UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, UNUSED_ASSIGNMENTS, UNUSED_ASSOCIATED_TYPE_BOUNDS, UNUSED_ATTRIBUTES, @@ -2925,16 +2927,16 @@ declare_lint! { /// ```rust /// #![feature(asm_experimental_arch, naked_functions)] /// - /// use std::arch::asm; + /// use std::arch::naked_asm; /// /// #[naked] /// pub fn default_abi() -> u32 { - /// unsafe { asm!("", options(noreturn)); } + /// unsafe { naked_asm!(""); } /// } /// /// #[naked] /// pub extern "Rust" fn rust_abi() -> u32 { - /// unsafe { asm!("", options(noreturn)); } + /// unsafe { naked_asm!(""); } /// } /// ``` /// @@ -3144,42 +3146,6 @@ declare_lint! { } declare_lint! { - /// The `deprecated_cfg_attr_crate_type_name` lint detects uses of the - /// `#![cfg_attr(..., crate_type = "...")]` and - /// `#![cfg_attr(..., crate_name = "...")]` attributes to conditionally - /// specify the crate type and name in the source code. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![cfg_attr(debug_assertions, crate_type = "lib")] - /// ``` - /// - /// {{produces}} - /// - /// - /// ### Explanation - /// - /// The `#![crate_type]` and `#![crate_name]` attributes require a hack in - /// the compiler to be able to change the used crate type and crate name - /// after macros have been expanded. Neither attribute works in combination - /// with Cargo as it explicitly passes `--crate-type` and `--crate-name` on - /// the commandline. These values must match the value used in the source - /// code to prevent an error. - /// - /// To fix the warning use `--crate-type` on the commandline when running - /// rustc instead of `#![cfg_attr(..., crate_type = "...")]` and - /// `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]`. - pub DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - Deny, - "detects usage of `#![cfg_attr(..., crate_type/crate_name = \"...\")]`", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #91632 <https://github.com/rust-lang/rust/issues/91632>", - }; -} - -declare_lint! { /// The `unexpected_cfgs` lint detects unexpected conditional compilation conditions. /// /// ### Example @@ -3875,6 +3841,50 @@ declare_lint! { } declare_lint! { + /// The `unsupported_fn_ptr_calling_conventions` lint is output whenever there is a use of + /// a target dependent calling convention on a target that does not support this calling + /// convention on a function pointer. + /// + /// For example `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc + /// code, because this calling convention was never specified for those targets. + /// + /// ### Example + /// + /// ```rust,ignore (needs specific targets) + /// fn stdcall_ptr(f: extern "stdcall" fn ()) { + /// f() + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: use of calling convention not supported on this target on function pointer + /// --> $DIR/unsupported.rs:34:15 + /// | + /// LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + /// | ^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + /// = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// On most of the targets the behaviour of `stdcall` and similar calling conventions is not + /// defined at all, but was previously accepted due to a bug in the implementation of the + /// compiler. + pub UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, + Warn, + "use of unsupported calling convention for function pointer", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reference: "issue #130260 <https://github.com/rust-lang/rust/issues/130260>", + }; +} + +declare_lint! { /// The `break_with_label_and_loop` lint detects labeled `break` expressions with /// an unlabeled loop as their value expression. /// @@ -4998,3 +5008,77 @@ declare_lint! { reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>", }; } + +declare_lint! { + /// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer + /// transmute in const functions and associated constants. + /// + /// ### Example + /// + /// ```rust + /// const fn foo(ptr: *const u8) -> usize { + /// unsafe { + /// std::mem::transmute::<*const u8, usize>(ptr) + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Transmuting pointers to integers in a `const` context is undefined behavior. + /// Any attempt to use the resulting integer will abort const-evaluation. + /// + /// But sometimes the compiler might not emit an error for pointer to integer transmutes + /// inside const functions and associated consts because they are evaluated only when referenced. + /// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior + /// from compiling without any warnings or errors. + /// + /// See [std::mem::transmute] in the reference for more details. + /// + /// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html + pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, + Warn, + "detects pointer to integer transmutes in const functions and associated constants", +} + +declare_lint! { + /// The `rust_2024_guarded_string_incompatible_syntax` lint detects `#` tokens + /// that will be parsed as part of a guarded string literal in Rust 2024. + /// + /// ### Example + /// + /// ```rust,edition2021,compile_fail + /// #![deny(rust_2024_guarded_string_incompatible_syntax)] + /// + /// macro_rules! m { + /// (# $x:expr #) => (); + /// (# $x:expr) => (); + /// } + /// + /// m!(#"hey"#); + /// m!(#"hello"); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Prior to Rust 2024, `#"hey"#` is three tokens: the first `#` + /// followed by the string literal `"hey"` then the final `#`. + /// In Rust 2024, the whole sequence is considered a single token. + /// + /// This lint suggests to add whitespace between the leading `#` + /// and the string to keep them separated in Rust 2024. + // Allow this lint -- rustdoc doesn't yet support threading edition into this lint's parser. + #[allow(rustdoc::invalid_rust_codeblocks)] + pub RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, + Allow, + "will be parsed as a guarded string in Rust 2024", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #123735 <https://github.com/rust-lang/rust/issues/123735>", + }; + crate_level_only +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 734e7069c90..c01fa5c54d6 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -614,6 +614,8 @@ pub enum BuiltinLintDiag { ReservedPrefix(Span, String), /// `'r#` in edition < 2021. RawPrefix(Span), + /// `##` or `#"` is edition < 2024. + ReservedString(Span), TrailingMacro(bool, Ident), BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), @@ -720,8 +722,6 @@ pub enum BuiltinLintDiag { UnnameableTestItems, DuplicateMacroAttribute, CfgAttrNoAttributes, - CrateTypeInCfgAttr, - CrateNameInCfgAttr, MissingFragmentSpecifier, MetaVariableStillRepeating(MacroRulesNormalizedIdent), MetaVariableWrongOperator, diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 4532fd8d48d..cda81d4a9b5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -88,38 +88,7 @@ struct LLVMRustMCDCParameters { LLVMRustMCDCBranchParameters BranchParameters; }; -// LLVM representations for `MCDCParameters` evolved from LLVM 18 to 19. -// Look at representations in 18 -// https://github.com/rust-lang/llvm-project/blob/66a2881a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L253-L263 -// and representations in 19 -// https://github.com/llvm/llvm-project/blob/843cc474faefad1d639f4c44c1cf3ad7dbda76c8/llvm/include/llvm/ProfileData/Coverage/MCDCTypes.h -#if LLVM_VERSION_LT(19, 0) -static coverage::CounterMappingRegion::MCDCParameters -fromRust(LLVMRustMCDCParameters Params) { - auto parameter = coverage::CounterMappingRegion::MCDCParameters{}; - switch (Params.Tag) { - case LLVMRustMCDCParametersTag::None: - return parameter; - case LLVMRustMCDCParametersTag::Decision: - parameter.BitmapIdx = - static_cast<unsigned>(Params.DecisionParameters.BitmapIdx), - parameter.NumConditions = - static_cast<unsigned>(Params.DecisionParameters.NumConditions); - return parameter; - case LLVMRustMCDCParametersTag::Branch: - parameter.ID = static_cast<coverage::CounterMappingRegion::MCDCConditionID>( - Params.BranchParameters.ConditionID), - parameter.FalseID = - static_cast<coverage::CounterMappingRegion::MCDCConditionID>( - Params.BranchParameters.ConditionIDs[0]), - parameter.TrueID = - static_cast<coverage::CounterMappingRegion::MCDCConditionID>( - Params.BranchParameters.ConditionIDs[1]); - return parameter; - } - report_fatal_error("Bad LLVMRustMCDCParametersTag!"); -} -#else +#if LLVM_VERSION_GE(19, 0) static coverage::mcdc::Parameters fromRust(LLVMRustMCDCParameters Params) { switch (Params.Tag) { case LLVMRustMCDCParametersTag::None: @@ -215,12 +184,16 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer( MappingRegions.emplace_back( fromRust(Region.Count), fromRust(Region.FalseCount), #if LLVM_VERSION_LT(19, 0) - // LLVM 19 may move this argument to last. - fromRust(Region.MCDCParameters), + coverage::CounterMappingRegion::MCDCParameters{}, #endif Region.FileID, Region.ExpandedFileID, // File IDs, then region info. Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd, - fromRust(Region.Kind)); + fromRust(Region.Kind) +#if LLVM_VERSION_GE(19, 0) + , + fromRust(Region.MCDCParameters) +#endif + ); } std::vector<coverage::CounterExpression> Expressions; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f9fc2bd6da3..72b03fa0560 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1533,29 +1533,40 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { +#if LLVM_VERSION_GE(20, 0) + return wrap(llvm::Intrinsic::getOrInsertDeclaration( + unwrap(M), llvm::Intrinsic::instrprof_increment)); +#else return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_increment)); +#endif } extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) { +#if LLVM_VERSION_LT(19, 0) + report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions"); +#endif +#if LLVM_VERSION_GE(20, 0) + return wrap(llvm::Intrinsic::getOrInsertDeclaration( + unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); +#else return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); +#endif } extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) { - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); -} - -extern "C" LLVMValueRef -LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(LLVMModuleRef M) { #if LLVM_VERSION_LT(19, 0) - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_condbitmap_update)); + report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions"); +#endif +#if LLVM_VERSION_GE(20, 0) + return wrap(llvm::Intrinsic::getOrInsertDeclaration( + unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); #else - report_fatal_error("LLVM 18.0 is required for mcdc intrinsic functions"); + return wrap(llvm::Intrinsic::getDeclaration( + unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); #endif } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index f206dba6cf4..b817b4cb7b8 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -2,7 +2,6 @@ #![allow(internal_features)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(control_flow_enum)] #![feature(coroutines)] #![feature(decl_macro)] #![feature(error_iter)] diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 82b907d2501..c7953d50406 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -1,7 +1,7 @@ use std::ops::ControlFlow; use std::path::{Path, PathBuf}; -use rustc_ast::{CRATE_NODE_ID, NestedMetaItem}; +use rustc_ast::CRATE_NODE_ID; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_middle::query::LocalCrate; @@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> { sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() }); continue; }; - let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else { + let [link_cfg] = link_cfg else { + sess.dcx() + .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); + continue; + }; + let Some(link_cfg) = link_cfg.meta_item_or_bool() else { sess.dcx() .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); continue; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f02fd2ab6fe..4b406496337 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1107,8 +1107,6 @@ impl<'a> CrateMetadataRef<'a> { parent_did, None, data.is_non_exhaustive, - // FIXME: unnamed fields in crate metadata is unimplemented yet. - false, ), ) } @@ -1151,7 +1149,6 @@ impl<'a> CrateMetadataRef<'a> { adt_kind, variants.into_iter().map(|(_, variant)| variant).collect(), repr, - false, ) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 610c682d3a4..afe03531861 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1100,9 +1100,12 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def | DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn => true, + DefKind::AssocTy => { + // Only encode variances for RPITITs (for traits) + matches!(tcx.opt_rpitit_info(def_id), Some(ty::ImplTraitInTraitData::Trait { .. })) + } DefKind::Mod | DefKind::Field - | DefKind::AssocTy | DefKind::AssocConst | DefKind::TyParam | DefKind::ConstParam diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index b23589afb58..8cb602d9ea8 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -12,6 +12,7 @@ field-offset = "0.3.5" gsgdt = "0.1.2" polonius-engine = "0.13.0" rustc-rayon-core = { version = "0.5.0", optional = true } +rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 72e6c96e6f6..8fd5ff1f369 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -732,6 +732,19 @@ impl<'hir> Map<'hir> { } } + #[track_caller] + pub fn expect_opaque_ty(self, id: LocalDefId) -> &'hir OpaqueTy<'hir> { + match self.tcx.hir_node_by_def_id(id) { + Node::OpaqueTy(opaq) => opaq, + _ => { + bug!( + "expected opaque type definition, found {}", + self.node_to_string(self.tcx.local_def_id_to_hir_id(id)) + ) + } + } + } + pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> { match self.tcx.hir_node(id) { Node::Expr(expr) => expr, @@ -923,6 +936,7 @@ impl<'hir> Map<'hir> { Node::Ty(ty) => ty.span, Node::AssocItemConstraint(constraint) => constraint.span, Node::TraitRef(tr) => tr.path.span, + Node::OpaqueTy(op) => op.span, Node::Pat(pat) => pat.span, Node::PatField(field) => field.span, Node::Arm(arm) => arm.span, @@ -1006,6 +1020,10 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { self.tcx.hir_node(hir_id) } + fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir> { + self.tcx.hir_node_by_def_id(def_id) + } + fn body(&self, id: BodyId) -> &'hir Body<'hir> { (*self).body(id) } @@ -1139,7 +1157,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { ItemKind::ForeignMod { .. } => "foreign mod", ItemKind::GlobalAsm(..) => "global asm", ItemKind::TyAlias(..) => "ty", - ItemKind::OpaqueTy(..) => "opaque type", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", @@ -1191,6 +1208,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { Node::Ty(_) => node_str("type"), Node::AssocItemConstraint(_) => node_str("assoc item constraint"), Node::TraitRef(_) => node_str("trait ref"), + Node::OpaqueTy(_) => node_str("opaque type"), Node::Pat(_) => node_str("pat"), Node::PatField(_) => node_str("pattern field"), Node::Param(_) => node_str("param"), @@ -1228,6 +1246,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod impl_items, foreign_items, body_owners, + opaques, .. } = collector; ModuleItems { @@ -1237,6 +1256,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), body_owners: body_owners.into_boxed_slice(), + opaques: opaques.into_boxed_slice(), } } @@ -1256,6 +1276,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { impl_items, foreign_items, body_owners, + opaques, .. } = collector; @@ -1266,6 +1287,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), body_owners: body_owners.into_boxed_slice(), + opaques: opaques.into_boxed_slice(), } } @@ -1280,6 +1302,7 @@ struct ItemCollector<'tcx> { impl_items: Vec<ImplItemId>, foreign_items: Vec<ForeignItemId>, body_owners: Vec<LocalDefId>, + opaques: Vec<LocalDefId>, } impl<'tcx> ItemCollector<'tcx> { @@ -1293,6 +1316,7 @@ impl<'tcx> ItemCollector<'tcx> { impl_items: Vec::default(), foreign_items: Vec::default(), body_owners: Vec::default(), + opaques: Vec::default(), } } } @@ -1338,6 +1362,11 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { intravisit::walk_inline_const(self, c) } + fn visit_opaque_ty(&mut self, o: &'hir OpaqueTy<'hir>) { + self.opaques.push(o.def_id); + intravisit::walk_opaque_ty(self, o) + } + fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { if let ExprKind::Closure(closure) = ex.kind { self.body_owners.push(closure.def_id); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 7a07ef80ded..ad0d70152e1 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -28,6 +28,7 @@ pub struct ModuleItems { trait_items: Box<[TraitItemId]>, impl_items: Box<[ImplItemId]>, foreign_items: Box<[ForeignItemId]>, + opaques: Box<[LocalDefId]>, body_owners: Box<[LocalDefId]>, } @@ -65,6 +66,10 @@ impl ModuleItems { .chain(self.foreign_items.iter().map(|id| id.owner_id)) } + pub fn opaques(&self) -> impl Iterator<Item = LocalDefId> + '_ { + self.opaques.iter().copied() + } + pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ { self.owners().map(|id| id.def_id) } @@ -96,6 +101,13 @@ impl ModuleItems { ) -> Result<(), ErrorGuaranteed> { try_par_for_each_in(&self.foreign_items[..], |&id| f(id)) } + + pub fn par_opaques( + &self, + f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, + ) -> Result<(), ErrorGuaranteed> { + try_par_for_each_in(&self.opaques[..], |&id| f(id)) + } } impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 70e61df1ab4..e9b73d25ba2 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -37,7 +37,6 @@ #![feature(box_as_ptr)] #![feature(box_patterns)] #![feature(closure_track_caller)] -#![feature(const_option)] #![feature(const_type_name)] #![feature(core_intrinsics)] #![feature(coroutines)] diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index 32e2f3b4b16..13e35cd0909 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -1,9 +1,9 @@ //! Name resolution for lifetimes and late-bound type and const variables: type declarations. -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::ErrorGuaranteed; +use rustc_hir::ItemLocalId; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{ItemLocalId, OwnerId}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; use crate::ty; @@ -47,11 +47,11 @@ pub enum ObjectLifetimeDefault { /// Maps the id of each lifetime reference to the lifetime decl /// that it corresponds to. -#[derive(Default, HashStable, Debug)] +#[derive(HashStable, Debug)] pub struct ResolveBoundVars { /// Maps from every use of a named (not anonymous) lifetime to a /// `Region` describing how that region is bound - pub defs: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, ResolvedArg>>, + pub defs: SortedMap<ItemLocalId, ResolvedArg>, - pub late_bound_vars: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>>, + pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>, } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index bfe2a2c2cb3..4a876dc1228 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -67,7 +67,7 @@ rustc_index::newtype_index! { } impl ConditionId { - pub const NONE: Self = Self::from_u32(0); + pub const START: Self = Self::from_usize(0); } /// Enum that can hold a constant zero value, the ID of an physical coverage @@ -128,8 +128,8 @@ pub enum CoverageKind { /// Marks the point in MIR control flow represented by a evaluated condition. /// - /// This is eventually lowered to `llvm.instrprof.mcdc.condbitmap.update` in LLVM IR. - CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 }, + /// This is eventually lowered to instruments updating mcdc temp variables. + CondBitmapUpdate { index: u32, decision_depth: u16 }, /// Marks the point in MIR control flow represented by a evaluated decision. /// @@ -145,14 +145,8 @@ impl Debug for CoverageKind { BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()), CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()), ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()), - CondBitmapUpdate { id, value, decision_depth } => { - write!( - fmt, - "CondBitmapUpdate({:?}, {:?}, depth={:?})", - id.index(), - value, - decision_depth - ) + CondBitmapUpdate { index, decision_depth } => { + write!(fmt, "CondBitmapUpdate(index={:?}, depth={:?})", index, decision_depth) } TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { write!(fmt, "TestVectorUpdate({:?}, depth={:?})", bitmap_idx, decision_depth) @@ -253,7 +247,7 @@ pub struct Mapping { pub struct FunctionCoverageInfo { pub function_source_hash: u64, pub num_counters: usize, - pub mcdc_bitmap_bytes: u32, + pub mcdc_bitmap_bits: usize, pub expressions: IndexVec<ExpressionId, Expression>, pub mappings: Vec<Mapping>, /// The depth of the deepest decision is used to know how many @@ -275,8 +269,10 @@ pub struct CoverageInfoHi { /// data structures without having to scan the entire body first. pub num_block_markers: usize, pub branch_spans: Vec<BranchSpan>, - pub mcdc_branch_spans: Vec<MCDCBranchSpan>, - pub mcdc_decision_spans: Vec<MCDCDecisionSpan>, + /// Branch spans generated by mcdc. Because of some limits mcdc builder give up generating + /// decisions including them so that they are handled as normal branch spans. + pub mcdc_degraded_branch_spans: Vec<MCDCBranchSpan>, + pub mcdc_spans: Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, } #[derive(Clone, Debug)] @@ -291,30 +287,17 @@ pub struct BranchSpan { #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct ConditionInfo { pub condition_id: ConditionId, - pub true_next_id: ConditionId, - pub false_next_id: ConditionId, -} - -impl Default for ConditionInfo { - fn default() -> Self { - Self { - condition_id: ConditionId::NONE, - true_next_id: ConditionId::NONE, - false_next_id: ConditionId::NONE, - } - } + pub true_next_id: Option<ConditionId>, + pub false_next_id: Option<ConditionId>, } #[derive(Clone, Debug)] #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct MCDCBranchSpan { pub span: Span, - /// If `None`, this actually represents a normal branch span inserted for - /// code that was too complex for MC/DC. - pub condition_info: Option<ConditionInfo>, + pub condition_info: ConditionInfo, pub true_marker: BlockMarkerId, pub false_marker: BlockMarkerId, - pub decision_depth: u16, } #[derive(Copy, Clone, Debug)] @@ -328,7 +311,7 @@ pub struct DecisionInfo { #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct MCDCDecisionSpan { pub span: Span, - pub num_conditions: usize, pub end_markers: Vec<BlockMarkerId>, pub decision_depth: u16, + pub num_conditions: usize, } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 431043b0431..fcb87e19435 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -754,6 +754,7 @@ impl Drop for Guard { /// /// We also make things panic if this type is ever implicitly dropped. #[derive(Debug)] +#[must_use] pub struct InterpResult_<'tcx, T> { res: Result<T, InterpErrorInfo<'tcx>>, guard: Guard, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 48789565218..2a3a070a6e7 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -4,7 +4,7 @@ use std::fs; use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_ast::InlineAsmTemplatePiece; use rustc_middle::mir::interpret::{ AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range, read_target_uint, @@ -538,8 +538,8 @@ fn write_coverage_info_hi( let coverage::CoverageInfoHi { num_block_markers: _, branch_spans, - mcdc_branch_spans, - mcdc_decision_spans, + mcdc_degraded_branch_spans, + mcdc_spans, } = coverage_info_hi; // Only add an extra trailing newline if we printed at least one thing. @@ -553,29 +553,35 @@ fn write_coverage_info_hi( did_print = true; } - for coverage::MCDCBranchSpan { - span, - condition_info, - true_marker, - false_marker, - decision_depth, - } in mcdc_branch_spans + for coverage::MCDCBranchSpan { span, true_marker, false_marker, .. } in + mcdc_degraded_branch_spans { writeln!( w, - "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?}, depth: {decision_depth:?} }} => {span:?}", - condition_info.map(|info| info.condition_id) + "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", )?; did_print = true; } - for coverage::MCDCDecisionSpan { span, num_conditions, end_markers, decision_depth } in - mcdc_decision_spans + for ( + coverage::MCDCDecisionSpan { span, end_markers, decision_depth, num_conditions: _ }, + conditions, + ) in mcdc_spans { + let num_conditions = conditions.len(); writeln!( w, "{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}" )?; + for coverage::MCDCBranchSpan { span, condition_info, true_marker, false_marker } in + conditions + { + writeln!( + w, + "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", + condition_info.condition_id + )?; + } did_print = true; } @@ -1024,9 +1030,9 @@ impl<'tcx> TerminatorKind<'tcx> { vec!["real".into(), "unwind".into()] } FalseUnwind { unwind: _, .. } => vec!["real".into()], - InlineAsm { options, ref targets, unwind, .. } => { + InlineAsm { asm_macro, options, ref targets, unwind, .. } => { let mut vec = Vec::with_capacity(targets.len() + 1); - if !options.contains(InlineAsmOptions::NORETURN) { + if !asm_macro.diverges(options) { vec.push("return".into()); } vec.resize(targets.len(), "label".into()); diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index ae75f2d4187..c610fac80f6 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -605,6 +605,25 @@ impl CallSource { } } +#[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] +#[derive(TypeFoldable, TypeVisitable)] +/// The macro that an inline assembly block was created by +pub enum InlineAsmMacro { + /// The `asm!` macro + Asm, + /// The `naked_asm!` macro + NakedAsm, +} + +impl InlineAsmMacro { + pub const fn diverges(self, options: InlineAsmOptions) -> bool { + match self { + InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), + InlineAsmMacro::NakedAsm => true, + } + } +} + /////////////////////////////////////////////////////////////////////////// // Terminators @@ -859,6 +878,9 @@ pub enum TerminatorKind<'tcx> { /// Block ends with an inline assembly block. This is a terminator since /// inline assembly is allowed to diverge. InlineAsm { + /// Macro used to create this inline asm: one of `asm!` or `naked_asm!` + asm_macro: InlineAsmMacro, + /// The template for the inline assembly, with placeholders. template: &'tcx [InlineAsmTemplatePiece], @@ -874,7 +896,7 @@ pub enum TerminatorKind<'tcx> { /// Valid targets for the inline assembly. /// The first element is the fallthrough destination, unless - /// InlineAsmOptions::NORETURN is set. + /// asm_macro == InlineAsmMacro::NakedAsm or InlineAsmOptions::NORETURN is set. targets: Box<[BasicBlock]>, /// Action to be taken if the inline assembly unwinds. This is present @@ -1135,8 +1157,10 @@ pub enum ProjectionElem<V, T> { ConstantIndex { /// index or -index (in Python terms), depending on from_end offset: u64, - /// The thing being indexed must be at least this long. For arrays this - /// is always the exact length. + /// The thing being indexed must be at least this long -- otherwise, the + /// projection is UB. + /// + /// For arrays this is always the exact length. min_length: u64, /// Counting backwards from end? This is always false when indexing an /// array. diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 783952fb9cb..b919f5726db 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -666,6 +666,7 @@ impl<'tcx> TerminatorKind<'tcx> { }, InlineAsm { + asm_macro: _, template: _, ref operands, options: _, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 64898a8495e..9f9ee8497b6 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -576,6 +576,7 @@ macro_rules! make_mir_visitor { } TerminatorKind::InlineAsm { + asm_macro: _, template: _, operands, options: _, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 989fbd711c3..f0be70e00df 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -16,6 +16,7 @@ use rustc_ast::expand::StrippedCfgItem; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; @@ -1552,7 +1553,7 @@ rustc_queries! { feedable } - query check_well_formed(key: hir::OwnerId) -> Result<(), ErrorGuaranteed> { + query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) } ensure_forwards_result_if_red } @@ -1738,29 +1739,28 @@ rustc_queries! { /// Does lifetime resolution on items. Importantly, we can't resolve /// lifetimes directly on things like trait methods, because of trait params. /// See `rustc_resolve::late::lifetimes` for details. - query resolve_bound_vars(_: hir::OwnerId) -> &'tcx ResolveBoundVars { + query resolve_bound_vars(owner_id: hir::OwnerId) -> &'tcx ResolveBoundVars { arena_cache - desc { "resolving lifetimes" } + desc { |tcx| "resolving lifetimes for `{}`", tcx.def_path_str(owner_id) } } - query named_variable_map(_: hir::OwnerId) -> - Option<&'tcx FxIndexMap<ItemLocalId, ResolvedArg>> { - desc { "looking up a named region" } + query named_variable_map(owner_id: hir::OwnerId) -> &'tcx SortedMap<ItemLocalId, ResolvedArg> { + desc { |tcx| "looking up a named region inside `{}`", tcx.def_path_str(owner_id) } } - query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> { - desc { "testing if a region is late bound" } + query is_late_bound_map(owner_id: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> { + desc { |tcx| "testing if a region is late bound inside `{}`", tcx.def_path_str(owner_id) } } /// For a given item's generic parameter, gets the default lifetimes to be used /// for each parameter if a trait object were to be passed for that parameter. /// For example, for `T` in `struct Foo<'a, T>`, this would be `'static`. /// For `T` in `struct Foo<'a, T: 'a>`, this would instead be `'a`. /// This query will panic if passed something that is not a type parameter. - query object_lifetime_default(key: DefId) -> ObjectLifetimeDefault { - desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) } + query object_lifetime_default(def_id: DefId) -> ObjectLifetimeDefault { + desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(def_id) } separate_provide_extern } - query late_bound_vars_map(_: hir::OwnerId) - -> Option<&'tcx FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>> { - desc { "looking up late bound vars" } + query late_bound_vars_map(owner_id: hir::OwnerId) + -> &'tcx SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>> { + desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) } } /// Computes the visibility of the provided `def_id`. diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e614d41899a..fe865b8a515 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering; use std::fmt; use std::ops::Index; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; @@ -173,6 +173,7 @@ pub struct ClosureExpr<'tcx> { #[derive(Clone, Debug, HashStable)] pub struct InlineAsmExpr<'tcx> { + pub asm_macro: AsmMacro, pub template: &'tcx [InlineAsmTemplatePiece], pub operands: Box<[InlineAsmOperand<'tcx>]>, pub options: InlineAsmOptions, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 58e2ebaeaf8..36f0e3d890c 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -148,7 +148,13 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( NamedConst { def_id: _, args: _, user_ty: _ } => {} ConstParam { param: _, def_id: _ } => {} StaticRef { alloc_id: _, ty: _, def_id: _ } => {} - InlineAsm(box InlineAsmExpr { ref operands, template: _, options: _, line_spans: _ }) => { + InlineAsm(box InlineAsmExpr { + asm_macro: _, + ref operands, + template: _, + options: _, + line_spans: _, + }) => { for op in &**operands { use InlineAsmOperand::*; match op { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 41a20e89cbf..71833eea5c0 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -25,10 +25,10 @@ pub enum PointerCoercion { ArrayToPointer, /// Unsize a pointer/reference value, e.g., `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - /// This will do things like convert thin pointers to fat + /// `&[T]`. Note that the source could be a thin or wide pointer. + /// This will do things like convert thin pointers to wide /// pointers, or convert structs containing thin pointers to - /// structs containing fat pointers, or convert between fat + /// structs containing wide pointers, or convert between wide /// pointers. We don't store the details of how the transform is /// done (in fact, we don't know that, because it might depend on /// the precise type parameters). We just store the target diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 8f89f5c25af..3322a2643d7 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -259,12 +259,8 @@ impl AdtDefData { kind: AdtKind, variants: IndexVec<VariantIdx, VariantDef>, repr: ReprOptions, - is_anonymous: bool, ) -> Self { - debug!( - "AdtDef::new({:?}, {:?}, {:?}, {:?}, {:?})", - did, kind, variants, repr, is_anonymous - ); + debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); let mut flags = AdtFlags::NO_ADT_FLAGS; if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) { @@ -297,9 +293,6 @@ impl AdtDefData { if tcx.is_lang_item(did, LangItem::UnsafeCell) { flags |= AdtFlags::IS_UNSAFE_CELL; } - if is_anonymous { - flags |= AdtFlags::IS_ANONYMOUS; - } AdtDefData { did, variants, flags, repr } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2ffb273cb6f..1bdcae4dfb4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -12,6 +12,7 @@ use std::marker::PhantomData; use std::ops::{Bound, Deref}; use std::{fmt, iter, mem}; +use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_ast::{self as ast, attr}; use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; @@ -48,7 +49,6 @@ use rustc_session::{Limit, MetadataKind, Session}; use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::TyKind::*; use rustc_type_ir::fold::TypeFoldable; @@ -56,7 +56,7 @@ use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::solve::SolverMode; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; -use tracing::{debug, instrument}; +use tracing::{debug, trace}; use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; @@ -539,6 +539,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_def(trait_def_id).implement_via_object } + fn is_impl_trait_in_trait(self, def_id: DefId) -> bool { + self.is_impl_trait_in_trait(def_id) + } + fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed { self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string()) } @@ -698,6 +702,12 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu } } +impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span { + fn dummy() -> Self { + DUMMY_SP + } +} + type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; pub struct CtxtInterners<'tcx> { @@ -1419,16 +1429,8 @@ impl<'tcx> TyCtxt<'tcx> { kind: AdtKind, variants: IndexVec<VariantIdx, ty::VariantDef>, repr: ReprOptions, - is_anonymous: bool, ) -> ty::AdtDef<'tcx> { - self.mk_adt_def_from_data(ty::AdtDefData::new( - self, - did, - kind, - variants, - repr, - is_anonymous, - )) + self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr)) } /// Allocates a read-only byte or string literal for `mir::interpret`. @@ -1451,9 +1453,8 @@ impl<'tcx> TyCtxt<'tcx> { debug!("layout_scalar_valid_range: attr={:?}", attr); if let Some( &[ - ast::NestedMetaItem::Lit(ast::MetaItemLit { - kind: ast::LitKind::Int(a, _), - .. + ast::MetaItemInner::Lit(ast::MetaItemLit { + kind: ast::LitKind::Int(a, _), .. }), ], ) = attr.meta_item_list().as_deref() @@ -2073,9 +2074,11 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns the origin of the opaque type `def_id`. - #[instrument(skip(self), level = "trace", ret)] + #[track_caller] pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { - self.hir().expect_item(def_id).expect_opaque_ty().origin + let origin = self.hir().expect_opaque_ty(def_id).origin; + trace!("opaque_type_origin({def_id:?}) => {origin:?}"); + origin } } @@ -2994,7 +2997,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn named_bound_var(self, id: HirId) -> Option<resolve_bound_vars::ResolvedArg> { debug!(?id, "named_region"); - self.named_variable_map(id.owner).and_then(|map| map.get(&id.local_id).cloned()) + self.named_variable_map(id.owner).get(&id.local_id).cloned() } pub fn is_late_bound(self, id: HirId) -> bool { @@ -3003,12 +3006,9 @@ impl<'tcx> TyCtxt<'tcx> { pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> { self.mk_bound_variable_kinds( - &self - .late_bound_vars_map(id.owner) - .and_then(|map| map.get(&id.local_id).cloned()) - .unwrap_or_else(|| { - bug!("No bound vars found for {}", self.hir().node_to_string(id)) - }), + &self.late_bound_vars_map(id.owner).get(&id.local_id).cloned().unwrap_or_else(|| { + bug!("No bound vars found for {}", self.hir().node_to_string(id)) + }), ) } @@ -3031,8 +3031,7 @@ impl<'tcx> TyCtxt<'tcx> { loop { let parent = self.local_parent(opaque_lifetime_param_def_id); - let hir::OpaqueTy { lifetime_mapping, .. } = - self.hir_node_by_def_id(parent).expect_item().expect_opaque_ty(); + let hir::OpaqueTy { lifetime_mapping, .. } = self.hir().expect_opaque_ty(parent); let Some((lifetime, _)) = lifetime_mapping .iter() diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d98e18c1b0c..354ca746b46 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -325,7 +325,7 @@ pub fn suggest_constraining_type_params<'a>( let suggestion = if span_to_replace.is_some() { constraint.clone() } else if constraint.starts_with('<') { - constraint.to_string() + constraint.clone() } else if bound_list_non_empty { format!(" + {constraint}") } else { @@ -507,14 +507,8 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { .. }, _, - ) => { - self.0.push(ty); - } - hir::TyKind::OpaqueDef(item_id, _) => { - self.0.push(ty); - let item = self.1.item(item_id); - hir::intravisit::walk_item(self, item); - } + ) + | hir::TyKind::OpaqueDef(..) => self.0.push(ty), _ => {} } hir::intravisit::walk_ty(self, ty); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index cf0c29e0c8c..6c12b691c26 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,11 +2,15 @@ use std::num::NonZero; use std::ops::Bound; use std::{cmp, fmt}; +use rustc_abi::Primitive::{self, Float, Int, Pointer}; +use rustc_abi::{ + Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutS, + PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, Variants, +}; use rustc_error_messages::DiagMessage; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; -use rustc_hir as hir; use rustc_hir::LangItem; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; @@ -15,10 +19,11 @@ use rustc_session::config::OptLevel; use rustc_span::symbol::{Symbol, sym}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_target::abi::call::FnAbi; -use rustc_target::abi::*; +use rustc_target::abi::{FieldIdx, TyAbiInterface, VariantIdx, call}; use rustc_target::spec::abi::Abi as SpecAbi; use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi}; use tracing::debug; +use {rustc_abi as abi, rustc_hir as hir}; use crate::error::UnsupportedFnAbi; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -27,9 +32,10 @@ use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt}; #[extension(pub trait IntegerExt)] -impl Integer { +impl abi::Integer { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> { + use abi::Integer::{I8, I16, I32, I64, I128}; match (*self, signed) { (I8, false) => tcx.types.u8, (I16, false) => tcx.types.u16, @@ -44,7 +50,8 @@ impl Integer { } } - fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer { + fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> abi::Integer { + use abi::Integer::{I8, I16, I32, I64, I128}; match ity { ty::IntTy::I8 => I8, ty::IntTy::I16 => I16, @@ -54,7 +61,8 @@ impl Integer { ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(), } } - fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> Integer { + fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> abi::Integer { + use abi::Integer::{I8, I16, I32, I64, I128}; match ity { ty::UintTy::U8 => I8, ty::UintTy::U16 => I16, @@ -102,7 +110,7 @@ impl Integer { tcx.data_layout().c_enum_min_size } else { // repr(Rust) enums try to be as small as possible - I8 + Integer::I8 }; // If there are no negative values, we can use the unsigned fit. @@ -115,9 +123,10 @@ impl Integer { } #[extension(pub trait FloatExt)] -impl Float { +impl abi::Float { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + use abi::Float::*; match *self { F16 => tcx.types.f16, F32 => tcx.types.f32, @@ -127,6 +136,7 @@ impl Float { } fn from_float_ty(fty: ty::FloatTy) -> Self { + use abi::Float::*; match fty { ty::FloatTy::F16 => F16, ty::FloatTy::F32 => F32, @@ -164,17 +174,17 @@ impl Primitive { } } -/// The first half of a fat pointer. +/// The first half of a wide pointer. /// /// - For a trait object, this is the address of the box. /// - For a slice, this is the base address. -pub const FAT_PTR_ADDR: usize = 0; +pub const WIDE_PTR_ADDR: usize = 0; -/// The second half of a fat pointer. +/// The second half of a wide pointer. /// /// - For a trait object, this is the address of the vtable. /// - For a slice, this is the length. -pub const FAT_PTR_EXTRA: usize = 1; +pub const WIDE_PTR_EXTRA: usize = 1; /// The maximum supported number of lanes in a SIMD vector. /// @@ -312,7 +322,7 @@ pub enum SizeSkeleton<'tcx> { /// that another SizeSkeleton is of equal size. Generic(ty::Const<'tcx>), - /// A potentially-fat pointer. + /// A potentially-wide pointer. Pointer { /// If true, this pointer is never null. non_zero: bool, @@ -785,11 +795,11 @@ where bug!("TyAndLayout::field({:?}): not applicable", this) } - // Potentially-fat pointers. + // Potentially-wide pointers. ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { assert!(i < this.fields.count()); - // Reuse the fat `*T` type as its own thin pointer data field. + // Reuse the wide `*T` type as its own thin pointer data field. // This provides information about, e.g., DST struct pointees // (which may have no non-DST form), and will work as long // as the `Abi` or `FieldsShape` is checked by users. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f32daee7c44..ed24fcc7eb8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1155,8 +1155,6 @@ bitflags::bitflags! { const NO_VARIANT_FLAGS = 0; /// Indicates whether the field list of this variant is `#[non_exhaustive]`. const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0; - /// Indicates whether this variant has unnamed fields. - const HAS_UNNAMED_FIELDS = 1 << 1; } } rustc_data_structures::external_bitflags_debug! { VariantFlags } @@ -1209,12 +1207,11 @@ impl VariantDef { parent_did: DefId, recover_tainted: Option<ErrorGuaranteed>, is_field_list_non_exhaustive: bool, - has_unnamed_fields: bool, ) -> Self { debug!( "VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?}, - fields = {:?}, adt_kind = {:?}, parent_did = {:?}, has_unnamed_fields = {:?})", - name, variant_did, ctor, discr, fields, adt_kind, parent_did, has_unnamed_fields, + fields = {:?}, adt_kind = {:?}, parent_did = {:?})", + name, variant_did, ctor, discr, fields, adt_kind, parent_did, ); let mut flags = VariantFlags::NO_VARIANT_FLAGS; @@ -1222,10 +1219,6 @@ impl VariantDef { flags |= VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; } - if has_unnamed_fields { - flags |= VariantFlags::HAS_UNNAMED_FIELDS; - } - VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, @@ -1243,12 +1236,6 @@ impl VariantDef { self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) } - /// Does this variant contains unnamed fields - #[inline] - pub fn has_unnamed_fields(&self) -> bool { - self.flags.intersects(VariantFlags::HAS_UNNAMED_FIELDS) - } - /// Computes the `Ident` of this variant by looking up the `Span` pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) @@ -1434,11 +1421,6 @@ impl<'tcx> FieldDef { pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.did).unwrap()) } - - /// Returns whether the field is unnamed - pub fn is_unnamed(&self) -> bool { - self.name == rustc_span::symbol::kw::Underscore - } } #[derive(Debug, PartialEq, Eq)] diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index fd4e8f1cd4e..d20cb368278 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -179,6 +179,10 @@ pub struct Clause<'tcx>( ); impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> { + fn as_predicate(self) -> Predicate<'tcx> { + self.as_predicate() + } + fn instantiate_supertrait(self, tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Self { self.instantiate_supertrait(tcx, trait_ref) } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 61c03922ac0..4c7bcb1bf2e 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -212,15 +212,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArg<'tcx> { (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => { Ok(relation.relate(a_ct, b_ct)?.into()) } - (ty::GenericArgKind::Lifetime(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } - (ty::GenericArgKind::Type(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } - (ty::GenericArgKind::Const(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } + _ => bug!("impossible case reached: can't relate: {a:?} with {b:?}"), } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index db9978a7f53..3f00458d195 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -21,6 +21,7 @@ use rustc_target::spec::abi; use rustc_type_ir::TyKind::*; use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; +use tracing::instrument; use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; use super::GenericParamDefKind; @@ -500,6 +501,7 @@ impl<'tcx> Ty<'tcx> { } #[inline] + #[instrument(level = "debug", skip(tcx))] pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { Ty::new_alias(tcx, ty::Opaque, AliasTy::new_from_args(tcx, def_id, args)) } @@ -584,6 +586,16 @@ impl<'tcx> Ty<'tcx> { Ty::new_ref(tcx, r, ty, hir::Mutability::Not) } + pub fn new_pinned_ref( + tcx: TyCtxt<'tcx>, + r: Region<'tcx>, + ty: Ty<'tcx>, + mutbl: ty::Mutability, + ) -> Ty<'tcx> { + let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None)); + Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()])) + } + #[inline] pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> { Ty::new(tcx, ty::RawPtr(ty, mutbl)) @@ -1589,7 +1601,7 @@ impl<'tcx> Ty<'tcx> { .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap()) } - /// Returns the type of metadata for (potentially fat) pointers to this type, + /// Returns the type of metadata for (potentially wide) pointers to this type, /// or the struct tail if the metadata type cannot be determined. pub fn ptr_metadata_ty_or_tail( self, @@ -1648,7 +1660,7 @@ impl<'tcx> Ty<'tcx> { } } - /// Returns the type of metadata for (potentially fat) pointers to this type. + /// Returns the type of metadata for (potentially wide) pointers to this type. /// Causes an ICE if the metadata type cannot be determined. pub fn ptr_metadata_ty( self, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 17280c3d047..c01d2120111 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -42,12 +42,6 @@ pub struct TypeckResults<'tcx> { /// belongs, but it may not exist if it's a tuple field (`tuple.0`). field_indices: ItemLocalMap<FieldIdx>, - /// Resolved types and indices for the nested fields' accesses of `obj.field` (expanded - /// to `obj._(1)._(2).field` in THIR). This map only stores the intermediate type - /// of `obj._(1)` and index of `_(1)._(2)`, and the type of `_(1)._(2)`, and the index of - /// `_(2).field`. - nested_fields: ItemLocalMap<Vec<(Ty<'tcx>, FieldIdx)>>, - /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated outside inference. See /// typeck::check::fn_ctxt for details. @@ -225,7 +219,6 @@ impl<'tcx> TypeckResults<'tcx> { hir_owner, type_dependent_defs: Default::default(), field_indices: Default::default(), - nested_fields: Default::default(), user_provided_types: Default::default(), user_provided_sigs: Default::default(), node_types: Default::default(), @@ -299,18 +292,6 @@ impl<'tcx> TypeckResults<'tcx> { self.field_indices().get(id).cloned() } - pub fn nested_fields(&self) -> LocalTableInContext<'_, Vec<(Ty<'tcx>, FieldIdx)>> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.nested_fields } - } - - pub fn nested_fields_mut(&mut self) -> LocalTableInContextMut<'_, Vec<(Ty<'tcx>, FieldIdx)>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.nested_fields } - } - - pub fn nested_field_tys_and_indices(&self, id: HirId) -> &[(Ty<'tcx>, FieldIdx)] { - self.nested_fields().get(id).map_or(&[], Vec::as_slice) - } - pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types } } diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 204ee45bfa2..52a4a4b4b51 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -175,7 +175,7 @@ impl CoverageInfoBuilder { let branch_spans = branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default(); - let (mcdc_decision_spans, mcdc_branch_spans) = + let (mcdc_spans, mcdc_degraded_branch_spans) = mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default(); // For simplicity, always return an info struct (without Option), even @@ -183,8 +183,8 @@ impl CoverageInfoBuilder { Box::new(CoverageInfoHi { num_block_markers, branch_spans, - mcdc_branch_spans, - mcdc_decision_spans, + mcdc_degraded_branch_spans, + mcdc_spans, }) } } diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 6019a93e787..343d4000043 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -12,16 +12,16 @@ use rustc_span::Span; use crate::build::Builder; use crate::errors::MCDCExceedsConditionLimit; -/// The MCDC bitmap scales exponentially (2^n) based on the number of conditions seen, -/// So llvm sets a maximum value prevents the bitmap footprint from growing too large without the user's knowledge. -/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged. -const MAX_CONDITIONS_IN_DECISION: usize = 6; +/// LLVM uses `i16` to represent condition id. Hence `i16::MAX` is the hard limit for number of +/// conditions in a decision. +const MAX_CONDITIONS_IN_DECISION: usize = i16::MAX as usize; #[derive(Default)] struct MCDCDecisionCtx { /// To construct condition evaluation tree. decision_stack: VecDeque<ConditionInfo>, processing_decision: Option<MCDCDecisionSpan>, + conditions: Vec<MCDCBranchSpan>, } struct MCDCState { @@ -106,22 +106,27 @@ impl MCDCState { }), }; - let parent_condition = decision_ctx.decision_stack.pop_back().unwrap_or_default(); - let lhs_id = if parent_condition.condition_id == ConditionId::NONE { + let parent_condition = decision_ctx.decision_stack.pop_back().unwrap_or_else(|| { + assert_eq!( + decision.num_conditions, 0, + "decision stack must be empty only for empty decision" + ); decision.num_conditions += 1; - ConditionId::from(decision.num_conditions) - } else { - parent_condition.condition_id - }; + ConditionInfo { + condition_id: ConditionId::START, + true_next_id: None, + false_next_id: None, + } + }); + let lhs_id = parent_condition.condition_id; - decision.num_conditions += 1; let rhs_condition_id = ConditionId::from(decision.num_conditions); - + decision.num_conditions += 1; let (lhs, rhs) = match op { LogicalOp::And => { let lhs = ConditionInfo { condition_id: lhs_id, - true_next_id: rhs_condition_id, + true_next_id: Some(rhs_condition_id), false_next_id: parent_condition.false_next_id, }; let rhs = ConditionInfo { @@ -135,7 +140,7 @@ impl MCDCState { let lhs = ConditionInfo { condition_id: lhs_id, true_next_id: parent_condition.true_next_id, - false_next_id: rhs_condition_id, + false_next_id: Some(rhs_condition_id), }; let rhs = ConditionInfo { condition_id: rhs_condition_id, @@ -150,44 +155,64 @@ impl MCDCState { decision_ctx.decision_stack.push_back(lhs); } - fn take_condition( + fn try_finish_decision( &mut self, + span: Span, true_marker: BlockMarkerId, false_marker: BlockMarkerId, - ) -> (Option<ConditionInfo>, Option<MCDCDecisionSpan>) { + degraded_branches: &mut Vec<MCDCBranchSpan>, + ) -> Option<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)> { let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else { bug!("Unexpected empty decision_ctx_stack") }; let Some(condition_info) = decision_ctx.decision_stack.pop_back() else { - return (None, None); + let branch = MCDCBranchSpan { + span, + condition_info: ConditionInfo { + condition_id: ConditionId::START, + true_next_id: None, + false_next_id: None, + }, + true_marker, + false_marker, + }; + degraded_branches.push(branch); + return None; }; let Some(decision) = decision_ctx.processing_decision.as_mut() else { bug!("Processing decision should have been created before any conditions are taken"); }; - if condition_info.true_next_id == ConditionId::NONE { + if condition_info.true_next_id.is_none() { decision.end_markers.push(true_marker); } - if condition_info.false_next_id == ConditionId::NONE { + if condition_info.false_next_id.is_none() { decision.end_markers.push(false_marker); } + decision_ctx.conditions.push(MCDCBranchSpan { + span, + condition_info, + true_marker, + false_marker, + }); if decision_ctx.decision_stack.is_empty() { - (Some(condition_info), decision_ctx.processing_decision.take()) + let conditions = std::mem::take(&mut decision_ctx.conditions); + decision_ctx.processing_decision.take().map(|decision| (decision, conditions)) } else { - (Some(condition_info), None) + None } } } pub(crate) struct MCDCInfoBuilder { - branch_spans: Vec<MCDCBranchSpan>, - decision_spans: Vec<MCDCDecisionSpan>, + degraded_spans: Vec<MCDCBranchSpan>, + mcdc_spans: Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, state: MCDCState, } impl MCDCInfoBuilder { pub(crate) fn new() -> Self { - Self { branch_spans: vec![], decision_spans: vec![], state: MCDCState::new() } + Self { degraded_spans: vec![], mcdc_spans: vec![], state: MCDCState::new() } } pub(crate) fn visit_evaluated_condition( @@ -201,50 +226,44 @@ impl MCDCInfoBuilder { let true_marker = inject_block_marker(source_info, true_block); let false_marker = inject_block_marker(source_info, false_block); - let decision_depth = self.state.decision_depth(); - let (mut condition_info, decision_result) = - self.state.take_condition(true_marker, false_marker); // take_condition() returns Some for decision_result when the decision stack // is empty, i.e. when all the conditions of the decision were instrumented, // and the decision is "complete". - if let Some(decision) = decision_result { - match decision.num_conditions { + if let Some((decision, conditions)) = self.state.try_finish_decision( + source_info.span, + true_marker, + false_marker, + &mut self.degraded_spans, + ) { + let num_conditions = conditions.len(); + assert_eq!( + num_conditions, decision.num_conditions, + "final number of conditions is not correct" + ); + match num_conditions { 0 => { unreachable!("Decision with no condition is not expected"); } 1..=MAX_CONDITIONS_IN_DECISION => { - self.decision_spans.push(decision); + self.mcdc_spans.push((decision, conditions)); } _ => { - // Do not generate mcdc mappings and statements for decisions with too many conditions. - // Therefore, first erase the condition info of the (N-1) previous branch spans. - let rebase_idx = self.branch_spans.len() - (decision.num_conditions - 1); - for branch in &mut self.branch_spans[rebase_idx..] { - branch.condition_info = None; - } - - // Then, erase this last branch span's info too, for a total of N. - condition_info = None; + self.degraded_spans.extend(conditions); tcx.dcx().emit_warn(MCDCExceedsConditionLimit { span: decision.span, - num_conditions: decision.num_conditions, + num_conditions, max_conditions: MAX_CONDITIONS_IN_DECISION, }); } } } - self.branch_spans.push(MCDCBranchSpan { - span: source_info.span, - condition_info, - true_marker, - false_marker, - decision_depth, - }); } - pub(crate) fn into_done(self) -> (Vec<MCDCDecisionSpan>, Vec<MCDCBranchSpan>) { - (self.decision_spans, self.branch_spans) + pub(crate) fn into_done( + self, + ) -> (Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, Vec<MCDCBranchSpan>) { + (self.mcdc_spans, self.degraded_spans) } } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 86fe447f399..dc317feb20c 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -2,7 +2,7 @@ use std::iter; -use rustc_ast::InlineAsmOptions; +use rustc_ast::{AsmMacro, InlineAsmOptions}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; @@ -384,6 +384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.unit() } ExprKind::InlineAsm(box InlineAsmExpr { + asm_macro, template, ref operands, options, @@ -392,11 +393,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { use rustc_middle::{mir, thir}; let destination_block = this.cfg.start_new_block(); - let mut targets = if options.contains(InlineAsmOptions::NORETURN) { - vec![] - } else { - vec![destination_block] - }; + let mut targets = + if asm_macro.diverges(options) { vec![] } else { vec![destination_block] }; let operands = operands .into_iter() @@ -474,7 +472,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign_unit(block, source_info, destination, this.tcx); } + let asm_macro = match asm_macro { + AsmMacro::Asm => InlineAsmMacro::Asm, + AsmMacro::GlobalAsm => { + span_bug!(expr_span, "unexpected global_asm! in inline asm") + } + AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm, + }; + this.cfg.terminate(block, source_info, TerminatorKind::InlineAsm { + asm_macro, template, operands, options, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 2ffad0b4834..5995d60e7e0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -672,6 +672,7 @@ impl<'tcx> Cx<'tcx> { } hir::ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr { + asm_macro: asm.asm_macro, template: asm.template, operands: asm .operands @@ -807,21 +808,11 @@ impl<'tcx> Cx<'tcx> { }); ExprKind::Loop { body } } - hir::ExprKind::Field(source, ..) => { - let mut kind = ExprKind::Field { - lhs: self.mirror_expr(source), - variant_index: FIRST_VARIANT, - name: self.typeck_results.field_index(expr.hir_id), - }; - let nested_field_tys_and_indices = - self.typeck_results.nested_field_tys_and_indices(expr.hir_id); - for &(ty, idx) in nested_field_tys_and_indices { - let expr = Expr { temp_lifetime, ty, span: source.span, kind }; - let lhs = self.thir.exprs.push(expr); - kind = ExprKind::Field { lhs, variant_index: FIRST_VARIANT, name: idx }; - } - kind - } + hir::ExprKind::Field(source, ..) => ExprKind::Field { + lhs: self.mirror_expr(source), + variant_index: FIRST_VARIANT, + name: self.typeck_results.field_index(expr.hir_id), + }, hir::ExprKind::Cast(source, cast_ty) => { // Check for a user-given type annotation on this `cast` let user_provided_types = self.typeck_results.user_provided_types(); diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 61317925d09..dae13df4054 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -818,10 +818,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) { - let InlineAsmExpr { template, operands, options, line_spans } = expr; + let InlineAsmExpr { asm_macro, template, operands, options, line_spans } = expr; print_indented!(self, "InlineAsmExpr {", depth_lvl); + print_indented!(self, format!("asm_macro: {:?}", asm_macro), depth_lvl + 1); + print_indented!(self, "template: [", depth_lvl + 1); for template_piece in template.iter() { print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index f2541c37167..a3b117a3f19 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -225,7 +225,7 @@ where // FIXME: I think we should just control the flags externally, // and then we do not need this machinery. #[instrument(level = "debug")] - pub fn elaborate_drop(&mut self, bb: BasicBlock) { + fn elaborate_drop(&mut self, bb: BasicBlock) { match self.elaborator.drop_style(self.path, DropFlagMode::Deep) { DropStyle::Dead => { self.elaborator diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index faf5c610a0c..9d50e57d668 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -367,7 +367,7 @@ impl RustcMirAttrs { fn set_field<T>( field: &mut Option<T>, tcx: TyCtxt<'_>, - attr: &ast::NestedMetaItem, + attr: &ast::MetaItemInner, mapper: impl FnOnce(Symbol) -> Result<T, ()>, ) -> Result<(), ()> { if field.is_some() { diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 3c8be2f73e1..162245cb950 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -481,6 +481,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { } } TerminatorKind::InlineAsm { + asm_macro: _, template: _, ref operands, options: _, diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index f9b79d72b05..c8992b8b834 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -9,6 +9,8 @@ mir_transform_const_mut_borrow = taking a mutable reference to a `const` item .note2 = the mutable reference will refer to this temporary, not the original `const` item .note3 = mutable reference created due to call to this method +mir_transform_exceeds_mcdc_test_vector_limit = number of total test vectors in one function will exceed limit ({$max_num_test_vectors}) if this decision is instrumented, so MC/DC analysis ignores it + mir_transform_ffi_unwind_call = call to {$foreign -> [true] foreign function *[false] function pointer @@ -27,3 +29,8 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval + .note = at compile-time, pointers do not have an integer value + .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + .help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs new file mode 100644 index 00000000000..8ba14a1158e --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs @@ -0,0 +1,77 @@ +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind}; +use rustc_middle::ty::{AssocItem, AssocKind, TyCtxt}; +use rustc_session::lint::builtin::PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS; +use rustc_span::sym; + +use crate::errors; + +/// Check for transmutes that exhibit undefined behavior. +/// For example, transmuting pointers to integers in a const context. +pub(super) struct CheckUndefinedTransmutes; + +impl<'tcx> crate::MirLint<'tcx> for CheckUndefinedTransmutes { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let mut checker = UndefinedTransmutesChecker { body, tcx }; + checker.visit_body(body); + } +} + +struct UndefinedTransmutesChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, +} + +impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> { + // This functions checks two things: + // 1. `function` takes a raw pointer as input and returns an integer as output. + // 2. `function` is called from a const function or an associated constant. + // + // Why do we consider const functions and associated constants only? + // + // Generally, undefined behavior in const items are handled by the evaluator. + // But, const functions and associated constants are evaluated only when referenced. + // This can result in undefined behavior in a library going unnoticed until + // the function or constant is actually used. + // + // Therefore, we only consider const functions and associated constants here and leave + // other const items to be handled by the evaluator. + fn is_ptr_to_int_in_const(&self, function: &Operand<'tcx>) -> bool { + let def_id = self.body.source.def_id(); + + if self.tcx.is_const_fn(def_id) + || matches!( + self.tcx.opt_associated_item(def_id), + Some(AssocItem { kind: AssocKind::Const, .. }) + ) + { + let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); + if let [input] = fn_sig.inputs() { + return input.is_unsafe_ptr() && fn_sig.output().is_integral(); + } + } + false + } +} + +impl<'tcx> Visitor<'tcx> for UndefinedTransmutesChecker<'_, 'tcx> { + // Check each block's terminator for calls to pointer to integer transmutes + // in const functions or associated constants and emit a lint. + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + if let TerminatorKind::Call { func, .. } = &terminator.kind + && let Some((func_def_id, _)) = func.const_fn_def() + && self.tcx.is_intrinsic(func_def_id, sym::transmute) + && self.is_ptr_to_int_in_const(func) + && let Some(call_id) = self.body.source.def_id().as_local() + { + let hir_id = self.tcx.local_def_id_to_hir_id(call_id); + let span = self.body.source_info(location).span; + self.tcx.emit_node_span_lint( + PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, + hir_id, + span, + errors::UndefinedTransmute, + ); + } + } +} diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index ef4031c5c03..94088156756 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -4,6 +4,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op}; use tracing::{debug, debug_span, instrument}; @@ -13,13 +14,13 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverage /// The coverage counter or counter expression associated with a particular /// BCB node or BCB edge. #[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub(super) enum BcbCounter { +enum BcbCounter { Counter { id: CounterId }, Expression { id: ExpressionId }, } impl BcbCounter { - pub(super) fn as_term(&self) -> CovTerm { + fn as_term(&self) -> CovTerm { match *self { BcbCounter::Counter { id, .. } => CovTerm::Counter(id), BcbCounter::Expression { id, .. } => CovTerm::Expression(id), @@ -78,21 +79,22 @@ impl CoverageCounters { /// counters or counter expressions for nodes and edges as required. pub(super) fn make_bcb_counters( basic_coverage_blocks: &CoverageGraph, - bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool, + bcb_needs_counter: &BitSet<BasicCoverageBlock>, ) -> Self { - let num_bcbs = basic_coverage_blocks.num_nodes(); + let mut counters = MakeBcbCounters::new(basic_coverage_blocks, bcb_needs_counter); + counters.make_bcb_counters(); - let mut this = Self { + counters.coverage_counters + } + + fn with_num_bcbs(num_bcbs: usize) -> Self { + Self { counter_increment_sites: IndexVec::new(), bcb_counters: IndexVec::from_elem_n(None, num_bcbs), bcb_edge_counters: FxHashMap::default(), expressions: IndexVec::new(), expressions_memo: FxHashMap::default(), - }; - - MakeBcbCounters::new(&mut this, basic_coverage_blocks).make_bcb_counters(bcb_needs_counter); - - this + } } /// Shared helper used by [`Self::make_phys_node_counter`] and @@ -218,8 +220,8 @@ impl CoverageCounters { } } - pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<BcbCounter> { - self.bcb_counters[bcb] + pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> { + self.bcb_counters[bcb].map(|counter| counter.as_term()) } /// Returns an iterator over all the nodes/edges in the coverage graph that @@ -265,19 +267,25 @@ impl CoverageCounters { /// Helper struct that allows counter creation to inspect the BCB graph. struct MakeBcbCounters<'a> { - coverage_counters: &'a mut CoverageCounters, + coverage_counters: CoverageCounters, basic_coverage_blocks: &'a CoverageGraph, + bcb_needs_counter: &'a BitSet<BasicCoverageBlock>, } impl<'a> MakeBcbCounters<'a> { fn new( - coverage_counters: &'a mut CoverageCounters, basic_coverage_blocks: &'a CoverageGraph, + bcb_needs_counter: &'a BitSet<BasicCoverageBlock>, ) -> Self { - Self { coverage_counters, basic_coverage_blocks } + assert_eq!(basic_coverage_blocks.num_nodes(), bcb_needs_counter.domain_size()); + Self { + coverage_counters: CoverageCounters::with_num_bcbs(basic_coverage_blocks.num_nodes()), + basic_coverage_blocks, + bcb_needs_counter, + } } - fn make_bcb_counters(&mut self, bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool) { + fn make_bcb_counters(&mut self) { debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock"); // Traverse the coverage graph, ensuring that every node that needs a @@ -290,7 +298,7 @@ impl<'a> MakeBcbCounters<'a> { let mut traversal = TraverseCoverageGraphWithLoops::new(self.basic_coverage_blocks); while let Some(bcb) = traversal.next() { let _span = debug_span!("traversal", ?bcb).entered(); - if bcb_needs_counter(bcb) { + if self.bcb_needs_counter.contains(bcb) { self.make_node_counter_and_out_edge_counters(&traversal, bcb); } } diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index ec5ba354805..bc86ae22a0d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -1,10 +1,11 @@ use std::collections::BTreeSet; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; use rustc_middle::mir::coverage::{ - BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind, + BlockMarkerId, BranchSpan, ConditionId, ConditionInfo, CoverageInfoHi, CoverageKind, }; use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; @@ -14,6 +15,7 @@ use crate::coverage::ExtractedHirInfo; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; use crate::coverage::spans::extract_refined_covspans; use crate::coverage::unexpand::unexpand_into_body_span; +use crate::errors::MCDCExceedsTestVectorLimit; /// Associates an ordinary executable code span with its corresponding BCB. #[derive(Debug)] @@ -38,10 +40,11 @@ pub(super) struct MCDCBranch { pub(super) span: Span, pub(super) true_bcb: BasicCoverageBlock, pub(super) false_bcb: BasicCoverageBlock, - /// If `None`, this actually represents a normal branch mapping inserted - /// for code that was too complex for MC/DC. - pub(super) condition_info: Option<ConditionInfo>, - pub(super) decision_depth: u16, + pub(super) condition_info: ConditionInfo, + // Offset added to test vector idx if this branch is evaluated to true. + pub(super) true_index: usize, + // Offset added to test vector idx if this branch is evaluated to false. + pub(super) false_index: usize, } /// Associates an MC/DC decision with its join BCBs. @@ -49,11 +52,15 @@ pub(super) struct MCDCBranch { pub(super) struct MCDCDecision { pub(super) span: Span, pub(super) end_bcbs: BTreeSet<BasicCoverageBlock>, - pub(super) bitmap_idx: u32, - pub(super) num_conditions: u16, + pub(super) bitmap_idx: usize, + pub(super) num_test_vectors: usize, pub(super) decision_depth: u16, } +// LLVM uses `i32` to index the bitmap. Thus `i32::MAX` is the hard limit for number of all test vectors +// in a function. +const MCDC_MAX_BITMAP_SIZE: usize = i32::MAX as usize; + #[derive(Default)] pub(super) struct ExtractedMappings { /// Store our own copy of [`CoverageGraph::num_nodes`], so that we don't @@ -62,9 +69,9 @@ pub(super) struct ExtractedMappings { pub(super) num_bcbs: usize, pub(super) code_mappings: Vec<CodeMapping>, pub(super) branch_pairs: Vec<BranchPair>, - pub(super) mcdc_bitmap_bytes: u32, - pub(super) mcdc_branches: Vec<MCDCBranch>, - pub(super) mcdc_decisions: Vec<MCDCDecision>, + pub(super) mcdc_bitmap_bits: usize, + pub(super) mcdc_degraded_branches: Vec<MCDCBranch>, + pub(super) mcdc_mappings: Vec<(MCDCDecision, Vec<MCDCBranch>)>, } /// Extracts coverage-relevant spans from MIR, and associates them with @@ -77,9 +84,9 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( ) -> ExtractedMappings { let mut code_mappings = vec![]; let mut branch_pairs = vec![]; - let mut mcdc_bitmap_bytes = 0; - let mut mcdc_branches = vec![]; - let mut mcdc_decisions = vec![]; + let mut mcdc_bitmap_bits = 0; + let mut mcdc_degraded_branches = vec![]; + let mut mcdc_mappings = vec![]; if hir_info.is_async_fn || tcx.sess.coverage_no_mir_spans() { // An async function desugars into a function that returns a future, @@ -102,20 +109,21 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( extract_mcdc_mappings( mir_body, + tcx, hir_info.body_span, basic_coverage_blocks, - &mut mcdc_bitmap_bytes, - &mut mcdc_branches, - &mut mcdc_decisions, + &mut mcdc_bitmap_bits, + &mut mcdc_degraded_branches, + &mut mcdc_mappings, ); ExtractedMappings { num_bcbs: basic_coverage_blocks.num_nodes(), code_mappings, branch_pairs, - mcdc_bitmap_bytes, - mcdc_branches, - mcdc_decisions, + mcdc_bitmap_bits, + mcdc_degraded_branches, + mcdc_mappings, } } @@ -126,9 +134,9 @@ impl ExtractedMappings { num_bcbs, code_mappings, branch_pairs, - mcdc_bitmap_bytes: _, - mcdc_branches, - mcdc_decisions, + mcdc_bitmap_bits: _, + mcdc_degraded_branches, + mcdc_mappings, } = self; // Identify which BCBs have one or more mappings. @@ -144,7 +152,10 @@ impl ExtractedMappings { insert(true_bcb); insert(false_bcb); } - for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches { + for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_degraded_branches + .iter() + .chain(mcdc_mappings.iter().map(|(_, branches)| branches.into_iter()).flatten()) + { insert(true_bcb); insert(false_bcb); } @@ -152,8 +163,8 @@ impl ExtractedMappings { // MC/DC decisions refer to BCBs, but don't require those BCBs to have counters. if bcbs_with_counter_mappings.is_empty() { debug_assert!( - mcdc_decisions.is_empty(), - "A function with no counter mappings shouldn't have any decisions: {mcdc_decisions:?}", + mcdc_mappings.is_empty(), + "A function with no counter mappings shouldn't have any decisions: {mcdc_mappings:?}", ); } @@ -230,11 +241,12 @@ pub(super) fn extract_branch_pairs( pub(super) fn extract_mcdc_mappings( mir_body: &mir::Body<'_>, + tcx: TyCtxt<'_>, body_span: Span, basic_coverage_blocks: &CoverageGraph, - mcdc_bitmap_bytes: &mut u32, - mcdc_branches: &mut impl Extend<MCDCBranch>, - mcdc_decisions: &mut impl Extend<MCDCDecision>, + mcdc_bitmap_bits: &mut usize, + mcdc_degraded_branches: &mut impl Extend<MCDCBranch>, + mcdc_mappings: &mut impl Extend<(MCDCDecision, Vec<MCDCBranch>)>, ) { let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return }; @@ -257,43 +269,146 @@ pub(super) fn extract_mcdc_mappings( Some((span, true_bcb, false_bcb)) }; - mcdc_branches.extend(coverage_info_hi.mcdc_branch_spans.iter().filter_map( - |&mir::coverage::MCDCBranchSpan { - span: raw_span, - condition_info, - true_marker, - false_marker, - decision_depth, - }| { - let (span, true_bcb, false_bcb) = - check_branch_bcb(raw_span, true_marker, false_marker)?; - Some(MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth }) - }, - )); - - mcdc_decisions.extend(coverage_info_hi.mcdc_decision_spans.iter().filter_map( - |decision: &mir::coverage::MCDCDecisionSpan| { - let span = unexpand_into_body_span(decision.span, body_span)?; - - let end_bcbs = decision - .end_markers - .iter() - .map(|&marker| bcb_from_marker(marker)) - .collect::<Option<_>>()?; - - // Each decision containing N conditions needs 2^N bits of space in - // the bitmap, rounded up to a whole number of bytes. - // The decision's "bitmap index" points to its first byte in the bitmap. - let bitmap_idx = *mcdc_bitmap_bytes; - *mcdc_bitmap_bytes += (1_u32 << decision.num_conditions).div_ceil(8); - - Some(MCDCDecision { + let to_mcdc_branch = |&mir::coverage::MCDCBranchSpan { + span: raw_span, + condition_info, + true_marker, + false_marker, + }| { + let (span, true_bcb, false_bcb) = check_branch_bcb(raw_span, true_marker, false_marker)?; + Some(MCDCBranch { + span, + true_bcb, + false_bcb, + condition_info, + true_index: usize::MAX, + false_index: usize::MAX, + }) + }; + + let mut get_bitmap_idx = |num_test_vectors: usize| -> Option<usize> { + let bitmap_idx = *mcdc_bitmap_bits; + let next_bitmap_bits = bitmap_idx.saturating_add(num_test_vectors); + (next_bitmap_bits <= MCDC_MAX_BITMAP_SIZE).then(|| { + *mcdc_bitmap_bits = next_bitmap_bits; + bitmap_idx + }) + }; + mcdc_degraded_branches + .extend(coverage_info_hi.mcdc_degraded_branch_spans.iter().filter_map(to_mcdc_branch)); + + mcdc_mappings.extend(coverage_info_hi.mcdc_spans.iter().filter_map(|(decision, branches)| { + if branches.len() == 0 { + return None; + } + let decision_span = unexpand_into_body_span(decision.span, body_span)?; + + let end_bcbs = decision + .end_markers + .iter() + .map(|&marker| bcb_from_marker(marker)) + .collect::<Option<_>>()?; + let mut branch_mappings: Vec<_> = branches.into_iter().filter_map(to_mcdc_branch).collect(); + if branch_mappings.len() != branches.len() { + mcdc_degraded_branches.extend(branch_mappings); + return None; + } + let num_test_vectors = calc_test_vectors_index(&mut branch_mappings); + let Some(bitmap_idx) = get_bitmap_idx(num_test_vectors) else { + tcx.dcx().emit_warn(MCDCExceedsTestVectorLimit { + span: decision_span, + max_num_test_vectors: MCDC_MAX_BITMAP_SIZE, + }); + mcdc_degraded_branches.extend(branch_mappings); + return None; + }; + // LLVM requires span of the decision contains all spans of its conditions. + // Usually the decision span meets the requirement well but in cases like macros it may not. + let span = branch_mappings + .iter() + .map(|branch| branch.span) + .reduce(|lhs, rhs| lhs.to(rhs)) + .map( + |joint_span| { + if decision_span.contains(joint_span) { decision_span } else { joint_span } + }, + ) + .expect("branch mappings are ensured to be non-empty as checked above"); + Some(( + MCDCDecision { span, end_bcbs, bitmap_idx, - num_conditions: decision.num_conditions as u16, + num_test_vectors, decision_depth: decision.decision_depth, - }) - }, - )); + }, + branch_mappings, + )) + })); +} + +// LLVM checks the executed test vector by accumulating indices of tested branches. +// We calculate number of all possible test vectors of the decision and assign indices +// to branches here. +// See [the rfc](https://discourse.llvm.org/t/rfc-coverage-new-algorithm-and-file-format-for-mc-dc/76798/) +// for more details about the algorithm. +// This function is mostly like [`TVIdxBuilder::TvIdxBuilder`](https://github.com/llvm/llvm-project/blob/d594d9f7f4dc6eb748b3261917db689fdc348b96/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp#L226) +fn calc_test_vectors_index(conditions: &mut Vec<MCDCBranch>) -> usize { + let mut indegree_stats = IndexVec::<ConditionId, usize>::from_elem_n(0, conditions.len()); + // `num_paths` is `width` described at the llvm rfc, which indicates how many paths reaching the condition node. + let mut num_paths_stats = IndexVec::<ConditionId, usize>::from_elem_n(0, conditions.len()); + let mut next_conditions = conditions + .iter_mut() + .map(|branch| { + let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info; + [true_next_id, false_next_id] + .into_iter() + .filter_map(std::convert::identity) + .for_each(|next_id| indegree_stats[next_id] += 1); + (condition_id, branch) + }) + .collect::<FxIndexMap<_, _>>(); + + let mut queue = std::collections::VecDeque::from_iter( + next_conditions.swap_remove(&ConditionId::START).into_iter(), + ); + num_paths_stats[ConditionId::START] = 1; + let mut decision_end_nodes = Vec::new(); + while let Some(branch) = queue.pop_front() { + let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info; + let (false_index, true_index) = (&mut branch.false_index, &mut branch.true_index); + let this_paths_count = num_paths_stats[condition_id]; + // Note. First check the false next to ensure conditions are touched in same order with llvm-cov. + for (next, index) in [(false_next_id, false_index), (true_next_id, true_index)] { + if let Some(next_id) = next { + let next_paths_count = &mut num_paths_stats[next_id]; + *index = *next_paths_count; + *next_paths_count = next_paths_count.saturating_add(this_paths_count); + let next_indegree = &mut indegree_stats[next_id]; + *next_indegree -= 1; + if *next_indegree == 0 { + queue.push_back(next_conditions.swap_remove(&next_id).expect( + "conditions with non-zero indegree before must be in next_conditions", + )); + } + } else { + decision_end_nodes.push((this_paths_count, condition_id, index)); + } + } + } + assert!(next_conditions.is_empty(), "the decision tree has untouched nodes"); + let mut cur_idx = 0; + // LLVM hopes the end nodes are sorted in descending order by `num_paths` so that it can + // optimize bitmap size for decisions in tree form such as `a && b && c && d && ...`. + decision_end_nodes.sort_by_key(|(num_paths, _, _)| usize::MAX - *num_paths); + for (num_paths, condition_id, index) in decision_end_nodes { + assert_eq!( + num_paths, num_paths_stats[condition_id], + "end nodes should not be updated since they were visited" + ); + assert_eq!(*index, usize::MAX, "end nodes should not be assigned index before"); + *index = cur_idx; + cur_idx += num_paths; + } + cur_idx } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 104f340c8d6..d0f30314e79 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -94,9 +94,8 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: return; } - let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb); let coverage_counters = - CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings); + CoverageCounters::make_bcb_counters(&basic_coverage_blocks, &bcbs_with_counter_mappings); let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters); if mappings.is_empty() { @@ -115,16 +114,16 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: inject_mcdc_statements(mir_body, &basic_coverage_blocks, &extracted_mappings); let mcdc_num_condition_bitmaps = extracted_mappings - .mcdc_decisions + .mcdc_mappings .iter() - .map(|&mappings::MCDCDecision { decision_depth, .. }| decision_depth) + .map(|&(mappings::MCDCDecision { decision_depth, .. }, _)| decision_depth) .max() .map_or(0, |max| usize::from(max) + 1); mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, num_counters: coverage_counters.num_counters(), - mcdc_bitmap_bytes: extracted_mappings.mcdc_bitmap_bytes, + mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits, expressions: coverage_counters.into_expressions(), mappings, mcdc_num_condition_bitmaps, @@ -153,12 +152,8 @@ fn create_mappings<'tcx>( &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), ); - let term_for_bcb = |bcb| { - coverage_counters - .bcb_counter(bcb) - .expect("all BCBs with spans were given counters") - .as_term() - }; + let term_for_bcb = + |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters"); let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span); // Fully destructure the mappings struct to make sure we don't miss any kinds. @@ -166,9 +161,9 @@ fn create_mappings<'tcx>( num_bcbs: _, code_mappings, branch_pairs, - mcdc_bitmap_bytes: _, - mcdc_branches, - mcdc_decisions, + mcdc_bitmap_bits: _, + mcdc_degraded_branches, + mcdc_mappings, } = extracted_mappings; let mut mappings = Vec::new(); @@ -191,26 +186,79 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(mcdc_branches.iter().filter_map( - |&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| { + let term_for_bcb = + |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters"); + + // MCDC branch mappings are appended with their decisions in case decisions were ignored. + mappings.extend(mcdc_degraded_branches.iter().filter_map( + |&mappings::MCDCBranch { + span, + true_bcb, + false_bcb, + condition_info: _, + true_index: _, + false_index: _, + }| { let source_region = region_for_span(span)?; let true_term = term_for_bcb(true_bcb); let false_term = term_for_bcb(false_bcb); - let kind = match condition_info { - Some(mcdc_params) => MappingKind::MCDCBranch { true_term, false_term, mcdc_params }, - None => MappingKind::Branch { true_term, false_term }, - }; - Some(Mapping { kind, source_region }) + Some(Mapping { kind: MappingKind::Branch { true_term, false_term }, source_region }) }, )); - mappings.extend(mcdc_decisions.iter().filter_map( - |&mappings::MCDCDecision { span, bitmap_idx, num_conditions, .. }| { - let source_region = region_for_span(span)?; - let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, num_conditions }); - Some(Mapping { kind, source_region }) - }, - )); + for (decision, branches) in mcdc_mappings { + let num_conditions = branches.len() as u16; + let conditions = branches + .into_iter() + .filter_map( + |&mappings::MCDCBranch { + span, + true_bcb, + false_bcb, + condition_info, + true_index: _, + false_index: _, + }| { + let source_region = region_for_span(span)?; + let true_term = term_for_bcb(true_bcb); + let false_term = term_for_bcb(false_bcb); + Some(Mapping { + kind: MappingKind::MCDCBranch { + true_term, + false_term, + mcdc_params: condition_info, + }, + source_region, + }) + }, + ) + .collect::<Vec<_>>(); + + if conditions.len() == num_conditions as usize + && let Some(source_region) = region_for_span(decision.span) + { + // LLVM requires end index for counter mapping regions. + let kind = MappingKind::MCDCDecision(DecisionInfo { + bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32, + num_conditions, + }); + mappings.extend( + std::iter::once(Mapping { kind, source_region }).chain(conditions.into_iter()), + ); + } else { + mappings.extend(conditions.into_iter().map(|mapping| { + let MappingKind::MCDCBranch { true_term, false_term, mcdc_params: _ } = + mapping.kind + else { + unreachable!("all mappings here are MCDCBranch as shown above"); + }; + Mapping { + kind: MappingKind::Branch { true_term, false_term }, + source_region: mapping.source_region, + } + })) + } + } mappings } @@ -279,44 +327,41 @@ fn inject_mcdc_statements<'tcx>( basic_coverage_blocks: &CoverageGraph, extracted_mappings: &ExtractedMappings, ) { - // Inject test vector update first because `inject_statement` always insert new statement at - // head. - for &mappings::MCDCDecision { - span: _, - ref end_bcbs, - bitmap_idx, - num_conditions: _, - decision_depth, - } in &extracted_mappings.mcdc_decisions - { - for end in end_bcbs { - let end_bb = basic_coverage_blocks[*end].leader_bb(); + for (decision, conditions) in &extracted_mappings.mcdc_mappings { + // Inject test vector update first because `inject_statement` always insert new statement at head. + for &end in &decision.end_bcbs { + let end_bb = basic_coverage_blocks[end].leader_bb(); inject_statement( mir_body, - CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth }, + CoverageKind::TestVectorBitmapUpdate { + bitmap_idx: decision.bitmap_idx as u32, + decision_depth: decision.decision_depth, + }, end_bb, ); } - } - for &mappings::MCDCBranch { span: _, true_bcb, false_bcb, condition_info, decision_depth } in - &extracted_mappings.mcdc_branches - { - let Some(condition_info) = condition_info else { continue }; - let id = condition_info.condition_id; - - let true_bb = basic_coverage_blocks[true_bcb].leader_bb(); - inject_statement( - mir_body, - CoverageKind::CondBitmapUpdate { id, value: true, decision_depth }, - true_bb, - ); - let false_bb = basic_coverage_blocks[false_bcb].leader_bb(); - inject_statement( - mir_body, - CoverageKind::CondBitmapUpdate { id, value: false, decision_depth }, - false_bb, - ); + for &mappings::MCDCBranch { + span: _, + true_bcb, + false_bcb, + condition_info: _, + true_index, + false_index, + } in conditions + { + for (index, bcb) in [(false_index, false_bcb), (true_index, true_bcb)] { + let bb = basic_coverage_blocks[bcb].leader_bb(); + inject_statement( + mir_body, + CoverageKind::CondBitmapUpdate { + index: index as u32, + decision_depth: decision.decision_depth, + }, + bb, + ); + } + } } } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 84d44c2ab4c..8b309147c64 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -89,6 +89,14 @@ pub(crate) struct FnItemRef { pub ident: String, } +#[derive(Diagnostic)] +#[diag(mir_transform_exceeds_mcdc_test_vector_limit)] +pub(crate) struct MCDCExceedsTestVectorLimit { + #[primary_span] + pub(crate) span: Span, + pub(crate) max_num_test_vectors: usize, +} + pub(crate) struct MustNotSupend<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, pub yield_sp: Span, @@ -121,3 +129,10 @@ pub(crate) struct MustNotSuspendReason { pub span: Span, pub reason: String, } + +#[derive(LintDiagnostic)] +#[diag(mir_transform_undefined_transmute)] +#[note] +#[note(mir_transform_note2)] +#[help] +pub(crate) struct UndefinedTransmute; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 50c9702cb9b..daf868559bc 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -103,7 +103,7 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; -use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; +use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx}; use smallvec::SmallVec; use tracing::{debug, instrument, trace}; @@ -568,13 +568,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { CastKind::Transmute => { let value = self.evaluated[value].as_ref()?; let to = self.ecx.layout_of(to).ok()?; - // `offset` for immediates only supports scalar/scalar-pair ABIs, - // so bail out if the target is not one. + // `offset` for immediates generally only supports projections that match the + // type of the immediate. However, as a HACK, we exploit that it can also do + // limited transmutes: it only works between types with the same layout, and + // cannot transmute pointers to integers. if value.as_mplace_or_imm().is_right() { - match (value.layout.abi, to.abi) { - (Abi::Scalar(..), Abi::Scalar(..)) => {} - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {} - _ => return None, + let can_transmute = match (value.layout.abi, to.abi) { + (Abi::Scalar(s1), Abi::Scalar(s2)) => { + s1.size(&self.ecx) == s2.size(&self.ecx) + && !matches!(s1.primitive(), Primitive::Pointer(..)) + } + (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { + a1.size(&self.ecx) == a2.size(&self.ecx) && + b1.size(&self.ecx) == b2.size(&self.ecx) && + // The alignment of the second component determines its offset, so that also needs to match. + b1.align(&self.ecx) == b2.align(&self.ecx) && + // None of the inputs may be a pointer. + !matches!(a1.primitive(), Primitive::Pointer(..)) + && !matches!(b1.primitive(), Primitive::Pointer(..)) + } + _ => false, + }; + if !can_transmute { + return None; } } value.offset(Size::ZERO, to, &self.ecx).discard_err()? @@ -1137,7 +1153,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => { return Some(fields[1]); } - // We have an unsizing cast, which assigns the length to fat pointer metadata. + // We have an unsizing cast, which assigns the length to wide pointer metadata. ( UnOp::PtrMetadata, Value::Cast { @@ -1421,7 +1437,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let mut inner = self.simplify_place_value(place, location)?; - // The length information is stored in the fat pointer. + // The length information is stored in the wide pointer. // Reborrowing copies length information from one pointer to the other. while let Value::Address { place: borrowed, .. } = self.get(inner) && let [PlaceElem::Deref] = borrowed.projection[..] @@ -1430,7 +1446,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { inner = borrowed; } - // We have an unsizing cast, which assigns the length to fat pointer metadata. + // We have an unsizing cast, which assigns the length to wide pointer metadata. if let Value::Cast { kind, from, to, .. } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind && let Some(from) = from.builtin_deref(true) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 1844b97887a..9b9b0b705bf 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -494,8 +494,16 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } // Transfer the conditions on the copy rhs, after inversing polarity. Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { + if !place.ty(self.body, self.tcx).ty.is_bool() { + // Constructing the conditions by inverting the polarity + // of equality is only correct for bools. That is to say, + // `!a == b` is not `a != b` for integers greater than 1 bit. + return; + } let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; let Some(place) = self.map.find(place.as_ref()) else { return }; + // FIXME: I think This could be generalized to not bool if we + // actually perform a logical not on the condition's value. let conds = conditions.map(self.arena, Condition::inv); state.insert_value_idx(place, conds, &self.map); } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index ccc029b1e28..8f490094d60 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -600,13 +600,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } Len(place) => { - let len = match self.get_const(place)? { - Value::Immediate(src) => src.len(&self.ecx).discard_err()?, - Value::Aggregate { fields, .. } => fields.len() as u64, - Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() { - ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, - _ => return None, - }, + let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind() + { + n.try_eval_target_usize(self.tcx, self.param_env)? + } else { + match self.get_const(place)? { + Value::Immediate(src) => src.len(&self.ecx).discard_err()?, + Value::Aggregate { fields, .. } => fields.len() as u64, + Value::Uninit => return None, + } }; ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into() } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4c090665992..d184328748f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -51,6 +51,7 @@ mod add_subtyping_projections; mod check_alignment; mod check_const_item_mutation; mod check_packed_ref; +mod check_undefined_transmutes; // This pass is public to allow external drivers to perform MIR cleanup pub mod cleanup_post_borrowck; mod copy_prop; @@ -298,6 +299,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), + &Lint(check_undefined_transmutes::CheckUndefinedTransmutes), // What we need to do constant evaluation. &simplify::SimplifyCfg::Initial, &Lint(sanity_check::SanityCheck), diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 05b3859e554..b4d084d4dff 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -119,7 +119,7 @@ //! //! #### Unsizing Casts //! A subtle way of introducing use edges is by casting to a trait object. -//! Since the resulting fat-pointer contains a reference to a vtable, we need to +//! Since the resulting wide-pointer contains a reference to a vtable, we need to //! instantiate all dyn-compatible methods of the trait, as we need to store //! pointers to these functions even if they never get called anywhere. This can //! be seen as a special case of taking a function reference. @@ -661,7 +661,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let span = self.body.source_info(location).span; match *rvalue { - // When doing an cast from a regular pointer to a fat pointer, we + // When doing an cast from a regular pointer to a wide pointer, we // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast( @@ -985,7 +985,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) - /// ``` /// /// Then the output of this function would be (SomeStruct, SomeTrait) since for -/// constructing the `target` fat-pointer we need the vtable for that pair. +/// constructing the `target` wide-pointer we need the vtable for that pair. /// /// Things can get more complicated though because there's also the case where /// the unsized type occurs as a field: @@ -999,7 +999,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) - /// ``` /// /// In this case, if `T` is sized, `&ComplexStruct<T>` is a thin pointer. If `T` -/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is +/// is unsized, `&SomeStruct` is a wide pointer, and the vtable it points to is /// for the pair of `T` (which is a trait) and the concrete type that `T` was /// originally coerced from: /// diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index ca140500e2c..de74ac32804 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -12,6 +12,5 @@ pub mod canonicalizer; pub mod coherence; pub mod delegate; -pub mod relate; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/relate.rs b/compiler/rustc_next_trait_solver/src/relate.rs deleted file mode 100644 index db819961bbd..00000000000 --- a/compiler/rustc_next_trait_solver/src/relate.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub use rustc_type_ir::relate::*; - -pub mod combine; - -/// Whether aliases should be related structurally or not. Used -/// to adjust the behavior of generalization and combine. -/// -/// This should always be `No` unless in a few special-cases when -/// instantiating canonical responses and in the new solver. Each -/// such case should have a comment explaining why it is used. -#[derive(Debug, Copy, Clone)] -pub enum StructurallyRelateAliases { - Yes, - No, -} diff --git a/compiler/rustc_next_trait_solver/src/relate/combine.rs b/compiler/rustc_next_trait_solver/src/relate/combine.rs deleted file mode 100644 index 96968327d8e..00000000000 --- a/compiler/rustc_next_trait_solver/src/relate/combine.rs +++ /dev/null @@ -1,34 +0,0 @@ -pub use rustc_type_ir::relate::*; -use rustc_type_ir::solve::Goal; -use rustc_type_ir::{InferCtxtLike, Interner, Upcast}; - -use super::StructurallyRelateAliases; - -pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>: - TypeRelation<I> -where - Infcx: InferCtxtLike<Interner = I>, - I: Interner, -{ - fn span(&self) -> I::Span; - - fn param_env(&self) -> I::ParamEnv; - - /// Whether aliases should be related structurally. This is pretty much - /// always `No` unless you're equating in some specific locations of the - /// new solver. See the comments in these use-cases for more details. - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; - - /// Register obligations that must hold in order for this relation to hold - fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>); - - /// Register predicates that must hold in order for this relation to hold. - /// This uses the default `param_env` of the obligation. - fn register_predicates( - &mut self, - obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>, - ); - - /// Register `AliasRelate` obligation(s) that both types must be related to each other. - fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty); -} diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 252a9ed1a2e..fdefec33eeb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -14,6 +14,7 @@ use std::iter; use rustc_index::IndexVec; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::inherent::*; +use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner}; use tracing::{instrument, trace}; @@ -443,7 +444,6 @@ where for &arg in &state.value.var_values.var_values.as_slice() [orig_values.len()..state.value.var_values.len()] { - // FIXME: This is so ugly. let unconstrained = delegate.fresh_var_for_kind_with_span(arg, span); orig_values.push(unconstrained); } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index ffa800348f2..daacc669118 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -4,9 +4,11 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack}; +use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; +use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; @@ -17,8 +19,8 @@ use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ - CanonicalInput, CanonicalResponse, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, - GoalSource, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, + CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource, + HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, SolverMode, }; @@ -91,7 +93,6 @@ where #[derive_where(Clone, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] -// FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate. struct NestedGoals<I: Interner> { /// These normalizes-to goals are treated specially during the evaluation /// loop. In each iteration we take the RHS of the projection, replace it with @@ -126,11 +127,31 @@ pub enum GenerateProofTree { } pub trait SolverDelegateEvalExt: SolverDelegate { + /// Evaluates a goal from **outside** of the trait solver. + /// + /// Using this while inside of the solver is wrong as it uses a new + /// search graph which would break cycle detection. fn evaluate_root_goal( &self, goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<Self::Interner>>); + ) -> ( + Result<(HasChanged, Certainty), NoSolution>, + Option<inspect::GoalEvaluation<Self::Interner>>, + ); + + /// Check whether evaluating `goal` with a depth of `root_depth` may + /// succeed. This only returns `false` if the goal is guaranteed to + /// not hold. In case evaluation overflows and fails with ambiguity this + /// returns `true`. + /// + /// This is only intended to be used as a performance optimization + /// in coherence checking. + fn root_goal_may_hold_with_depth( + &self, + root_depth: usize, + goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, + ) -> bool; // FIXME: This is only exposed because we need to use it in `analyse.rs` // which is not yet uplifted. Once that's done, we should remove this. @@ -139,7 +160,7 @@ pub trait SolverDelegateEvalExt: SolverDelegate { goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, generate_proof_tree: GenerateProofTree, ) -> ( - Result<(NestedNormalizationGoals<Self::Interner>, bool, Certainty), NoSolution>, + Result<(NestedNormalizationGoals<Self::Interner>, HasChanged, Certainty), NoSolution>, Option<inspect::GoalEvaluation<Self::Interner>>, ); } @@ -149,31 +170,41 @@ where D: SolverDelegate<Interner = I>, I: Interner, { - /// Evaluates a goal from **outside** of the trait solver. - /// - /// Using this while inside of the solver is wrong as it uses a new - /// search graph which would break cycle detection. #[instrument(level = "debug", skip(self))] fn evaluate_root_goal( &self, goal: Goal<I, I::Predicate>, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) { - EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + ) -> (Result<(HasChanged, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) { + EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, |ecx| { ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) } + fn root_goal_may_hold_with_depth( + &self, + root_depth: usize, + goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, + ) -> bool { + self.probe(|| { + EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, |ecx| { + ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) + }) + .0 + }) + .is_ok() + } + #[instrument(level = "debug", skip(self))] fn evaluate_root_goal_raw( &self, goal: Goal<I, I::Predicate>, generate_proof_tree: GenerateProofTree, ) -> ( - Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution>, + Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>, ) { - EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, |ecx| { ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) } @@ -197,10 +228,11 @@ where /// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]). pub(super) fn enter_root<R>( delegate: &D, + root_depth: usize, generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option<inspect::GoalEvaluation<I>>) { - let mut search_graph = SearchGraph::new(delegate.solver_mode()); + let mut search_graph = SearchGraph::new(delegate.solver_mode(), root_depth); let mut ecx = EvalCtxt { delegate, @@ -339,7 +371,7 @@ where goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, goal: Goal<I, I::Predicate>, - ) -> Result<(bool, Certainty), NoSolution> { + ) -> Result<(HasChanged, Certainty), NoSolution> { let (normalization_nested_goals, has_changed, certainty) = self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?; assert!(normalization_nested_goals.is_empty()); @@ -360,7 +392,7 @@ where goal_evaluation_kind: GoalEvaluationKind, _source: GoalSource, goal: Goal<I, I::Predicate>, - ) -> Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution> { + ) -> Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -378,12 +410,18 @@ where Ok(response) => response, }; - let has_changed = !response.value.var_values.is_identity_modulo_regions() - || !response.value.external_constraints.opaque_types.is_empty(); + let has_changed = if !response.value.var_values.is_identity_modulo_regions() + || !response.value.external_constraints.opaque_types.is_empty() + { + HasChanged::Yes + } else { + HasChanged::No + }; let (normalization_nested_goals, certainty) = self.instantiate_and_apply_query_response(goal.param_env, orig_values, response); self.inspect.goal_evaluation(goal_evaluation); + // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. // @@ -552,7 +590,7 @@ where for (source, goal) in goals.goals { let (has_changed, certainty) = self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?; - if has_changed { + if has_changed == HasChanged::Yes { unchanged_certainty = None; } @@ -835,7 +873,7 @@ where lhs: T, rhs: T, ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> { - self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs) + Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs)?) } pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>( @@ -950,40 +988,22 @@ where // Do something for each opaque/hidden pair defined with `def_id` in the // current inference context. - pub(super) fn unify_existing_opaque_tys( + pub(super) fn probe_existing_opaque_ty( &mut self, - param_env: I::ParamEnv, key: ty::OpaqueTypeKey<I>, - ty: I::Ty, - ) -> Vec<CanonicalResponse<I>> { - // FIXME: Super inefficient to be cloning this... - let opaques = self.delegate.clone_opaque_types_for_query_response(); - - let mut values = vec![]; - for (candidate_key, candidate_ty) in opaques { - if candidate_key.def_id != key.def_id { - continue; - } - values.extend( - self.probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup { - result: *result, - }) - .enter(|ecx| { - for (a, b) in std::iter::zip(candidate_key.args.iter(), key.args.iter()) { - ecx.eq(param_env, a, b)?; - } - ecx.eq(param_env, candidate_ty, ty)?; - ecx.add_item_bounds_for_hidden_type( - candidate_key.def_id.into(), - candidate_key.args, - param_env, - candidate_ty, - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }), + ) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> { + let mut matching = + self.delegate.clone_opaque_types_for_query_response().into_iter().filter( + |(candidate_key, _)| { + candidate_key.def_id == key.def_id + && DeepRejectCtxt::relate_rigid_rigid(self.cx()) + .args_may_unify(candidate_key.args, key.args) + }, ); - } - values + let first = matching.next(); + let second = matching.next(); + assert_eq!(second, None); + first } // Try to evaluate a const, or return `None` if the const is too generic. diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 309ab7f28d1..8fe39bb4ee1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -10,9 +10,6 @@ //! //! For a high-level overview of how this solver works, check out the relevant //! section of the rustc-dev-guide. -//! -//! FIXME(@lcnr): Write that section. If you read this before then ask me -//! about it on zulip. mod alias_relate; mod assembly; @@ -48,6 +45,14 @@ enum GoalEvaluationKind { Nested, } +/// Whether evaluating this goal ended up changing the +/// inference state. +#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] +pub enum HasChanged { + Yes, + No, +} + // FIXME(trait-system-refactor-initiative#117): we don't detect whether a response // ended up pulling down any universes. fn has_no_inference_or_external_constraints<I: Interner>( diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index fc9c634942b..005b293621a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -899,7 +899,7 @@ where for ty in types.iter() { // We can't find the intersection if the types used are generic. // - // FIXME(effects) do we want to look at where clauses to get some + // FIXME(effects): do we want to look at where clauses to get some // clue for the case where generic types are being used? let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else { return Err(NoSolution); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 6a0703c5313..f8d51f304f3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -7,7 +7,9 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::{self as ty, Interner}; use crate::delegate::SolverDelegate; -use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode}; +use crate::solve::{ + Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode, inspect, +}; impl<D, I> EvalCtxt<'_, D> where @@ -52,14 +54,28 @@ where // // If that fails, we insert `expected` as a new hidden type instead of // eagerly emitting an error. - let matches = - self.unify_existing_opaque_tys(goal.param_env, opaque_type_key, expected); - if !matches.is_empty() { - if let Some(response) = self.try_merge_responses(&matches) { - return Ok(response); - } else { - return self.flounder(&matches); - } + let existing = self.probe_existing_opaque_ty(opaque_type_key); + if let Some((candidate_key, candidate_ty)) = existing { + return self + .probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup { + result: *result, + }) + .enter(|ecx| { + for (a, b) in std::iter::zip( + candidate_key.args.iter(), + opaque_type_key.args.iter(), + ) { + ecx.eq(goal.param_env, a, b)?; + } + ecx.eq(goal.param_env, candidate_ty, expected)?; + ecx.add_item_bounds_for_hidden_type( + candidate_key.def_id.into(), + candidate_key.args, + goal.param_env, + candidate_ty, + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }); } // Otherwise, define a new opaque type diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index e47cc03f5ad..0e3f179b0c8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -40,9 +40,6 @@ where } const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize = 4; - fn recursion_limit(cx: I) -> usize { - cx.recursion_limit() - } fn initial_provisional_result( cx: I, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 2074bdec485..5828b2ecf34 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -108,7 +108,6 @@ where ecx: &mut EvalCtxt<'_, D>, _guar: I::ErrorGuaranteed, ) -> Result<Candidate<I>, NoSolution> { - // FIXME: don't need to enter a probe here. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } @@ -463,7 +462,6 @@ where // Async coroutine unconditionally implement `Future` // Technically, we need to check that the future output type is Sized, // but that's already proven by the coroutine being WF. - // FIXME: use `consider_implied` ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } @@ -489,7 +487,6 @@ where // Gen coroutines unconditionally implement `Iterator` // Technically, we need to check that the iterator output type is Sized, // but that's already proven by the coroutines being WF. - // FIXME: use `consider_implied` ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } @@ -512,8 +509,7 @@ where return Err(NoSolution); } - // Gen coroutines unconditionally implement `FusedIterator` - // FIXME: use `consider_implied` + // Gen coroutines unconditionally implement `FusedIterator`. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } @@ -539,7 +535,6 @@ where // Gen coroutines unconditionally implement `Iterator` // Technically, we need to check that the iterator output type is Sized, // but that's already proven by the coroutines being WF. - // FIXME: use `consider_implied` ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } @@ -610,7 +605,7 @@ where return Err(NoSolution); } - // FIXME(-Znext-solver): Implement this when we get const working in the new solver + // FIXME(effects): Implement this when we get const working in the new solver // `Destruct` is automatically implemented for every type in // non-const environments. @@ -631,8 +626,6 @@ where return Err(NoSolution); } - // FIXME: This actually should destructure the `Result` we get from transmutability and - // register candidates. We probably need to register >1 since we may have an OR of ANDs. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let certainty = ecx.is_transmutable( goal.param_env, diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index c59ae48a07d..2360914a0ab 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -20,7 +20,7 @@ rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" tracing = "0.1" unicode-normalization = "0.1.11" -unicode-width = "0.1.4" +unicode-width = "0.2.0" # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 5d1c300b453..1af7fb9b86a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -422,6 +422,9 @@ parse_invalid_meta_item = expected unsuffixed literal, found `{$token}` parse_invalid_offset_of = offset_of expects dot-separated field and variant names +parse_invalid_path_sep_in_fn_definition = invalid path separator in function definition + .suggestion = remove invalid path separator + parse_invalid_unicode_escape = invalid unicode character escape .label = invalid escape .help = unicode escape must {$surrogate -> @@ -706,6 +709,10 @@ parse_require_colon_after_labeled_expression = labeled expression must be follow .label = the label .suggestion = add `:` after the label +parse_reserved_string = invalid string literal + .note = unprefixed guarded string literals are reserved for future use since Rust 2024 + .suggestion_whitespace = consider inserting whitespace here + parse_return_types_use_thin_arrow = return types are denoted using `->` .suggestion = use `->` instead @@ -812,7 +819,8 @@ parse_unexpected_expr_in_pat = *[false] a pattern }, found an expression - .label = arbitrary expressions are not allowed in patterns + .label = not a pattern + .note = arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> parse_unexpected_expr_in_pat_const_sugg = consider extracting the expression into a `const` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 40502158469..fdd500e90f8 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1756,6 +1756,14 @@ pub(crate) struct MissingFnParams { } #[derive(Diagnostic)] +#[diag(parse_invalid_path_sep_in_fn_definition)] +pub(crate) struct InvalidPathSepInFnDefinition { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_missing_trait_in_trait_impl)] pub(crate) struct MissingTraitInTraitImpl { #[primary_span] @@ -2111,6 +2119,24 @@ pub(crate) enum UnknownPrefixSugg { } #[derive(Diagnostic)] +#[diag(parse_reserved_string)] +#[note] +pub(crate) struct ReservedString { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: Option<GuardedStringSugg>, +} +#[derive(Subdiagnostic)] +#[suggestion( + parse_suggestion_whitespace, + code = " ", + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct GuardedStringSugg(#[primary_span] pub Span); + +#[derive(Diagnostic)] #[diag(parse_too_many_hashes)] pub(crate) struct TooManyHashes { #[primary_span] @@ -2608,6 +2634,7 @@ pub(crate) struct ExpectedCommaAfterPatternField { #[derive(Diagnostic)] #[diag(parse_unexpected_expr_in_pat)] +#[note] pub(crate) struct UnexpectedExpressionInPattern { /// The unexpected expr's span. #[primary_span] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 3e46fc93fa4..d627ef3d2cb 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -10,7 +10,8 @@ use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ - RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, + RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, + TEXT_DIRECTION_CODEPOINT_IN_COMMENT, }; use rustc_session::parse::ParseSess; use rustc_span::symbol::Symbol; @@ -251,6 +252,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let prefix_span = self.mk_sp(start, lit_start); return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace); } + rustc_lexer::TokenKind::GuardedStrPrefix => self.maybe_report_guarded_str(start, str_before), rustc_lexer::TokenKind::Literal { kind, suffix_start } => { let suffix_start = start + BytePos(suffix_start); let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind); @@ -781,6 +783,86 @@ impl<'psess, 'src> StringReader<'psess, 'src> { } } + /// Detect guarded string literal syntax + /// + /// RFC 3598 reserved this syntax for future use. As of Rust 2024, + /// using this syntax produces an error. In earlier editions, however, it + /// only results in an (allowed by default) lint, and is treated as + /// separate tokens. + fn maybe_report_guarded_str(&mut self, start: BytePos, str_before: &'src str) -> TokenKind { + let span = self.mk_sp(start, self.pos); + let edition2024 = span.edition().at_least_rust_2024(); + + let space_pos = start + BytePos(1); + let space_span = self.mk_sp(space_pos, space_pos); + + let mut cursor = Cursor::new(str_before); + + let (span, unterminated) = match cursor.guarded_double_quoted_string() { + Some(rustc_lexer::GuardedStr { n_hashes, terminated, token_len }) => { + let end = start + BytePos(token_len); + let span = self.mk_sp(start, end); + let str_start = start + BytePos(n_hashes); + + if edition2024 { + self.cursor = cursor; + self.pos = end; + } + + let unterminated = if terminated { None } else { Some(str_start) }; + + (span, unterminated) + } + _ => { + // We should only get here in the `##+` case. + debug_assert_eq!(self.str_from_to(start, start + BytePos(2)), "##"); + + (span, None) + } + }; + if edition2024 { + if let Some(str_start) = unterminated { + // Only a fatal error if string is unterminated. + self.dcx() + .struct_span_fatal( + self.mk_sp(str_start, self.pos), + "unterminated double quote string", + ) + .with_code(E0765) + .emit() + } + + let sugg = if span.from_expansion() { + None + } else { + Some(errors::GuardedStringSugg(space_span)) + }; + + // In Edition 2024 and later, emit a hard error. + let err = self.dcx().emit_err(errors::ReservedString { span, sugg }); + + token::Literal(token::Lit { + kind: token::Err(err), + symbol: self.symbol_from_to(start, self.pos), + suffix: None, + }) + } else { + // Before Rust 2024, only emit a lint for migration. + self.psess.buffer_lint( + RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, + span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::ReservedString(space_span), + ); + + // For backwards compatibility, roll back to after just the first `#` + // and return the `Pound` token. + self.pos = start + BytePos(1); + self.cursor = Cursor::new(&str_before[1..]); + token::Pound + } + } + fn report_too_many_hashes(&self, start: BytePos, num: u32) -> ! { self.dcx().emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num }); } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f7a8b8780ed..2792050a0b3 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -18,7 +18,7 @@ use std::path::Path; use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrItem, Attribute, MetaItem, token}; +use rustc_ast::{AttrItem, Attribute, MetaItemInner, token}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, FatalError, PResult}; @@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok pub fn parse_cfg_attr( cfg_attr: &Attribute, psess: &ParseSess, -) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { +) -> Option<(MetaItemInner, Vec<(AttrItem, Span)>)> { const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>"; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index c65cf3f40f6..b6fa2099588 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -356,8 +356,10 @@ impl<'a> Parser<'a> { } /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. - pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { - let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?; + pub fn parse_cfg_attr( + &mut self, + ) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> { + let cfg_predicate = self.parse_meta_item_inner()?; self.expect(&token::Comma)?; // Presumably, the majority of the time there will only be one attr. @@ -375,7 +377,7 @@ impl<'a> Parser<'a> { } /// Matches `COMMASEP(meta_item_inner)`. - pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::NestedMetaItem>> { + pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::MetaItemInner>> { // Presumably, the majority of the time there will only be one attr. let mut nmis = ThinVec::with_capacity(1); while self.token != token::Eof { @@ -452,14 +454,14 @@ impl<'a> Parser<'a> { /// ```ebnf /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ; /// ``` - fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { + pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::MetaItemInner> { match self.parse_unsuffixed_meta_item_lit() { - Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)), + Ok(lit) => return Ok(ast::MetaItemInner::Lit(lit)), Err(err) => err.cancel(), // we provide a better error below } match self.parse_meta_item(AllowLeadingUnsafe::No) { - Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), + Ok(mi) => return Ok(ast::MetaItemInner::MetaItem(mi)), Err(err) => err.cancel(), // we provide a better error below } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index b9256daa725..5aebe716b0a 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -269,6 +269,13 @@ impl<'a> Parser<'a> { /// | ( < lifetimes , typaramseq ( , )? > ) /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { + // invalid path separator `::` in function definition + // for example `fn invalid_path_separator::<T>() {}` + if self.eat_noexpect(&token::PathSep) { + self.dcx() + .emit_err(errors::InvalidPathSepInFnDefinition { span: self.prev_token.span }); + } + let span_lo = self.token.span; let (params, span) = if self.eat_lt() { let params = self.parse_generic_params()?; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9fc82d84225..36733726564 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1984,7 +1984,7 @@ impl<'a> Parser<'a> { } } self.expect_field_ty_separator()?; - let ty = self.parse_ty_for_field_def()?; + let ty = self.parse_ty()?; if self.token == token::Colon && self.look_ahead(1, |t| *t != token::Colon) { self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span }); } @@ -2009,9 +2009,7 @@ impl<'a> Parser<'a> { /// for better diagnostics and suggestions. fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { let (ident, is_raw) = self.ident_or_err(true)?; - if ident.name == kw::Underscore { - self.psess.gated_spans.gate(sym::unnamed_fields, lo); - } else if matches!(is_raw, IdentIsRaw::No) && ident.is_reserved() { + if matches!(is_raw, IdentIsRaw::No) && ident.is_reserved() { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { let inherited_vis = diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a8ed8b5df9c..625a4cabdf2 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -128,17 +128,6 @@ impl<'a> Parser<'a> { ) } - /// Parse a type suitable for a field definition. - /// The difference from `parse_ty` is that this version - /// allows anonymous structs and unions. - pub(super) fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> { - if self.can_begin_anon_struct_or_union() { - self.parse_anon_struct_or_union() - } else { - self.parse_ty() - } - } - /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the type. @@ -382,37 +371,6 @@ impl<'a> Parser<'a> { if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } } - /// Parse an anonymous struct or union (only for field definitions): - /// ```ignore (feature-not-ready) - /// #[repr(C)] - /// struct Foo { - /// _: struct { // anonymous struct - /// x: u32, - /// y: f64, - /// } - /// _: union { // anonymous union - /// z: u32, - /// w: f64, - /// } - /// } - /// ``` - fn parse_anon_struct_or_union(&mut self) -> PResult<'a, P<Ty>> { - assert!(self.token.is_keyword(kw::Union) || self.token.is_keyword(kw::Struct)); - let is_union = self.token.is_keyword(kw::Union); - - let lo = self.token.span; - self.bump(); - - let (fields, _recovered) = - self.parse_record_struct_body(if is_union { "union" } else { "struct" }, lo, false)?; - let span = lo.to(self.prev_token.span); - self.psess.gated_spans.gate(sym::unnamed_fields, span); - let id = ast::DUMMY_NODE_ID; - let kind = - if is_union { TyKind::AnonUnion(id, fields) } else { TyKind::AnonStruct(id, fields) }; - Ok(self.mk_ty(span, kind)) - } - /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. @@ -813,11 +771,6 @@ impl<'a> Parser<'a> { Ok(bounds) } - pub(super) fn can_begin_anon_struct_or_union(&mut self) -> bool { - (self.token.is_keyword(kw::Struct) || self.token.is_keyword(kw::Union)) - && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)) - } - /// Can the current token begin a bound? fn can_begin_bound(&mut self) -> bool { self.check_path() diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index b15d1edf79c..f3174e7dea2 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -3,8 +3,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ - self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, MetaItemKind, - NestedMetaItem, Safety, + self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, + Safety, }; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -143,7 +143,7 @@ pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim /// Checks that the given meta-item is compatible with this `AttributeTemplate`. fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool { - let is_one_allowed_subword = |items: &[NestedMetaItem]| match items { + let is_one_allowed_subword = |items: &[MetaItemInner]| match items { [item] => item.is_word() && template.one_of.iter().any(|&word| item.has_name(word)), _ => false, }; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 5369f54afb9..c11c3850034 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -391,7 +391,7 @@ passes_lang_item_fn_with_target_feature = passes_lang_item_fn_with_track_caller = {passes_lang_item_fn} is not allowed to have `#[track_caller]` - .label = {passes_lang_item_fn} is not allowed to have `#[target_feature]` + .label = {passes_lang_item_fn} is not allowed to have `#[track_caller]` passes_lang_item_on_incorrect_target = `{$name}` lang item must be applied to a {$expected_target} @@ -488,24 +488,18 @@ passes_naked_asm_outside_naked_fn = the `naked_asm!` macro can only be used in functions marked with `#[naked]` passes_naked_functions_asm_block = - naked functions must contain a single asm block - .label_multiple_asm = multiple asm blocks are unsupported in naked functions - .label_non_asm = non-asm is unsupported in naked functions - -passes_naked_functions_asm_options = - asm options unsupported in naked functions: {$unsupported_options} + naked functions must contain a single `naked_asm!` invocation + .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions + .label_non_asm = not allowed in naked functions passes_naked_functions_incompatible_attribute = attribute incompatible with `#[naked]` .label = the `{$attr}` attribute is incompatible with `#[naked]` .naked_attribute = function marked with `#[naked]` here -passes_naked_functions_must_use_noreturn = - asm in naked functions must use `noreturn` option - .suggestion = consider specifying that the asm block is responsible for returning from the function - -passes_naked_functions_operands = - only `const` and `sym` operands are supported in naked functions +passes_naked_functions_must_naked_asm = + the `asm!` macro is not allowed in naked functions + .label = consider using the `naked_asm!` macro instead passes_no_link = attribute should be applied to an `extern crate` item @@ -745,6 +739,12 @@ passes_unrecognized_repr_hint = unrecognized representation hint .help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` +passes_unstable_attr_for_already_stable_feature = + can't mark as unstable using an already stable feature + .label = this feature is already stable + .item = the stability attribute annotates this item + .help = consider removing the attribute + passes_unused = unused attribute .suggestion = remove this attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a24259a1e35..44a62383e6e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,7 +8,7 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use rustc_ast::{ - AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem, ast, + AttrKind, AttrStyle, Attribute, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -742,13 +742,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) { + fn doc_attr_str_error(&self, meta: &MetaItemInner, attr_name: &str) { self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name }); } fn check_doc_alias_value( &self, - meta: &NestedMetaItem, + meta: &MetaItemInner, doc_alias: Symbol, hir_id: HirId, target: Target, @@ -814,7 +814,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Mod | Target::GlobalAsm | Target::TyAlias - | Target::OpaqueTy | Target::Enum | Target::Variant | Target::Struct @@ -851,7 +850,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_alias( &self, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, target: Target, aliases: &mut FxHashMap<String, Span>, @@ -883,7 +882,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) { + fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) { let doc_keyword = meta.value_str().unwrap_or(kw::Empty); if doc_keyword == kw::Empty { self.doc_attr_str_error(meta, "keyword"); @@ -913,7 +912,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) { + fn check_doc_fake_variadic(&self, meta: &MetaItemInner, hir_id: HirId) { let item_kind = match self.tcx.hir_node(hir_id) { hir::Node::Item(item) => Some(&item.kind), _ => None, @@ -958,7 +957,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_inline( &self, attr: &Attribute, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, target: Target, specified_inline: &mut Option<(bool, Span)>, @@ -998,7 +997,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_masked( &self, attr: &Attribute, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, target: Target, ) { @@ -1033,7 +1032,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. fn check_attr_not_crate_level( &self, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, attr_name: &str, ) -> bool { @@ -1048,7 +1047,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_attr_crate_level( &self, attr: &Attribute, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, ) -> bool { if hir_id != CRATE_HIR_ID { @@ -1072,7 +1071,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if /// valid. - fn check_test_attr(&self, meta: &NestedMetaItem, hir_id: HirId) { + fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name_or_empty(), i_meta.meta_item()) { @@ -1109,7 +1108,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes. /// - fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) { + fn check_doc_cfg_hide(&self, meta: &MetaItemInner, hir_id: HirId) { if meta.meta_item_list().is_none() { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1328,7 +1327,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) { let article = match target { Target::ExternCrate - | Target::OpaqueTy | Target::Enum | Target::Impl | Target::Expression @@ -1501,8 +1499,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; }; - if !matches!(&list[..], &[NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) - { + if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) { self.tcx .dcx() .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span }); @@ -2075,7 +2072,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut candidates = Vec::new(); for meta in metas { - let NestedMetaItem::Lit(meta_lit) = meta else { + let MetaItemInner::Lit(meta_lit) = meta else { self.dcx().emit_err(errors::IncorrectMetaItem { span: meta.span(), suggestion: errors::IncorrectMetaItemSuggestion { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 100f3e80603..af17fbf7e4d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -41,6 +41,7 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { | Node::TraitItem(..) | Node::Variant(..) | Node::AnonConst(..) + | Node::OpaqueTy(..) ) } @@ -494,6 +495,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { Node::ForeignItem(foreign_item) => { intravisit::walk_foreign_item(self, foreign_item); } + Node::OpaqueTy(opaq) => intravisit::walk_opaque_ty(self, opaq), _ => {} } self.repr_has_repr_simd = had_repr_simd; @@ -655,14 +657,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { intravisit::walk_path(self, path); } - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let TyKind::OpaqueDef(item_id, _) = ty.kind { - let item = self.tcx.hir().item(item_id); - intravisit::walk_item(self, item); - } - intravisit::walk_ty(self, ty); - } - fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { // When inline const blocks are used in pattern position, paths // referenced by it should be considered as used. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 29a087bf759..f9186d3089a 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1187,27 +1187,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock { } #[derive(Diagnostic)] -#[diag(passes_naked_functions_operands, code = E0787)] -pub(crate) struct NakedFunctionsOperands { - #[primary_span] - pub unsupported_operands: Vec<Span>, -} - -#[derive(Diagnostic)] -#[diag(passes_naked_functions_asm_options, code = E0787)] -pub(crate) struct NakedFunctionsAsmOptions { - #[primary_span] - pub span: Span, - pub unsupported_options: String, -} - -#[derive(Diagnostic)] -#[diag(passes_naked_functions_must_use_noreturn, code = E0787)] -pub(crate) struct NakedFunctionsMustUseNoreturn { +#[diag(passes_naked_functions_must_naked_asm, code = E0787)] +pub(crate) struct NakedFunctionsMustNakedAsm { #[primary_span] + #[label] pub span: Span, - #[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")] - pub last_span: Span, } #[derive(Diagnostic)] @@ -1497,6 +1481,17 @@ pub(crate) struct CannotStabilizeDeprecated { } #[derive(Diagnostic)] +#[diag(passes_unstable_attr_for_already_stable_feature)] +pub(crate) struct UnstableAttrForAlreadyStableFeature { + #[primary_span] + #[label] + #[help] + pub span: Span, + #[label(passes_item)] + pub item_sp: Span, +} + +#[derive(Diagnostic)] #[diag(passes_missing_stability_attr)] pub(crate) struct MissingStabilityAttr<'a> { #[primary_span] diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 903fb114744..b5dccf85041 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -230,7 +230,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { ForeignMod, GlobalAsm, TyAlias, - OpaqueTy, Enum, Struct, Union, @@ -583,8 +582,6 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { BareFn, Never, Tup, - AnonStruct, - AnonUnion, Path, Pat, TraitObject, diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 8d3f7e0231f..b2f8d7dadff 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,13 +1,13 @@ //! Checks validity of naked functions. -use rustc_ast::InlineAsmOptions; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, HirIdSet, InlineAsmOperand, StmtKind}; +use rustc_hir::{ExprKind, HirIdSet, StmtKind}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; use rustc_span::Span; @@ -15,9 +15,8 @@ use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use crate::errors::{ - NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, - NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, - UndefinedNakedFunctionAbi, + NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, + ParamsNotAllowed, UndefinedNakedFunctionAbi, }; pub(crate) fn provide(providers: &mut Providers) { @@ -119,23 +118,28 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { /// Checks that function body contains a single inline assembly block. fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { - let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; + let mut this = CheckInlineAssembly { items: Vec::new() }; this.visit_body(body); - if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] { + if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] { // Ok. } else { let mut must_show_error = false; - let mut has_asm = false; + let mut has_naked_asm = false; let mut has_err = false; let mut multiple_asms = vec![]; let mut non_asms = vec![]; for &(kind, span) in &this.items { match kind { - ItemKind::Asm if has_asm => { + ItemKind::NakedAsm if has_naked_asm => { must_show_error = true; multiple_asms.push(span); } - ItemKind::Asm => has_asm = true, + ItemKind::NakedAsm => has_naked_asm = true, + ItemKind::InlineAsm => { + has_err = true; + + tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span }); + } ItemKind::NonAsm => { must_show_error = true; non_asms.push(span); @@ -157,20 +161,20 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body< } } -struct CheckInlineAssembly<'tcx> { - tcx: TyCtxt<'tcx>, +struct CheckInlineAssembly { items: Vec<(ItemKind, Span)>, } #[derive(Copy, Clone)] enum ItemKind { - Asm, + NakedAsm, + InlineAsm, NonAsm, Err, } -impl<'tcx> CheckInlineAssembly<'tcx> { - fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { +impl CheckInlineAssembly { + fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { match expr.kind { ExprKind::ConstBlock(..) | ExprKind::Array(..) @@ -204,10 +208,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> { self.items.push((ItemKind::NonAsm, span)); } - ExprKind::InlineAsm(asm) => { - self.items.push((ItemKind::Asm, span)); - self.check_inline_asm(asm, span); - } + ExprKind::InlineAsm(asm) => match asm.asm_macro { + rustc_ast::AsmMacro::Asm => { + self.items.push((ItemKind::InlineAsm, span)); + } + rustc_ast::AsmMacro::NakedAsm => { + self.items.push((ItemKind::NakedAsm, span)); + } + rustc_ast::AsmMacro::GlobalAsm => { + span_bug!(span, "`global_asm!` is not allowed in this position") + } + }, ExprKind::DropTemps(..) | ExprKind::Block(..) => { hir::intravisit::walk_expr(self, expr); @@ -218,52 +229,9 @@ impl<'tcx> CheckInlineAssembly<'tcx> { } } } - - fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) { - let unsupported_operands: Vec<Span> = asm - .operands - .iter() - .filter_map(|&(ref op, op_sp)| match op { - InlineAsmOperand::Const { .. } - | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } => None, - InlineAsmOperand::In { .. } - | InlineAsmOperand::Out { .. } - | InlineAsmOperand::InOut { .. } - | InlineAsmOperand::SplitInOut { .. } - | InlineAsmOperand::Label { .. } => Some(op_sp), - }) - .collect(); - if !unsupported_operands.is_empty() { - self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands }); - } - - let unsupported_options = asm.options.difference(InlineAsmOptions::NAKED_OPTIONS); - if !unsupported_options.is_empty() { - self.tcx.dcx().emit_err(NakedFunctionsAsmOptions { - span, - unsupported_options: unsupported_options - .human_readable_names() - .into_iter() - .map(|name| format!("`{name}`")) - .collect::<Vec<_>>() - .join(", "), - }); - } - - if !asm.options.contains(InlineAsmOptions::NORETURN) { - let last_span = asm - .operands - .last() - .map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1) - .shrink_to_hi(); - - self.tcx.dcx().emit_err(NakedFunctionsMustUseNoreturn { span, last_span }); - } - } } -impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> { +impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { match stmt.kind { StmtKind::Item(..) => {} diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 925ee262022..056318fbcb7 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -236,7 +236,6 @@ impl<'tcx> ReachableContext<'tcx> { // worklist, as determined by the privacy pass hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) - | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::TyAlias(..) | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) @@ -287,7 +286,8 @@ impl<'tcx> ReachableContext<'tcx> { | Node::Field(_) | Node::Ty(_) | Node::Crate(_) - | Node::Synthetic => {} + | Node::Synthetic + | Node::OpaqueTy(..) => {} _ => { bug!( "found unexpected node kind in worklist: {} ({:?})", diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 46b67e930d5..751c87a9fe5 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -10,6 +10,7 @@ use rustc_attr::{ }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; +use rustc_feature::ACCEPTED_FEATURES; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; @@ -246,12 +247,27 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + if let Stability { level: Unstable { .. }, feature } = stab { + if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() { + self.tcx + .dcx() + .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); + } + } if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab { self.index.implications.insert(implied_by, feature); } + if let Some(ConstStability { level: Unstable { .. }, feature, .. }) = const_stab { + if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() { + self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { + span: const_span.unwrap(), // If const_stab contains Some(..), same is true for const_span + item_sp, + }); + } + } if let Some(ConstStability { level: Unstable { implied_by: Some(implied_by), .. }, feature, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d00e7eff752..f67c4cb922c 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -402,8 +402,6 @@ struct EmbargoVisitor<'tcx> { /// n::p::f() /// } macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>, - /// Preliminary pass for marking all underlying types of `impl Trait`s as reachable. - impl_trait_pass: bool, /// Has something changed in the level map? changed: bool, } @@ -635,48 +633,6 @@ impl<'tcx> EmbargoVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - if self.impl_trait_pass - && let hir::ItemKind::OpaqueTy(opaque) = item.kind - { - let should_visit = match opaque.origin { - hir::OpaqueTyOrigin::FnReturn { - parent, - in_trait_or_impl: Some(hir::RpitContext::Trait), - } - | hir::OpaqueTyOrigin::AsyncFn { - parent, - in_trait_or_impl: Some(hir::RpitContext::Trait), - } => match self.tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 { - hir::TraitFn::Required(_) => false, - hir::TraitFn::Provided(..) => true, - }, - - // Always visit RPITs in functions that have definitions, - // and all TAITs. - hir::OpaqueTyOrigin::FnReturn { - in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), - .. - } - | hir::OpaqueTyOrigin::AsyncFn { - in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), - .. - } - | hir::OpaqueTyOrigin::TyAlias { .. } => true, - }; - - if should_visit { - // FIXME: This is some serious pessimization intended to workaround deficiencies - // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time - // reachable if they are returned via `impl Trait`, even from private functions. - let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public); - self.reach_through_impl_trait(item.owner_id.def_id, pub_ev) - .generics() - .predicates() - .ty(); - return; - } - } - // Update levels of nested things and mark all items // in interfaces of reachable items as reachable. let item_ev = self.get(item.owner_id.def_id); @@ -686,7 +642,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { | hir::ItemKind::ExternCrate(..) | hir::ItemKind::GlobalAsm(..) => {} // The interface is empty, and all nested items are processed by `visit_item`. - hir::ItemKind::Mod(..) | hir::ItemKind::OpaqueTy(..) => {} + hir::ItemKind::Mod(..) => {} hir::ItemKind::Macro(macro_def, _) => { if let Some(item_ev) = item_ev { self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev); @@ -1752,19 +1708,59 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { tcx, effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(), macro_reachable: Default::default(), - // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and - // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't - // care about link-time reachability, keep them unreachable (issue #75100). - impl_trait_pass: !tcx.sess.opts.actually_rustdoc, changed: false, }; visitor.effective_visibilities.check_invariants(tcx); - if visitor.impl_trait_pass { + + // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and + // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't + // care about link-time reachability, keep them unreachable (issue #75100). + let impl_trait_pass = !tcx.sess.opts.actually_rustdoc; + if impl_trait_pass { // Underlying types of `impl Trait`s are marked as reachable unconditionally, // so this pass doesn't need to be a part of the fixed point iteration below. - tcx.hir().visit_all_item_likes_in_crate(&mut visitor); - visitor.impl_trait_pass = false; + let krate = tcx.hir_crate_items(()); + for id in krate.opaques() { + let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty(); + let should_visit = match opaque.origin { + hir::OpaqueTyOrigin::FnReturn { + parent, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } + | hir::OpaqueTyOrigin::AsyncFn { + parent, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 { + hir::TraitFn::Required(_) => false, + hir::TraitFn::Provided(..) => true, + }, + + // Always visit RPITs in functions that have definitions, + // and all TAITs. + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::TyAlias { .. } => true, + }; + if should_visit { + // FIXME: This is some serious pessimization intended to workaround deficiencies + // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time + // reachable if they are returned via `impl Trait`, even from private functions. + let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public); + visitor + .reach_through_impl_trait(opaque.def_id, pub_ev) + .generics() + .predicates() + .ty(); + } + } + visitor.changed = false; } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a9ea268e51a..0145ffd3a4b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -724,29 +724,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Record field names for error reporting. self.insert_field_idents(def_id, fields); self.insert_field_visibilities_local(def_id.to_def_id(), fields); - - for field in fields { - match &field.ty.kind { - ast::TyKind::AnonStruct(id, nested_fields) - | ast::TyKind::AnonUnion(id, nested_fields) => { - let feed = self.r.feed(*id); - let local_def_id = feed.key(); - let def_id = local_def_id.to_def_id(); - let def_kind = self.r.tcx.def_kind(local_def_id); - let res = Res::Def(def_kind, def_id); - self.build_reduced_graph_for_struct_variant( - &nested_fields, - Ident::empty(), - feed, - res, - // Anonymous adts inherit visibility from their parent adts. - adt_vis, - field.ty.span, - ); - } - _ => {} - } - } } /// Constructs the reduced graph for one item. @@ -1072,13 +1049,13 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { import_all = Some(meta.span); break; } - MetaItemKind::List(nested_metas) => { - for nested_meta in nested_metas { - match nested_meta.ident() { - Some(ident) if nested_meta.is_word() => { + MetaItemKind::List(meta_item_inners) => { + for meta_item_inner in meta_item_inners { + match meta_item_inner.ident() { + Some(ident) if meta_item_inner.is_word() => { single_imports.push(ident) } - _ => ill_formed(nested_meta.span()), + _ => ill_formed(meta_item_inner.span()), } } } @@ -1198,8 +1175,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = nested_meta.ident() { + if let Some(meta_item_inner) = + attr.meta_item_list().and_then(|list| list.get(0).cloned()) + { + if let Some(ident) = meta_item_inner.ident() { return Some((MacroKind::Derive, ident, ident.span)); } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 98662385434..0047f2c4b51 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -105,22 +105,6 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); let def = self.create_def(field.id, name, DefKind::Field, field.span); self.with_parent(def, |this| visit::walk_field_def(this, field)); - self.visit_anon_adt(&field.ty); - } - } - - fn visit_anon_adt(&mut self, ty: &'a Ty) { - let def_kind = match &ty.kind { - TyKind::AnonStruct(..) => DefKind::Struct, - TyKind::AnonUnion(..) => DefKind::Union, - _ => return, - }; - match &ty.kind { - TyKind::AnonStruct(node_id, _) | TyKind::AnonUnion(node_id, _) => { - let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span); - self.with_parent(def_id, |this| visit::walk_ty(this, ty)); - } - _ => {} } } @@ -476,8 +460,6 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { fn visit_ty(&mut self, ty: &'a Ty) { match &ty.kind { TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), - // Anonymous structs or unions are visited later after defined. - TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {} TyKind::ImplTrait(id, _) => { // HACK: pprust breaks strings with newlines when the type // gets too long. We don't want these to show up in compiler diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 582db97e1ce..5437ca65935 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2,8 +2,7 @@ use rustc_ast::expand::StrippedCfgItem; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ - self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemKind, ModKind, NestedMetaItem, NodeId, - Path, + self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -2541,7 +2540,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(note); if let MetaItemKind::List(nested) = &cfg.kind - && let NestedMetaItem::MetaItem(meta_item) = &nested[0] + && let MetaItemInner::MetaItem(meta_item) = &nested[0] && let MetaItemKind::NameValue(feature_name) = &meta_item.kind { let note = errors::ItemWasBehindFeature { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 35d166e8b4a..fce5ec36c66 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -443,6 +443,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.suggest_bare_struct_literal(&mut err); self.suggest_changing_type_to_const_param(&mut err, res, source, span); + self.explain_functions_in_pattern(&mut err, res, source); if self.suggest_pattern_match_with_let(&mut err, source, span) { // Fallback label. @@ -1166,6 +1167,18 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + fn explain_functions_in_pattern( + &mut self, + err: &mut Diag<'_>, + res: Option<Res>, + source: PathSource<'_>, + ) { + let PathSource::TupleStruct(_, _) = source else { return }; + let Some(Res::Def(DefKind::Fn, _)) = res else { return }; + err.primary_message("expected a pattern, found a function call"); + err.note("function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>"); + } + fn suggest_changing_type_to_const_param( &mut self, err: &mut Diag<'_>, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fcbbb523cfc..24a0c252e55 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2148,7 +2148,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), - PathResult::NonModule(path_res) => path_res.full_res(), + PathResult::NonModule(path_res) => { + path_res.full_res().filter(|res| !matches!(res, Res::Def(DefKind::Ctor(..), _))) + } PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => { None } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 21924437a4a..fa2be8216c7 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -129,8 +129,8 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) { - for nested_meta in attr.meta_item_list().unwrap_or_default() { - match nested_meta.ident() { + for meta_item_inner in attr.meta_item_list().unwrap_or_default() { + match meta_item_inner.ident() { Some(ident) => { if let Some(old_ident) = registered_tools.replace(ident) { tcx.dcx().emit_err(errors::ToolWasAlreadyRegistered { @@ -142,7 +142,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { } None => { tcx.dcx().emit_err(errors::ToolOnlyAcceptsIdentifiers { - span: nested_meta.span(), + span: meta_item_inner.span(), tool: sym::register_tool, }); } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index d1c1b6c882e..02e255d7726 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -6,7 +6,7 @@ use pulldown_cmark::{ }; use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::symbol::{Symbol, kw, sym}; @@ -235,8 +235,8 @@ fn span_for_value(attr: &ast::Attribute) -> Span { /// early and late doc link resolution regardless of their position. pub fn prepare_to_doc_link_resolution( doc_fragments: &[DocFragment], -) -> FxHashMap<Option<DefId>, String> { - let mut res = FxHashMap::default(); +) -> FxIndexMap<Option<DefId>, String> { + let mut res = FxIndexMap::default(); for fragment in doc_fragments { let out_str = res.entry(fragment.item_id).or_default(); add_doc_fragment(out_str, fragment); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 320d6616384..53834198f63 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -315,7 +315,7 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for /// Rust types that are not used at the FFI boundary. #[instrument(level = "trace", skip(tcx, dict))] -pub fn encode_ty<'tcx>( +pub(crate) fn encode_ty<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>, 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 5f7184a4240..83dcceeaa84 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 @@ -291,7 +291,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc /// the Fn trait that defines the method (for being attached as a secondary type id). /// #[instrument(level = "trace", skip(tcx))] -pub fn transform_instance<'tcx>( +pub(crate) fn transform_instance<'tcx>( tcx: TyCtxt<'tcx>, mut instance: Instance<'tcx>, options: TransformTyOptions, diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index b7977a848ce..47f72298e22 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -10,7 +10,6 @@ test(attr(allow(unused_variables), deny(warnings))) )] #![doc(rust_logo)] -#![feature(const_option)] #![feature(core_intrinsics)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index c7c561156e3..27e9f817894 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -437,10 +437,10 @@ impl IntEncodedWithFixedSize { impl Encodable<FileEncoder> for IntEncodedWithFixedSize { #[inline] fn encode(&self, e: &mut FileEncoder) { - let _start_pos = e.position(); + let start_pos = e.position(); e.write_array(self.0.to_le_bytes()); - let _end_pos = e.position(); - debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); + let end_pos = e.position(); + debug_assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); } } diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 2d37f5bdab8..bae5f259fcc 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -325,7 +325,7 @@ impl<D: Decoder, const N: usize> Decodable<D> for [u8; N] { } } -impl<'a, S: Encoder, T: Encodable<S>> Encodable<S> for Cow<'a, [T]> +impl<S: Encoder, T: Encodable<S>> Encodable<S> for Cow<'_, [T]> where [T]: ToOwned<Owned = Vec<T>>, { @@ -345,14 +345,14 @@ where } } -impl<'a, S: Encoder> Encodable<S> for Cow<'a, str> { +impl<S: Encoder> Encodable<S> for Cow<'_, str> { fn encode(&self, s: &mut S) { let val: &str = self; val.encode(s) } } -impl<'a, D: Decoder> Decodable<D> for Cow<'a, str> { +impl<D: Decoder> Decodable<D> for Cow<'_, str> { fn decode(d: &mut D) -> Cow<'static, str> { let v: String = Decodable::decode(d); Cow::Owned(v) diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 66ad70d8d18..041a10475ea 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -72,7 +72,7 @@ pub struct NativeLib { pub name: Symbol, /// If packed_bundled_libs enabled, actual filename of library is stored. pub filename: Option<Symbol>, - pub cfg: Option<ast::MetaItem>, + pub cfg: Option<ast::MetaItemInner>, pub foreign_module: Option<DefId>, pub verbatim: Option<bool>, pub dll_imports: Vec<DllImport>, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 9781c746520..3d44810e7dd 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -66,7 +66,7 @@ impl GatedSpans { #[derive(Default)] pub struct SymbolGallery { /// All symbols occurred and their first occurrence span. - pub symbols: Lock<FxHashMap<Symbol, Span>>, + pub symbols: Lock<FxIndexMap<Symbol, Span>>, } impl SymbolGallery { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index d67e69fe0fb..27879d817b2 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -454,6 +454,8 @@ impl Session { let bin_path = filesearch::make_target_bin_path(&self.sysroot, config::host_triple()); let fallback_sysroot_paths = filesearch::sysroot_candidates() .into_iter() + // Ignore sysroot candidate if it was the same as the sysroot path we just used. + .filter(|sysroot| *sysroot != self.sysroot) .map(|sysroot| filesearch::make_target_bin_path(&sysroot, config::host_triple())); let search_paths = std::iter::once(bin_path).chain(fallback_sysroot_paths); diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 37528a4425f..9182789cf02 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -137,7 +137,7 @@ pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> { let content = if arg.len() == a.len() { // A space-separated option, like `-C incremental=foo` or `--crate-type rlib` match args.next() { - Some(arg) => arg.to_string(), + Some(arg) => arg, None => continue, } } else if arg.get(a.len()..a.len() + 1) == Some("=") { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 0dbbc338e73..dbae4b7e719 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -655,6 +655,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { } } mir::TerminatorKind::InlineAsm { + asm_macro: _, template, operands, options, diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index c52d1fcc07f..781fe6a11fe 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -19,5 +19,5 @@ scoped-tls = "1.0" sha1 = "0.10.0" sha2 = "0.10.1" tracing = "0.1" -unicode-width = "0.1.4" +unicode-width = "0.2.0" # tidy-alphabetical-end diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b55465ddef7..5b1be5bca05 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1380,7 +1380,7 @@ pub enum ExternalSourceKind { } impl ExternalSource { - pub fn get_source(&self) -> Option<&Lrc<String>> { + pub fn get_source(&self) -> Option<&str> { match self { ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src), _ => None, diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 360baec273d..5b39706f3ad 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -257,7 +257,7 @@ fn t10() { ); imported_src_file.add_external_src(|| Some(unnormalized.to_string())); assert_eq!( - imported_src_file.external_src.borrow().get_source().unwrap().as_ref(), + imported_src_file.external_src.borrow().get_source().unwrap(), normalized, "imported source file should be normalized" ); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e8aa129c6cd..cc3bda99a11 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -544,6 +544,7 @@ symbols! { cfg_accessible, cfg_attr, cfg_attr_multi, + cfg_boolean_literals, cfg_doctest, cfg_eval, cfg_fmt_debug, @@ -776,6 +777,7 @@ symbols! { dropck_eyepatch, dropck_parametricity, dylib, + dyn_compatible_for_dispatch, dyn_metadata, dyn_star, dyn_trait, @@ -912,6 +914,10 @@ symbols! { fmt_debug, fmul_algebraic, fmul_fast, + fmuladdf128, + fmuladdf16, + fmuladdf32, + fmuladdf64, fn_align, fn_delegation, fn_must_use, @@ -1478,6 +1484,7 @@ symbols! { powif64, pre_dash_lto: "pre-lto", precise_capturing, + precise_capturing_in_traits, precise_pointer_size_matching, pref_align_of, prefetch_read_data, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index df13d24cb9e..73ae1ae96ae 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -893,6 +893,7 @@ pub enum InlineAsmClobberAbi { RiscV, LoongArch, S390x, + Msp430, } impl InlineAsmClobberAbi { @@ -946,6 +947,10 @@ impl InlineAsmClobberAbi { "C" | "system" => Ok(InlineAsmClobberAbi::S390x), _ => Err(&["C", "system"]), }, + InlineAsmArch::Msp430 => match name { + "C" | "system" => Ok(InlineAsmClobberAbi::Msp430), + _ => Err(&["C", "system"]), + }, _ => Err(&[]), } } @@ -1125,6 +1130,11 @@ impl InlineAsmClobberAbi { a8, a9, a10, a11, a12, a13, a14, a15, } }, + InlineAsmClobberAbi::Msp430 => clobbered_regs! { + Msp430 Msp430InlineAsmReg { + r11, r12, r13, r14, r15, + } + }, } } } diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs index 55b65fb1caa..55b65fb1caa 100644 --- a/compiler/rustc_target/src/abi/call/aarch64.rs +++ b/compiler/rustc_target/src/callconv/aarch64.rs diff --git a/compiler/rustc_target/src/abi/call/amdgpu.rs b/compiler/rustc_target/src/callconv/amdgpu.rs index 3007a729a8b..3007a729a8b 100644 --- a/compiler/rustc_target/src/abi/call/amdgpu.rs +++ b/compiler/rustc_target/src/callconv/amdgpu.rs diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index bd6f781fb81..bd6f781fb81 100644 --- a/compiler/rustc_target/src/abi/call/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs diff --git a/compiler/rustc_target/src/abi/call/avr.rs b/compiler/rustc_target/src/callconv/avr.rs index dfc991e0954..dfc991e0954 100644 --- a/compiler/rustc_target/src/abi/call/avr.rs +++ b/compiler/rustc_target/src/callconv/avr.rs diff --git a/compiler/rustc_target/src/abi/call/bpf.rs b/compiler/rustc_target/src/callconv/bpf.rs index f19772ac709..f19772ac709 100644 --- a/compiler/rustc_target/src/abi/call/bpf.rs +++ b/compiler/rustc_target/src/callconv/bpf.rs diff --git a/compiler/rustc_target/src/abi/call/csky.rs b/compiler/rustc_target/src/callconv/csky.rs index b1c1ae814a7..b1c1ae814a7 100644 --- a/compiler/rustc_target/src/abi/call/csky.rs +++ b/compiler/rustc_target/src/callconv/csky.rs diff --git a/compiler/rustc_target/src/abi/call/hexagon.rs b/compiler/rustc_target/src/callconv/hexagon.rs index 0a0688880c0..0a0688880c0 100644 --- a/compiler/rustc_target/src/abi/call/hexagon.rs +++ b/compiler/rustc_target/src/callconv/hexagon.rs diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 4a21935623b..4a21935623b 100644 --- a/compiler/rustc_target/src/abi/call/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs diff --git a/compiler/rustc_target/src/abi/call/m68k.rs b/compiler/rustc_target/src/callconv/m68k.rs index 82fe81f8c52..82fe81f8c52 100644 --- a/compiler/rustc_target/src/abi/call/m68k.rs +++ b/compiler/rustc_target/src/callconv/m68k.rs diff --git a/compiler/rustc_target/src/abi/call/mips.rs b/compiler/rustc_target/src/callconv/mips.rs index 37980a91c76..37980a91c76 100644 --- a/compiler/rustc_target/src/abi/call/mips.rs +++ b/compiler/rustc_target/src/callconv/mips.rs diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 2c3258c8d42..2c3258c8d42 100644 --- a/compiler/rustc_target/src/abi/call/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index f4469467249..832246495bc 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -1,10 +1,11 @@ use std::fmt; use std::str::FromStr; +pub use rustc_abi::{Reg, RegKind}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; -use crate::abi::{self, Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; +use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi}; mod aarch64; @@ -192,63 +193,6 @@ impl ArgAttributes { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum RegKind { - Integer, - Float, - Vector, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub struct Reg { - pub kind: RegKind, - pub size: Size, -} - -macro_rules! reg_ctor { - ($name:ident, $kind:ident, $bits:expr) => { - pub fn $name() -> Reg { - Reg { kind: RegKind::$kind, size: Size::from_bits($bits) } - } - }; -} - -impl Reg { - reg_ctor!(i8, Integer, 8); - reg_ctor!(i16, Integer, 16); - reg_ctor!(i32, Integer, 32); - reg_ctor!(i64, Integer, 64); - reg_ctor!(i128, Integer, 128); - - reg_ctor!(f32, Float, 32); - reg_ctor!(f64, Float, 64); -} - -impl Reg { - pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { - let dl = cx.data_layout(); - match self.kind { - RegKind::Integer => match self.size.bits() { - 1 => dl.i1_align.abi, - 2..=8 => dl.i8_align.abi, - 9..=16 => dl.i16_align.abi, - 17..=32 => dl.i32_align.abi, - 33..=64 => dl.i64_align.abi, - 65..=128 => dl.i128_align.abi, - _ => panic!("unsupported integer: {self:?}"), - }, - RegKind::Float => match self.size.bits() { - 16 => dl.f16_align.abi, - 32 => dl.f32_align.abi, - 64 => dl.f64_align.abi, - 128 => dl.f128_align.abi, - _ => panic!("unsupported float: {self:?}"), - }, - RegKind::Vector => dl.vector_align(self.size).abi, - } - } -} - /// An argument passed entirely registers with the /// same kind (e.g., HFA / HVA on PPC64 and AArch64). #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] @@ -380,195 +324,6 @@ impl CastTarget { } } -/// Return value from the `homogeneous_aggregate` test function. -#[derive(Copy, Clone, Debug)] -pub enum HomogeneousAggregate { - /// Yes, all the "leaf fields" of this struct are passed in the - /// same way (specified in the `Reg` value). - Homogeneous(Reg), - - /// There are no leaf fields at all. - NoData, -} - -/// Error from the `homogeneous_aggregate` test function, indicating -/// there are distinct leaf fields passed in different ways, -/// or this is uninhabited. -#[derive(Copy, Clone, Debug)] -pub struct Heterogeneous; - -impl HomogeneousAggregate { - /// If this is a homogeneous aggregate, returns the homogeneous - /// unit, else `None`. - pub fn unit(self) -> Option<Reg> { - match self { - HomogeneousAggregate::Homogeneous(reg) => Some(reg), - HomogeneousAggregate::NoData => None, - } - } - - /// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in - /// the same `struct`. Only succeeds if only one of them has any data, - /// or both units are identical. - fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> { - match (self, other) { - (x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x), - - (HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => { - if a != b { - return Err(Heterogeneous); - } - Ok(self) - } - } - } -} - -impl<'a, Ty> TyAndLayout<'a, Ty> { - /// Returns `true` if this is an aggregate type (including a ScalarPair!) - fn is_aggregate(&self) -> bool { - match self.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, - } - } - - /// Returns `Homogeneous` if this layout is an aggregate containing fields of - /// only a single type (e.g., `(u32, u32)`). Such aggregates are often - /// special-cased in ABIs. - /// - /// Note: We generally ignore 1-ZST fields when computing this value (see #56877). - /// - /// This is public so that it can be used in unit tests, but - /// should generally only be relevant to the ABI details of - /// specific targets. - pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous> - where - Ty: TyAbiInterface<'a, C> + Copy, - { - match self.abi { - Abi::Uninhabited => Err(Heterogeneous), - - // The primitive for this algorithm. - Abi::Scalar(scalar) => { - let kind = match scalar.primitive() { - abi::Int(..) | abi::Pointer(_) => RegKind::Integer, - abi::Float(_) => RegKind::Float, - }; - Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) - } - - Abi::Vector { .. } => { - assert!(!self.is_zst()); - Ok(HomogeneousAggregate::Homogeneous(Reg { - kind: RegKind::Vector, - size: self.size, - })) - } - - Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => { - // Helper for computing `homogeneous_aggregate`, allowing a custom - // starting offset (used below for handling variants). - let from_fields_at = - |layout: Self, - start: Size| - -> Result<(HomogeneousAggregate, Size), Heterogeneous> { - let is_union = match layout.fields { - FieldsShape::Primitive => { - unreachable!("aggregates can't have `FieldsShape::Primitive`") - } - FieldsShape::Array { count, .. } => { - assert_eq!(start, Size::ZERO); - - let result = if count > 0 { - layout.field(cx, 0).homogeneous_aggregate(cx)? - } else { - HomogeneousAggregate::NoData - }; - return Ok((result, layout.size)); - } - FieldsShape::Union(_) => true, - FieldsShape::Arbitrary { .. } => false, - }; - - let mut result = HomogeneousAggregate::NoData; - let mut total = start; - - for i in 0..layout.fields.count() { - let field = layout.field(cx, i); - if field.is_1zst() { - // No data here and no impact on layout, can be ignored. - // (We might be able to also ignore all aligned ZST but that's less clear.) - continue; - } - - if !is_union && total != layout.fields.offset(i) { - // This field isn't just after the previous one we considered, abort. - return Err(Heterogeneous); - } - - result = result.merge(field.homogeneous_aggregate(cx)?)?; - - // Keep track of the offset (without padding). - let size = field.size; - if is_union { - total = total.max(size); - } else { - total += size; - } - } - - Ok((result, total)) - }; - - let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; - - match &self.variants { - abi::Variants::Single { .. } => {} - abi::Variants::Multiple { variants, .. } => { - // Treat enum variants like union members. - // HACK(eddyb) pretend the `enum` field (discriminant) - // is at the start of every variant (otherwise the gap - // at the start of all variants would disqualify them). - // - // NB: for all tagged `enum`s (which include all non-C-like - // `enum`s with defined FFI representation), this will - // match the homogeneous computation on the equivalent - // `struct { tag; union { variant1; ... } }` and/or - // `union { struct { tag; variant1; } ... }` - // (the offsets of variant fields should be identical - // between the two for either to be a homogeneous aggregate). - let variant_start = total; - for variant_idx in variants.indices() { - let (variant_result, variant_total) = - from_fields_at(self.for_variant(cx, variant_idx), variant_start)?; - - result = result.merge(variant_result)?; - total = total.max(variant_total); - } - } - } - - // There needs to be no padding. - if total != self.size { - Err(Heterogeneous) - } else { - match result { - HomogeneousAggregate::Homogeneous(_) => { - assert_ne!(total, Size::ZERO); - } - HomogeneousAggregate::NoData => { - assert_eq!(total, Size::ZERO); - } - } - Ok(result) - } - } - Abi::Aggregate { sized: false } => Err(Heterogeneous), - } - } -} - /// Information about how to pass an argument to, /// or return a value from, a function, under some ABI. #[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)] @@ -637,7 +392,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } } - /// Pass this argument indirectly, by passing a (thin or fat) pointer to the argument instead. + /// Pass this argument indirectly, by passing a (thin or wide) pointer to the argument instead. /// This is valid for both sized and unsized arguments. pub fn make_indirect(&mut self) { match self.mode { diff --git a/compiler/rustc_target/src/abi/call/msp430.rs b/compiler/rustc_target/src/callconv/msp430.rs index 4f613aa6c15..4f613aa6c15 100644 --- a/compiler/rustc_target/src/abi/call/msp430.rs +++ b/compiler/rustc_target/src/callconv/msp430.rs diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs index 2e8b16d3a93..2e8b16d3a93 100644 --- a/compiler/rustc_target/src/abi/call/nvptx64.rs +++ b/compiler/rustc_target/src/callconv/nvptx64.rs diff --git a/compiler/rustc_target/src/abi/call/powerpc.rs b/compiler/rustc_target/src/callconv/powerpc.rs index f3b05c48173..f3b05c48173 100644 --- a/compiler/rustc_target/src/abi/call/powerpc.rs +++ b/compiler/rustc_target/src/callconv/powerpc.rs diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index b9767bf906b..71e533b8cc5 100644 --- a/compiler/rustc_target/src/abi/call/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -10,6 +10,7 @@ use crate::spec::HasTargetSpec; enum ABI { ELFv1, // original ABI used for powerpc64 (big-endian) ELFv2, // newer ABI used for powerpc64le and musl (both endians) + AIX, // used by AIX OS, big-endian only } use ABI::*; @@ -23,9 +24,9 @@ where C: HasDataLayout, { arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| { - // ELFv1 only passes one-member aggregates transparently. + // ELFv1 and AIX only passes one-member aggregates transparently. // ELFv2 passes up to eight uniquely addressable members. - if (abi == ELFv1 && arg.layout.size > unit.size) + if ((abi == ELFv1 || abi == AIX) && arg.layout.size > unit.size) || arg.layout.size > unit.size.checked_mul(8, cx).unwrap() { return None; @@ -55,8 +56,15 @@ where return; } + // The AIX ABI expect byval for aggregates + // See https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/Targets/PPC.cpp. + if !is_ret && abi == AIX { + arg.pass_by_stack_offset(None); + return; + } + // The ELFv1 ABI doesn't return aggregates in registers - if is_ret && abi == ELFv1 { + if is_ret && (abi == ELFv1 || abi == AIX) { arg.make_indirect(); return; } @@ -93,6 +101,8 @@ where { let abi = if cx.target_spec().env == "musl" { ELFv2 + } else if cx.target_spec().os == "aix" { + AIX } else { match cx.data_layout().endian { Endian::Big => ELFv1, diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index be6bc701b49..be6bc701b49 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index 502e7331267..502e7331267 100644 --- a/compiler/rustc_target/src/abi/call/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs diff --git a/compiler/rustc_target/src/abi/call/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs index 37980a91c76..37980a91c76 100644 --- a/compiler/rustc_target/src/abi/call/sparc.rs +++ b/compiler/rustc_target/src/callconv/sparc.rs diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 835353f76fc..835353f76fc 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs index 3c4cd76a754..3c4cd76a754 100644 --- a/compiler/rustc_target/src/abi/call/wasm.rs +++ b/compiler/rustc_target/src/callconv/wasm.rs diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index d9af83d3205..d9af83d3205 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 9910e623ac9..9910e623ac9 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index e5a20b248e4..e5a20b248e4 100644 --- a/compiler/rustc_target/src/abi/call/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs diff --git a/compiler/rustc_target/src/abi/call/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index e1728b08a39..e1728b08a39 100644 --- a/compiler/rustc_target/src/abi/call/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 2c367defe7b..b09d8d724ef 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -134,3 +134,9 @@ impl ToJson for TargetMetadata { }) } } + +impl ToJson for rustc_abi::Endian { + fn to_json(&self) -> Json { + self.as_str().to_json() + } +} diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 2121c4110dd..50679ab8cc8 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -21,8 +21,8 @@ use std::path::{Path, PathBuf}; -pub mod abi; pub mod asm; +pub mod callconv; pub mod json; pub mod spec; pub mod target_features; @@ -30,6 +30,15 @@ pub mod target_features; #[cfg(test)] mod tests; +pub mod abi { + pub(crate) use Float::*; + pub(crate) use Primitive::*; + // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`. + pub use rustc_abi::{Float, *}; + + pub use crate::callconv as call; +} + pub use rustc_abi::HashStableContext; /// The name of rustc's own place to organize libraries. diff --git a/compiler/rustc_target/src/spec/base/avr_gnu.rs b/compiler/rustc_target/src/spec/base/avr_gnu.rs index fb97738618b..4f348af21ad 100644 --- a/compiler/rustc_target/src/spec/base/avr_gnu.rs +++ b/compiler/rustc_target/src/spec/base/avr_gnu.rs @@ -19,6 +19,8 @@ pub(crate) fn target(target_cpu: &'static str, mmcu: &'static str) -> Target { llvm_target: "avr-unknown-unknown".into(), pointer_width: 16, options: TargetOptions { + env: "gnu".into(), + c_int_width: "16".into(), cpu: target_cpu.into(), exe_suffix: ".elf".into(), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c557091242e..82e11a3afce 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1830,6 +1830,7 @@ supported_targets! { ("armv7-unknown-trusty", armv7_unknown_trusty), ("aarch64-unknown-trusty", aarch64_unknown_trusty), + ("x86_64-unknown-trusty", x86_64_unknown_trusty), ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf), @@ -1840,6 +1841,10 @@ supported_targets! { ("riscv32imac-esp-espidf", riscv32imac_esp_espidf), ("riscv32imafc-esp-espidf", riscv32imafc_esp_espidf), + ("riscv32e-unknown-none-elf", riscv32e_unknown_none_elf), + ("riscv32em-unknown-none-elf", riscv32em_unknown_none_elf), + ("riscv32emc-unknown-none-elf", riscv32emc_unknown_none_elf), + ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), ("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf), ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf), 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 de8d99977b4..e869314d4d8 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,4 @@ -use crate::spec::{CodeModel, Target, TargetOptions, base}; +use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -18,6 +18,11 @@ pub(crate) fn target() -> Target { features: "+f,+d".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), + supported_sanitizers: SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::LEAK + | SanitizerSet::MEMORY + | SanitizerSet::THREAD, direct_access_external_data: Some(false), ..base::linux_gnu::opts() }, 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 a5088bcd5c2..70e8bf633a9 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,4 @@ -use crate::spec::{CodeModel, Target, TargetOptions, base}; +use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -19,6 +19,11 @@ pub(crate) fn target() -> Target { llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), crt_static_default: false, + supported_sanitizers: SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::LEAK + | SanitizerSet::MEMORY + | SanitizerSet::THREAD, ..base::linux_musl::opts() }, } 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 32a856be669..90bcd9a45cf 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,4 @@ -use crate::spec::{Target, TargetOptions, base}; +use crate::spec::{SanitizerSet, Target, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -17,6 +17,11 @@ pub(crate) fn target() -> Target { features: "+f,+d".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), + supported_sanitizers: SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::LEAK + | SanitizerSet::MEMORY + | SanitizerSet::THREAD, ..base::linux_ohos::opts() }, } 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 new file mode 100644 index 00000000000..b1f52973c10 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs @@ -0,0 +1,34 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + Target { + // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also + // `options.llvm_abiname`. + data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), + llvm_target: "riscv32".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Bare RISC-V (RV32E ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + 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(), + max_atomic_width: Some(32), + atomic_cas: false, + features: "+e,+forced-atomics".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} 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 new file mode 100644 index 00000000000..feeaa48778d --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs @@ -0,0 +1,34 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + Target { + // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also + // `options.llvm_abiname`. + data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), + llvm_target: "riscv32".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Bare RISC-V (RV32EM ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + 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(), + max_atomic_width: Some(32), + atomic_cas: false, + features: "+e,+m,+forced-atomics".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} 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 new file mode 100644 index 00000000000..45d73c13233 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs @@ -0,0 +1,34 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + Target { + // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also + // `options.llvm_abiname`. + data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), + llvm_target: "riscv32".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Bare RISC-V (RV32EMC ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + 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(), + max_atomic_width: Some(32), + atomic_cas: false, + features: "+e,+m,+c,+forced-atomics".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs index 0cd4faefd6b..0157d03f854 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs @@ -7,7 +7,6 @@ pub(crate) fn target() -> Target { linker: Some("sparc-elf-gcc".into()), endian: Endian::Big, cpu: "v7".into(), - abi: "elf".into(), max_atomic_width: Some(32), atomic_cas: true, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs new file mode 100644 index 00000000000..a6af06b03db --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs @@ -0,0 +1,38 @@ +// Trusty OS target for X86_64. + +use crate::spec::{ + LinkSelfContainedDefault, PanicStrategy, RelroLevel, StackProbeType, Target, TargetOptions, +}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "x86_64-unknown-unknown-musl".into(), + metadata: crate::spec::TargetMetadata { + description: Some("x86_64 Trusty".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: TargetOptions { + executables: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + os: "trusty".into(), + link_self_contained: LinkSelfContainedDefault::InferredForMusl, + position_independent_executables: true, + static_position_independent_executables: true, + crt_static_default: true, + crt_static_respected: true, + dynamic_linking: false, + plt_by_default: false, + relro_level: RelroLevel::Full, + stack_probes: StackProbeType::Inline, + mcount: "\u{1}_mcount".into(), + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs index 51960dbec4a..254ae54db21 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs @@ -15,6 +15,7 @@ pub(crate) fn target() -> Target { }, options: TargetOptions { + vendor: "espressif".into(), cpu: "esp32".into(), linker: Some("xtensa-esp32-elf-gcc".into()), max_atomic_width: Some(32), diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs index 21330615a87..34d8383a604 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs @@ -15,6 +15,7 @@ pub(crate) fn target() -> Target { }, options: TargetOptions { + vendor: "espressif".into(), cpu: "esp32-s2".into(), linker: Some("xtensa-esp32s2-elf-gcc".into()), max_atomic_width: Some(32), diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs index fca47b4bdb1..023a67f2871 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs @@ -15,6 +15,7 @@ pub(crate) fn target() -> Target { }, options: TargetOptions { + vendor: "espressif".into(), cpu: "esp32-s3".into(), linker: Some("xtensa-esp32s3-elf-gcc".into()), max_atomic_width: Some(32), diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 0a98b363b1a..e92366d5c5c 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -191,6 +191,8 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sm4", Stable, &["neon"]), // FEAT_SME ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), + // FEAT_SME_B16B16 + ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]), // FEAT_SME_F16F16 ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), // FEAT_SME_F64F64 @@ -227,7 +229,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // // "For backwards compatibility, Neon and VFP are required in the latest architectures." ("sve", Stable, &["neon"]), - // FEAT_SVE_B16B16 (SVE or SME Instructions) + // FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), // FEAT_SVE2 ("sve2", Stable, &["sve"]), 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 c7b3f704330..bd78a6ee3af 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1285,9 +1285,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ValuePairs::ExistentialProjection(_) => { (false, Mismatch::Fixed("existential projection")) } - ValuePairs::Dummy => { - bug!("do not expect to report a type error from a ValuePairs::Dummy") - } }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -1853,9 +1850,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found); Some((exp, fnd, None)) } - ValuePairs::Dummy => { - bug!("do not expect to report a type error from a ValuePairs::Dummy") - } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 31256bca55e..a6ecd1cc987 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -284,14 +284,9 @@ pub fn suggest_new_region_bound( } match fn_return.kind { // FIXME(precise_captures): Suggest adding to `use<...>` list instead. - TyKind::OpaqueDef(item_id, _) => { - let item = tcx.hir().item(item_id); - let ItemKind::OpaqueTy(opaque) = &item.kind else { - return; - }; - + TyKind::OpaqueDef(opaque, _) => { // Get the identity type for this RPIT - let did = item_id.owner_id.to_def_id(); + let did = opaque.def_id.to_def_id(); let ty = Ty::new_opaque(tcx, did, ty::GenericArgs::identity_for_item(tcx, did)); if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg { 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 7802d5bf7a6..cf0ab630f2e 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 @@ -720,7 +720,7 @@ fn foo(&self) -> Self::T { String::new() } if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() { let opaque_local_def_id = def_id.as_local(); let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { - tcx.hir().expect_item(opaque_local_def_id).expect_opaque_ty() + tcx.hir().expect_opaque_ty(opaque_local_def_id) } else { return false; }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index a2d717817db..94610a9e0e6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -842,14 +842,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { lifetime: Region<'tcx>, add_lt_suggs: &mut Vec<(Span, String)>, ) -> String { - struct LifetimeReplaceVisitor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, + struct LifetimeReplaceVisitor<'a> { needle: hir::LifetimeName, new_lt: &'a str, add_lt_suggs: &'a mut Vec<(Span, String)>, } - impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_, 'tcx> { + impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> { fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) { if lt.res == self.needle { self.add_lt_suggs.push(lt.suggestion(self.new_lt)); @@ -857,10 +856,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) { - let hir::TyKind::OpaqueDef(item_id, _) = ty.kind else { + let hir::TyKind::OpaqueDef(opaque_ty, _) = ty.kind else { return hir::intravisit::walk_ty(self, ty); }; - let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty(); if let Some(&(_, b)) = opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle) { @@ -905,7 +903,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let mut visitor = LifetimeReplaceVisitor { - tcx: self.tcx, needle: hir::LifetimeName::Param(lifetime_def_id), add_lt_suggs, new_lt: &new_lt, @@ -1269,7 +1266,7 @@ fn suggest_precise_capturing<'tcx>( diag: &mut Diag<'_>, ) { let hir::OpaqueTy { bounds, origin, .. } = - tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty(); let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } = *origin else { return; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 6c3f3afce11..709b6eb18e3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -731,12 +731,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let exp_local_id = exp_def_id.as_local()?; match ( - &self.tcx.hir().expect_item(last_local_id).kind, - &self.tcx.hir().expect_item(exp_local_id).kind, + &self.tcx.hir().expect_opaque_ty(last_local_id), + &self.tcx.hir().expect_opaque_ty(exp_local_id), ) { ( - hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), - hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), + hir::OpaqueTy { bounds: last_bounds, .. }, + hir::OpaqueTy { bounds: exp_bounds, .. }, ) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| match ( left, right, ) { 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 1889ecc7670..824c25db07d 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 @@ -1,6 +1,7 @@ use core::ops::ControlFlow; use std::borrow::Cow; +use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; @@ -573,7 +574,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::PredicateKind::DynCompatible(trait_def_id) => { let violations = self.tcx.dyn_compatibility_violations(trait_def_id); - report_dyn_incompatibility(self.tcx, span, None, trait_def_id, violations) + let mut err = report_dyn_incompatibility( + self.tcx, + span, + None, + trait_def_id, + violations, + ); + if let hir::Node::Item(item) = + self.tcx.hir_node_by_def_id(obligation.cause.body_id) + && let hir::ItemKind::Impl(impl_) = item.kind + && let None = impl_.of_trait + && let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind + && let TraitObjectSyntax::None = syntax + && impl_.self_ty.span.edition().at_least_rust_2021() + { + // Silence the dyn-compatibility error in favor of the missing dyn on + // self type error. #131051. + err.downgrade_to_delayed_bug(); + } + err } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { 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 2c7ca50f954..c3100c48b0a 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 @@ -1,7 +1,7 @@ use std::iter; use std::path::PathBuf; -use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem}; +use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItemInner}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; @@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString { #[derive(Debug)] pub struct OnUnimplementedDirective { - pub condition: Option<MetaItem>, + pub condition: Option<MetaItemInner>, pub subcommands: Vec<OnUnimplementedDirective>, pub message: Option<OnUnimplementedFormatString>, pub label: Option<OnUnimplementedFormatString>, @@ -389,7 +389,7 @@ impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, item_def_id: DefId, - items: &[NestedMetaItem], + items: &[MetaItemInner], span: Span, is_root: bool, is_diagnostic_namespace_variant: bool, @@ -414,7 +414,7 @@ impl<'tcx> OnUnimplementedDirective { let cond = item_iter .next() .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))? - .meta_item() + .meta_item_or_bool() .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?; attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| { if let Some(value) = cfg.value @@ -558,8 +558,8 @@ impl<'tcx> OnUnimplementedDirective { IgnoredDiagnosticOption::maybe_emit_warning( tcx, item_def_id, - directive.condition.as_ref().map(|i| i.span), - aggr.condition.as_ref().map(|i| i.span), + directive.condition.as_ref().map(|i| i.span()), + aggr.condition.as_ref().map(|i| i.span()), "condition", ); IgnoredDiagnosticOption::maybe_emit_warning( 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 6df7fac949c..87834c329e1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -355,12 +355,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) | hir::ItemKind::Const(_, generics, _) - | hir::ItemKind::TraitAlias(generics, _) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), + | hir::ItemKind::TraitAlias(generics, _), .. }) | hir::Node::TraitItem(hir::TraitItem { generics, .. }) | hir::Node::ImplItem(hir::ImplItem { generics, .. }) + | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) if param_ty => { // We skip the 0'th arg (self) because we do not want @@ -421,10 +421,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) | hir::ItemKind::Const(_, generics, _) - | hir::ItemKind::TraitAlias(generics, _) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), + | hir::ItemKind::TraitAlias(generics, _), .. - }) if !param_ty => { + }) + | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) + if !param_ty => + { // Missing generic type parameter bound. if suggest_arbitrary_trait_bound( self.tcx, @@ -4542,7 +4544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // ... whose signature is `async` (i.e. this is an AFIT) let (sig, body) = item.expect_fn(); - let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = + let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(opaq_def, ..), .. }) = sig.decl.output else { // This should never happen, but let's not ICE. @@ -4551,7 +4553,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Check that this is *not* a nested `impl Future` RPIT in an async fn // (i.e. `async fn foo() -> impl Future`) - if def.owner_id.to_def_id() != opaque_def_id { + if opaq_def.def_id.to_def_id() != opaque_def_id { return; } @@ -5159,7 +5161,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( }; let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span); - let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let future = tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty(); let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else { // `async fn` should always lower to a single bound... but don't ICE. return None; diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index a17c007debd..11d72106b22 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -20,7 +20,6 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(cfg_version)] -#![feature(control_flow_enum)] #![feature(extract_if)] #![feature(if_let_guard)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index e47f5389cd1..d425ab50ae0 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -6,6 +6,7 @@ pub mod inspect; mod normalize; mod select; +pub(crate) use delegate::SolverDelegate; pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 5c344930314..df9ac2b80fd 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -223,6 +223,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) } } + // FIXME: This actually should destructure the `Result` we get from transmutability and + // register candidates. We probably need to register >1 since we may have an OR of ANDs. fn is_transmutable( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index c6e3ba3c957..081d7a6a769 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -12,7 +12,7 @@ use rustc_infer::traits::{ use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; +use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; use tracing::instrument; use super::Certainty; @@ -86,10 +86,7 @@ impl<'tcx> ObligationStorage<'tcx> { let result = <&SolverDelegate<'tcx>>::from(infcx) .evaluate_root_goal(goal, GenerateProofTree::No) .0; - match result { - Ok((has_changed, _)) => has_changed, - _ => false, - } + matches!(result, Ok((HasChanged::Yes, _))) })); }) } @@ -113,7 +110,7 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> { &self, infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - result: &Result<(bool, Certainty), NoSolution>, + result: &Result<(HasChanged, Certainty), NoSolution>, ) { if let Some(inspector) = infcx.obligation_inspector.get() { let result = match result { @@ -181,7 +178,11 @@ where continue; } }; - has_changed |= changed; + + if changed == HasChanged::Yes { + has_changed = true; + } + match certainty { Certainty::Yes => {} Certainty::Maybe(_) => self.obligations.register(obligation), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 27d2a3c15b9..b29e41beab5 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; pub use rustc_next_trait_solver::coherence::*; +use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, warn}; @@ -28,7 +29,7 @@ use crate::error_reporting::traits::suggest_new_overflow_limit; use crate::infer::InferOk; use crate::infer::outlives::env::OutlivesEnvironment; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; -use crate::solve::{deeply_normalize_for_diagnostics, inspect}; +use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::{ @@ -333,6 +334,16 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( let infcx = selcx.infcx; if infcx.next_trait_solver() { + // A fast path optimization, try evaluating all goals with + // a very low recursion depth and bail if any of them don't + // hold. + if !obligations.iter().all(|o| { + <&SolverDelegate<'tcx>>::from(infcx) + .root_goal_may_hold_with_depth(8, Goal::new(infcx.tcx, o.param_env, o.predicate)) + }) { + return IntersectionHasImpossibleObligations::Yes; + } + let ocx = ObligationCtxt::new_with_diagnostics(infcx); ocx.register_obligations(obligations.iter().cloned()); let errors_and_ambiguities = ocx.select_all_or_error(); diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index d5d7681a8d6..45e7de942fb 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -1,12 +1,8 @@ -//! "Object safety" refers to the ability for a trait to be converted -//! to an object. In general, traits may only be converted to an -//! object if all of their methods meet certain criteria. In particular, -//! they must: +//! "Dyn-compatibility"[^1] refers to the ability for a trait to be converted +//! to a trait object. In general, traits may only be converted to a trait +//! object if certain criteria are met. //! -//! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version -//! that doesn't contain the vtable; -//! - not reference the erased type `Self` except for in this receiver; -//! - not have generic type parameters. +//! [^1]: Formerly known as "object safety". use std::iter; use std::ops::ControlFlow; @@ -506,8 +502,8 @@ fn virtual_call_violations_for_method<'tcx>( /// This code checks that `receiver_is_dispatchable` is correctly implemented. /// -/// This check is outlined from the object safety check to avoid cycles with -/// layout computation, which relies on knowing whether methods are object safe. +/// This check is outlined from the dyn-compatibility check to avoid cycles with +/// layout computation, which relies on knowing whether methods are dyn-compatible. fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: ty::AssocItem) { if !is_vtable_safe_method(tcx, trait_def_id, method) { return; @@ -643,8 +639,8 @@ fn object_ty_for_trait<'tcx>( /// contained by the trait object, because the object that needs to be coerced is behind /// a pointer. /// -/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result -/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch +/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in +/// a new check that `Trait` is dyn-compatible, creating a cycle (until dyn_compatible_for_dispatch /// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>). /// Instead, we fudge a little by introducing a new type parameter `U` such that /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. @@ -678,7 +674,7 @@ fn receiver_is_dispatchable<'tcx>( // the type `U` in the query // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now. - // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can + // FIXME(mikeyhew) this is a total hack. Once dyn_compatible_for_dispatch is stabilized, we can // replace this with `dyn Trait` let unsized_self_ty: Ty<'tcx> = Ty::new_param(tcx, u32::MAX, Symbol::intern("RustaceansAreAwesome")); @@ -865,7 +861,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> { } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result { - // Constants can only influence object safety if they are generic and reference `Self`. + // Constants can only influence dyn-compatibility if they are generic and reference `Self`. // This is only possible for unevaluated constants, so we walk these here. self.tcx.expand_abstract_consts(ct).super_visit_with(self) } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 084b61115db..20adda6f0de 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -881,7 +881,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().object_safe_for_dispatch { + if !self.infcx.tcx.features().dyn_compatible_for_dispatch { principal.with_self_ty(self.tcx(), self_ty) } else if self.tcx().is_dyn_compatible(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 7e140ecfee0..a849cdfe125 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -829,7 +829,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { // obligations that don't refer to Self and // checking those - let defer_to_coercion = tcx.features().object_safe_for_dispatch; + let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch; if !defer_to_coercion { if let Some(principal) = data.principal_def_id() { diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 1e5da4ec49d..9dabcea706f 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -40,7 +40,7 @@ mod rustc { /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, /// then computes an answer using those trees. #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] - pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> { + pub(crate) fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> { let Self { src, dst, assume, context } = self; let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all()); diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 01d5251bfa0..40356e0c978 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start itertools = "0.12" +rustc_abi = { path = "../rustc_abi" } rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f23c2cf2c07..deda16b76b5 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,5 +1,8 @@ use std::iter; +use rustc_abi::Float::*; +use rustc_abi::Primitive::{Float, Pointer}; +use rustc_abi::{Abi, AddressSpace, PointerKind, Scalar, Size}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::bug; @@ -14,7 +17,6 @@ use rustc_target::abi::call::{ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, RiscvInterruptKind, }; -use rustc_target::abi::*; use rustc_target::spec::abi::Abi as SpecAbi; use tracing::debug; @@ -357,7 +359,7 @@ fn fn_abi_of_instance<'tcx>( ) } -// Handle safe Rust thin and fat pointers. +// Handle safe Rust thin and wide pointers. fn adjust_for_rust_scalar<'tcx>( cx: LayoutCx<'tcx>, attrs: &mut ArgAttributes, @@ -810,7 +812,7 @@ fn make_thin_self_ptr<'tcx>( layout: TyAndLayout<'tcx>, ) -> TyAndLayout<'tcx> { let tcx = cx.tcx(); - let fat_pointer_ty = if layout.is_unsized() { + let wide_pointer_ty = if layout.is_unsized() { // unsized `self` is passed as a pointer to `self` // FIXME (mikeyhew) change this to use &own if it is ever added to the language Ty::new_mut_ptr(tcx, layout.ty) @@ -825,15 +827,15 @@ fn make_thin_self_ptr<'tcx>( // elsewhere in the compiler as a method on a `dyn Trait`. // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we // get a built-in pointer type - let mut fat_pointer_layout = layout; - while !fat_pointer_layout.ty.is_unsafe_ptr() && !fat_pointer_layout.ty.is_ref() { - fat_pointer_layout = fat_pointer_layout + let mut wide_pointer_layout = layout; + while !wide_pointer_layout.ty.is_unsafe_ptr() && !wide_pointer_layout.ty.is_ref() { + wide_pointer_layout = wide_pointer_layout .non_1zst_field(cx) .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type") .1 } - fat_pointer_layout.ty + wide_pointer_layout.ty }; // we now have a type like `*mut RcBox<dyn Trait>` @@ -842,7 +844,7 @@ fn make_thin_self_ptr<'tcx>( let unit_ptr_ty = Ty::new_mut_ptr(tcx, tcx.types.unit); TyAndLayout { - ty: fat_pointer_ty, + ty: wide_pointer_ty, // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result` // should always work because the type is always `*mut ()`. diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index e41f2c8ce48..a057caa9329 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -316,19 +316,16 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { - struct RPITVisitor<'tcx> { + struct RPITVisitor { rpits: FxIndexSet<LocalDefId>, - tcx: TyCtxt<'tcx>, } - impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> { + impl<'tcx> Visitor<'tcx> for RPITVisitor { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let hir::TyKind::OpaqueDef(item_id, _) = ty.kind - && self.rpits.insert(item_id.owner_id.def_id) + if let hir::TyKind::OpaqueDef(opaq, _) = ty.kind + && self.rpits.insert(opaq.def_id) { - let opaque_item = - self.tcx.hir().expect_item(item_id.owner_id.def_id).expect_opaque_ty(); - for bound in opaque_item.bounds { + for bound in opaq.bounds { intravisit::walk_param_bound(self, bound); } } @@ -336,7 +333,7 @@ fn associated_types_for_impl_traits_in_associated_fn( } } - let mut visitor = RPITVisitor { tcx, rpits: FxIndexSet::default() }; + let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; if let Some(output) = tcx.hir().get_fn_output(fn_def_id) { visitor.visit_fn_ret_ty(output); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 34c9f1b63c0..afdfa2e80c1 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -2,7 +2,12 @@ use std::fmt::Debug; use std::iter; use hir::def_id::DefId; -use rustc_hir as hir; +use rustc_abi::Integer::{I8, I32}; +use rustc_abi::Primitive::{self, Float, Int, Pointer}; +use rustc_abi::{ + Abi, AbiAndPrefAlign, AddressSpace, Align, FieldsShape, HasDataLayout, LayoutCalculatorError, + LayoutS, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, +}; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::bug; @@ -18,8 +23,9 @@ use rustc_middle::ty::{ use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use rustc_span::sym; use rustc_span::symbol::Symbol; -use rustc_target::abi::*; +use rustc_target::abi::{FIRST_VARIANT, FieldIdx, Layout, VariantIdx}; use tracing::{debug, instrument, trace}; +use {rustc_abi as abi, rustc_hir as hir}; use crate::errors::{ MultipleArrayFieldsSimdType, NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType, @@ -202,9 +208,9 @@ fn layout_of_uncached<'tcx>( value: Int(I32, false), valid_range: WrappingRange { start: 0, end: 0x10FFFF }, })), - ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)), - ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)), - ty::Float(fty) => scalar(Float(Float::from_float_ty(fty))), + ty::Int(ity) => scalar(Int(abi::Integer::from_int_ty(dl, ity), true)), + ty::Uint(ity) => scalar(Int(abi::Integer::from_uint_ty(dl, ity), false)), + ty::Float(fty) => scalar(Float(abi::Float::from_float_ty(fty))), ty::FnPtr(..) => { let mut ptr = scalar_unit(Pointer(dl.instruction_address_space)); ptr.valid_range_mut().start = 1; @@ -563,7 +569,7 @@ fn layout_of_uncached<'tcx>( } let get_discriminant_type = - |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max); + |min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max); let discriminants_iter = || { def.is_enum() @@ -816,7 +822,7 @@ fn coroutine_layout<'tcx>( // `info.variant_fields` already accounts for the reserved variants, so no need to add them. let max_discr = (info.variant_fields.len() - 1) as u128; - let discr_int = Integer::fit_unsigned(max_discr); + let discr_int = abi::Integer::fit_unsigned(max_discr); let tag = Scalar::Initialized { value: Primitive::Int(discr_int, /* signed = */ false), valid_range: WrappingRange { start: 0, end: max_discr }, diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 7c4b4887b2d..5e2232ff47d 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -132,6 +132,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { TaitInBodyFinder { collector: self }.visit_expr(body); } + #[instrument(level = "debug", skip(self))] fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) { if !self.seen.insert(alias_ty.def_id.expect_local()) { return; diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 61736633cfa..dac45ff2aba 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -44,6 +44,46 @@ pub trait Elaboratable<I: Interner> { ) -> Self; } +pub struct ClauseWithSupertraitSpan<I: Interner> { + pub pred: I::Predicate, + // Span of the original elaborated predicate. + pub original_span: I::Span, + // Span of the supertrait predicatae that lead to this clause. + pub supertrait_span: I::Span, +} +impl<I: Interner> ClauseWithSupertraitSpan<I> { + pub fn new(pred: I::Predicate, span: I::Span) -> Self { + ClauseWithSupertraitSpan { pred, original_span: span, supertrait_span: span } + } +} +impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> { + fn predicate(&self) -> <I as Interner>::Predicate { + self.pred + } + + fn child(&self, clause: <I as Interner>::Clause) -> Self { + ClauseWithSupertraitSpan { + pred: clause.as_predicate(), + original_span: self.original_span, + supertrait_span: self.supertrait_span, + } + } + + fn child_with_derived_cause( + &self, + clause: <I as Interner>::Clause, + supertrait_span: <I as Interner>::Span, + _parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>, + _index: usize, + ) -> Self { + ClauseWithSupertraitSpan { + pred: clause.as_predicate(), + original_span: self.original_span, + supertrait_span: supertrait_span, + } + } +} + pub fn elaborate<I: Interner, O: Elaboratable<I>>( cx: I, obligations: impl IntoIterator<Item = O>, diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 1d0b2345b80..b9f5cde653e 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,12 +1,21 @@ use crate::fold::TypeFoldable; -use crate::relate::Relate; -use crate::solve::{Goal, NoSolution, SolverMode}; +use crate::relate::RelateResult; +use crate::relate::combine::PredicateEmittingRelation; +use crate::solve::SolverMode; use crate::{self as ty, Interner}; pub trait InferCtxtLike: Sized { type Interner: Interner; fn cx(&self) -> Self::Interner; + /// Whether the new trait solver is enabled. This only exists because rustc + /// shares code between the new and old trait solvers; for all other users, + /// this should always be true. If this is unknowingly false and you try to + /// use the new trait solver, things will break badly. + fn next_trait_solver(&self) -> bool { + true + } + fn solver_mode(&self) -> SolverMode; fn universe(&self) -> ty::UniverseIndex; @@ -58,25 +67,45 @@ pub trait InferCtxtLike: Sized { f: impl FnOnce(T) -> U, ) -> U; - fn relate<T: Relate<Self::Interner>>( - &self, - param_env: <Self::Interner as Interner>::ParamEnv, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; + fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid); + fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid); + fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid); + fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid); + fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid); - fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>( + fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: ty::TyVid, + instantiation_variance: ty::Variance, + source_ty: <Self::Interner as Interner>::Ty, + ) -> RelateResult<Self::Interner, ()>; + fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue); + fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue); + fn instantiate_effect_var_raw( + &self, + vid: ty::EffectVid, + value: <Self::Interner as Interner>::Const, + ); + fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>( &self, - param_env: <Self::Interner as Interner>::ParamEnv, - lhs: T, - rhs: T, - ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; + relation: &mut R, + target_is_expected: bool, + target_vid: ty::ConstVid, + source_ct: <Self::Interner as Interner>::Const, + ) -> RelateResult<Self::Interner, ()>; + + fn set_tainted_by_errors(&self, e: <Self::Interner as Interner>::ErrorGuaranteed); fn shallow_resolve( &self, ty: <Self::Interner as Interner>::Ty, ) -> <Self::Interner as Interner>::Ty; + fn shallow_resolve_const( + &self, + ty: <Self::Interner as Interner>::Const, + ) -> <Self::Interner as Interner>::Const; fn resolve_vars_if_possible<T>(&self, value: T) -> T where @@ -90,6 +119,12 @@ pub trait InferCtxtLike: Sized { sup: <Self::Interner as Interner>::Region, ); + fn equate_regions( + &self, + a: <Self::Interner as Interner>::Region, + b: <Self::Interner as Interner>::Region, + ); + fn register_ty_outlives( &self, ty: <Self::Interner as Interner>::Ty, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 59a83ea5412..f7875bb5152 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -460,6 +460,8 @@ pub trait Clause<I: Interner<Clause = Self>>: + IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>> + Elaboratable<I> { + fn as_predicate(self) -> I::Predicate; + fn as_trait_clause(self) -> Option<ty::Binder<I, ty::TraitPredicate<I>>> { self.kind() .map_bound(|clause| if let ty::ClauseKind::Trait(t) = clause { Some(t) } else { None }) @@ -563,6 +565,10 @@ pub trait BoundExistentialPredicates<I: Interner>: ) -> impl IntoIterator<Item = ty::Binder<I, ty::ExistentialProjection<I>>>; } +pub trait Span<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> { + fn dummy() -> Self; +} + pub trait SliceLike: Sized + Copy { type Item: Copy; type IntoIter: Iterator<Item = Self::Item>; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b2ac67efef6..f06017d7e5c 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -36,7 +36,7 @@ pub trait Interner: { type DefId: DefId<Self>; type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>; - type Span: Copy + Debug + Hash + Eq + TypeFoldable<Self>; + type Span: Span<Self>; type GenericArgs: GenericArgs<Self>; type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>; @@ -261,6 +261,8 @@ pub trait Interner: fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool; + fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool; + fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed; fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 02a9ad1e35f..51c887fc4da 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -206,8 +206,8 @@ pub fn debug_bound_var<T: std::fmt::Write>( } } -#[derive(Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "nightly", derive(Decodable, Encodable, Hash, HashStable_NoContext))] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(Decodable, Encodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", rustc_pass_by_value)] pub enum Variance { Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 9c725f34d8e..e1f3e493e36 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -9,8 +9,23 @@ use crate::fold::TypeFoldable; use crate::inherent::*; use crate::{self as ty, Interner}; +pub mod combine; +pub mod solver_relating; + pub type RelateResult<I, T> = Result<T, TypeError<I>>; +/// Whether aliases should be related structurally or not. Used +/// to adjust the behavior of generalization and combine. +/// +/// This should always be `No` unless in a few special-cases when +/// instantiating canonical responses and in the new solver. Each +/// such case should have a comment explaining why it is used. +#[derive(Debug, Copy, Clone)] +pub enum StructurallyRelateAliases { + Yes, + No, +} + /// Extra information about why we ended up with a particular variance. /// This is only used to add more information to error messages, and /// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` @@ -239,6 +254,16 @@ impl<I: Interner> Relate<I> for ty::AliasTy<I> { b.args, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?, + ty::Projection if relation.cx().is_impl_trait_in_trait(a.def_id) => { + relate_args_with_variances( + relation, + a.def_id, + relation.cx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )? + } ty::Projection | ty::Weak | ty::Inherent => { relate_args_invariantly(relation, a.args, b.args)? } diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs new file mode 100644 index 00000000000..60a953801a4 --- /dev/null +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -0,0 +1,246 @@ +use tracing::debug; + +use super::{ + ExpectedFound, RelateResult, StructurallyRelateAliases, TypeRelation, + structurally_relate_consts, structurally_relate_tys, +}; +use crate::error::TypeError; +use crate::inherent::*; +use crate::solve::{Goal, SolverMode}; +use crate::visit::TypeVisitableExt as _; +use crate::{self as ty, InferCtxtLike, Interner, Upcast}; + +pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>: + TypeRelation<I> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + fn span(&self) -> I::Span; + + fn param_env(&self) -> I::ParamEnv; + + /// Whether aliases should be related structurally. This is pretty much + /// always `No` unless you're equating in some specific locations of the + /// new solver. See the comments in these use-cases for more details. + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; + + /// Register obligations that must hold in order for this relation to hold + fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>); + + /// Register predicates that must hold in order for this relation to hold. + /// This uses the default `param_env` of the obligation. + fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>, + ); + + /// Register `AliasRelate` obligation(s) that both types must be related to each other. + fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty); +} + +pub fn super_combine_tys<Infcx, I, R>( + infcx: &Infcx, + relation: &mut R, + a: I::Ty, + b: I::Ty, +) -> RelateResult<I, I::Ty> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, + R: PredicateEmittingRelation<Infcx>, +{ + debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b); + debug_assert!(!a.has_escaping_bound_vars()); + debug_assert!(!b.has_escaping_bound_vars()); + + match (a.kind(), b.kind()) { + (ty::Error(e), _) | (_, ty::Error(e)) => { + infcx.set_tainted_by_errors(e); + return Ok(Ty::new_error(infcx.cx(), e)); + } + + // Relate integral variables to other types + (ty::Infer(ty::IntVar(a_id)), ty::Infer(ty::IntVar(b_id))) => { + infcx.equate_int_vids_raw(a_id, b_id); + Ok(a) + } + (ty::Infer(ty::IntVar(v_id)), ty::Int(v)) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v)); + Ok(b) + } + (ty::Int(v), ty::Infer(ty::IntVar(v_id))) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v)); + Ok(a) + } + (ty::Infer(ty::IntVar(v_id)), ty::Uint(v)) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v)); + Ok(b) + } + (ty::Uint(v), ty::Infer(ty::IntVar(v_id))) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v)); + Ok(a) + } + + // Relate floating-point variables to other types + (ty::Infer(ty::FloatVar(a_id)), ty::Infer(ty::FloatVar(b_id))) => { + infcx.equate_float_vids_raw(a_id, b_id); + Ok(a) + } + (ty::Infer(ty::FloatVar(v_id)), ty::Float(v)) => { + infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v)); + Ok(b) + } + (ty::Float(v), ty::Infer(ty::FloatVar(v_id))) => { + infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v)); + Ok(a) + } + + // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm. + (ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..)) + if infcx.next_trait_solver() => + { + panic!( + "We do not expect to encounter `TyVar` this late in combine \ + -- they should have been handled earlier" + ) + } + (_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))) + | (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _) + if infcx.next_trait_solver() => + { + panic!("We do not expect to encounter `Fresh` variables in the new solver") + } + + (_, ty::Alias(..)) | (ty::Alias(..), _) if infcx.next_trait_solver() => { + match relation.structurally_relate_aliases() { + StructurallyRelateAliases::Yes => structurally_relate_tys(relation, a, b), + StructurallyRelateAliases::No => { + relation.register_alias_relate_predicate(a, b); + Ok(a) + } + } + } + + // All other cases of inference are errors + (ty::Infer(_), _) | (_, ty::Infer(_)) => { + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) + } + + (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => { + match infcx.solver_mode() { + SolverMode::Normal => { + assert!(!infcx.next_trait_solver()); + structurally_relate_tys(relation, a, b) + } + // During coherence, opaque types should be treated as *possibly* + // equal to any other type (except for possibly itinfcx). This is an + // extremely heavy hammer, but can be relaxed in a forwards-compatible + // way later. + SolverMode::Coherence => { + relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); + Ok(a) + } + } + } + + _ => structurally_relate_tys(relation, a, b), + } +} + +pub fn super_combine_consts<Infcx, I, R>( + infcx: &Infcx, + relation: &mut R, + a: I::Const, + b: I::Const, +) -> RelateResult<I, I::Const> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, + R: PredicateEmittingRelation<Infcx>, +{ + debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b); + debug_assert!(!a.has_escaping_bound_vars()); + debug_assert!(!b.has_escaping_bound_vars()); + + if a == b { + return Ok(a); + } + + let a = infcx.shallow_resolve_const(a); + let b = infcx.shallow_resolve_const(b); + + match (a.kind(), b.kind()) { + ( + ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), + ty::ConstKind::Infer(ty::InferConst::Var(b_vid)), + ) => { + infcx.equate_const_vids_raw(a_vid, b_vid); + Ok(a) + } + + ( + ty::ConstKind::Infer(ty::InferConst::EffectVar(a_vid)), + ty::ConstKind::Infer(ty::InferConst::EffectVar(b_vid)), + ) => { + infcx.equate_effect_vids_raw(a_vid, b_vid); + Ok(a) + } + + // All other cases of inference with other variables are errors. + ( + ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)), + ty::ConstKind::Infer(_), + ) + | ( + ty::ConstKind::Infer(_), + ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)), + ) => { + panic!( + "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}" + ) + } + + (ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => { + infcx.instantiate_const_var_raw(relation, true, vid, b)?; + Ok(b) + } + + (_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => { + infcx.instantiate_const_var_raw(relation, false, vid, a)?; + Ok(a) + } + + (ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)), _) => { + infcx.instantiate_effect_var_raw(vid, b); + Ok(b) + } + + (_, ty::ConstKind::Infer(ty::InferConst::EffectVar(vid))) => { + infcx.instantiate_effect_var_raw(vid, a); + Ok(a) + } + + (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) + if infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver() => + { + match relation.structurally_relate_aliases() { + StructurallyRelateAliases::No => { + relation.register_predicates([if infcx.next_trait_solver() { + ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ) + } else { + ty::PredicateKind::ConstEquate(a, b) + }]); + + Ok(b) + } + StructurallyRelateAliases::Yes => structurally_relate_consts(relation, a, b), + } + } + _ => structurally_relate_consts(relation, a, b), + } +} diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs new file mode 100644 index 00000000000..ad10ad5af9c --- /dev/null +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -0,0 +1,394 @@ +pub use rustc_type_ir::relate::*; +use rustc_type_ir::solve::Goal; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; +use tracing::{debug, instrument}; + +use self::combine::{PredicateEmittingRelation, super_combine_consts, super_combine_tys}; +use crate::data_structures::DelayedSet; + +pub trait RelateExt: InferCtxtLike { + fn relate<T: Relate<Self::Interner>>( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result< + Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, + TypeError<Self::Interner>, + >; + + fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + lhs: T, + rhs: T, + ) -> Result< + Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, + TypeError<Self::Interner>, + >; +} + +impl<Infcx: InferCtxtLike> RelateExt for Infcx { + fn relate<T: Relate<Self::Interner>>( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result< + Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, + TypeError<Self::Interner>, + > { + let mut relate = + SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env); + relate.relate(lhs, rhs)?; + Ok(relate.goals) + } + + fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + lhs: T, + rhs: T, + ) -> Result< + Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, + TypeError<Self::Interner>, + > { + let mut relate = + SolverRelating::new(self, StructurallyRelateAliases::Yes, ty::Invariant, param_env); + relate.relate(lhs, rhs)?; + Ok(relate.goals) + } +} + +/// Enforce that `a` is equal to or a subtype of `b`. +pub struct SolverRelating<'infcx, Infcx, I: Interner> { + infcx: &'infcx Infcx, + // Immutable fields. + structurally_relate_aliases: StructurallyRelateAliases, + param_env: I::ParamEnv, + // Mutable fields. + ambient_variance: ty::Variance, + goals: Vec<Goal<I, I::Predicate>>, + /// The cache only tracks the `ambient_variance` as it's the + /// only field which is mutable and which meaningfully changes + /// the result when relating types. + /// + /// The cache does not track whether the state of the + /// `Infcx` has been changed or whether we've added any + /// goals to `self.goals`. Whether a goal is added once or multiple + /// times is not really meaningful. + /// + /// Changes in the inference state may delay some type inference to + /// the next fulfillment loop. Given that this loop is already + /// necessary, this is also not a meaningful change. Consider + /// the following three relations: + /// ```text + /// Vec<?0> sub Vec<?1> + /// ?0 eq u32 + /// Vec<?0> sub Vec<?1> + /// ``` + /// Without a cache, the second `Vec<?0> sub Vec<?1>` would eagerly + /// constrain `?1` to `u32`. When using the cache entry from the + /// first time we've related these types, this only happens when + /// later proving the `Subtype(?0, ?1)` goal from the first relation. + cache: DelayedSet<(ty::Variance, I::Ty, I::Ty)>, +} + +impl<'infcx, Infcx, I> SolverRelating<'infcx, Infcx, I> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + pub fn new( + infcx: &'infcx Infcx, + structurally_relate_aliases: StructurallyRelateAliases, + ambient_variance: ty::Variance, + param_env: I::ParamEnv, + ) -> Self { + SolverRelating { + infcx, + structurally_relate_aliases, + ambient_variance, + param_env, + goals: vec![], + cache: Default::default(), + } + } +} + +impl<Infcx, I> TypeRelation<I> for SolverRelating<'_, Infcx, I> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + fn cx(&self) -> I { + self.infcx.cx() + } + + fn relate_item_args( + &mut self, + item_def_id: I::DefId, + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, + ) -> RelateResult<I, I::GenericArgs> { + if self.ambient_variance == ty::Invariant { + // Avoid fetching the variance if we are in an invariant + // context; no need, and it can induce dependency cycles + // (e.g., #41849). + relate_args_invariantly(self, a_arg, b_arg) + } else { + let tcx = self.cx(); + let opt_variances = tcx.variances_of(item_def_id); + relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false) + } + } + + fn relate_with_variance<T: Relate<I>>( + &mut self, + variance: ty::Variance, + _info: VarianceDiagInfo<I>, + a: T, + b: T, + ) -> RelateResult<I, T> { + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + debug!(?self.ambient_variance, "new ambient variance"); + + let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) }; + + self.ambient_variance = old_ambient_variance; + r + } + + #[instrument(skip(self), level = "trace")] + fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty> { + if a == b { + return Ok(a); + } + + let infcx = self.infcx; + let a = infcx.shallow_resolve(a); + let b = infcx.shallow_resolve(b); + + if self.cache.contains(&(self.ambient_variance, a, b)) { + return Ok(a); + } + + match (a.kind(), b.kind()) { + (ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => { + match self.ambient_variance { + ty::Covariant => { + // can't make progress on `A <: B` if both A and B are + // type variables, so record an obligation. + self.goals.push(Goal::new( + self.cx(), + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { + a_is_expected: true, + a, + b, + })), + )); + } + ty::Contravariant => { + // can't make progress on `B <: A` if both A and B are + // type variables, so record an obligation. + self.goals.push(Goal::new( + self.cx(), + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { + a_is_expected: false, + a: b, + b: a, + })), + )); + } + ty::Invariant => { + infcx.equate_ty_vids_raw(a_id, b_id); + } + ty::Bivariant => { + unreachable!("Expected bivariance to be handled in relate_with_variance") + } + } + } + + (ty::Infer(ty::TyVar(a_vid)), _) => { + infcx.instantiate_ty_var_raw(self, true, a_vid, self.ambient_variance, b)?; + } + (_, ty::Infer(ty::TyVar(b_vid))) => { + infcx.instantiate_ty_var_raw( + self, + false, + b_vid, + self.ambient_variance.xform(ty::Contravariant), + a, + )?; + } + + _ => { + super_combine_tys(self.infcx, self, a, b)?; + } + } + + assert!(self.cache.insert((self.ambient_variance, a, b))); + + Ok(a) + } + + #[instrument(skip(self), level = "trace")] + fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region> { + match self.ambient_variance { + // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) + ty::Covariant => self.infcx.sub_regions(b, a), + // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b) + ty::Contravariant => self.infcx.sub_regions(a, b), + ty::Invariant => self.infcx.equate_regions(a, b), + ty::Bivariant => { + unreachable!("Expected bivariance to be handled in relate_with_variance") + } + } + + Ok(a) + } + + #[instrument(skip(self), level = "trace")] + fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const> { + super_combine_consts(self.infcx, self, a, b) + } + + fn binders<T>( + &mut self, + a: ty::Binder<I, T>, + b: ty::Binder<I, T>, + ) -> RelateResult<I, ty::Binder<I, T>> + where + T: Relate<I>, + { + // If they're equal, then short-circuit. + if a == b { + return Ok(a); + } + + // If they have no bound vars, relate normally. + if let Some(a_inner) = a.no_bound_vars() { + if let Some(b_inner) = b.no_bound_vars() { + self.relate(a_inner, b_inner)?; + return Ok(a); + } + }; + + match self.ambient_variance { + // Checks whether `for<..> sub <: for<..> sup` holds. + // + // For this to hold, **all** instantiations of the super type + // have to be a super type of **at least one** instantiation of + // the subtype. + // + // This is implemented by first entering a new universe. + // We then replace all bound variables in `sup` with placeholders, + // and all bound variables in `sub` with inference vars. + // We can then just relate the two resulting types as normal. + // + // Note: this is a subtle algorithm. For a full explanation, please see + // the [rustc dev guide][rd] + // + // [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html + ty::Covariant => { + self.infcx.enter_forall(b, |b| { + let a = self.infcx.instantiate_binder_with_infer(a); + self.relate(a, b) + })?; + } + ty::Contravariant => { + self.infcx.enter_forall(a, |a| { + let b = self.infcx.instantiate_binder_with_infer(b); + self.relate(a, b) + })?; + } + + // When **equating** binders, we check that there is a 1-to-1 + // correspondence between the bound vars in both types. + // + // We do so by separately instantiating one of the binders with + // placeholders and the other with inference variables and then + // equating the instantiated types. + // + // We want `for<..> A == for<..> B` -- therefore we want + // `exists<..> A == for<..> B` and `exists<..> B == for<..> A`. + // Check if `exists<..> A == for<..> B` + ty::Invariant => { + self.infcx.enter_forall(b, |b| { + let a = self.infcx.instantiate_binder_with_infer(a); + self.relate(a, b) + })?; + + // Check if `exists<..> B == for<..> A`. + self.infcx.enter_forall(a, |a| { + let b = self.infcx.instantiate_binder_with_infer(b); + self.relate(a, b) + })?; + } + ty::Bivariant => { + unreachable!("Expected bivariance to be handled in relate_with_variance") + } + } + Ok(a) + } +} + +impl<Infcx, I> PredicateEmittingRelation<Infcx> for SolverRelating<'_, Infcx, I> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + fn span(&self) -> I::Span { + Span::dummy() + } + + fn param_env(&self) -> I::ParamEnv { + self.param_env + } + + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + self.structurally_relate_aliases + } + + fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: ty::Upcast<I, I::Predicate>>, + ) { + self.goals.extend( + obligations.into_iter().map(|pred| Goal::new(self.infcx.cx(), self.param_env, pred)), + ); + } + + fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>) { + self.goals.extend(obligations); + } + + fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty) { + self.register_predicates([ty::Binder::dummy(match self.ambient_variance { + ty::Covariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Subtype, + ), + // a :> b is b <: a + ty::Contravariant => ty::PredicateKind::AliasRelate( + b.into(), + a.into(), + ty::AliasRelationDirection::Subtype, + ), + ty::Invariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ), + ty::Bivariant => { + unreachable!("Expected bivariance to be handled in relate_with_variance") + } + })]); + } +} diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index ac4d0795a92..f4fb03562de 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -81,7 +81,6 @@ pub trait Delegate { fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool; const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize; - fn recursion_limit(cx: Self::Cx) -> usize; fn initial_provisional_result( cx: Self::Cx, @@ -156,7 +155,7 @@ impl AvailableDepth { /// the remaining depth of all nested goals to prevent hangs /// in case there is exponential blowup. fn allowed_depth_for_nested<D: Delegate>( - cx: D::Cx, + root_depth: AvailableDepth, stack: &IndexVec<StackDepth, StackEntry<D::Cx>>, ) -> Option<AvailableDepth> { if let Some(last) = stack.raw.last() { @@ -170,7 +169,7 @@ impl AvailableDepth { AvailableDepth(last.available_depth.0 - 1) }) } else { - Some(AvailableDepth(D::recursion_limit(cx))) + Some(root_depth) } } @@ -360,6 +359,7 @@ struct ProvisionalCacheEntry<X: Cx> { pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> { mode: SolverMode, + root_depth: AvailableDepth, /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. @@ -374,9 +374,10 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> { } impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { - pub fn new(mode: SolverMode) -> SearchGraph<D> { + pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph<D> { Self { mode, + root_depth: AvailableDepth(root_depth), stack: Default::default(), provisional_cache: Default::default(), _marker: PhantomData, @@ -460,7 +461,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { inspect: &mut D::ProofTreeBuilder, mut evaluate_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, ) -> X::Result { - let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::<D>(cx, &self.stack) + let Some(available_depth) = + AvailableDepth::allowed_depth_for_nested::<D>(self.root_depth, &self.stack) else { return self.handle_overflow(cx, input, inspect); }; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index ab9fc218d19..742469a1c93 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -768,8 +768,10 @@ pub enum ProjectionElem { ConstantIndex { /// index or -index (in Python terms), depending on from_end offset: u64, - /// The thing being indexed must be at least this long. For arrays this - /// is always the exact length. + /// The thing being indexed must be at least this long -- otherwise, the + /// projection is UB. + /// + /// For arrays this is always the exact length. min_length: u64, /// Counting backwards from end? This is always false when indexing an /// array. @@ -946,10 +948,10 @@ pub enum PointerCoercion { ArrayToPointer, /// Unsize a pointer/reference value, e.g., `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - /// This will do things like convert thin pointers to fat + /// `&[T]`. Note that the source could be a thin or wide pointer. + /// This will do things like convert thin pointers to wide /// pointers, or convert structs containing thin pointers to - /// structs containing fat pointers, or convert between fat + /// structs containing wide pointers, or convert between wide /// pointers. Unsize, } diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index aeae866e9d3..e2d1ff7fdd3 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -76,9 +76,9 @@ pub trait MirVisitor { self.super_place(place, ptx, location) } - fn visit_projection_elem<'a>( + fn visit_projection_elem( &mut self, - place_ref: PlaceRef<'a>, + place_ref: PlaceRef<'_>, elem: &ProjectionElem, ptx: PlaceContext, location: Location, diff --git a/config.example.toml b/config.example.toml index 47ebb20d8fa..4b591b949b3 100644 --- a/config.example.toml +++ b/config.example.toml @@ -759,6 +759,16 @@ # Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std` #validate-mir-opts = 3 +# Configure `std` features used during bootstrap. +# Default features will be expanded in the following cases: +# - If `rust.llvm-libunwind` or `target.llvm-libunwind` is enabled: +# - "llvm-libunwind" will be added for in-tree LLVM builds. +# - "system-llvm-libunwind" will be added for system LLVM builds. +# - If `rust.backtrace` is enabled, "backtrace" will be added. +# - If `rust.profiler` or `target.profiler` is enabled, "profiler" will be added. +# - If building for a zkvm target, "compiler-builtins-mem" will be added. +#std-features = ["panic_unwind"] + # ============================================================================= # Options for specific targets # diff --git a/library/Cargo.lock b/library/Cargo.lock index 209e30b3040..59b76d8d442 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.130" +version = "0.1.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64c30475571756801eff60a811520c3d18e0ceb9c56c97bad2047ae601f6709" +checksum = "ab10bf45b2ed1b4f4c25401527a61684142c042b3c86ace7da7ea6881e26741b" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 11db50a0fdf..259a3ed2beb 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.130", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.133", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index f86face3f90..dbfd2e74abe 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -225,7 +225,6 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> { /// assert!(!bull.is_borrowed()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] - #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] pub const fn is_borrowed(&self) -> bool { match *self { Borrowed(_) => true, @@ -248,7 +247,6 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> { /// assert!(!bull.is_owned()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] - #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] pub const fn is_owned(&self) -> bool { !self.is_borrowed() } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index b1759a486ac..54739c50d1d 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -103,6 +103,7 @@ pub struct VecDeque< #[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone, A: Allocator + Clone> Clone for VecDeque<T, A> { + #[track_caller] fn clone(&self) -> Self { let mut deq = Self::with_capacity_in(self.len(), self.allocator().clone()); deq.extend(self.iter().cloned()); @@ -113,6 +114,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for VecDeque<T, A> { /// /// This method is preferred over simply assigning `source.clone()` to `self`, /// as it avoids reallocation if possible. + #[track_caller] fn clone_from(&mut self, source: &Self) { self.clear(); self.extend(source.iter().cloned()); @@ -570,6 +572,7 @@ impl<T> VecDeque<T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] + #[track_caller] pub fn with_capacity(capacity: usize) -> VecDeque<T> { Self::with_capacity_in(capacity, Global) } @@ -625,6 +628,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// let deque: VecDeque<u32> = VecDeque::with_capacity(10); /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[track_caller] pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> { VecDeque { head: 0, len: 0, buf: RawVec::with_capacity_in(capacity, alloc) } } @@ -789,6 +793,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// /// [`reserve`]: VecDeque::reserve #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn reserve_exact(&mut self, additional: usize) { let new_cap = self.len.checked_add(additional).expect("capacity overflow"); let old_cap = self.capacity(); @@ -818,6 +823,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert!(buf.capacity() >= 11); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn reserve(&mut self, additional: usize) { let new_cap = self.len.checked_add(additional).expect("capacity overflow"); let old_cap = self.capacity(); @@ -949,6 +955,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert!(buf.capacity() >= 4); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] + #[track_caller] pub fn shrink_to_fit(&mut self) { self.shrink_to(0); } @@ -974,6 +981,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert!(buf.capacity() >= 4); /// ``` #[stable(feature = "shrink_to", since = "1.56.0")] + #[track_caller] pub fn shrink_to(&mut self, min_capacity: usize) { let target_cap = min_capacity.max(self.len); @@ -1740,6 +1748,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert_eq!(d.front(), Some(&2)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn push_front(&mut self, value: T) { if self.is_full() { self.grow(); @@ -1767,6 +1776,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push", "put", "append")] + #[track_caller] pub fn push_back(&mut self, value: T) { if self.is_full() { self.grow(); @@ -1876,6 +1886,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c']); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] + #[track_caller] pub fn insert(&mut self, index: usize, value: T) { assert!(index <= self.len(), "index out of bounds"); if self.is_full() { @@ -1979,6 +1990,7 @@ impl<T, A: Allocator> VecDeque<T, A> { #[inline] #[must_use = "use `.truncate()` if you don't need the other half"] #[stable(feature = "split_off", since = "1.4.0")] + #[track_caller] pub fn split_off(&mut self, at: usize) -> Self where A: Clone, @@ -2045,6 +2057,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` #[inline] #[stable(feature = "append", since = "1.4.0")] + #[track_caller] pub fn append(&mut self, other: &mut Self) { if T::IS_ZST { self.len = self.len.checked_add(other.len).expect("capacity overflow"); @@ -2167,6 +2180,7 @@ impl<T, A: Allocator> VecDeque<T, A> { // be called in cold paths. // This may panic or abort #[inline(never)] + #[track_caller] fn grow(&mut self) { // Extend or possibly remove this assertion when valid use-cases for growing the // buffer without it being full emerge @@ -2205,6 +2219,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert_eq!(buf, [5, 10, 101, 102, 103]); /// ``` #[stable(feature = "vec_resize_with", since = "1.33.0")] + #[track_caller] pub fn resize_with(&mut self, new_len: usize, generator: impl FnMut() -> T) { let len = self.len; @@ -2751,6 +2766,7 @@ impl<T: Clone, A: Allocator> VecDeque<T, A> { /// assert_eq!(buf, [5, 10, 20, 20, 20]); /// ``` #[stable(feature = "deque_extras", since = "1.16.0")] + #[track_caller] pub fn resize(&mut self, new_len: usize, value: T) { if new_len > self.len() { let extra = new_len - self.len(); @@ -2870,6 +2886,7 @@ impl<T, A: Allocator> IndexMut<usize> for VecDeque<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T> FromIterator<T> for VecDeque<T> { + #[track_caller] fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> VecDeque<T> { SpecFromIter::spec_from_iter(iter.into_iter()) } @@ -2909,16 +2926,19 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut VecDeque<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T, A: Allocator> Extend<T> for VecDeque<T, A> { + #[track_caller] fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { <Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter()); } #[inline] + #[track_caller] fn extend_one(&mut self, elem: T) { self.push_back(elem); } #[inline] + #[track_caller] fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } @@ -2934,16 +2954,19 @@ impl<T, A: Allocator> Extend<T> for VecDeque<T, A> { #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> { + #[track_caller] fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { self.spec_extend(iter.into_iter()); } #[inline] + #[track_caller] fn extend_one(&mut self, &elem: &'a T) { self.push_back(elem); } #[inline] + #[track_caller] fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } @@ -3041,6 +3064,7 @@ impl<T, const N: usize> From<[T; N]> for VecDeque<T> { /// let deq2: VecDeque<_> = [1, 2, 3, 4].into(); /// assert_eq!(deq1, deq2); /// ``` + #[track_caller] fn from(arr: [T; N]) -> Self { let mut deq = VecDeque::with_capacity(N); let arr = ManuallyDrop::new(arr); diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index a9b0fd073b5..d246385ca84 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -7,6 +7,7 @@ use crate::vec; // Specialization trait used for VecDeque::extend pub(super) trait SpecExtend<T, I> { + #[track_caller] fn spec_extend(&mut self, iter: I); } @@ -14,6 +15,7 @@ impl<T, I, A: Allocator> SpecExtend<T, I> for VecDeque<T, A> where I: Iterator<Item = T>, { + #[track_caller] default fn spec_extend(&mut self, mut iter: I) { // This function should be the moral equivalent of: // @@ -44,6 +46,7 @@ impl<T, I, A: Allocator> SpecExtend<T, I> for VecDeque<T, A> where I: TrustedLen<Item = T>, { + #[track_caller] default fn spec_extend(&mut self, iter: I) { // This is the case for a TrustedLen iterator. let (low, high) = iter.size_hint(); @@ -76,6 +79,7 @@ where } impl<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> { + #[track_caller] fn spec_extend(&mut self, mut iterator: vec::IntoIter<T>) { let slice = iterator.as_slice(); self.reserve(slice.len()); @@ -93,6 +97,7 @@ where I: Iterator<Item = &'a T>, T: Copy, { + #[track_caller] default fn spec_extend(&mut self, iterator: I) { self.spec_extend(iterator.copied()) } @@ -102,6 +107,7 @@ impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for VecDeque where T: Copy, { + #[track_caller] fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { let slice = iterator.as_slice(); self.reserve(slice.len()); diff --git a/library/alloc/src/collections/vec_deque/spec_from_iter.rs b/library/alloc/src/collections/vec_deque/spec_from_iter.rs index 2708c7fe102..1efe84d6d7d 100644 --- a/library/alloc/src/collections/vec_deque/spec_from_iter.rs +++ b/library/alloc/src/collections/vec_deque/spec_from_iter.rs @@ -9,6 +9,7 @@ impl<T, I> SpecFromIter<T, I> for VecDeque<T> where I: Iterator<Item = T>, { + #[track_caller] default fn spec_from_iter(iterator: I) -> Self { // Since converting is O(1) now, just re-use the `Vec` logic for // anything where we can't do something extra-special for `VecDeque`, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ff5ddd16e07..50bf385d671 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -108,13 +108,12 @@ #![feature(coerce_unsized)] #![feature(const_align_of_val)] #![feature(const_box)] -#![feature(const_cow_is_borrowed)] #![feature(const_eval_select)] #![feature(const_heap)] #![feature(const_maybe_uninit_write)] -#![feature(const_option)] #![feature(const_pin)] #![feature(const_size_of_val)] +#![feature(const_vec_string_slice)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] @@ -172,7 +171,6 @@ #![feature(allow_internal_unstable)] #![feature(cfg_sanitize)] #![feature(const_precise_live_drops)] -#![feature(const_ptr_write)] #![feature(const_try)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 436e0596e3d..45de0617f33 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -20,6 +20,7 @@ mod tests; // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[track_caller] fn capacity_overflow() -> ! { panic!("capacity overflow"); } @@ -125,6 +126,7 @@ impl<T> RawVec<T, Global> { #[cfg(not(any(no_global_oom_handling, test)))] #[must_use] #[inline] + #[track_caller] pub fn with_capacity(capacity: usize) -> Self { Self { inner: RawVecInner::with_capacity(capacity, T::LAYOUT), _marker: PhantomData } } @@ -133,6 +135,7 @@ impl<T> RawVec<T, Global> { #[cfg(not(any(no_global_oom_handling, test)))] #[must_use] #[inline] + #[track_caller] pub fn with_capacity_zeroed(capacity: usize) -> Self { Self { inner: RawVecInner::with_capacity_zeroed_in(capacity, Global, T::LAYOUT), @@ -145,6 +148,7 @@ impl RawVecInner<Global> { #[cfg(not(any(no_global_oom_handling, test)))] #[must_use] #[inline] + #[track_caller] fn with_capacity(capacity: usize, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global, elem_layout) { Ok(res) => res, @@ -184,6 +188,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), @@ -205,6 +210,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// of allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_zeroed_in(capacity, alloc, T::LAYOUT), @@ -280,7 +286,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// be careful. #[inline] - pub fn ptr(&self) -> *mut T { + pub const fn ptr(&self) -> *mut T { self.inner.ptr() } @@ -293,7 +299,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// /// This will always be `usize::MAX` if `T` is zero-sized. #[inline] - pub fn capacity(&self) -> usize { + pub const fn capacity(&self) -> usize { self.inner.capacity(size_of::<T>()) } @@ -324,6 +330,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] pub fn reserve(&mut self, len: usize, additional: usize) { self.inner.reserve(len, additional, T::LAYOUT) } @@ -332,6 +339,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// caller to ensure `len == self.capacity()`. #[cfg(not(no_global_oom_handling))] #[inline(never)] + #[track_caller] pub fn grow_one(&mut self) { self.inner.grow_one(T::LAYOUT) } @@ -359,6 +367,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] + #[track_caller] pub fn reserve_exact(&mut self, len: usize, additional: usize) { self.inner.reserve_exact(len, additional, T::LAYOUT) } @@ -383,6 +392,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] + #[track_caller] #[inline] pub fn shrink_to_fit(&mut self, cap: usize) { self.inner.shrink_to_fit(cap, T::LAYOUT) @@ -408,6 +418,7 @@ impl<A: Allocator> RawVecInner<A> { #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { @@ -432,6 +443,7 @@ impl<A: Allocator> RawVecInner<A> { #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) { Ok(res) => res, @@ -488,17 +500,17 @@ impl<A: Allocator> RawVecInner<A> { } #[inline] - fn ptr<T>(&self) -> *mut T { + const fn ptr<T>(&self) -> *mut T { self.non_null::<T>().as_ptr() } #[inline] - fn non_null<T>(&self) -> NonNull<T> { - self.ptr.cast().into() + const fn non_null<T>(&self) -> NonNull<T> { + self.ptr.cast().as_non_null_ptr() } #[inline] - fn capacity(&self, elem_size: usize) -> usize { + const fn capacity(&self, elem_size: usize) -> usize { if elem_size == 0 { usize::MAX } else { self.cap.0 } } @@ -526,6 +538,7 @@ impl<A: Allocator> RawVecInner<A> { #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) { // Callers expect this function to be very cheap when there is already sufficient capacity. // Therefore, we move all the resizing and error-handling logic from grow_amortized and @@ -550,6 +563,7 @@ impl<A: Allocator> RawVecInner<A> { #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] fn grow_one(&mut self, elem_layout: Layout) { if let Err(err) = self.grow_amortized(self.cap.0, 1, elem_layout) { handle_error(err); @@ -573,6 +587,7 @@ impl<A: Allocator> RawVecInner<A> { } #[cfg(not(no_global_oom_handling))] + #[track_caller] fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) { if let Err(err) = self.try_reserve_exact(len, additional, elem_layout) { handle_error(err); @@ -597,6 +612,7 @@ impl<A: Allocator> RawVecInner<A> { #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) { if let Err(err) = self.shrink(cap, elem_layout) { handle_error(err); @@ -770,6 +786,7 @@ where #[cfg(not(no_global_oom_handling))] #[cold] #[optimize(size)] +#[track_caller] fn handle_error(e: TryReserveError) -> ! { match e.kind() { CapacityOverflow => capacity_overflow(), diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index a92d22b1c30..e3c7835f1d1 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -19,20 +19,6 @@ use core::cmp::Ordering::{self, Less}; use core::mem::{self, MaybeUninit}; #[cfg(not(no_global_oom_handling))] use core::ptr; -#[cfg(not(no_global_oom_handling))] -use core::slice::sort; - -use crate::alloc::Allocator; -#[cfg(not(no_global_oom_handling))] -use crate::alloc::Global; -#[cfg(not(no_global_oom_handling))] -use crate::borrow::ToOwned; -use crate::boxed::Box; -use crate::vec::Vec; - -#[cfg(test)] -mod tests; - #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] @@ -43,6 +29,8 @@ pub use core::slice::ArrayWindows; pub use core::slice::EscapeAscii; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; +#[cfg(not(no_global_oom_handling))] +use core::slice::sort; #[stable(feature = "slice_group_by", since = "1.77.0")] pub use core::slice::{ChunkBy, ChunkByMut}; #[stable(feature = "rust1", since = "1.0.0")] @@ -83,6 +71,14 @@ pub use hack::into_vec; #[cfg(test)] pub use hack::to_vec; +use crate::alloc::Allocator; +#[cfg(not(no_global_oom_handling))] +use crate::alloc::Global; +#[cfg(not(no_global_oom_handling))] +use crate::borrow::ToOwned; +use crate::boxed::Box; +use crate::vec::Vec; + // HACK(japaric): With cfg(test) `impl [T]` is not available, these three // functions are actually methods that are in `impl [T]` but not in // `core::slice::SliceExt` - we need to supply these functions for the diff --git a/library/alloc/src/slice/tests.rs b/library/alloc/src/slice/tests.rs deleted file mode 100644 index 786704caeb0..00000000000 --- a/library/alloc/src/slice/tests.rs +++ /dev/null @@ -1,369 +0,0 @@ -use core::cell::Cell; -use core::cmp::Ordering::{self, Equal, Greater, Less}; -use core::convert::identity; -use core::sync::atomic::AtomicUsize; -use core::sync::atomic::Ordering::Relaxed; -use core::{fmt, mem}; -use std::panic; - -use rand::distributions::Standard; -use rand::prelude::*; -use rand::{Rng, RngCore}; - -use crate::borrow::ToOwned; -use crate::rc::Rc; -use crate::string::ToString; -use crate::test_helpers::test_rng; -use crate::vec::Vec; - -macro_rules! do_test { - ($input:ident, $func:ident) => { - let len = $input.len(); - - // Work out the total number of comparisons required to sort - // this array... - let mut count = 0usize; - $input.to_owned().$func(|a, b| { - count += 1; - a.cmp(b) - }); - - // ... and then panic on each and every single one. - for panic_countdown in 0..count { - // Refresh the counters. - VERSIONS.store(0, Relaxed); - for i in 0..len { - DROP_COUNTS[i].store(0, Relaxed); - } - - let v = $input.to_owned(); - let _ = panic::catch_unwind(move || { - let mut v = v; - let mut panic_countdown = panic_countdown; - v.$func(|a, b| { - if panic_countdown == 0 { - SILENCE_PANIC.with(|s| s.set(true)); - panic!(); - } - panic_countdown -= 1; - a.cmp(b) - }) - }); - - // Check that the number of things dropped is exactly - // what we expect (i.e., the contents of `v`). - for (i, c) in DROP_COUNTS.iter().enumerate().take(len) { - let count = c.load(Relaxed); - assert!(count == 1, "found drop count == {} for i == {}, len == {}", count, i, len); - } - - // Check that the most recent versions of values were dropped. - assert_eq!(VERSIONS.load(Relaxed), 0); - } - }; -} - -const MAX_LEN: usize = 80; - -static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [ - // FIXME(RFC 1109): AtomicUsize is not Copy. - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), - AtomicUsize::new(0), -]; - -static VERSIONS: AtomicUsize = AtomicUsize::new(0); - -#[derive(Clone, Eq)] -struct DropCounter { - x: u32, - id: usize, - version: Cell<usize>, -} - -impl PartialEq for DropCounter { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for DropCounter { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - self.version.set(self.version.get() + 1); - other.version.set(other.version.get() + 1); - VERSIONS.fetch_add(2, Relaxed); - self.x.partial_cmp(&other.x) - } -} - -impl Ord for DropCounter { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() - } -} - -impl Drop for DropCounter { - fn drop(&mut self) { - DROP_COUNTS[self.id].fetch_add(1, Relaxed); - VERSIONS.fetch_sub(self.version.get(), Relaxed); - } -} - -std::thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false)); - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] // no threads -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn panic_safe() { - panic::update_hook(move |prev, info| { - if !SILENCE_PANIC.with(|s| s.get()) { - prev(info); - } - }); - - let mut rng = test_rng(); - - // Miri is too slow (but still need to `chain` to make the types match) - let lens = if cfg!(miri) { (1..10).chain(0..0) } else { (1..20).chain(70..MAX_LEN) }; - let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] }; - - for len in lens { - for &modulus in moduli { - for &has_runs in &[false, true] { - let mut input = (0..len) - .map(|id| DropCounter { - x: rng.next_u32() % modulus, - id: id, - version: Cell::new(0), - }) - .collect::<Vec<_>>(); - - if has_runs { - for c in &mut input { - c.x = c.id as u32; - } - - for _ in 0..5 { - let a = rng.gen::<usize>() % len; - let b = rng.gen::<usize>() % len; - if a < b { - input[a..b].reverse(); - } else { - input.swap(a, b); - } - } - } - - do_test!(input, sort_by); - do_test!(input, sort_unstable_by); - } - } - } - - // Set default panic hook again. - drop(panic::take_hook()); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_sort() { - let mut rng = test_rng(); - - for len in (2..25).chain(500..510) { - for &modulus in &[5, 10, 100, 1000] { - for _ in 0..10 { - let orig: Vec<_> = (&mut rng) - .sample_iter::<i32, _>(&Standard) - .map(|x| x % modulus) - .take(len) - .collect(); - - // Sort in default order. - let mut v = orig.clone(); - v.sort(); - assert!(v.windows(2).all(|w| w[0] <= w[1])); - - // Sort in ascending order. - let mut v = orig.clone(); - v.sort_by(|a, b| a.cmp(b)); - assert!(v.windows(2).all(|w| w[0] <= w[1])); - - // Sort in descending order. - let mut v = orig.clone(); - v.sort_by(|a, b| b.cmp(a)); - assert!(v.windows(2).all(|w| w[0] >= w[1])); - - // Sort in lexicographic order. - let mut v1 = orig.clone(); - let mut v2 = orig.clone(); - v1.sort_by_key(|x| x.to_string()); - v2.sort_by_cached_key(|x| x.to_string()); - assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string())); - assert!(v1 == v2); - - // Sort with many pre-sorted runs. - let mut v = orig.clone(); - v.sort(); - v.reverse(); - for _ in 0..5 { - let a = rng.gen::<usize>() % len; - let b = rng.gen::<usize>() % len; - if a < b { - v[a..b].reverse(); - } else { - v.swap(a, b); - } - } - v.sort(); - assert!(v.windows(2).all(|w| w[0] <= w[1])); - } - } - } - - const ORD_VIOLATION_MAX_LEN: usize = 500; - let mut v = [0; ORD_VIOLATION_MAX_LEN]; - for i in 0..ORD_VIOLATION_MAX_LEN { - v[i] = i as i32; - } - - // Sort using a completely random comparison function. This will reorder the elements *somehow*, - // it may panic but the original elements must still be present. - let _ = panic::catch_unwind(move || { - v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); - }); - - v.sort(); - for i in 0..ORD_VIOLATION_MAX_LEN { - assert_eq!(v[i], i as i32); - } - - // Should not panic. - [0i32; 0].sort(); - [(); 10].sort(); - [(); 100].sort(); - - let mut v = [0xDEADBEEFu64]; - v.sort(); - assert!(v == [0xDEADBEEF]); -} - -#[test] -fn test_sort_stability() { - // Miri is too slow - let large_range = if cfg!(miri) { 0..0 } else { 500..510 }; - let rounds = if cfg!(miri) { 1 } else { 10 }; - - let mut rng = test_rng(); - for len in (2..25).chain(large_range) { - for _ in 0..rounds { - let mut counts = [0; 10]; - - // create a vector like [(6, 1), (5, 1), (6, 2), ...], - // where the first item of each tuple is random, but - // the second item represents which occurrence of that - // number this element is, i.e., the second elements - // will occur in sorted order. - let orig: Vec<_> = (0..len) - .map(|_| { - let n = rng.gen::<usize>() % 10; - counts[n] += 1; - (n, counts[n]) - }) - .collect(); - - let mut v = orig.clone(); - // Only sort on the first element, so an unstable sort - // may mix up the counts. - v.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); - - // This comparison includes the count (the second item - // of the tuple), so elements with equal first items - // will need to be ordered with increasing - // counts... i.e., exactly asserting that this sort is - // stable. - assert!(v.windows(2).all(|w| w[0] <= w[1])); - - let mut v = orig.clone(); - v.sort_by_cached_key(|&(x, _)| x); - assert!(v.windows(2).all(|w| w[0] <= w[1])); - } - } -} diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ee878e879e9..82dbf030608 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1059,7 +1059,8 @@ impl String { #[inline] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_bytes(self) -> Vec<u8> { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn into_bytes(self) -> Vec<u8> { self.vec } @@ -1076,8 +1077,11 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")] - pub fn as_str(&self) -> &str { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_str(&self) -> &str { + // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error + // at construction. + unsafe { str::from_utf8_unchecked(self.vec.as_slice()) } } /// Converts a `String` into a mutable string slice. @@ -1096,8 +1100,11 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")] - pub fn as_mut_str(&mut self) -> &mut str { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_mut_str(&mut self) -> &mut str { + // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error + // at construction. + unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) } } /// Appends a given string slice onto the end of this `String`. @@ -1168,7 +1175,8 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn capacity(&self) -> usize { self.vec.capacity() } @@ -1431,8 +1439,9 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_bytes(&self) -> &[u8] { - &self.vec + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_bytes(&self) -> &[u8] { + self.vec.as_slice() } /// Shortens this `String` to the specified length. @@ -1784,7 +1793,8 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> { &mut self.vec } @@ -1805,8 +1815,9 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_confusables("length", "size")] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.vec.len() } @@ -1824,7 +1835,8 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2589,7 +2601,7 @@ impl ops::Deref for String { #[inline] fn deref(&self) -> &str { - unsafe { str::from_utf8_unchecked(&self.vec) } + self.as_str() } } @@ -2600,7 +2612,7 @@ unsafe impl ops::DerefPure for String {} impl ops::DerefMut for String { #[inline] fn deref_mut(&mut self) -> &mut str { - unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } + self.as_mut_str() } } diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index c18091705a6..4deb35efffc 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -58,6 +58,7 @@ impl<'a, T> FromIterator<T> for Cow<'a, [T]> where T: Clone, { + #[track_caller] fn from_iter<I: IntoIterator<Item = T>>(it: I) -> Cow<'a, [T]> { Cow::Owned(FromIterator::from_iter(it)) } diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index fd94bbbdeb1..a7dba16944e 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -229,6 +229,7 @@ where I: Iterator<Item = T> + InPlaceCollect, <I as SourceIter>::Source: AsVecIntoIter, { + #[track_caller] default fn from_iter(iterator: I) -> Self { // Select the implementation in const eval to avoid codegen of the dead branch to improve compile times. let fun: fn(I) -> Vec<T> = const { @@ -246,6 +247,7 @@ where } } +#[track_caller] fn from_iter_in_place<I, T>(mut iterator: I) -> Vec<T> where I: Iterator<Item = T> + InPlaceCollect, diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1984cfeefc1..07a1bd49321 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -478,6 +478,7 @@ impl<T> Vec<T> { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_with_capacity")] + #[track_caller] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) } @@ -797,6 +798,7 @@ impl<T, A: Allocator> Vec<T, A> { #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "allocator_api", issue = "32838")] + #[track_caller] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } @@ -1240,7 +1242,8 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn capacity(&self) -> usize { self.buf.capacity() } @@ -1263,6 +1266,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); } @@ -1293,6 +1297,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn reserve_exact(&mut self, additional: usize) { self.buf.reserve_exact(self.len, additional); } @@ -1396,6 +1401,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] #[inline] pub fn shrink_to_fit(&mut self) { // The capacity is never less than the length, and there's nothing to do when @@ -1426,6 +1432,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "shrink_to", since = "1.56.0")] + #[track_caller] pub fn shrink_to(&mut self, min_capacity: usize) { if self.capacity() > min_capacity { self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); @@ -1459,6 +1466,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn into_boxed_slice(mut self) -> Box<[T], A> { unsafe { self.shrink_to_fit(); @@ -1548,8 +1556,22 @@ impl<T, A: Allocator> Vec<T, A> { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")] - pub fn as_slice(&self) -> &[T] { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_slice(&self) -> &[T] { + // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size + // `len` containing properly-initialized `T`s. Data must not be mutated for the returned + // lifetime. Further, `len * mem::size_of::<T>` <= `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 + // * is aligned, contiguous, and valid for `len` reads + // * obeys size and address-wrapping constraints + // + // * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow- + // check ensures that it is not possible to mutably alias `self.buf` within the + // returned lifetime. + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } } /// Extracts a mutable slice of the entire vector. @@ -1566,8 +1588,22 @@ impl<T, A: Allocator> Vec<T, A> { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")] - pub fn as_mut_slice(&mut self) -> &mut [T] { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + 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 * mem::size_of::<T>` <= + // `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 + // * is aligned, contiguous, and valid for `len` reads + // * obeys size and address-wrapping constraints + // + // * We only construct references to `self.buf` through `&self` and `&mut self` methods; + // borrow-check ensures that it is not possible to construct a reference to `self.buf` + // within the returned lifetime. + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } } /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer @@ -1624,9 +1660,10 @@ impl<T, A: Allocator> Vec<T, A> { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] #[inline] - pub fn as_ptr(&self) -> *const T { + pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through // `deref`, which creates an intermediate reference. self.buf.ptr() @@ -1685,9 +1722,10 @@ impl<T, A: Allocator> Vec<T, A> { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] #[inline] - pub fn as_mut_ptr(&mut self) -> *mut T { + pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through // `deref_mut`, which creates an intermediate reference. self.buf.ptr() @@ -1927,6 +1965,7 @@ impl<T, A: Allocator> Vec<T, A> { /// the insertion index is 0. #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn insert(&mut self, index: usize, element: T) { #[cold] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] @@ -2366,6 +2405,7 @@ impl<T, A: Allocator> Vec<T, A> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push_back", "put", "append")] + #[track_caller] pub fn push(&mut self, value: T) { // Inform codegen that the length does not change across grow_one(). let len = self.len; @@ -2507,6 +2547,7 @@ impl<T, A: Allocator> Vec<T, A> { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "append", since = "1.4.0")] + #[track_caller] pub fn append(&mut self, other: &mut Self) { unsafe { self.append_elements(other.as_slice() as _); @@ -2517,6 +2558,7 @@ impl<T, A: Allocator> Vec<T, A> { /// Appends elements to `self` from other buffer. #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] unsafe fn append_elements(&mut self, other: *const [T]) { let count = unsafe { (*other).len() }; self.reserve(count); @@ -2628,8 +2670,9 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_confusables("length", "size")] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.len } @@ -2646,7 +2689,8 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2678,6 +2722,7 @@ impl<T, A: Allocator> Vec<T, A> { #[inline] #[must_use = "use `.truncate()` if you don't need the other half"] #[stable(feature = "split_off", since = "1.4.0")] + #[track_caller] pub fn split_off(&mut self, at: usize) -> Self where A: Clone, @@ -2735,6 +2780,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_resize_with", since = "1.33.0")] + #[track_caller] pub fn resize_with<F>(&mut self, new_len: usize, f: F) where F: FnMut() -> T, @@ -2940,6 +2986,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_resize", since = "1.5.0")] + #[track_caller] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); @@ -2971,6 +3018,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> { /// [`extend`]: Vec::extend #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] + #[track_caller] pub fn extend_from_slice(&mut self, other: &[T]) { self.spec_extend(other.iter()) } @@ -2998,6 +3046,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_extend_from_within", since = "1.53.0")] + #[track_caller] pub fn extend_from_within<R>(&mut self, src: R) where R: RangeBounds<usize>, @@ -3058,6 +3107,7 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> { impl<T: Clone, A: Allocator> Vec<T, A> { #[cfg(not(no_global_oom_handling))] + #[track_caller] /// Extend the vector by `n` clones of value. fn extend_with(&mut self, n: usize, value: T) { self.reserve(n); @@ -3118,6 +3168,7 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_from_elem")] +#[track_caller] pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> { <T as SpecFromElem>::from_elem(elem, n, Global) } @@ -3125,6 +3176,7 @@ pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> { #[doc(hidden)] #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] +#[track_caller] pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> { <T as SpecFromElem>::from_elem(elem, n, alloc) } @@ -3197,7 +3249,7 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> { #[inline] fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + self.as_slice() } } @@ -3205,7 +3257,7 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> { impl<T, A: Allocator> ops::DerefMut for Vec<T, A> { #[inline] fn deref_mut(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + self.as_mut_slice() } } @@ -3216,6 +3268,7 @@ unsafe impl<T, A: Allocator> ops::DerefPure for Vec<T, A> {} #[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { #[cfg(not(test))] + #[track_caller] fn clone(&self) -> Self { let alloc = self.allocator().clone(); <[T]>::to_vec_in(&**self, alloc) @@ -3253,6 +3306,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { /// // And no reallocation occurred /// assert_eq!(yp, y.as_ptr()); /// ``` + #[track_caller] fn clone_from(&mut self, source: &Self) { crate::slice::SpecCloneIntoVec::clone_into(source.as_slice(), self); } @@ -3351,6 +3405,7 @@ impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T> FromIterator<T> for Vec<T> { #[inline] + #[track_caller] fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> { <Self as SpecFromIter<T, I::IntoIter>>::from_iter(iter.into_iter()) } @@ -3419,16 +3474,19 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T, A: Allocator> Extend<T> for Vec<T, A> { #[inline] + #[track_caller] fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { <Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter()) } #[inline] + #[track_caller] fn extend_one(&mut self, item: T) { self.push(item); } #[inline] + #[track_caller] fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } @@ -3448,6 +3506,7 @@ impl<T, A: Allocator> Vec<T, A> { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply #[cfg(not(no_global_oom_handling))] + #[track_caller] fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) { // This is the case for a general iterator. // @@ -3475,6 +3534,7 @@ impl<T, A: Allocator> Vec<T, A> { // specific extend for `TrustedLen` iterators, called both by the specializations // and internal places where resolving specialization makes compilation slower #[cfg(not(no_global_oom_handling))] + #[track_caller] fn extend_trusted(&mut self, iterator: impl iter::TrustedLen<Item = T>) { let (low, high) = iterator.size_hint(); if let Some(additional) = high { @@ -3625,16 +3685,19 @@ impl<T, A: Allocator> Vec<T, A> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec<T, A> { + #[track_caller] fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { self.spec_extend(iter.into_iter()) } #[inline] + #[track_caller] fn extend_one(&mut self, &item: &'a T) { self.push(item); } #[inline] + #[track_caller] fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } @@ -3745,6 +3808,7 @@ impl<T: Clone> From<&[T]> for Vec<T> { /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); /// ``` #[cfg(not(test))] + #[track_caller] fn from(s: &[T]) -> Vec<T> { s.to_vec() } @@ -3765,6 +3829,7 @@ impl<T: Clone> From<&mut [T]> for Vec<T> { /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); /// ``` #[cfg(not(test))] + #[track_caller] fn from(s: &mut [T]) -> Vec<T> { s.to_vec() } @@ -3784,6 +3849,7 @@ impl<T: Clone, const N: usize> From<&[T; N]> for Vec<T> { /// ``` /// assert_eq!(Vec::from(&[1, 2, 3]), vec![1, 2, 3]); /// ``` + #[track_caller] fn from(s: &[T; N]) -> Vec<T> { Self::from(s.as_slice()) } @@ -3799,6 +3865,7 @@ impl<T: Clone, const N: usize> From<&mut [T; N]> for Vec<T> { /// ``` /// assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]); /// ``` + #[track_caller] fn from(s: &mut [T; N]) -> Vec<T> { Self::from(s.as_mut_slice()) } @@ -3815,6 +3882,7 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> { /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); /// ``` #[cfg(not(test))] + #[track_caller] fn from(s: [T; N]) -> Vec<T> { <[T]>::into_vec(Box::new(s)) } @@ -3844,6 +3912,7 @@ where /// let b: Cow<'_, [i32]> = Cow::Borrowed(&[1, 2, 3]); /// assert_eq!(Vec::from(o), Vec::from(b)); /// ``` + #[track_caller] fn from(s: Cow<'a, [T]>) -> Vec<T> { s.into_owned() } @@ -3892,6 +3961,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> { /// /// assert_eq!(Box::from(vec), vec![1, 2, 3].into_boxed_slice()); /// ``` + #[track_caller] fn from(v: Vec<T, A>) -> Self { v.into_boxed_slice() } @@ -3907,6 +3977,7 @@ impl From<&str> for Vec<u8> { /// ``` /// assert_eq!(Vec::from("123"), vec![b'1', b'2', b'3']); /// ``` + #[track_caller] fn from(s: &str) -> Vec<u8> { From::from(s.as_bytes()) } diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 7085bceef5b..b98db669059 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -6,6 +6,7 @@ use crate::alloc::Allocator; // Specialization trait used for Vec::extend pub(super) trait SpecExtend<T, I> { + #[track_caller] fn spec_extend(&mut self, iter: I); } @@ -13,6 +14,7 @@ impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A> where I: Iterator<Item = T>, { + #[track_caller] default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter) } @@ -22,12 +24,14 @@ impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A> where I: TrustedLen<Item = T>, { + #[track_caller] default fn spec_extend(&mut self, iterator: I) { self.extend_trusted(iterator) } } impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> { + #[track_caller] fn spec_extend(&mut self, mut iterator: IntoIter<T>) { unsafe { self.append_elements(iterator.as_slice() as _); @@ -41,6 +45,7 @@ where I: Iterator<Item = &'a T>, T: Clone, { + #[track_caller] default fn spec_extend(&mut self, iterator: I) { self.spec_extend(iterator.cloned()) } @@ -50,6 +55,7 @@ impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A where T: Copy, { + #[track_caller] fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { let slice = iterator.as_slice(); unsafe { self.append_elements(slice) }; diff --git a/library/alloc/src/vec/spec_from_elem.rs b/library/alloc/src/vec/spec_from_elem.rs index 96d701e15d4..6c7b4d89f2d 100644 --- a/library/alloc/src/vec/spec_from_elem.rs +++ b/library/alloc/src/vec/spec_from_elem.rs @@ -10,6 +10,7 @@ pub(super) trait SpecFromElem: Sized { } impl<T: Clone> SpecFromElem for T { + #[track_caller] default fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A> { let mut v = Vec::with_capacity_in(n, alloc); v.extend_with(n, elem); @@ -19,6 +20,7 @@ impl<T: Clone> SpecFromElem for T { impl<T: Clone + IsZero> SpecFromElem for T { #[inline] + #[track_caller] default fn from_elem<A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> { if elem.is_zero() { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; @@ -31,6 +33,7 @@ impl<T: Clone + IsZero> SpecFromElem for T { impl SpecFromElem for i8 { #[inline] + #[track_caller] fn from_elem<A: Allocator>(elem: i8, n: usize, alloc: A) -> Vec<i8, A> { if elem == 0 { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; @@ -46,6 +49,7 @@ impl SpecFromElem for i8 { impl SpecFromElem for u8 { #[inline] + #[track_caller] fn from_elem<A: Allocator>(elem: u8, n: usize, alloc: A) -> Vec<u8, A> { if elem == 0 { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index e1f0b639bdf..ad7688e1c59 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -29,12 +29,14 @@ impl<T, I> SpecFromIter<T, I> for Vec<T> where I: Iterator<Item = T>, { + #[track_caller] default fn from_iter(iterator: I) -> Self { SpecFromIterNested::from_iter(iterator) } } impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> { + #[track_caller] fn from_iter(iterator: IntoIter<T>) -> Self { // A common case is passing a vector into a function which immediately // re-collects into a vector. We can short circuit this if the IntoIter diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs index 77f7761d22f..22eed238798 100644 --- a/library/alloc/src/vec/spec_from_iter_nested.rs +++ b/library/alloc/src/vec/spec_from_iter_nested.rs @@ -15,6 +15,7 @@ impl<T, I> SpecFromIterNested<T, I> for Vec<T> where I: Iterator<Item = T>, { + #[track_caller] default fn from_iter(mut iterator: I) -> Self { // Unroll the first iteration, as the vector is going to be // expanded on this iteration in every case when the iterable is not @@ -47,6 +48,7 @@ impl<T, I> SpecFromIterNested<T, I> for Vec<T> where I: TrustedLen<Item = T>, { + #[track_caller] fn from_iter(iterator: I) -> Self { let mut vector = match iterator.size_hint() { (_, Some(upper)) => Vec::with_capacity(upper), diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs index 9e36377c148..ca5cb17f8bf 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -52,6 +52,7 @@ impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {} #[stable(feature = "vec_splice", since = "1.21.0")] impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> { + #[track_caller] fn drop(&mut self) { self.drain.by_ref().for_each(drop); // At this point draining is done and the only remaining tasks are splicing @@ -123,6 +124,7 @@ impl<T, A: Allocator> Drain<'_, T, A> { } /// Makes room for inserting more elements before the tail. + #[track_caller] unsafe fn move_tail(&mut self, additional: usize) { let vec = unsafe { self.vec.as_mut() }; let len = self.tail_start + self.tail_len; diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 1d07a7690da..3ec4332c71b 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -4,11 +4,8 @@ #![feature(assert_matches)] #![feature(btree_extract_if)] #![feature(cow_is_borrowed)] -#![feature(const_cow_is_borrowed)] #![feature(const_heap)] #![cfg_attr(bootstrap, feature(const_mut_refs))] -#![feature(const_slice_from_raw_parts_mut)] -#![feature(const_ptr_write)] #![feature(const_try)] #![feature(core_intrinsics)] #![feature(extract_if)] @@ -41,6 +38,7 @@ #![feature(local_waker)] #![feature(vec_pop_if)] #![feature(unique_rc_arc)] +#![feature(macro_metavar_expr_concat)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] @@ -60,6 +58,7 @@ mod heap; mod linked_list; mod rc; mod slice; +mod sort; mod str; mod string; mod task; diff --git a/library/alloc/tests/sort/ffi_types.rs b/library/alloc/tests/sort/ffi_types.rs new file mode 100644 index 00000000000..11515ea4769 --- /dev/null +++ b/library/alloc/tests/sort/ffi_types.rs @@ -0,0 +1,82 @@ +use std::cmp::Ordering; + +// Very large stack value. +#[repr(C)] +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct FFIOneKibiByte { + values: [i64; 128], +} + +impl FFIOneKibiByte { + pub fn new(val: i32) -> Self { + let mut values = [0i64; 128]; + let mut val_i64 = val as i64; + + for elem in &mut values { + *elem = val_i64; + val_i64 = std::hint::black_box(val_i64 + 1); + } + Self { values } + } + + fn as_i64(&self) -> i64 { + self.values[11] + self.values[55] + self.values[77] + } +} + +impl PartialOrd for FFIOneKibiByte { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for FFIOneKibiByte { + fn cmp(&self, other: &Self) -> Ordering { + self.as_i64().cmp(&other.as_i64()) + } +} + +// 16 byte stack value, with more expensive comparison. +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub struct F128 { + x: f64, + y: f64, +} + +impl F128 { + pub fn new(val: i32) -> Self { + let val_f = (val as f64) + (i32::MAX as f64) + 10.0; + + let x = val_f + 0.1; + let y = val_f.log(4.1); + + assert!(y < x); + assert!(x.is_normal() && y.is_normal()); + + Self { x, y } + } +} + +// This is kind of hacky, but we know we only have normal comparable floats in there. +impl Eq for F128 {} + +impl PartialOrd for F128 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +// Goal is similar code-gen between Rust and C++ +// - Rust https://godbolt.org/z/3YM3xenPP +// - C++ https://godbolt.org/z/178M6j1zz +impl Ord for F128 { + fn cmp(&self, other: &Self) -> Ordering { + // Simulate expensive comparison function. + let this_div = self.x / self.y; + let other_div = other.x / other.y; + + // SAFETY: We checked in the ctor that both are normal. + unsafe { this_div.partial_cmp(&other_div).unwrap_unchecked() } + } +} diff --git a/library/alloc/tests/sort/known_good_stable_sort.rs b/library/alloc/tests/sort/known_good_stable_sort.rs new file mode 100644 index 00000000000..f8615435fc2 --- /dev/null +++ b/library/alloc/tests/sort/known_good_stable_sort.rs @@ -0,0 +1,192 @@ +// This module implements a known good stable sort implementation that helps provide better error +// messages when the correctness tests fail, we can't use the stdlib sort functions because we are +// testing them for correctness. +// +// Based on https://github.com/voultapher/tiny-sort-rs. + +use alloc::alloc::{Layout, alloc, dealloc}; +use std::{mem, ptr}; + +/// Sort `v` preserving initial order of equal elements. +/// +/// - Guaranteed O(N * log(N)) worst case perf +/// - No adaptiveness +/// - Branch miss-prediction not affected by outcome of comparison function +/// - Uses `v.len()` auxiliary memory. +/// +/// If `T: Ord` does not implement a total order the resulting order is +/// unspecified. All original elements will remain in `v` and any possible modifications via +/// interior mutability will be observable. Same is true if `T: Ord` panics. +/// +/// Panics if allocating the auxiliary memory fails. +#[inline(always)] +pub fn sort<T: Ord>(v: &mut [T]) { + stable_sort(v, |a, b| a.lt(b)) +} + +#[inline(always)] +fn stable_sort<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], mut is_less: F) { + if mem::size_of::<T>() == 0 { + return; + } + + let len = v.len(); + + // Inline the check for len < 2. This happens a lot, instrumenting the Rust compiler suggests + // len < 2 accounts for 94% of its calls to `slice::sort`. + if len < 2 { + return; + } + + // SAFETY: We checked that len is > 0 and that T is not a ZST. + unsafe { + mergesort_main(v, &mut is_less); + } +} + +/// The core logic should not be inlined. +/// +/// SAFETY: The caller has to ensure that len is > 0 and that T is not a ZST. +#[inline(never)] +unsafe fn mergesort_main<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) { + // While it would be nice to have a merge implementation that only requires N / 2 auxiliary + // memory. Doing so would make the merge implementation significantly more complex and + + // SAFETY: See function safety description. + let buf = unsafe { BufGuard::new(v.len()) }; + + // SAFETY: `scratch` has space for `v.len()` writes. And does not alias `v`. + unsafe { + mergesort_core(v, buf.buf_ptr.as_ptr(), is_less); + } +} + +/// Tiny recursive top-down merge sort optimized for binary size. It has no adaptiveness whatsoever, +/// no run detection, etc. +/// +/// Buffer as pointed to by `scratch` must have space for `v.len()` writes. And must not alias `v`. +#[inline(always)] +unsafe fn mergesort_core<T, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch_ptr: *mut T, + is_less: &mut F, +) { + let len = v.len(); + + if len > 2 { + // SAFETY: `mid` is guaranteed in-bounds. And caller has to ensure that `scratch_ptr` can + // hold `v.len()` values. + unsafe { + let mid = len / 2; + // Sort the left half recursively. + mergesort_core(v.get_unchecked_mut(..mid), scratch_ptr, is_less); + // Sort the right half recursively. + mergesort_core(v.get_unchecked_mut(mid..), scratch_ptr, is_less); + // Combine the two halves. + merge(v, scratch_ptr, is_less, mid); + } + } else if len == 2 { + if is_less(&v[1], &v[0]) { + v.swap(0, 1); + } + } +} + +/// Branchless merge function. +/// +/// SAFETY: The caller must ensure that `scratch_ptr` is valid for `v.len()` writes. And that mid is +/// in-bounds. +#[inline(always)] +unsafe fn merge<T, F>(v: &mut [T], scratch_ptr: *mut T, is_less: &mut F, mid: usize) +where + F: FnMut(&T, &T) -> bool, +{ + let len = v.len(); + debug_assert!(mid > 0 && mid < len); + + let len = v.len(); + + // Indexes to track the positions while merging. + let mut l = 0; + let mut r = mid; + + // SAFETY: No matter what the result of is_less is we check that l and r remain in-bounds and if + // is_less panics the original elements remain in `v`. + unsafe { + let arr_ptr = v.as_ptr(); + + for i in 0..len { + let left_ptr = arr_ptr.add(l); + let right_ptr = arr_ptr.add(r); + + let is_lt = !is_less(&*right_ptr, &*left_ptr); + let copy_ptr = if is_lt { left_ptr } else { right_ptr }; + ptr::copy_nonoverlapping(copy_ptr, scratch_ptr.add(i), 1); + + l += is_lt as usize; + r += !is_lt as usize; + + // As long as neither side is exhausted merge left and right elements. + if ((l == mid) as u8 + (r == len) as u8) != 0 { + break; + } + } + + // The left or right side is exhausted, drain the right side in one go. + let copy_ptr = if l == mid { arr_ptr.add(r) } else { arr_ptr.add(l) }; + let i = l + (r - mid); + ptr::copy_nonoverlapping(copy_ptr, scratch_ptr.add(i), len - i); + + // Now that scratch_ptr holds the full merged content, write it back on-top of v. + ptr::copy_nonoverlapping(scratch_ptr, v.as_mut_ptr(), len); + } +} + +// SAFETY: The caller has to ensure that Option is Some, UB otherwise. +unsafe fn unwrap_unchecked<T>(opt_val: Option<T>) -> T { + match opt_val { + Some(val) => val, + None => { + // SAFETY: See function safety description. + unsafe { + core::hint::unreachable_unchecked(); + } + } + } +} + +// Extremely basic versions of Vec. +// Their use is super limited and by having the code here, it allows reuse between the sort +// implementations. +struct BufGuard<T> { + buf_ptr: ptr::NonNull<T>, + capacity: usize, +} + +impl<T> BufGuard<T> { + // SAFETY: The caller has to ensure that len is not 0 and that T is not a ZST. + unsafe fn new(len: usize) -> Self { + debug_assert!(len > 0 && mem::size_of::<T>() > 0); + + // SAFETY: See function safety description. + let layout = unsafe { unwrap_unchecked(Layout::array::<T>(len).ok()) }; + + // SAFETY: We checked that T is not a ZST. + let buf_ptr = unsafe { alloc(layout) as *mut T }; + + if buf_ptr.is_null() { + panic!("allocation failure"); + } + + Self { buf_ptr: ptr::NonNull::new(buf_ptr).unwrap(), capacity: len } + } +} + +impl<T> Drop for BufGuard<T> { + fn drop(&mut self) { + // SAFETY: We checked that T is not a ZST. + unsafe { + dealloc(self.buf_ptr.as_ptr() as *mut u8, Layout::array::<T>(self.capacity).unwrap()); + } + } +} diff --git a/library/alloc/tests/sort/mod.rs b/library/alloc/tests/sort/mod.rs new file mode 100644 index 00000000000..0e2494ca9d3 --- /dev/null +++ b/library/alloc/tests/sort/mod.rs @@ -0,0 +1,17 @@ +pub trait Sort { + fn name() -> String; + + fn sort<T>(v: &mut [T]) + where + T: Ord; + + fn sort_by<T, F>(v: &mut [T], compare: F) + where + F: FnMut(&T, &T) -> std::cmp::Ordering; +} + +mod ffi_types; +mod known_good_stable_sort; +mod patterns; +mod tests; +mod zipf; diff --git a/library/alloc/tests/sort/patterns.rs b/library/alloc/tests/sort/patterns.rs new file mode 100644 index 00000000000..e5d31d868b2 --- /dev/null +++ b/library/alloc/tests/sort/patterns.rs @@ -0,0 +1,211 @@ +use std::env; +use std::hash::Hash; +use std::str::FromStr; +use std::sync::OnceLock; + +use rand::prelude::*; +use rand_xorshift::XorShiftRng; + +use crate::sort::zipf::ZipfDistribution; + +/// Provides a set of patterns useful for testing and benchmarking sorting algorithms. +/// Currently limited to i32 values. + +// --- Public --- + +pub fn random(len: usize) -> Vec<i32> { + // . + // : . : : + // :.:::.:: + + random_vec(len) +} + +pub fn random_uniform<R>(len: usize, range: R) -> Vec<i32> +where + R: Into<rand::distributions::Uniform<i32>> + Hash, +{ + // :.:.:.:: + + let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + + // Abstracting over ranges in Rust :( + let dist: rand::distributions::Uniform<i32> = range.into(); + (0..len).map(|_| dist.sample(&mut rng)).collect() +} + +pub fn random_zipf(len: usize, exponent: f64) -> Vec<i32> { + // https://en.wikipedia.org/wiki/Zipf's_law + + let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + + // Abstracting over ranges in Rust :( + let dist = ZipfDistribution::new(len, exponent).unwrap(); + (0..len).map(|_| dist.sample(&mut rng) as i32).collect() +} + +pub fn random_sorted(len: usize, sorted_percent: f64) -> Vec<i32> { + // .: + // .:::. : + // .::::::.:: + // [----][--] + // ^ ^ + // | | + // sorted | + // unsorted + + // Simulate pre-existing sorted slice, where len - sorted_percent are the new unsorted values + // and part of the overall distribution. + let mut v = random_vec(len); + let sorted_len = ((len as f64) * (sorted_percent / 100.0)).round() as usize; + + v[0..sorted_len].sort_unstable(); + + v +} + +pub fn all_equal(len: usize) -> Vec<i32> { + // ...... + // :::::: + + (0..len).map(|_| 66).collect::<Vec<_>>() +} + +pub fn ascending(len: usize) -> Vec<i32> { + // .: + // .::: + // .::::: + + (0..len as i32).collect::<Vec<_>>() +} + +pub fn descending(len: usize) -> Vec<i32> { + // :. + // :::. + // :::::. + + (0..len as i32).rev().collect::<Vec<_>>() +} + +pub fn saw_mixed(len: usize, saw_count: usize) -> Vec<i32> { + // :. :. .::. .: + // :::.:::..::::::..::: + + if len == 0 { + return Vec::new(); + } + + let mut vals = random_vec(len); + let chunks_size = len / saw_count.max(1); + let saw_directions = random_uniform((len / chunks_size) + 1, 0..=1); + + for (i, chunk) in vals.chunks_mut(chunks_size).enumerate() { + if saw_directions[i] == 0 { + chunk.sort_unstable(); + } else if saw_directions[i] == 1 { + chunk.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); + } else { + unreachable!(); + } + } + + vals +} + +pub fn saw_mixed_range(len: usize, range: std::ops::Range<usize>) -> Vec<i32> { + // :. + // :. :::. .::. .: + // :::.:::::..::::::..:.::: + + // ascending and descending randomly picked, with length in `range`. + + if len == 0 { + return Vec::new(); + } + + let mut vals = random_vec(len); + + let max_chunks = len / range.start; + let saw_directions = random_uniform(max_chunks + 1, 0..=1); + let chunk_sizes = random_uniform(max_chunks + 1, (range.start as i32)..(range.end as i32)); + + let mut i = 0; + let mut l = 0; + while l < len { + let chunk_size = chunk_sizes[i] as usize; + let chunk_end = std::cmp::min(l + chunk_size, len); + let chunk = &mut vals[l..chunk_end]; + + if saw_directions[i] == 0 { + chunk.sort_unstable(); + } else if saw_directions[i] == 1 { + chunk.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); + } else { + unreachable!(); + } + + i += 1; + l += chunk_size; + } + + vals +} + +pub fn pipe_organ(len: usize) -> Vec<i32> { + // .:. + // .:::::. + + let mut vals = random_vec(len); + + let first_half = &mut vals[0..(len / 2)]; + first_half.sort_unstable(); + + let second_half = &mut vals[(len / 2)..len]; + second_half.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); + + vals +} + +pub fn get_or_init_rand_seed() -> u64 { + *SEED_VALUE.get_or_init(|| { + env::var("OVERRIDE_SEED") + .ok() + .map(|seed| u64::from_str(&seed).unwrap()) + .unwrap_or_else(rand_root_seed) + }) +} + +// --- Private --- + +static SEED_VALUE: OnceLock<u64> = OnceLock::new(); + +#[cfg(not(miri))] +fn rand_root_seed() -> u64 { + // Other test code hashes `panic::Location::caller()` and constructs a seed from that, in these + // tests we want to have a fuzzer like exploration of the test space, if we used the same caller + // based construction we would always test the same. + // + // Instead we use the seconds since UNIX epoch / 10, given CI log output this value should be + // reasonably easy to re-construct. + + use std::time::{SystemTime, UNIX_EPOCH}; + + let epoch_seconds = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); + + epoch_seconds / 10 +} + +#[cfg(miri)] +fn rand_root_seed() -> u64 { + // Miri is usually run with isolation with gives us repeatability but also permutations based on + // other code that runs before. + use core::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + core::panic::Location::caller().hash(&mut hasher); + hasher.finish() +} + +fn random_vec(len: usize) -> Vec<i32> { + let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + (0..len).map(|_| rng.gen::<i32>()).collect() +} diff --git a/library/alloc/tests/sort/tests.rs b/library/alloc/tests/sort/tests.rs new file mode 100644 index 00000000000..14e6013f965 --- /dev/null +++ b/library/alloc/tests/sort/tests.rs @@ -0,0 +1,1233 @@ +use std::cell::Cell; +use std::cmp::Ordering; +use std::fmt::Debug; +use std::panic::{self, AssertUnwindSafe}; +use std::rc::Rc; +use std::{env, fs}; + +use crate::sort::ffi_types::{F128, FFIOneKibiByte}; +use crate::sort::{Sort, known_good_stable_sort, patterns}; + +#[cfg(miri)] +const TEST_LENGTHS: &[usize] = &[2, 3, 4, 7, 10, 15, 20, 24, 33, 50, 100, 171, 300]; + +#[cfg(not(miri))] +const TEST_LENGTHS: &[usize] = &[ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000, + 2_048, 5_000, 10_000, 100_000, 1_100_000, +]; + +fn check_is_sorted<T: Ord + Clone + Debug, S: Sort>(v: &mut [T]) { + let seed = patterns::get_or_init_rand_seed(); + + let is_small_test = v.len() <= 100; + let v_orig = v.to_vec(); + + <S as Sort>::sort(v); + + assert_eq!(v.len(), v_orig.len()); + + for window in v.windows(2) { + if window[0] > window[1] { + let mut known_good_sorted_vec = v_orig.clone(); + known_good_stable_sort::sort(known_good_sorted_vec.as_mut_slice()); + + if is_small_test { + eprintln!("Orginal: {:?}", v_orig); + eprintln!("Expected: {:?}", known_good_sorted_vec); + eprintln!("Got: {:?}", v); + } else { + if env::var("WRITE_LARGE_FAILURE").is_ok() { + // Large arrays output them as files. + let original_name = format!("original_{}.txt", seed); + let std_name = format!("known_good_sorted_{}.txt", seed); + let testsort_name = format!("{}_sorted_{}.txt", S::name(), seed); + + fs::write(&original_name, format!("{:?}", v_orig)).unwrap(); + fs::write(&std_name, format!("{:?}", known_good_sorted_vec)).unwrap(); + fs::write(&testsort_name, format!("{:?}", v)).unwrap(); + + eprintln!( + "Failed comparison, see files {original_name}, {std_name}, and {testsort_name}" + ); + } else { + eprintln!( + "Failed comparison, re-run with WRITE_LARGE_FAILURE env var set, to get output." + ); + } + } + + panic!("Test assertion failed!") + } + } +} + +fn test_is_sorted<T: Ord + Clone + Debug, S: Sort>( + test_len: usize, + map_fn: impl Fn(i32) -> T, + pattern_fn: impl Fn(usize) -> Vec<i32>, +) { + let mut test_data: Vec<T> = pattern_fn(test_len).into_iter().map(map_fn).collect(); + check_is_sorted::<T, S>(test_data.as_mut_slice()); +} + +trait DynTrait: Debug { + fn get_val(&self) -> i32; +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct DynValA { + value: i32, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct DynValB { + value: u64, +} + +impl DynTrait for DynValA { + fn get_val(&self) -> i32 { + self.value + } +} +impl DynTrait for DynValB { + fn get_val(&self) -> i32 { + let bytes = self.value.to_ne_bytes(); + i32::from_ne_bytes([bytes[0], bytes[1], bytes[6], bytes[7]]) + } +} + +impl PartialOrd for dyn DynTrait { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for dyn DynTrait { + fn cmp(&self, other: &Self) -> Ordering { + self.get_val().cmp(&other.get_val()) + } +} + +impl PartialEq for dyn DynTrait { + fn eq(&self, other: &Self) -> bool { + self.get_val() == other.get_val() + } +} + +impl Eq for dyn DynTrait {} + +fn shift_i32_to_u32(val: i32) -> u32 { + (val as i64 + (i32::MAX as i64 + 1)) as u32 +} + +fn reverse_shift_i32_to_u32(val: u32) -> i32 { + (val as i64 - (i32::MAX as i64 + 1)) as i32 +} + +fn extend_i32_to_u64(val: i32) -> u64 { + // Extends the value into the 64 bit range, + // while preserving input order. + (shift_i32_to_u32(val) as u64) * i32::MAX as u64 +} + +fn extend_i32_to_u128(val: i32) -> u128 { + // Extends the value into the 64 bit range, + // while preserving input order. + (shift_i32_to_u32(val) as u128) * i64::MAX as u128 +} + +fn dyn_trait_from_i32(val: i32) -> Rc<dyn DynTrait> { + if val % 2 == 0 { + Rc::new(DynValA { value: val }) + } else { + Rc::new(DynValB { value: extend_i32_to_u64(val) }) + } +} + +fn i32_from_i32(val: i32) -> i32 { + val +} + +fn i32_from_i32_ref(val: &i32) -> i32 { + *val +} + +fn string_from_i32(val: i32) -> String { + format!("{:010}", shift_i32_to_u32(val)) +} + +fn i32_from_string(val: &String) -> i32 { + reverse_shift_i32_to_u32(val.parse::<u32>().unwrap()) +} + +fn cell_i32_from_i32(val: i32) -> Cell<i32> { + Cell::new(val) +} + +fn i32_from_cell_i32(val: &Cell<i32>) -> i32 { + val.get() +} + +fn calc_comps_required<T, S: Sort>(v: &mut [T], mut cmp_fn: impl FnMut(&T, &T) -> Ordering) -> u32 { + let mut comp_counter = 0u32; + + <S as Sort>::sort_by(v, |a, b| { + comp_counter += 1; + + cmp_fn(a, b) + }); + + comp_counter +} + +#[derive(PartialEq, Eq, Debug, Clone)] +#[repr(C)] +struct CompCount { + val: i32, + comp_count: Cell<u32>, +} + +impl CompCount { + fn new(val: i32) -> Self { + Self { val, comp_count: Cell::new(0) } + } +} + +/// Generates $base_name_pattern_name_impl functions calling the test_fns for all test_len. +macro_rules! gen_sort_test_fns { + ( + $base_name:ident, + $test_fn:expr, + $test_lengths:expr, + [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? + ) => { + $(fn ${concat($base_name, _, $pattern_name, _impl)}<S: Sort>() { + for test_len in $test_lengths { + $test_fn(*test_len, $pattern_fn); + } + })* + }; +} + +/// Generates $base_name_pattern_name_impl functions calling the test_fns for all test_len, +/// with a default set of patterns that can be extended by the caller. +macro_rules! gen_sort_test_fns_with_default_patterns { + ( + $base_name:ident, + $test_fn:expr, + $test_lengths:expr, + [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? + ) => { + gen_sort_test_fns!( + $base_name, + $test_fn, + $test_lengths, + [ + (random, patterns::random), + (random_z1, |len| patterns::random_zipf(len, 1.0)), + (random_d2, |len| patterns::random_uniform(len, 0..2)), + (random_d20, |len| patterns::random_uniform(len, 0..16)), + (random_s95, |len| patterns::random_sorted(len, 95.0)), + (ascending, patterns::ascending), + (descending, patterns::descending), + (saw_mixed, |len| patterns::saw_mixed( + len, + ((len as f64).log2().round()) as usize + )), + $(($pattern_name, $pattern_fn),)* + ] + ); + }; +} + +/// Generates $base_name_type_pattern_name_impl functions calling the test_fns for all test_len for +/// three types that cover the core specialization differences in the sort implementations, with a +/// default set of patterns that can be extended by the caller. +macro_rules! gen_sort_test_fns_with_default_patterns_3_ty { + ( + $base_name:ident, + $test_fn:ident, + [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? + ) => { + gen_sort_test_fns_with_default_patterns!( + ${concat($base_name, _i32)}, + |len, pattern_fn| $test_fn::<i32, S>(len, i32_from_i32, i32_from_i32_ref, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [$(($pattern_name, $pattern_fn),)*], + ); + + gen_sort_test_fns_with_default_patterns!( + ${concat($base_name, _cell_i32)}, + |len, pattern_fn| $test_fn::<Cell<i32>, S>(len, cell_i32_from_i32, i32_from_cell_i32, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 3], + [$(($pattern_name, $pattern_fn),)*], + ); + + gen_sort_test_fns_with_default_patterns!( + ${concat($base_name, _string)}, + |len, pattern_fn| $test_fn::<String, S>(len, string_from_i32, i32_from_string, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 3], + [$(($pattern_name, $pattern_fn),)*], + ); + }; +} + +// --- TESTS --- + +pub fn basic_impl<S: Sort>() { + check_is_sorted::<i32, S>(&mut []); + check_is_sorted::<(), S>(&mut []); + check_is_sorted::<(), S>(&mut [()]); + check_is_sorted::<(), S>(&mut [(), ()]); + check_is_sorted::<(), S>(&mut [(), (), ()]); + check_is_sorted::<i32, S>(&mut []); + check_is_sorted::<i32, S>(&mut [77]); + check_is_sorted::<i32, S>(&mut [2, 3]); + check_is_sorted::<i32, S>(&mut [2, 3, 6]); + check_is_sorted::<i32, S>(&mut [2, 3, 99, 6]); + check_is_sorted::<i32, S>(&mut [2, 7709, 400, 90932]); + check_is_sorted::<i32, S>(&mut [15, -1, 3, -1, -3, -1, 7]); +} + +fn fixed_seed_impl<S: Sort>() { + let fixed_seed_a = patterns::get_or_init_rand_seed(); + let fixed_seed_b = patterns::get_or_init_rand_seed(); + + assert_eq!(fixed_seed_a, fixed_seed_b); +} + +fn fixed_seed_rand_vec_prefix_impl<S: Sort>() { + let vec_rand_len_5 = patterns::random(5); + let vec_rand_len_7 = patterns::random(7); + + assert_eq!(vec_rand_len_5, vec_rand_len_7[..5]); +} + +fn int_edge_impl<S: Sort>() { + // Ensure that the sort can handle integer edge cases. + check_is_sorted::<i32, S>(&mut [i32::MIN, i32::MAX]); + check_is_sorted::<i32, S>(&mut [i32::MAX, i32::MIN]); + check_is_sorted::<i32, S>(&mut [i32::MIN, 3]); + check_is_sorted::<i32, S>(&mut [i32::MIN, -3]); + check_is_sorted::<i32, S>(&mut [i32::MIN, -3, i32::MAX]); + check_is_sorted::<i32, S>(&mut [i32::MIN, -3, i32::MAX, i32::MIN, 5]); + check_is_sorted::<i32, S>(&mut [i32::MAX, 3, i32::MIN, 5, i32::MIN, -3, 60, 200, 50, 7, 10]); + + check_is_sorted::<u64, S>(&mut [u64::MIN, u64::MAX]); + check_is_sorted::<u64, S>(&mut [u64::MAX, u64::MIN]); + check_is_sorted::<u64, S>(&mut [u64::MIN, 3]); + check_is_sorted::<u64, S>(&mut [u64::MIN, u64::MAX - 3]); + check_is_sorted::<u64, S>(&mut [u64::MIN, u64::MAX - 3, u64::MAX]); + check_is_sorted::<u64, S>(&mut [u64::MIN, u64::MAX - 3, u64::MAX, u64::MIN, 5]); + check_is_sorted::<u64, S>(&mut [ + u64::MAX, + 3, + u64::MIN, + 5, + u64::MIN, + u64::MAX - 3, + 60, + 200, + 50, + 7, + 10, + ]); + + let mut large = patterns::random(TEST_LENGTHS[TEST_LENGTHS.len() - 2]); + large.push(i32::MAX); + large.push(i32::MIN); + large.push(i32::MAX); + check_is_sorted::<i32, S>(&mut large); +} + +fn sort_vs_sort_by_impl<S: Sort>() { + // Ensure that sort and sort_by produce the same result. + let mut input_normal = [800, 3, -801, 5, -801, -3, 60, 200, 50, 7, 10]; + let expected = [-801, -801, -3, 3, 5, 7, 10, 50, 60, 200, 800]; + + let mut input_sort_by = input_normal.to_vec(); + + <S as Sort>::sort(&mut input_normal); + <S as Sort>::sort_by(&mut input_sort_by, |a, b| a.cmp(b)); + + assert_eq!(input_normal, expected); + assert_eq!(input_sort_by, expected); +} + +gen_sort_test_fns_with_default_patterns!( + correct_i32, + |len, pattern_fn| test_is_sorted::<i32, S>(len, |val| val, pattern_fn), + TEST_LENGTHS, + [ + (random_d4, |len| patterns::random_uniform(len, 0..4)), + (random_d8, |len| patterns::random_uniform(len, 0..8)), + (random_d311, |len| patterns::random_uniform(len, 0..311)), + (random_d1024, |len| patterns::random_uniform(len, 0..1024)), + (random_z1_03, |len| patterns::random_zipf(len, 1.03)), + (random_z2, |len| patterns::random_zipf(len, 2.0)), + (random_s50, |len| patterns::random_sorted(len, 50.0)), + (narrow, |len| patterns::random_uniform( + len, + 0..=(((len as f64).log2().round()) as i32) * 100 + )), + (all_equal, patterns::all_equal), + (saw_mixed_range, |len| patterns::saw_mixed_range(len, 20..50)), + (pipe_organ, patterns::pipe_organ), + ] +); + +gen_sort_test_fns_with_default_patterns!( + correct_u64, + |len, pattern_fn| test_is_sorted::<u64, S>(len, extend_i32_to_u64, pattern_fn), + TEST_LENGTHS, + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_u128, + |len, pattern_fn| test_is_sorted::<u128, S>(len, extend_i32_to_u128, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_cell_i32, + |len, pattern_fn| test_is_sorted::<Cell<i32>, S>(len, Cell::new, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_string, + |len, pattern_fn| test_is_sorted::<String, S>( + len, + |val| format!("{:010}", shift_i32_to_u32(val)), + pattern_fn + ), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_f128, + |len, pattern_fn| test_is_sorted::<F128, S>(len, F128::new, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_1k, + |len, pattern_fn| test_is_sorted::<FFIOneKibiByte, S>(len, FFIOneKibiByte::new, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +// Dyn values are fat pointers, something the implementation might have overlooked. +gen_sort_test_fns_with_default_patterns!( + correct_dyn_val, + |len, pattern_fn| test_is_sorted::<Rc<dyn DynTrait>, S>(len, dyn_trait_from_i32, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn stability_legacy_impl<S: Sort>() { + // This non pattern variant has proven to catch some bugs the pattern version of this function + // doesn't catch, so it remains in conjunction with the other one. + + if <S as Sort>::name().contains("unstable") { + // It would be great to mark the test as skipped, but that isn't possible as of now. + return; + } + + let large_range = if cfg!(miri) { 100..110 } else { 3000..3010 }; + let rounds = if cfg!(miri) { 1 } else { 10 }; + + let rand_vals = patterns::random_uniform(5_000, 0..=9); + let mut rand_idx = 0; + + for len in (2..55).chain(large_range) { + for _ in 0..rounds { + let mut counts = [0; 10]; + + // create a vector like [(6, 1), (5, 1), (6, 2), ...], + // where the first item of each tuple is random, but + // the second item represents which occurrence of that + // number this element is, i.e., the second elements + // will occur in sorted order. + let orig: Vec<_> = (0..len) + .map(|_| { + let n = rand_vals[rand_idx]; + rand_idx += 1; + if rand_idx >= rand_vals.len() { + rand_idx = 0; + } + + counts[n as usize] += 1; + i32_tup_as_u64((n, counts[n as usize])) + }) + .collect(); + + let mut v = orig.clone(); + // Only sort on the first element, so an unstable sort + // may mix up the counts. + <S as Sort>::sort_by(&mut v, |a_packed, b_packed| { + let a = i32_tup_from_u64(*a_packed).0; + let b = i32_tup_from_u64(*b_packed).0; + + a.cmp(&b) + }); + + // This comparison includes the count (the second item + // of the tuple), so elements with equal first items + // will need to be ordered with increasing + // counts... i.e., exactly asserting that this sort is + // stable. + assert!(v.windows(2).all(|w| i32_tup_from_u64(w[0]) <= i32_tup_from_u64(w[1]))); + } + } + + // For cpp_sorts that only support u64 we can pack the two i32 inside a u64. + fn i32_tup_as_u64(val: (i32, i32)) -> u64 { + let a_bytes = val.0.to_le_bytes(); + let b_bytes = val.1.to_le_bytes(); + + u64::from_le_bytes([a_bytes, b_bytes].concat().try_into().unwrap()) + } + + fn i32_tup_from_u64(val: u64) -> (i32, i32) { + let bytes = val.to_le_bytes(); + + let a = i32::from_le_bytes(bytes[0..4].try_into().unwrap()); + let b = i32::from_le_bytes(bytes[4..8].try_into().unwrap()); + + (a, b) + } +} + +fn stability_with_patterns<T: Ord + Clone, S: Sort>( + len: usize, + type_into_fn: impl Fn(i32) -> T, + _type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec<i32>, +) { + if <S as Sort>::name().contains("unstable") { + // It would be great to mark the test as skipped, but that isn't possible as of now. + return; + } + + let pattern = pattern_fn(len); + + let mut counts = [0i32; 128]; + + // create a vector like [(6, 1), (5, 1), (6, 2), ...], + // where the first item of each tuple is random, but + // the second item represents which occurrence of that + // number this element is, i.e., the second elements + // will occur in sorted order. + let orig: Vec<_> = pattern + .iter() + .map(|val| { + let n = val.saturating_abs() % counts.len() as i32; + counts[n as usize] += 1; + (type_into_fn(n), counts[n as usize]) + }) + .collect(); + + let mut v = orig.clone(); + // Only sort on the first element, so an unstable sort + // may mix up the counts. + <S as Sort>::sort(&mut v); + + // This comparison includes the count (the second item + // of the tuple), so elements with equal first items + // will need to be ordered with increasing + // counts... i.e., exactly asserting that this sort is + // stable. + assert!(v.windows(2).all(|w| w[0] <= w[1])); +} + +gen_sort_test_fns_with_default_patterns_3_ty!(stability, stability_with_patterns, []); + +fn observable_is_less<S: Sort>(len: usize, pattern_fn: fn(usize) -> Vec<i32>) { + // This test, tests that every is_less is actually observable. Ie. this can go wrong if a hole + // is created using temporary memory and, the whole is used as comparison but not copied back. + // + // If this is not upheld a custom type + comparison function could yield UB in otherwise safe + // code. Eg T == Mutex<Option<Box<str>>> which replaces the pointer with none in the comparison + // function, which would not be observed in the original slice and would lead to a double free. + + let pattern = pattern_fn(len); + let mut test_input = pattern.into_iter().map(|val| CompCount::new(val)).collect::<Vec<_>>(); + + let mut comp_count_global = 0; + + <S as Sort>::sort_by(&mut test_input, |a, b| { + a.comp_count.replace(a.comp_count.get() + 1); + b.comp_count.replace(b.comp_count.get() + 1); + comp_count_global += 1; + + a.val.cmp(&b.val) + }); + + let total_inner: u64 = test_input.iter().map(|c| c.comp_count.get() as u64).sum(); + + assert_eq!(total_inner, comp_count_global * 2); +} + +gen_sort_test_fns_with_default_patterns!( + observable_is_less, + observable_is_less::<S>, + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn panic_retain_orig_set<T: Ord + Clone, S: Sort>( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec<i32>, +) { + let mut test_data: Vec<T> = pattern_fn(len).into_iter().map(type_into_fn).collect(); + + let sum_before: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); + + // Calculate a specific comparison that should panic. + // Ensure that it can be any of the possible comparisons and that it always panics. + let required_comps = calc_comps_required::<T, S>(&mut test_data.clone(), |a, b| a.cmp(b)); + let panic_threshold = patterns::random_uniform(1, 1..=required_comps as i32)[0] as usize - 1; + + let mut comp_counter = 0; + + let res = panic::catch_unwind(AssertUnwindSafe(|| { + <S as Sort>::sort_by(&mut test_data, |a, b| { + if comp_counter == panic_threshold { + // Make the panic dependent on the test len and some random factor. We want to + // make sure that panicking may also happen when comparing elements a second + // time. + panic!(); + } + comp_counter += 1; + + a.cmp(b) + }); + })); + + assert!(res.is_err()); + + // If the sum before and after don't match, it means the set of elements hasn't remained the + // same. + let sum_after: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); + assert_eq!(sum_before, sum_after); +} + +gen_sort_test_fns_with_default_patterns_3_ty!(panic_retain_orig_set, panic_retain_orig_set, []); + +fn panic_observable_is_less<S: Sort>(len: usize, pattern_fn: fn(usize) -> Vec<i32>) { + // This test, tests that every is_less is actually observable. Ie. this can go wrong if a hole + // is created using temporary memory and, the whole is used as comparison but not copied back. + // This property must also hold if the user provided comparison panics. + // + // If this is not upheld a custom type + comparison function could yield UB in otherwise safe + // code. Eg T == Mutex<Option<Box<str>>> which replaces the pointer with none in the comparison + // function, which would not be observed in the original slice and would lead to a double free. + + let mut test_input = + pattern_fn(len).into_iter().map(|val| CompCount::new(val)).collect::<Vec<_>>(); + + let sum_before: i64 = test_input.iter().map(|x| x.val as i64).sum(); + + // Calculate a specific comparison that should panic. + // Ensure that it can be any of the possible comparisons and that it always panics. + let required_comps = + calc_comps_required::<CompCount, S>(&mut test_input.clone(), |a, b| a.val.cmp(&b.val)); + + let panic_threshold = patterns::random_uniform(1, 1..=required_comps as i32)[0] as u64 - 1; + + let mut comp_count_global = 0; + + let res = panic::catch_unwind(AssertUnwindSafe(|| { + <S as Sort>::sort_by(&mut test_input, |a, b| { + if comp_count_global == panic_threshold { + // Make the panic dependent on the test len and some random factor. We want to + // make sure that panicking may also happen when comparing elements a second + // time. + panic!(); + } + + a.comp_count.replace(a.comp_count.get() + 1); + b.comp_count.replace(b.comp_count.get() + 1); + comp_count_global += 1; + + a.val.cmp(&b.val) + }); + })); + + assert!(res.is_err()); + + let total_inner: u64 = test_input.iter().map(|c| c.comp_count.get() as u64).sum(); + + assert_eq!(total_inner, comp_count_global * 2); + + // If the sum before and after don't match, it means the set of elements hasn't remained the + // same. + let sum_after: i64 = test_input.iter().map(|x| x.val as i64).sum(); + assert_eq!(sum_before, sum_after); +} + +gen_sort_test_fns_with_default_patterns!( + panic_observable_is_less, + panic_observable_is_less::<S>, + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn deterministic<T: Ord + Clone + Debug, S: Sort>( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec<i32>, +) { + // A property similar to stability is deterministic output order. If the entire value is used as + // the comparison key a lack of determinism has no effect. But if only a part of the value is + // used as comparison key, a lack of determinism can manifest itself in the order of values + // considered equal by the comparison predicate. + // + // This test only tests that results are deterministic across runs, it does not test determinism + // on different platforms and with different toolchains. + + let mut test_input = + pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::<Vec<_>>(); + + let mut test_input_clone = test_input.clone(); + + let comparison_fn = |a: &T, b: &T| { + let a_i32 = type_from_fn(a); + let b_i32 = type_from_fn(b); + + let a_i32_key_space_reduced = a_i32 % 10_000; + let b_i32_key_space_reduced = b_i32 % 10_000; + + a_i32_key_space_reduced.cmp(&b_i32_key_space_reduced) + }; + + <S as Sort>::sort_by(&mut test_input, comparison_fn); + <S as Sort>::sort_by(&mut test_input_clone, comparison_fn); + + assert_eq!(test_input, test_input_clone); +} + +gen_sort_test_fns_with_default_patterns_3_ty!(deterministic, deterministic, []); + +fn self_cmp<T: Ord + Clone + Debug, S: Sort>( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + _type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec<i32>, +) { + // It's possible for comparisons to run into problems if the values of `a` and `b` passed into + // the comparison function are the same reference. So this tests that they never are. + + let mut test_input = + pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::<Vec<_>>(); + + let comparison_fn = |a: &T, b: &T| { + assert_ne!(a as *const T as usize, b as *const T as usize); + a.cmp(b) + }; + + <S as Sort>::sort_by(&mut test_input, comparison_fn); + + // Check that the output is actually sorted and wasn't stopped by the assert. + for window in test_input.windows(2) { + assert!(window[0] <= window[1]); + } +} + +gen_sort_test_fns_with_default_patterns_3_ty!(self_cmp, self_cmp, []); + +fn violate_ord_retain_orig_set<T: Ord, S: Sort>( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec<i32>, +) { + // A user may implement Ord incorrectly for a type or violate it by calling sort_by with a + // comparison function that violates Ord with the orderings it returns. Even under such + // circumstances the input must retain its original set of elements. + + // Ord implies a strict total order see https://en.wikipedia.org/wiki/Total_order. + + // Generating random numbers with miri is quite expensive. + let random_orderings_len = if cfg!(miri) { 200 } else { 10_000 }; + + // Make sure we get a good distribution of random orderings, that are repeatable with the seed. + // Just using random_uniform with the same len and range will always yield the same value. + let random_orderings = patterns::random_uniform(random_orderings_len, 0..2); + + let get_random_0_1_or_2 = |random_idx: &mut usize| { + let ridx = *random_idx; + *random_idx += 1; + if ridx + 1 == random_orderings.len() { + *random_idx = 0; + } + + random_orderings[ridx] as usize + }; + + let mut random_idx_a = 0; + let mut random_idx_b = 0; + let mut random_idx_c = 0; + + let mut last_element_a = -1; + let mut last_element_b = -1; + + let mut rand_counter_b = 0; + let mut rand_counter_c = 0; + + let mut streak_counter_a = 0; + let mut streak_counter_b = 0; + + // Examples, a = 3, b = 5, c = 9. + // Correct Ord -> 10010 | is_less(a, b) is_less(a, a) is_less(b, a) is_less(a, c) is_less(c, a) + let mut invalid_ord_comp_functions: Vec<Box<dyn FnMut(&T, &T) -> Ordering>> = vec![ + Box::new(|_a, _b| -> Ordering { + // random + // Eg. is_less(3, 5) == true, is_less(3, 5) == false + + let idx = get_random_0_1_or_2(&mut random_idx_a); + [Ordering::Less, Ordering::Equal, Ordering::Greater][idx] + }), + Box::new(|_a, _b| -> Ordering { + // everything is less -> 11111 + Ordering::Less + }), + Box::new(|_a, _b| -> Ordering { + // everything is equal -> 00000 + Ordering::Equal + }), + Box::new(|_a, _b| -> Ordering { + // everything is greater -> 00000 + // Eg. is_less(3, 5) == false, is_less(5, 3) == false, is_less(3, 3) == false + Ordering::Greater + }), + Box::new(|a, b| -> Ordering { + // equal means less else greater -> 01000 + if a == b { Ordering::Less } else { Ordering::Greater } + }), + Box::new(|a, b| -> Ordering { + // Transitive breaker. remember last element -> 10001 + let lea = last_element_a; + let leb = last_element_b; + + let a_as_i32 = type_from_fn(a); + let b_as_i32 = type_from_fn(b); + + last_element_a = a_as_i32; + last_element_b = b_as_i32; + + if a_as_i32 == lea && b_as_i32 != leb { b.cmp(a) } else { a.cmp(b) } + }), + Box::new(|a, b| -> Ordering { + // Sampled random 1% of comparisons are reversed. + rand_counter_b += get_random_0_1_or_2(&mut random_idx_b); + if rand_counter_b >= 100 { + rand_counter_b = 0; + b.cmp(a) + } else { + a.cmp(b) + } + }), + Box::new(|a, b| -> Ordering { + // Sampled random 33% of comparisons are reversed. + rand_counter_c += get_random_0_1_or_2(&mut random_idx_c); + if rand_counter_c >= 3 { + rand_counter_c = 0; + b.cmp(a) + } else { + a.cmp(b) + } + }), + Box::new(|a, b| -> Ordering { + // STREAK_LEN comparisons yield a.cmp(b) then STREAK_LEN comparisons less. This can + // discover bugs that neither, random Ord, or just Less or Greater can find. Because it + // can push a pointer further than expected. Random Ord will average out how far a + // comparison based pointer travels. Just Less or Greater will be caught by pattern + // analysis and never enter interesting code. + const STREAK_LEN: usize = 50; + + streak_counter_a += 1; + if streak_counter_a <= STREAK_LEN { + a.cmp(b) + } else { + if streak_counter_a == STREAK_LEN * 2 { + streak_counter_a = 0; + } + Ordering::Less + } + }), + Box::new(|a, b| -> Ordering { + // See above. + const STREAK_LEN: usize = 50; + + streak_counter_b += 1; + if streak_counter_b <= STREAK_LEN { + a.cmp(b) + } else { + if streak_counter_b == STREAK_LEN * 2 { + streak_counter_b = 0; + } + Ordering::Greater + } + }), + ]; + + for comp_func in &mut invalid_ord_comp_functions { + let mut test_data: Vec<T> = pattern_fn(len).into_iter().map(type_into_fn).collect(); + let sum_before: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); + + // It's ok to panic on Ord violation or to complete. + // In both cases the original elements must still be present. + let _ = panic::catch_unwind(AssertUnwindSafe(|| { + <S as Sort>::sort_by(&mut test_data, &mut *comp_func); + })); + + // If the sum before and after don't match, it means the set of elements hasn't remained the + // same. + let sum_after: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); + assert_eq!(sum_before, sum_after); + + if cfg!(miri) { + // This test is prohibitively expensive in miri, so only run one of the comparison + // functions. This test is not expected to yield direct UB, but rather surface potential + // UB by showing that the sum is different now. + break; + } + } +} + +gen_sort_test_fns_with_default_patterns_3_ty!( + violate_ord_retain_orig_set, + violate_ord_retain_orig_set, + [] +); + +macro_rules! instantiate_sort_test_inner { + ($sort_impl:ty, miri_yes, $test_fn_name:ident) => { + #[test] + fn $test_fn_name() { + $crate::sort::tests::$test_fn_name::<$sort_impl>(); + } + }; + ($sort_impl:ty, miri_no, $test_fn_name:ident) => { + #[test] + #[cfg_attr(miri, ignore)] + fn $test_fn_name() { + $crate::sort::tests::$test_fn_name::<$sort_impl>(); + } + }; +} + +// Using this construct allows us to get warnings for unused test functions. +macro_rules! define_instantiate_sort_tests { + ($([$miri_use:ident, $test_fn_name:ident]),*,) => { + $(pub fn $test_fn_name<S: Sort>() { + ${concat($test_fn_name, _impl)}::<S>(); + })* + + + macro_rules! instantiate_sort_tests_gen { + ($sort_impl:ty) => { + $( + instantiate_sort_test_inner!( + $sort_impl, + $miri_use, + $test_fn_name + ); + )* + } + } + }; +} + +// Some tests are not tested with miri to avoid prohibitively long test times. This leaves coverage +// holes, but the way they are selected should make for relatively small holes. Many properties that +// can lead to UB are tested directly, for example that the original set of elements is retained +// even when a panic occurs or Ord is implemented incorrectly. +define_instantiate_sort_tests!( + [miri_yes, basic], + [miri_yes, fixed_seed], + [miri_yes, fixed_seed_rand_vec_prefix], + [miri_yes, int_edge], + [miri_yes, sort_vs_sort_by], + [miri_yes, correct_i32_random], + [miri_yes, correct_i32_random_z1], + [miri_yes, correct_i32_random_d2], + [miri_yes, correct_i32_random_d20], + [miri_yes, correct_i32_random_s95], + [miri_yes, correct_i32_ascending], + [miri_yes, correct_i32_descending], + [miri_yes, correct_i32_saw_mixed], + [miri_no, correct_i32_random_d4], + [miri_no, correct_i32_random_d8], + [miri_no, correct_i32_random_d311], + [miri_no, correct_i32_random_d1024], + [miri_no, correct_i32_random_z1_03], + [miri_no, correct_i32_random_z2], + [miri_no, correct_i32_random_s50], + [miri_no, correct_i32_narrow], + [miri_no, correct_i32_all_equal], + [miri_no, correct_i32_saw_mixed_range], + [miri_yes, correct_i32_pipe_organ], + [miri_no, correct_u64_random], + [miri_yes, correct_u64_random_z1], + [miri_no, correct_u64_random_d2], + [miri_no, correct_u64_random_d20], + [miri_no, correct_u64_random_s95], + [miri_no, correct_u64_ascending], + [miri_no, correct_u64_descending], + [miri_no, correct_u64_saw_mixed], + [miri_no, correct_u128_random], + [miri_yes, correct_u128_random_z1], + [miri_no, correct_u128_random_d2], + [miri_no, correct_u128_random_d20], + [miri_no, correct_u128_random_s95], + [miri_no, correct_u128_ascending], + [miri_no, correct_u128_descending], + [miri_no, correct_u128_saw_mixed], + [miri_no, correct_cell_i32_random], + [miri_yes, correct_cell_i32_random_z1], + [miri_no, correct_cell_i32_random_d2], + [miri_no, correct_cell_i32_random_d20], + [miri_no, correct_cell_i32_random_s95], + [miri_no, correct_cell_i32_ascending], + [miri_no, correct_cell_i32_descending], + [miri_no, correct_cell_i32_saw_mixed], + [miri_no, correct_string_random], + [miri_yes, correct_string_random_z1], + [miri_no, correct_string_random_d2], + [miri_no, correct_string_random_d20], + [miri_no, correct_string_random_s95], + [miri_no, correct_string_ascending], + [miri_no, correct_string_descending], + [miri_no, correct_string_saw_mixed], + [miri_no, correct_f128_random], + [miri_yes, correct_f128_random_z1], + [miri_no, correct_f128_random_d2], + [miri_no, correct_f128_random_d20], + [miri_no, correct_f128_random_s95], + [miri_no, correct_f128_ascending], + [miri_no, correct_f128_descending], + [miri_no, correct_f128_saw_mixed], + [miri_no, correct_1k_random], + [miri_yes, correct_1k_random_z1], + [miri_no, correct_1k_random_d2], + [miri_no, correct_1k_random_d20], + [miri_no, correct_1k_random_s95], + [miri_no, correct_1k_ascending], + [miri_no, correct_1k_descending], + [miri_no, correct_1k_saw_mixed], + [miri_no, correct_dyn_val_random], + [miri_yes, correct_dyn_val_random_z1], + [miri_no, correct_dyn_val_random_d2], + [miri_no, correct_dyn_val_random_d20], + [miri_no, correct_dyn_val_random_s95], + [miri_no, correct_dyn_val_ascending], + [miri_no, correct_dyn_val_descending], + [miri_no, correct_dyn_val_saw_mixed], + [miri_no, stability_legacy], + [miri_no, stability_i32_random], + [miri_yes, stability_i32_random_z1], + [miri_no, stability_i32_random_d2], + [miri_no, stability_i32_random_d20], + [miri_no, stability_i32_random_s95], + [miri_no, stability_i32_ascending], + [miri_no, stability_i32_descending], + [miri_no, stability_i32_saw_mixed], + [miri_no, stability_cell_i32_random], + [miri_yes, stability_cell_i32_random_z1], + [miri_no, stability_cell_i32_random_d2], + [miri_no, stability_cell_i32_random_d20], + [miri_no, stability_cell_i32_random_s95], + [miri_no, stability_cell_i32_ascending], + [miri_no, stability_cell_i32_descending], + [miri_no, stability_cell_i32_saw_mixed], + [miri_no, stability_string_random], + [miri_yes, stability_string_random_z1], + [miri_no, stability_string_random_d2], + [miri_no, stability_string_random_d20], + [miri_no, stability_string_random_s95], + [miri_no, stability_string_ascending], + [miri_no, stability_string_descending], + [miri_no, stability_string_saw_mixed], + [miri_no, observable_is_less_random], + [miri_yes, observable_is_less_random_z1], + [miri_no, observable_is_less_random_d2], + [miri_no, observable_is_less_random_d20], + [miri_no, observable_is_less_random_s95], + [miri_no, observable_is_less_ascending], + [miri_no, observable_is_less_descending], + [miri_no, observable_is_less_saw_mixed], + [miri_no, panic_retain_orig_set_i32_random], + [miri_yes, panic_retain_orig_set_i32_random_z1], + [miri_no, panic_retain_orig_set_i32_random_d2], + [miri_no, panic_retain_orig_set_i32_random_d20], + [miri_no, panic_retain_orig_set_i32_random_s95], + [miri_no, panic_retain_orig_set_i32_ascending], + [miri_no, panic_retain_orig_set_i32_descending], + [miri_no, panic_retain_orig_set_i32_saw_mixed], + [miri_no, panic_retain_orig_set_cell_i32_random], + [miri_yes, panic_retain_orig_set_cell_i32_random_z1], + [miri_no, panic_retain_orig_set_cell_i32_random_d2], + [miri_no, panic_retain_orig_set_cell_i32_random_d20], + [miri_no, panic_retain_orig_set_cell_i32_random_s95], + [miri_no, panic_retain_orig_set_cell_i32_ascending], + [miri_no, panic_retain_orig_set_cell_i32_descending], + [miri_no, panic_retain_orig_set_cell_i32_saw_mixed], + [miri_no, panic_retain_orig_set_string_random], + [miri_yes, panic_retain_orig_set_string_random_z1], + [miri_no, panic_retain_orig_set_string_random_d2], + [miri_no, panic_retain_orig_set_string_random_d20], + [miri_no, panic_retain_orig_set_string_random_s95], + [miri_no, panic_retain_orig_set_string_ascending], + [miri_no, panic_retain_orig_set_string_descending], + [miri_no, panic_retain_orig_set_string_saw_mixed], + [miri_no, panic_observable_is_less_random], + [miri_yes, panic_observable_is_less_random_z1], + [miri_no, panic_observable_is_less_random_d2], + [miri_no, panic_observable_is_less_random_d20], + [miri_no, panic_observable_is_less_random_s95], + [miri_no, panic_observable_is_less_ascending], + [miri_no, panic_observable_is_less_descending], + [miri_no, panic_observable_is_less_saw_mixed], + [miri_no, deterministic_i32_random], + [miri_yes, deterministic_i32_random_z1], + [miri_no, deterministic_i32_random_d2], + [miri_no, deterministic_i32_random_d20], + [miri_no, deterministic_i32_random_s95], + [miri_no, deterministic_i32_ascending], + [miri_no, deterministic_i32_descending], + [miri_no, deterministic_i32_saw_mixed], + [miri_no, deterministic_cell_i32_random], + [miri_yes, deterministic_cell_i32_random_z1], + [miri_no, deterministic_cell_i32_random_d2], + [miri_no, deterministic_cell_i32_random_d20], + [miri_no, deterministic_cell_i32_random_s95], + [miri_no, deterministic_cell_i32_ascending], + [miri_no, deterministic_cell_i32_descending], + [miri_no, deterministic_cell_i32_saw_mixed], + [miri_no, deterministic_string_random], + [miri_yes, deterministic_string_random_z1], + [miri_no, deterministic_string_random_d2], + [miri_no, deterministic_string_random_d20], + [miri_no, deterministic_string_random_s95], + [miri_no, deterministic_string_ascending], + [miri_no, deterministic_string_descending], + [miri_no, deterministic_string_saw_mixed], + [miri_no, self_cmp_i32_random], + [miri_yes, self_cmp_i32_random_z1], + [miri_no, self_cmp_i32_random_d2], + [miri_no, self_cmp_i32_random_d20], + [miri_no, self_cmp_i32_random_s95], + [miri_no, self_cmp_i32_ascending], + [miri_no, self_cmp_i32_descending], + [miri_no, self_cmp_i32_saw_mixed], + [miri_no, self_cmp_cell_i32_random], + [miri_yes, self_cmp_cell_i32_random_z1], + [miri_no, self_cmp_cell_i32_random_d2], + [miri_no, self_cmp_cell_i32_random_d20], + [miri_no, self_cmp_cell_i32_random_s95], + [miri_no, self_cmp_cell_i32_ascending], + [miri_no, self_cmp_cell_i32_descending], + [miri_no, self_cmp_cell_i32_saw_mixed], + [miri_no, self_cmp_string_random], + [miri_yes, self_cmp_string_random_z1], + [miri_no, self_cmp_string_random_d2], + [miri_no, self_cmp_string_random_d20], + [miri_no, self_cmp_string_random_s95], + [miri_no, self_cmp_string_ascending], + [miri_no, self_cmp_string_descending], + [miri_no, self_cmp_string_saw_mixed], + [miri_no, violate_ord_retain_orig_set_i32_random], + [miri_yes, violate_ord_retain_orig_set_i32_random_z1], + [miri_no, violate_ord_retain_orig_set_i32_random_d2], + [miri_no, violate_ord_retain_orig_set_i32_random_d20], + [miri_no, violate_ord_retain_orig_set_i32_random_s95], + [miri_no, violate_ord_retain_orig_set_i32_ascending], + [miri_no, violate_ord_retain_orig_set_i32_descending], + [miri_no, violate_ord_retain_orig_set_i32_saw_mixed], + [miri_no, violate_ord_retain_orig_set_cell_i32_random], + [miri_yes, violate_ord_retain_orig_set_cell_i32_random_z1], + [miri_no, violate_ord_retain_orig_set_cell_i32_random_d2], + [miri_no, violate_ord_retain_orig_set_cell_i32_random_d20], + [miri_no, violate_ord_retain_orig_set_cell_i32_random_s95], + [miri_no, violate_ord_retain_orig_set_cell_i32_ascending], + [miri_no, violate_ord_retain_orig_set_cell_i32_descending], + [miri_no, violate_ord_retain_orig_set_cell_i32_saw_mixed], + [miri_no, violate_ord_retain_orig_set_string_random], + [miri_yes, violate_ord_retain_orig_set_string_random_z1], + [miri_no, violate_ord_retain_orig_set_string_random_d2], + [miri_no, violate_ord_retain_orig_set_string_random_d20], + [miri_no, violate_ord_retain_orig_set_string_random_s95], + [miri_no, violate_ord_retain_orig_set_string_ascending], + [miri_no, violate_ord_retain_orig_set_string_descending], + [miri_no, violate_ord_retain_orig_set_string_saw_mixed], +); + +macro_rules! instantiate_sort_tests { + ($sort_impl:ty) => { + instantiate_sort_tests_gen!($sort_impl); + }; +} + +mod unstable { + struct SortImpl {} + + impl crate::sort::Sort for SortImpl { + fn name() -> String { + "rust_std_unstable".into() + } + + fn sort<T>(v: &mut [T]) + where + T: Ord, + { + v.sort_unstable(); + } + + fn sort_by<T, F>(v: &mut [T], mut compare: F) + where + F: FnMut(&T, &T) -> std::cmp::Ordering, + { + v.sort_unstable_by(|a, b| compare(a, b)); + } + } + + instantiate_sort_tests!(SortImpl); +} + +mod stable { + struct SortImpl {} + + impl crate::sort::Sort for SortImpl { + fn name() -> String { + "rust_std_stable".into() + } + + fn sort<T>(v: &mut [T]) + where + T: Ord, + { + v.sort(); + } + + fn sort_by<T, F>(v: &mut [T], mut compare: F) + where + F: FnMut(&T, &T) -> std::cmp::Ordering, + { + v.sort_by(|a, b| compare(a, b)); + } + } + + instantiate_sort_tests!(SortImpl); +} diff --git a/library/alloc/tests/sort/zipf.rs b/library/alloc/tests/sort/zipf.rs new file mode 100644 index 00000000000..cc774ee5c43 --- /dev/null +++ b/library/alloc/tests/sort/zipf.rs @@ -0,0 +1,208 @@ +// This module implements a Zipfian distribution generator. +// +// Based on https://github.com/jonhoo/rust-zipf. + +use rand::Rng; + +/// Random number generator that generates Zipf-distributed random numbers using rejection +/// inversion. +#[derive(Clone, Copy)] +pub struct ZipfDistribution { + /// Number of elements + num_elements: f64, + /// Exponent parameter of the distribution + exponent: f64, + /// `hIntegral(1.5) - 1}` + h_integral_x1: f64, + /// `hIntegral(num_elements + 0.5)}` + h_integral_num_elements: f64, + /// `2 - hIntegralInverse(hIntegral(2.5) - h(2)}` + s: f64, +} + +impl ZipfDistribution { + /// Creates a new [Zipf-distributed](https://en.wikipedia.org/wiki/Zipf's_law) + /// random number generator. + /// + /// Note that both the number of elements and the exponent must be greater than 0. + pub fn new(num_elements: usize, exponent: f64) -> Result<Self, ()> { + if num_elements == 0 { + return Err(()); + } + if exponent <= 0f64 { + return Err(()); + } + + let z = ZipfDistribution { + num_elements: num_elements as f64, + exponent, + h_integral_x1: ZipfDistribution::h_integral(1.5, exponent) - 1f64, + h_integral_num_elements: ZipfDistribution::h_integral( + num_elements as f64 + 0.5, + exponent, + ), + s: 2f64 + - ZipfDistribution::h_integral_inv( + ZipfDistribution::h_integral(2.5, exponent) + - ZipfDistribution::h(2f64, exponent), + exponent, + ), + }; + + // populate cache + + Ok(z) + } +} + +impl ZipfDistribution { + fn next<R: Rng + ?Sized>(&self, rng: &mut R) -> usize { + // The paper describes an algorithm for exponents larger than 1 (Algorithm ZRI). + // + // The original method uses + // H(x) = (v + x)^(1 - q) / (1 - q) + // as the integral of the hat function. + // + // This function is undefined for q = 1, which is the reason for the limitation of the + // exponent. + // + // If instead the integral function + // H(x) = ((v + x)^(1 - q) - 1) / (1 - q) + // is used, for which a meaningful limit exists for q = 1, the method works for all + // positive exponents. + // + // The following implementation uses v = 0 and generates integral number in the range [1, + // num_elements]. This is different to the original method where v is defined to + // be positive and numbers are taken from [0, i_max]. This explains why the implementation + // looks slightly different. + + let hnum = self.h_integral_num_elements; + + loop { + use std::cmp; + let u: f64 = hnum + rng.gen::<f64>() * (self.h_integral_x1 - hnum); + // u is uniformly distributed in (h_integral_x1, h_integral_num_elements] + + let x: f64 = ZipfDistribution::h_integral_inv(u, self.exponent); + + // Limit k to the range [1, num_elements] if it would be outside + // due to numerical inaccuracies. + let k64 = x.max(1.0).min(self.num_elements); + // float -> integer rounds towards zero, so we add 0.5 + // to prevent bias towards k == 1 + let k = cmp::max(1, (k64 + 0.5) as usize); + + // Here, the distribution of k is given by: + // + // P(k = 1) = C * (hIntegral(1.5) - h_integral_x1) = C + // P(k = m) = C * (hIntegral(m + 1/2) - hIntegral(m - 1/2)) for m >= 2 + // + // where C = 1 / (h_integral_num_elements - h_integral_x1) + if k64 - x <= self.s + || u >= ZipfDistribution::h_integral(k64 + 0.5, self.exponent) + - ZipfDistribution::h(k64, self.exponent) + { + // Case k = 1: + // + // The right inequality is always true, because replacing k by 1 gives + // u >= hIntegral(1.5) - h(1) = h_integral_x1 and u is taken from + // (h_integral_x1, h_integral_num_elements]. + // + // Therefore, the acceptance rate for k = 1 is P(accepted | k = 1) = 1 + // and the probability that 1 is returned as random value is + // P(k = 1 and accepted) = P(accepted | k = 1) * P(k = 1) = C = C / 1^exponent + // + // Case k >= 2: + // + // The left inequality (k - x <= s) is just a short cut + // to avoid the more expensive evaluation of the right inequality + // (u >= hIntegral(k + 0.5) - h(k)) in many cases. + // + // If the left inequality is true, the right inequality is also true: + // Theorem 2 in the paper is valid for all positive exponents, because + // the requirements h'(x) = -exponent/x^(exponent + 1) < 0 and + // (-1/hInverse'(x))'' = (1+1/exponent) * x^(1/exponent-1) >= 0 + // are both fulfilled. + // Therefore, f(x) = x - hIntegralInverse(hIntegral(x + 0.5) - h(x)) + // is a non-decreasing function. If k - x <= s holds, + // k - x <= s + f(k) - f(2) is obviously also true which is equivalent to + // -x <= -hIntegralInverse(hIntegral(k + 0.5) - h(k)), + // -hIntegralInverse(u) <= -hIntegralInverse(hIntegral(k + 0.5) - h(k)), + // and finally u >= hIntegral(k + 0.5) - h(k). + // + // Hence, the right inequality determines the acceptance rate: + // P(accepted | k = m) = h(m) / (hIntegrated(m+1/2) - hIntegrated(m-1/2)) + // The probability that m is returned is given by + // P(k = m and accepted) = P(accepted | k = m) * P(k = m) + // = C * h(m) = C / m^exponent. + // + // In both cases the probabilities are proportional to the probability mass + // function of the Zipf distribution. + + return k; + } + } + } +} + +impl rand::distributions::Distribution<usize> for ZipfDistribution { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize { + self.next(rng) + } +} + +use std::fmt; +impl fmt::Debug for ZipfDistribution { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.debug_struct("ZipfDistribution") + .field("e", &self.exponent) + .field("n", &self.num_elements) + .finish() + } +} + +impl ZipfDistribution { + /// Computes `H(x)`, defined as + /// + /// - `(x^(1 - exponent) - 1) / (1 - exponent)`, if `exponent != 1` + /// - `log(x)`, if `exponent == 1` + /// + /// `H(x)` is an integral function of `h(x)`, the derivative of `H(x)` is `h(x)`. + fn h_integral(x: f64, exponent: f64) -> f64 { + let log_x = x.ln(); + helper2((1f64 - exponent) * log_x) * log_x + } + + /// Computes `h(x) = 1 / x^exponent` + fn h(x: f64, exponent: f64) -> f64 { + (-exponent * x.ln()).exp() + } + + /// The inverse function of `H(x)`. + /// Returns the `y` for which `H(y) = x`. + fn h_integral_inv(x: f64, exponent: f64) -> f64 { + let mut t: f64 = x * (1f64 - exponent); + if t < -1f64 { + // Limit value to the range [-1, +inf). + // t could be smaller than -1 in some rare cases due to numerical errors. + t = -1f64; + } + (helper1(t) * x).exp() + } +} + +/// Helper function that calculates `log(1 + x) / x`. +/// A Taylor series expansion is used, if x is close to 0. +fn helper1(x: f64) -> f64 { + if x.abs() > 1e-8 { x.ln_1p() / x } else { 1f64 - x * (0.5 - x * (1.0 / 3.0 - 0.25 * x)) } +} + +/// Helper function to calculate `(exp(x) - 1) / x`. +/// A Taylor series expansion is used, if x is close to 0. +fn helper2(x: f64) -> f64 { + if x.abs() > 1e-8 { + x.exp_m1() / x + } else { + 1f64 + x * 0.5 * (1f64 + x * 1.0 / 3.0 * (1f64 + 0.25 * x)) + } +} diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 107d82267e5..fca32b9d3c5 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -540,7 +540,8 @@ impl Layout { )] pub type LayoutErr = LayoutError; -/// The parameters given to `Layout::from_size_align` +/// The `LayoutError` is returned when the parameters given +/// to `Layout::from_size_align` /// or some other `Layout` constructor /// do not satisfy its documented constraints. #[stable(feature = "alloc_layout_error", since = "1.50.0")] diff --git a/library/core/src/array/ascii.rs b/library/core/src/array/ascii.rs index 05797b042ee..e2faef855bc 100644 --- a/library/core/src/array/ascii.rs +++ b/library/core/src/array/ascii.rs @@ -9,7 +9,6 @@ impl<const N: usize> [u8; N] { /// /// ``` /// #![feature(ascii_char)] - /// #![feature(const_option)] /// /// const HEX_DIGITS: [std::ascii::Char; 16] = /// *b"0123456789abcdef".as_ascii().unwrap(); diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 24c42bc85dd..a95046162d2 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -146,7 +146,8 @@ pub const fn from_ref<T>(s: &T) -> &[T; 1] { /// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying). #[stable(feature = "array_from_ref", since = "1.53.0")] -#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")] +#[rustc_const_stable(feature = "const_array_from_ref", since = "CURRENT_RUSTC_VERSION")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn from_mut<T>(s: &mut T) -> &mut [T; 1] { // SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound. unsafe { &mut *(s as *mut T).cast::<[T; 1]>() } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index de212581e82..8ccd1a44ff1 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -494,8 +494,9 @@ impl<T> Cell<T> { /// ``` #[inline] #[stable(feature = "move_cell", since = "1.17.0")] + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] #[rustc_confusables("swap")] - pub fn replace(&self, val: T) -> T { + pub const fn replace(&self, val: T) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. mem::replace(unsafe { &mut *self.value.get() }, val) @@ -535,7 +536,8 @@ impl<T: Copy> Cell<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> T { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn get(&self) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. unsafe { *self.value.get() } @@ -613,7 +615,8 @@ impl<T: ?Sized> Cell<T> { /// ``` #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn get_mut(&mut self) -> &mut T { self.value.get_mut() } @@ -632,7 +635,8 @@ impl<T: ?Sized> Cell<T> { /// ``` #[inline] #[stable(feature = "as_cell", since = "1.37.0")] - pub fn from_mut(t: &mut T) -> &Cell<T> { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn from_mut(t: &mut T) -> &Cell<T> { // SAFETY: `&mut` ensures unique access. unsafe { &*(t as *mut T as *const Cell<T>) } } @@ -662,7 +666,7 @@ impl<T: Default> Cell<T> { impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {} // Allow types that wrap `Cell` to also implement `DispatchFromDyn` -// and become object safe method receivers. +// and become dyn-compatible method receivers. // Note that currently `Cell` itself cannot be a method receiver // because it does not implement Deref. // In other words: @@ -686,7 +690,8 @@ impl<T> Cell<[T]> { /// assert_eq!(slice_cell.len(), 3); /// ``` #[stable(feature = "as_cell", since = "1.37.0")] - pub fn as_slice_of_cells(&self) -> &[Cell<T>] { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn as_slice_of_cells(&self) -> &[Cell<T>] { // SAFETY: `Cell<T>` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T]> as *const [Cell<T>]) } } @@ -706,7 +711,8 @@ impl<T, const N: usize> Cell<[T; N]> { /// let array_cell: &[Cell<i32>; 3] = cell_array.as_array_of_cells(); /// ``` #[unstable(feature = "as_array_of_cells", issue = "88248")] - pub fn as_array_of_cells(&self) -> &[Cell<T>; N] { + #[rustc_const_unstable(feature = "as_array_of_cells", issue = "88248")] + pub const fn as_array_of_cells(&self) -> &[Cell<T>; N] { // SAFETY: `Cell<T>` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T; N]> as *const [Cell<T>; N]) } } @@ -2175,7 +2181,8 @@ impl<T: ?Sized> UnsafeCell<T> { /// ``` #[inline(always)] #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")] - #[rustc_const_unstable(feature = "const_unsafecell_get_mut", issue = "88836")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_unsafecell_get_mut", since = "CURRENT_RUSTC_VERSION")] pub const fn get_mut(&mut self) -> &mut T { &mut self.value } @@ -2240,7 +2247,7 @@ impl<T> From<T> for UnsafeCell<T> { impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {} // Allow types that wrap `UnsafeCell` to also implement `DispatchFromDyn` -// and become object safe method receivers. +// and become dyn-compatible method receivers. // Note that currently `UnsafeCell` itself cannot be a method receiver // because it does not implement Deref. // In other words: @@ -2342,7 +2349,7 @@ impl<T> From<T> for SyncUnsafeCell<T> { impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {} // Allow types that wrap `SyncUnsafeCell` to also implement `DispatchFromDyn` -// and become object safe method receivers. +// and become dyn-compatible method receivers. // Note that currently `SyncUnsafeCell` itself cannot be a method receiver // because it does not implement Deref. // In other words: diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 7f3c998aaa5..6bedb0d0dc4 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -674,8 +674,9 @@ impl char { /// 'ß'.encode_utf8(&mut b); /// ``` #[stable(feature = "unicode_encode_char", since = "1.15.0")] - #[rustc_const_unstable(feature = "const_char_encode_utf8", issue = "130512")] + #[rustc_const_stable(feature = "const_char_encode_utf8", since = "CURRENT_RUSTC_VERSION")] #[inline] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn encode_utf8(self, dst: &mut [u8]) -> &mut str { // SAFETY: `char` is not a surrogate, so this is valid UTF-8. unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } @@ -1770,9 +1771,11 @@ const fn len_utf16(code: u32) -> usize { /// Panics if the buffer is not large enough. /// A buffer of length four is large enough to encode any `char`. #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -#[rustc_const_unstable(feature = "const_char_encode_utf8", issue = "130512")] +#[rustc_const_stable(feature = "const_char_encode_utf8", since = "CURRENT_RUSTC_VERSION")] #[doc(hidden)] #[inline] +#[rustc_allow_const_fn_unstable(const_eval_select)] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { const fn panic_at_const(_code: u32, _len: usize, _dst_len: usize) { // Note that we cannot format in constant expressions. diff --git a/library/core/src/error.rs b/library/core/src/error.rs index cac00b37d1f..95a39cc3aed 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -335,16 +335,17 @@ impl dyn Error { #[unstable(feature = "error_iter", issue = "58520")] #[inline] pub fn sources(&self) -> Source<'_> { - // You may think this method would be better in the Error trait, and you'd be right. - // Unfortunately that doesn't work, not because of the object safety rules but because we - // save a reference to self in Sources below as a trait object. If this method was - // declared in Error, then self would have the type &T where T is some concrete type which - // implements Error. We would need to coerce self to have type &dyn Error, but that requires - // that Self has a known size (i.e., Self: Sized). We can't put that bound on Error - // since that would forbid Error trait objects, and we can't put that bound on the method - // because that means the method can't be called on trait objects (we'd also need the - // 'static bound, but that isn't allowed because methods with bounds on Self other than - // Sized are not object-safe). Requiring an Unsize bound is not backwards compatible. + // You may think this method would be better in the `Error` trait, and you'd be right. + // Unfortunately that doesn't work, not because of the dyn-incompatibility rules but + // because we save a reference to `self` in `Source`s below as a trait object. + // If this method was declared in `Error`, then `self` would have the type `&T` where + // `T` is some concrete type which implements `Error`. We would need to coerce `self` + // to have type `&dyn Error`, but that requires that `Self` has a known size + // (i.e., `Self: Sized`). We can't put that bound on `Error` since that would forbid + // `Error` trait objects, and we can't put that bound on the method because that means + // the method can't be called on trait objects (we'd also need the `'static` bound, + // but that isn't allowed because methods with bounds on `Self` other than `Sized` are + // dyn-incompatible). Requiring an `Unsize` bound is not backwards compatible. Source { current: Some(self) } } diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs index b213cc2b916..0685f525dca 100644 --- a/library/core/src/escape.rs +++ b/library/core/src/escape.rs @@ -18,38 +18,106 @@ const fn backslash<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], Range<u (output, 0..2) } +#[inline] +const fn hex_escape<const N: usize>(byte: u8) -> ([ascii::Char; N], Range<u8>) { + const { assert!(N >= 4) }; + + let mut output = [ascii::Char::Null; N]; + + let hi = HEX_DIGITS[(byte >> 4) as usize]; + let lo = HEX_DIGITS[(byte & 0xf) as usize]; + + output[0] = ascii::Char::ReverseSolidus; + output[1] = ascii::Char::SmallX; + output[2] = hi; + output[3] = lo; + + (output, 0..4) +} + +#[inline] +const fn verbatim<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], Range<u8>) { + const { assert!(N >= 1) }; + + let mut output = [ascii::Char::Null; N]; + + output[0] = a; + + (output, 0..1) +} + /// Escapes an ASCII character. /// /// Returns a buffer and the length of the escaped representation. const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], Range<u8>) { const { assert!(N >= 4) }; - match byte { - b'\t' => backslash(ascii::Char::SmallT), - b'\r' => backslash(ascii::Char::SmallR), - b'\n' => backslash(ascii::Char::SmallN), - b'\\' => backslash(ascii::Char::ReverseSolidus), - b'\'' => backslash(ascii::Char::Apostrophe), - b'\"' => backslash(ascii::Char::QuotationMark), - byte => { - let mut output = [ascii::Char::Null; N]; - - if let Some(c) = byte.as_ascii() - && !byte.is_ascii_control() - { - output[0] = c; - (output, 0..1) - } else { - let hi = HEX_DIGITS[(byte >> 4) as usize]; - let lo = HEX_DIGITS[(byte & 0xf) as usize]; + #[cfg(feature = "optimize_for_size")] + { + match byte { + b'\t' => backslash(ascii::Char::SmallT), + b'\r' => backslash(ascii::Char::SmallR), + b'\n' => backslash(ascii::Char::SmallN), + b'\\' => backslash(ascii::Char::ReverseSolidus), + b'\'' => backslash(ascii::Char::Apostrophe), + b'"' => backslash(ascii::Char::QuotationMark), + 0x00..=0x1F | 0x7F => hex_escape(byte), + _ => match ascii::Char::from_u8(byte) { + Some(a) => verbatim(a), + None => hex_escape(byte), + }, + } + } + + #[cfg(not(feature = "optimize_for_size"))] + { + /// Lookup table helps us determine how to display character. + /// + /// Since ASCII characters will always be 7 bits, we can exploit this to store the 8th bit to + /// indicate whether the result is escaped or unescaped. + /// + /// We additionally use 0x80 (escaped NUL character) to indicate hex-escaped bytes, since + /// escaped NUL will not occur. + const LOOKUP: [u8; 256] = { + let mut arr = [0; 256]; + let mut idx = 0; + while idx <= 255 { + arr[idx] = match idx as u8 { + // use 8th bit to indicate escaped + b'\t' => 0x80 | b't', + b'\r' => 0x80 | b'r', + b'\n' => 0x80 | b'n', + b'\\' => 0x80 | b'\\', + b'\'' => 0x80 | b'\'', + b'"' => 0x80 | b'"', + + // use NUL to indicate hex-escaped + 0x00..=0x1F | 0x7F..=0xFF => 0x80 | b'\0', + + idx => idx, + }; + idx += 1; + } + arr + }; - output[0] = ascii::Char::ReverseSolidus; - output[1] = ascii::Char::SmallX; - output[2] = hi; - output[3] = lo; + let lookup = LOOKUP[byte as usize]; - (output, 0..4) + // 8th bit indicates escape + let lookup_escaped = lookup & 0x80 != 0; + + // SAFETY: We explicitly mask out the eighth bit to get a 7-bit ASCII character. + let lookup_ascii = unsafe { ascii::Char::from_u8_unchecked(lookup & 0x7F) }; + + if lookup_escaped { + // NUL indicates hex-escaped + if matches!(lookup_ascii, ascii::Char::Null) { + hex_escape(byte) + } else { + backslash(lookup_ascii) } + } else { + verbatim(lookup_ascii) } } } diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index c7c462a4df1..3d0c9f7c964 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -366,8 +366,6 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { /// # Examples /// /// ``` - /// #![feature(debug_more_non_exhaustive)] - /// /// use std::fmt; /// /// struct Foo(i32, String); @@ -385,7 +383,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { /// "Foo(10, ..)", /// ); /// ``` - #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")] + #[stable(feature = "debug_more_non_exhaustive", since = "CURRENT_RUSTC_VERSION")] pub fn finish_non_exhaustive(&mut self) -> fmt::Result { self.result = self.result.and_then(|_| { if self.fields > 0 { @@ -606,8 +604,6 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// # Examples /// /// ``` - /// #![feature(debug_more_non_exhaustive)] - /// /// use std::fmt; /// /// struct Foo(Vec<i32>); @@ -630,7 +626,7 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// "{1, 2, ..}", /// ); /// ``` - #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")] + #[stable(feature = "debug_more_non_exhaustive", since = "CURRENT_RUSTC_VERSION")] pub fn finish_non_exhaustive(&mut self) -> fmt::Result { self.inner.result = self.inner.result.and_then(|_| { if self.inner.has_fields { @@ -800,8 +796,6 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// # Examples /// /// ``` - /// #![feature(debug_more_non_exhaustive)] - /// /// use std::fmt; /// /// struct Foo(Vec<i32>); @@ -824,7 +818,7 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// "[1, 2, ..]", /// ); /// ``` - #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")] + #[stable(feature = "debug_more_non_exhaustive", since = "CURRENT_RUSTC_VERSION")] pub fn finish_non_exhaustive(&mut self) -> fmt::Result { self.inner.result.and_then(|_| { if self.inner.has_fields { @@ -1126,8 +1120,6 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// # Examples /// /// ``` - /// #![feature(debug_more_non_exhaustive)] - /// /// use std::fmt; /// /// struct Foo(Vec<(String, i32)>); @@ -1154,7 +1146,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// r#"{"A": 10, "B": 11, ..}"#, /// ); /// ``` - #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")] + #[stable(feature = "debug_more_non_exhaustive", since = "CURRENT_RUSTC_VERSION")] pub fn finish_non_exhaustive(&mut self) -> fmt::Result { self.result = self.result.and_then(|_| { assert!(!self.has_key, "attempted to finish a map with a partial entry"); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d7a2f1909ca..e3b4628e184 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1084,7 +1084,7 @@ extern "rust-intrinsic" { /// it does not require an `unsafe` block. /// Therefore, implementations must not require the user to uphold /// any safety invariants. - #[rustc_const_unstable(feature = "const_intrinsic_forget", issue = "none")] + #[rustc_const_stable(feature = "const_intrinsic_forget", since = "CURRENT_RUSTC_VERSION")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn forget<T: ?Sized>(_: T); @@ -1795,6 +1795,59 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; + /// Returns `a * b + c` for `f16` values, non-deterministically executing + /// either a fused multiply-add or two operations with rounding of the + /// intermediate result. + /// + /// The operation is fused if the code generator determines that target + /// instruction set has support for a fused operation, and that the fused + /// operation is more efficient than the equivalent, separate pair of mul + /// and add instructions. It is unspecified whether or not a fused operation + /// is selected, and that may depend on optimization level and context, for + /// example. + #[rustc_nounwind] + #[cfg(not(bootstrap))] + pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; + /// Returns `a * b + c` for `f32` values, non-deterministically executing + /// either a fused multiply-add or two operations with rounding of the + /// intermediate result. + /// + /// The operation is fused if the code generator determines that target + /// instruction set has support for a fused operation, and that the fused + /// operation is more efficient than the equivalent, separate pair of mul + /// and add instructions. It is unspecified whether or not a fused operation + /// is selected, and that may depend on optimization level and context, for + /// example. + #[rustc_nounwind] + #[cfg(not(bootstrap))] + pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; + /// Returns `a * b + c` for `f64` values, non-deterministically executing + /// either a fused multiply-add or two operations with rounding of the + /// intermediate result. + /// + /// The operation is fused if the code generator determines that target + /// instruction set has support for a fused operation, and that the fused + /// operation is more efficient than the equivalent, separate pair of mul + /// and add instructions. It is unspecified whether or not a fused operation + /// is selected, and that may depend on optimization level and context, for + /// example. + #[rustc_nounwind] + #[cfg(not(bootstrap))] + pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; + /// Returns `a * b + c` for `f128` values, non-deterministically executing + /// either a fused multiply-add or two operations with rounding of the + /// intermediate result. + /// + /// The operation is fused if the code generator determines that target + /// instruction set has support for a fused operation, and that the fused + /// operation is more efficient than the equivalent, separate pair of mul + /// and add instructions. It is unspecified whether or not a fused operation + /// is selected, and that may depend on optimization level and context, for + /// example. + #[rustc_nounwind] + #[cfg(not(bootstrap))] + pub fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; + /// Returns the absolute value of an `f16`. /// /// The stabilized version of this intrinsic is @@ -2635,7 +2688,7 @@ extern "rust-intrinsic" { /// This intrinsic can *only* be called where the pointer is a local without /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so /// that it trivially obeys runtime-MIR rules about derefs in operands. - #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] #[rustc_nounwind] pub fn write_via_move<T>(ptr: *mut T, value: T); @@ -3472,13 +3525,13 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] -#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] +#[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { - #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] #[rustc_nounwind] fn write_bytes<T>(dst: *mut T, val: u8, count: usize); } diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index fb0aa5398a5..a2ab39caade 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -213,7 +213,7 @@ //! - All other locals need to be declared with `let` somewhere and then can be accessed by name. //! //! #### Places -//! - Locals implicit convert to places. +//! - Locals implicitly convert to places. //! - Field accesses, derefs, and indexing work normally. //! - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions, //! see their documentation for details. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 7963459bfb5..302720eddef 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -9,7 +9,7 @@ use crate::cmp::{self, Ordering}; use crate::num::NonZero; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; -fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} +fn _assert_is_dyn_compatible(_: &dyn Iterator<Item = ()>) {} /// A trait for dealing with iterators. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 817d9e3b962..08c0d6e34cd 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -114,44 +114,28 @@ #![feature(const_align_offset)] #![feature(const_alloc_layout)] #![feature(const_arguments_as_str)] -#![feature(const_array_from_ref)] #![feature(const_array_into_iter_constructors)] #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] #![feature(const_char_encode_utf16)] -#![feature(const_char_encode_utf8)] #![feature(const_eval_select)] #![feature(const_exact_div)] -#![feature(const_float_classify)] #![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] #![feature(const_index_range_slice_index)] -#![feature(const_intrinsic_forget)] -#![feature(const_ipv4)] -#![feature(const_ipv6)] #![feature(const_likely)] #![feature(const_make_ascii)] -#![feature(const_maybe_uninit_assume_init)] #![feature(const_nonnull_new)] #![feature(const_num_midpoint)] -#![feature(const_option)] #![feature(const_option_ext)] #![feature(const_pin)] #![feature(const_pointer_is_aligned)] -#![feature(const_ptr_as_ref)] #![feature(const_ptr_is_null)] #![feature(const_ptr_sub_ptr)] -#![feature(const_ptr_write)] #![feature(const_raw_ptr_comparison)] -#![feature(const_replace)] #![feature(const_size_of_val)] #![feature(const_size_of_val_raw)] -#![feature(const_slice_from_raw_parts_mut)] -#![feature(const_slice_from_ref)] -#![feature(const_slice_split_at_mut)] -#![feature(const_str_as_mut)] -#![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] @@ -160,12 +144,8 @@ #![feature(const_typed_swap)] #![feature(const_ub_checks)] #![feature(const_unicode_case_lookup)] -#![feature(const_unsafecell_get_mut)] #![feature(coverage_attribute)] #![feature(do_not_recommend)] -#![feature(duration_consts_float)] -#![feature(f128_const)] -#![feature(f16_const)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] @@ -195,6 +175,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(const_mut_refs))] #![cfg_attr(bootstrap, feature(const_refs_to_cell))] +#![cfg_attr(bootstrap, feature(const_refs_to_static))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index fd41b80cdbd..aed6be4c627 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -158,7 +158,7 @@ pub trait Sized { /// - Arrays `[T; N]` implement `Unsize<[T]>`. /// - A type implements `Unsize<dyn Trait + 'a>` if all of these conditions are met: /// - The type implements `Trait`. -/// - `Trait` is object safe. +/// - `Trait` is dyn-compatible[^1]. /// - The type is sized. /// - The type outlives `'a`. /// - Structs `Foo<..., T1, ..., Tn, ...>` implement `Unsize<Foo<..., U1, ..., Un, ...>>` @@ -178,6 +178,7 @@ pub trait Sized { /// [`Rc`]: ../../std/rc/struct.Rc.html /// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md /// [nomicon-coerce]: ../../nomicon/coercions.html +/// [^1]: Formerly known as *object safe*. #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] #[rustc_deny_explicit_impl(implement_via_object = false)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index c67796ad3db..f992785c43b 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -913,7 +913,11 @@ impl<T> MaybeUninit<T> { /// }; /// ``` #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] - #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable( + feature = "const_maybe_uninit_assume_init", + since = "CURRENT_RUSTC_VERSION" + )] #[inline(always)] pub const unsafe fn assume_init_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` is initialized. @@ -999,7 +1003,8 @@ impl<T> MaybeUninit<T> { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 414262fcf5a..9bf2aa594c0 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -857,7 +857,8 @@ pub fn take<T: Default>(dest: &mut T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] -#[rustc_const_unstable(feature = "const_replace", issue = "83164")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] +#[rustc_const_stable(feature = "const_replace", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(not(test), rustc_diagnostic_item = "mem_replace")] pub const fn replace<T>(dest: &mut T, src: T) -> T { // It may be tempting to use `swap` to avoid `unsafe` here. Don't! diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 919f681f911..d3360c18207 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -295,7 +295,6 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -348,7 +347,6 @@ impl IpAddr { /// true /// ); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -600,6 +598,24 @@ impl Ipv4Addr { self.octets } + /// Creates an `Ipv4Addr` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_from)] + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from_octets([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` + #[unstable(feature = "ip_from", issue = "131360")] + #[must_use] + #[inline] + pub const fn from_octets(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr { octets } + } + /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). /// /// This property is defined in _UNIX Network Programming, Second Edition_, @@ -776,7 +792,6 @@ impl Ipv4Addr { /// /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry. /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -813,7 +828,6 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -841,7 +855,6 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -878,7 +891,6 @@ impl Ipv4Addr { /// // The broadcast address is not considered as reserved for future use by this implementation /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1400,6 +1412,34 @@ impl Ipv6Addr { ] } + /// Creates an `Ipv6Addr` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_from)] + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from_segments([ + /// 0x20du16, 0x20cu16, 0x20bu16, 0x20au16, + /// 0x209u16, 0x208u16, 0x207u16, 0x206u16, + /// ]); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x20d, 0x20c, 0x20b, 0x20a, + /// 0x209, 0x208, 0x207, 0x206, + /// ), + /// addr + /// ); + /// ``` + #[unstable(feature = "ip_from", issue = "131360")] + #[must_use] + #[inline] + pub const fn from_segments(segments: [u16; 8]) -> Ipv6Addr { + let [a, b, c, d, e, f, g, h] = segments; + Ipv6Addr::new(a, b, c, d, e, f, g, h) + } + /// Returns [`true`] for the special 'unspecified' address (`::`). /// /// This property is defined in [IETF RFC 4291]. @@ -1510,7 +1550,6 @@ impl Ipv6Addr { /// /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry. /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1562,7 +1601,6 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1591,7 +1629,6 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1643,7 +1680,6 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1668,7 +1704,6 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1729,7 +1764,6 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1758,7 +1792,6 @@ impl Ipv6Addr { /// ); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1818,7 +1851,6 @@ impl Ipv6Addr { /// /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_ipv4_mapped(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] @@ -1932,7 +1964,7 @@ impl Ipv6Addr { /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), - /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// [0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// ``` #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] #[stable(feature = "ipv6_to_octets", since = "1.12.0")] @@ -1941,6 +1973,33 @@ impl Ipv6Addr { pub const fn octets(&self) -> [u8; 16] { self.octets } + + /// Creates an `Ipv6Addr` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_from)] + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from_octets([ + /// 0x19u8, 0x18u8, 0x17u8, 0x16u8, 0x15u8, 0x14u8, 0x13u8, 0x12u8, + /// 0x11u8, 0x10u8, 0x0fu8, 0x0eu8, 0x0du8, 0x0cu8, 0x0bu8, 0x0au8, + /// ]); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x1918, 0x1716, 0x1514, 0x1312, + /// 0x1110, 0x0f0e, 0x0d0c, 0x0b0a, + /// ), + /// addr + /// ); + /// ``` + #[unstable(feature = "ip_from", issue = "131360")] + #[must_use] + #[inline] + pub const fn from_octets(octets: [u8; 16]) -> Ipv6Addr { + Ipv6Addr { octets } + } } /// Writes an Ipv6Addr, conforming to the canonical style described by @@ -2113,15 +2172,13 @@ impl From<[u8; 16]> for Ipv6Addr { /// use std::net::Ipv6Addr; /// /// let addr = Ipv6Addr::from([ - /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, - /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// 0x19u8, 0x18u8, 0x17u8, 0x16u8, 0x15u8, 0x14u8, 0x13u8, 0x12u8, + /// 0x11u8, 0x10u8, 0x0fu8, 0x0eu8, 0x0du8, 0x0cu8, 0x0bu8, 0x0au8, /// ]); /// assert_eq!( /// Ipv6Addr::new( - /// 0x1918, 0x1716, - /// 0x1514, 0x1312, - /// 0x1110, 0x0f0e, - /// 0x0d0c, 0x0b0a + /// 0x1918, 0x1716, 0x1514, 0x1312, + /// 0x1110, 0x0f0e, 0x0d0c, 0x0b0a, /// ), /// addr /// ); @@ -2142,15 +2199,13 @@ impl From<[u16; 8]> for Ipv6Addr { /// use std::net::Ipv6Addr; /// /// let addr = Ipv6Addr::from([ - /// 525u16, 524u16, 523u16, 522u16, - /// 521u16, 520u16, 519u16, 518u16, + /// 0x20du16, 0x20cu16, 0x20bu16, 0x20au16, + /// 0x209u16, 0x208u16, 0x207u16, 0x206u16, /// ]); /// assert_eq!( /// Ipv6Addr::new( - /// 0x20d, 0x20c, - /// 0x20b, 0x20a, - /// 0x209, 0x208, - /// 0x207, 0x206 + /// 0x20d, 0x20c, 0x20b, 0x20a, + /// 0x209, 0x208, 0x207, 0x206, /// ), /// addr /// ); @@ -2172,15 +2227,13 @@ impl From<[u8; 16]> for IpAddr { /// use std::net::{IpAddr, Ipv6Addr}; /// /// let addr = IpAddr::from([ - /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, - /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// 0x19u8, 0x18u8, 0x17u8, 0x16u8, 0x15u8, 0x14u8, 0x13u8, 0x12u8, + /// 0x11u8, 0x10u8, 0x0fu8, 0x0eu8, 0x0du8, 0x0cu8, 0x0bu8, 0x0au8, /// ]); /// assert_eq!( /// IpAddr::V6(Ipv6Addr::new( - /// 0x1918, 0x1716, - /// 0x1514, 0x1312, - /// 0x1110, 0x0f0e, - /// 0x0d0c, 0x0b0a + /// 0x1918, 0x1716, 0x1514, 0x1312, + /// 0x1110, 0x0f0e, 0x0d0c, 0x0b0a, /// )), /// addr /// ); @@ -2201,15 +2254,13 @@ impl From<[u16; 8]> for IpAddr { /// use std::net::{IpAddr, Ipv6Addr}; /// /// let addr = IpAddr::from([ - /// 525u16, 524u16, 523u16, 522u16, - /// 521u16, 520u16, 519u16, 518u16, + /// 0x20du16, 0x20cu16, 0x20bu16, 0x20au16, + /// 0x209u16, 0x208u16, 0x207u16, 0x206u16, /// ]); /// assert_eq!( /// IpAddr::V6(Ipv6Addr::new( - /// 0x20d, 0x20c, - /// 0x20b, 0x20a, - /// 0x209, 0x208, - /// 0x207, 0x206 + /// 0x20d, 0x20c, 0x20b, 0x20a, + /// 0x209, 0x208, 0x207, 0x206, /// )), /// addr /// ); diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 100271fa54c..764df4fe4b0 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -288,7 +288,7 @@ impl f128 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub(crate) const fn abs_private(self) -> f128 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { @@ -319,7 +319,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_infinite(self) -> bool { (self == f128::INFINITY) | (self == f128::NEG_INFINITY) } @@ -346,7 +346,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. @@ -380,7 +380,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } @@ -412,7 +412,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } @@ -437,7 +437,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn classify(self) -> FpCategory { let bits = self.to_bits(); match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) { @@ -910,7 +910,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u128 { // SAFETY: `u128` is a plain old datatype so we can always transmute to it. @@ -959,7 +959,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_bits(v: u128) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u128` is a plain old datatype so we can always transmute from it. @@ -986,7 +986,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 16] { self.to_bits().to_be_bytes() @@ -1012,7 +1012,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 16] { self.to_bits().to_le_bytes() @@ -1049,7 +1049,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 16] { self.to_bits().to_ne_bytes() @@ -1077,7 +1077,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_be_bytes(bytes)) } @@ -1104,7 +1104,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_le_bytes(bytes)) } @@ -1141,7 +1141,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 6bdc569df28..897fc8c105d 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -282,7 +282,7 @@ impl f16 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub(crate) const fn abs_private(self) -> f16 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) } @@ -310,7 +310,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_infinite(self) -> bool { (self == f16::INFINITY) | (self == f16::NEG_INFINITY) } @@ -336,7 +336,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. @@ -368,7 +368,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } @@ -398,7 +398,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } @@ -422,7 +422,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn classify(self) -> FpCategory { let b = self.to_bits(); match (b & Self::MAN_MASK, b & Self::EXP_MASK) { @@ -896,7 +896,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u16 { // SAFETY: `u16` is a plain old datatype so we can always transmute to it. @@ -944,7 +944,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_bits(v: u16) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u16` is a plain old datatype so we can always transmute from it. @@ -970,7 +970,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() @@ -995,7 +995,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() @@ -1033,7 +1033,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() @@ -1057,7 +1057,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } @@ -1080,7 +1080,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } @@ -1114,7 +1114,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index d0eb6bb3f28..a9a2595c25c 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -517,7 +517,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :) pub const fn is_nan(self) -> bool { @@ -528,7 +528,6 @@ impl f32 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] pub(crate) const fn abs_private(self) -> f32 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { mem::transmute::<u32, f32>(mem::transmute::<f32, u32>(self) & !Self::SIGN_MASK) } @@ -551,7 +550,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_infinite(self) -> bool { // Getting clever with transmutation can result in incorrect answers on some FPUs @@ -576,7 +575,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, @@ -604,7 +603,7 @@ impl f32 { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[stable(feature = "is_subnormal", since = "1.53.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) @@ -631,7 +630,7 @@ impl f32 { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) @@ -651,7 +650,7 @@ impl f32 { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] pub const fn classify(self) -> FpCategory { // We used to have complicated logic here that avoids the simple bit-based tests to work // around buggy codegen for x87 targets (see @@ -687,7 +686,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_sign_positive(self) -> bool { !self.is_sign_negative() @@ -712,7 +711,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 4bc275ad147..aa7a54ca650 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -516,7 +516,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :) pub const fn is_nan(self) -> bool { @@ -527,7 +527,6 @@ impl f64 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] pub(crate) const fn abs_private(self) -> f64 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { mem::transmute::<u64, f64>(mem::transmute::<f64, u64>(self) & !Self::SIGN_MASK) } @@ -550,7 +549,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_infinite(self) -> bool { // Getting clever with transmutation can result in incorrect answers on some FPUs @@ -575,7 +574,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, @@ -603,7 +602,7 @@ impl f64 { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[stable(feature = "is_subnormal", since = "1.53.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) @@ -630,7 +629,7 @@ impl f64 { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) @@ -650,7 +649,7 @@ impl f64 { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] pub const fn classify(self) -> FpCategory { // We used to have complicated logic here that avoids the simple bit-based tests to work // around buggy codegen for x87 targets (see @@ -686,7 +685,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_sign_positive(self) -> bool { !self.is_sign_negative() @@ -720,7 +719,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index ab73dc19fcc..7a8158b8231 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -171,14 +171,13 @@ impl<B, C> ControlFlow<B, C> { /// # Examples /// /// ``` - /// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3)); /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None); /// ``` #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] pub fn break_value(self) -> Option<B> { match self { ControlFlow::Continue(..) => None, @@ -189,11 +188,8 @@ impl<B, C> ControlFlow<B, C> { /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function /// to the break value in case it exists. #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C> - where - F: FnOnce(B) -> T, - { + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] + pub fn map_break<T>(self, f: impl FnOnce(B) -> T) -> ControlFlow<T, C> { match self { ControlFlow::Continue(x) => ControlFlow::Continue(x), ControlFlow::Break(x) => ControlFlow::Break(f(x)), @@ -206,14 +202,13 @@ impl<B, C> ControlFlow<B, C> { /// # Examples /// /// ``` - /// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// assert_eq!(ControlFlow::<i32, String>::Break(3).continue_value(), None); /// assert_eq!(ControlFlow::<String, i32>::Continue(3).continue_value(), Some(3)); /// ``` #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] pub fn continue_value(self) -> Option<C> { match self { ControlFlow::Continue(x) => Some(x), @@ -224,11 +219,8 @@ impl<B, C> ControlFlow<B, C> { /// Maps `ControlFlow<B, C>` to `ControlFlow<B, T>` by applying a function /// to the continue value in case it exists. #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub fn map_continue<T, F>(self, f: F) -> ControlFlow<B, T> - where - F: FnOnce(C) -> T, - { + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] + pub fn map_continue<T>(self, f: impl FnOnce(C) -> T) -> ControlFlow<B, T> { match self { ControlFlow::Continue(x) => ControlFlow::Continue(f(x)), ControlFlow::Break(x) => ControlFlow::Break(x), diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 25c4b87f4e7..5464bf645d9 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -162,7 +162,7 @@ pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; pub use self::bit::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; #[stable(feature = "op_assign_traits", since = "1.8.0")] pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; -#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +#[stable(feature = "control_flow_enum_type", since = "1.55.0")] pub use self::control_flow::ControlFlow; #[unstable(feature = "coroutine_trait", issue = "43122")] pub use self::coroutine::{Coroutine, CoroutineState}; diff --git a/library/core/src/ops/unsize.rs b/library/core/src/ops/unsize.rs index b51f12580ea..d2a07197f6f 100644 --- a/library/core/src/ops/unsize.rs +++ b/library/core/src/ops/unsize.rs @@ -68,8 +68,8 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {} #[unstable(feature = "coerce_unsized", issue = "18598")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} -/// `DispatchFromDyn` is used in the implementation of object safety checks (specifically allowing -/// arbitrary self types), to guarantee that a method's receiver type can be dispatched on. +/// `DispatchFromDyn` is used in the implementation of dyn-compatibility[^1] checks (specifically +/// allowing arbitrary self types), to guarantee that a method's receiver type can be dispatched on. /// /// Note: `DispatchFromDyn` was briefly named `CoerceSized` (and had a slightly different /// interpretation). @@ -80,7 +80,7 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} /// type). The compiler must generate an implicit conversion from the trait object/wide pointer to /// the concrete reference/narrow pointer. Implementing `DispatchFromDyn` indicates that that /// conversion is allowed and thus that the type implementing `DispatchFromDyn` is safe to use as -/// the self type in an object-safe method. (in the above example, the compiler will require +/// the self type in an dyn-compatible method. (in the above example, the compiler will require /// `DispatchFromDyn` is implemented for `&'a U`). /// /// `DispatchFromDyn` does not specify the conversion from wide pointer to narrow pointer; the @@ -112,6 +112,8 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} /// T: Unsize<U>, /// {} /// ``` +/// +/// [^1]: Formerly known as *object safety*. #[unstable(feature = "dispatch_from_dyn", issue = "none")] #[lang = "dispatch_from_dyn"] pub trait DispatchFromDyn<T> { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 154e52e288b..84ccb7a1f66 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -723,7 +723,8 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn as_mut(&mut self) -> Option<&mut T> { match *self { Some(ref mut x) => Some(x), @@ -924,7 +925,8 @@ impl<T> Option<T> { #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "option_expect")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn expect(self, msg: &str) -> T { match self { Some(val) => val, @@ -962,7 +964,8 @@ impl<T> Option<T> { #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "option_unwrap")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn unwrap(self) -> T { match self { Some(val) => val, @@ -1069,7 +1072,8 @@ impl<T> Option<T> { #[inline] #[track_caller] #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn unwrap_unchecked(self) -> T { match self { Some(val) => val, @@ -1712,7 +1716,8 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn take(&mut self) -> Option<T> { // FIXME(const-hack) replace `mem::replace` by `mem::take` when the latter is const ready mem::replace(self, None) @@ -1769,8 +1774,9 @@ impl<T> Option<T> { /// assert_eq!(old, None); /// ``` #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] #[stable(feature = "option_replace", since = "1.31.0")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn replace(&mut self, value: T) -> Option<T> { mem::replace(self, Some(value)) } @@ -1878,7 +1884,7 @@ impl<T> Option<&T> { /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "copied", since = "1.35.0")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn copied(self) -> Option<T> where T: Copy, @@ -1931,7 +1937,8 @@ impl<T> Option<&mut T> { /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "copied", since = "1.35.0")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn copied(self) -> Option<T> where T: Copy, @@ -1986,7 +1993,8 @@ impl<T, E> Option<Result<T, E>> { /// ``` #[inline] #[stable(feature = "transpose_result", since = "1.33.0")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn transpose(self) -> Result<Option<T>, E> { match self { Some(Ok(x)) => Ok(Some(x)), @@ -2009,7 +2017,6 @@ const fn unwrap_failed() -> ! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[cold] #[track_caller] -#[rustc_const_unstable(feature = "const_option", issue = "67441")] const fn expect_failed(msg: &str) -> ! { panic_display(&msg) } @@ -2534,7 +2541,8 @@ impl<T> Option<Option<T>> { /// ``` #[inline] #[stable(feature = "option_flattening", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_option", since = "CURRENT_RUSTC_VERSION")] pub const fn flatten(self) -> Option<T> { // FIXME(const-hack): could be written with `and_then` match self { diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 962da6643dd..89936dc12ac 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -862,6 +862,27 @@ mod prim_array {} /// assert_eq!(x, &[1, 7, 3]); /// ``` /// +/// It is possible to slice empty subranges of slices by using empty ranges (including `slice.len()..slice.len()`): +/// ``` +/// let x = [1, 2, 3]; +/// let empty = &x[0..0]; // subslice before the first element +/// assert_eq!(empty, &[]); +/// let empty = &x[..0]; // same as &x[0..0] +/// assert_eq!(empty, &[]); +/// let empty = &x[1..1]; // empty subslice in the middle +/// assert_eq!(empty, &[]); +/// let empty = &x[3..3]; // subslice after the last element +/// assert_eq!(empty, &[]); +/// let empty = &x[3..]; // same as &x[3..3] +/// assert_eq!(empty, &[]); +/// ``` +/// +/// It is not allowed to use subranges that start with lower bound bigger than `slice.len()`: +/// ```should_panic +/// let x = vec![1, 2, 3]; +/// let _ = &x[4..4]; +/// ``` +/// /// As slices store the length of the sequence they refer to, they have twice /// the size of pointers to [`Sized`](marker/trait.Sized.html) types. /// Also see the reference on @@ -1251,7 +1272,7 @@ mod prim_f16 {} /// - **Unchanged NaN propagation**: The quiet bit and payload are copied from any input operand /// that is a NaN. If the inputs and outputs do not have the same size (i.e., for `as` casts), the /// same rules as for "quieting NaN propagation" apply, with one caveat: if the output is smaller -/// than the input, droppig the low-order bits may result in a payload of 0; a payload of 0 is not +/// than the input, dropping the low-order bits may result in a payload of 0; a payload of 0 is not /// possible with a signaling NaN (the all-0 significand encodes an infinity) so unchanged NaN /// propagation cannot occur with some inputs. /// - **Target-specific NaN**: The quiet bit is set and the payload is picked from a target-specific diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 332c5e904d7..c9af7f13e46 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -395,6 +395,36 @@ impl<T: ?Sized> *const T { where T: Sized, { + #[inline] + const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: isize, size: usize) -> bool { + // We know `size <= isize::MAX` so the `as` cast here is not lossy. + let Some(byte_offset) = count.checked_mul(size as isize) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); + !overflow + } + + const fn comptime(_: *const (), _: isize, _: usize) -> bool { + true + } + + // We can use const_eval_select here because this is only for UB checks. + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::offset requires the address calculation to not overflow", + ( + this: *const () = self as *const (), + count: isize = count, + size: usize = size_of::<T>(), + ) => runtime_offset_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -726,7 +756,6 @@ impl<T: ?Sized> *const T { true } - #[allow(unused_unsafe)] intrinsics::const_eval_select((this, origin), comptime, runtime) } @@ -858,6 +887,36 @@ impl<T: ?Sized> *const T { where T: Sized, { + #[cfg(debug_assertions)] + #[inline] + const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add(byte_offset); + byte_offset <= (isize::MAX as usize) && !overflow + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::add requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::<T>(), + ) => runtime_add_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -936,6 +995,35 @@ impl<T: ?Sized> *const T { where T: Sized, { + #[cfg(debug_assertions)] + #[inline] + const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::sub requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::<T>(), + ) => runtime_sub_nowrap(this, count, size) + ); + if T::IS_ZST { // Pointer arithmetic does nothing when the pointee is a ZST. self @@ -943,7 +1031,7 @@ impl<T: ?Sized> *const T { // SAFETY: the caller must uphold the safety contract for `offset`. // Because the pointee is *not* a ZST, that means that `count` is // at most `isize::MAX`, and thus the negation cannot overflow. - unsafe { self.offset((count as isize).unchecked_neg()) } + unsafe { intrinsics::offset(self, intrinsics::unchecked_sub(0, count as isize)) } } } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index b6df780fe2f..6b074492924 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -992,7 +992,7 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] { /// ``` #[inline] #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] -#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"] pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { from_raw_parts_mut(data, len) @@ -1263,7 +1263,8 @@ const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, coun /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_replace", issue = "83164")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] +#[rustc_const_stable(feature = "const_replace", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_replace"] pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T { // SAFETY: the caller must guarantee that `dst` is valid to be @@ -1611,7 +1612,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] +#[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_write"] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write<T>(dst: *mut T, src: T) { @@ -1719,7 +1720,8 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) { /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] -#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_refs_to_cell))] +#[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_write_unaligned"] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { @@ -1909,6 +1911,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) { /// than trying to adapt this to accommodate that change. /// /// Any questions go to @nagisa. +#[cfg_attr(not(bootstrap), allow(ptr_to_integer_transmute_in_consts))] #[lang = "align_offset"] pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize { // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <= diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 287073497f8..ced6cb7d520 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -393,6 +393,37 @@ impl<T: ?Sized> *mut T { where T: Sized, { + #[inline] + const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: isize, size: usize) -> bool { + // `size` is the size of a Rust type, so we know that + // `size <= isize::MAX` and thus `as` cast here is not lossy. + let Some(byte_offset) = count.checked_mul(size as isize) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); + !overflow + } + + const fn comptime(_: *const (), _: isize, _: usize) -> bool { + true + } + + // We can use const_eval_select here because this is only for UB checks. + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::offset requires the address calculation to not overflow", + ( + this: *const () = self as *const (), + count: isize = count, + size: usize = size_of::<T>(), + ) => runtime_offset_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. // The obtained pointer is valid for writes since the caller must // guarantee that it points to the same allocated object as `self`. @@ -940,6 +971,36 @@ impl<T: ?Sized> *mut T { where T: Sized, { + #[cfg(debug_assertions)] + #[inline] + const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add(byte_offset); + byte_offset <= (isize::MAX as usize) && !overflow + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::add requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::<T>(), + ) => runtime_add_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -1018,6 +1079,35 @@ impl<T: ?Sized> *mut T { where T: Sized, { + #[cfg(debug_assertions)] + #[inline] + const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::sub requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::<T>(), + ) => runtime_sub_nowrap(this, count, size) + ); + if T::IS_ZST { // Pointer arithmetic does nothing when the pointee is a ZST. self @@ -1025,7 +1115,7 @@ impl<T: ?Sized> *mut T { // SAFETY: the caller must uphold the safety contract for `offset`. // Because the pointee is *not* a ZST, that means that `count` is // at most `isize::MAX`, and thus the negation cannot overflow. - unsafe { self.offset((count as isize).unchecked_neg()) } + unsafe { intrinsics::offset(self, intrinsics::unchecked_sub(0, count as isize)) } } } @@ -1359,7 +1449,7 @@ impl<T: ?Sized> *mut T { /// /// [`ptr::write`]: crate::ptr::write() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write(self, val: T) @@ -1378,7 +1468,7 @@ impl<T: ?Sized> *mut T { /// [`ptr::write_bytes`]: crate::ptr::write_bytes() #[doc(alias = "memset")] #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_bytes(self, val: u8, count: usize) @@ -1419,7 +1509,7 @@ impl<T: ?Sized> *mut T { /// /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_unaligned(self, val: T) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index e7a265f7e2b..980d4a3cf6c 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -394,7 +394,8 @@ impl<T: ?Sized> NonNull<T> { /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_ptr_as_ref", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline(always)] pub const unsafe fn as_mut<'a>(&mut self) -> &'a mut T { @@ -1012,7 +1013,7 @@ impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn write(self, val: T) where T: Sized, @@ -1031,7 +1032,7 @@ impl<T: ?Sized> NonNull<T> { #[doc(alias = "memset")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn write_bytes(self, val: u8, count: usize) where T: Sized, @@ -1072,7 +1073,7 @@ impl<T: ?Sized> NonNull<T> { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_const_stable(feature = "const_ptr_write", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn write_unaligned(self, val: T) where T: Sized, @@ -1210,7 +1211,6 @@ impl<T: ?Sized> NonNull<T> { /// /// ``` /// #![feature(const_nonnull_new)] - /// #![feature(const_option)] /// #![feature(const_pointer_is_aligned)] /// use std::ptr::NonNull; /// @@ -1263,7 +1263,6 @@ impl<T: ?Sized> NonNull<T> { /// /// ``` /// #![feature(const_pointer_is_aligned)] - /// #![feature(const_option)] /// #![feature(const_nonnull_new)] /// use std::ptr::NonNull; /// @@ -1433,7 +1432,10 @@ impl<T> NonNull<[T]> { /// (Note that this example artificially demonstrates a use of this method, /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.) #[stable(feature = "nonnull_slice_from_raw_parts", since = "1.70.0")] - #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] + #[rustc_const_stable( + feature = "const_slice_from_raw_parts_mut", + since = "CURRENT_RUSTC_VERSION" + )] #[must_use] #[inline] pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 610edae48d3..95faacbf96d 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -734,7 +734,8 @@ impl<T, E> Result<T, E> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_result", issue = "82814")] + #[rustc_const_stable(feature = "const_result", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn as_mut(&mut self) -> Result<&mut T, &mut E> { match *self { Ok(ref mut x) => Ok(x), @@ -1536,7 +1537,8 @@ impl<T, E> Result<&T, E> { /// ``` #[inline] #[stable(feature = "result_copied", since = "1.59.0")] - #[rustc_const_unstable(feature = "const_result", issue = "82814")] + #[rustc_const_stable(feature = "const_result", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn copied(self) -> Result<T, E> where T: Copy, @@ -1586,7 +1588,9 @@ impl<T, E> Result<&mut T, E> { /// ``` #[inline] #[stable(feature = "result_copied", since = "1.59.0")] - #[rustc_const_unstable(feature = "const_result", issue = "82814")] + #[rustc_const_stable(feature = "const_result", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn copied(self) -> Result<T, E> where T: Copy, @@ -1639,7 +1643,8 @@ impl<T, E> Result<Option<T>, E> { /// ``` #[inline] #[stable(feature = "transpose_result", since = "1.33.0")] - #[rustc_const_unstable(feature = "const_result", issue = "82814")] + #[rustc_const_stable(feature = "const_result", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn transpose(self) -> Option<Result<T, E>> { match self { Ok(Some(x)) => Some(Ok(x)), diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 922168b9e8e..90ddc9c1d85 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -171,7 +171,8 @@ impl<T> [T] { /// assert_eq!(None, y.first_mut()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use] pub const fn first_mut(&mut self) -> Option<&mut T> { @@ -213,7 +214,8 @@ impl<T> [T] { /// assert_eq!(x, &[3, 4, 5]); /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use] pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { @@ -255,7 +257,8 @@ impl<T> [T] { /// assert_eq!(x, &[4, 5, 3]); /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use] pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { @@ -297,7 +300,8 @@ impl<T> [T] { /// assert_eq!(None, y.last_mut()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use] pub const fn last_mut(&mut self) -> Option<&mut T> { @@ -352,7 +356,8 @@ impl<T> [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn first_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -417,7 +422,8 @@ impl<T> [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn split_first_chunk_mut<const N: usize>( &mut self, ) -> Option<(&mut [T; N], &mut [T])> { @@ -487,7 +493,8 @@ impl<T> [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn split_last_chunk_mut<const N: usize>( &mut self, ) -> Option<(&mut [T], &mut [T; N])> { @@ -556,7 +563,8 @@ impl<T> [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn last_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -1899,7 +1907,8 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { match self.split_at_mut_checked(mid) { Some(pair) => pair, @@ -2001,7 +2010,8 @@ impl<T> [T] { /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); /// ``` #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[inline] #[must_use] pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { @@ -2101,7 +2111,8 @@ impl<T> [T] { /// assert_eq!(None, v.split_at_mut_checked(7)); /// ``` #[stable(feature = "split_at_checked", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[inline] #[must_use] pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> { diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 2cf3fecb475..998f9360332 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -171,7 +171,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// [`NonNull::dangling()`]: ptr::NonNull::dangling #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "CURRENT_RUSTC_VERSION")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[must_use] #[rustc_diagnostic_item = "slice_from_raw_parts_mut"] pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { @@ -203,7 +204,8 @@ pub const fn from_ref<T>(s: &T) -> &[T] { /// Converts a reference to T into a slice of length 1 (without copying). #[stable(feature = "from_ref", since = "1.28.0")] -#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")] +#[rustc_const_stable(feature = "const_slice_from_ref", since = "CURRENT_RUSTC_VERSION")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[must_use] pub const fn from_mut<T>(s: &mut T) -> &mut [T] { array::from_mut(s) diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index d6459607221..194db56fdaf 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -195,7 +195,11 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[inline] #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] +#[rustc_const_stable( + feature = "const_str_from_utf8_unchecked_mut", + since = "CURRENT_RUSTC_VERSION" +)] #[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 3d535214637..e93c52f2799 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -339,7 +339,8 @@ impl str { /// assert_eq!("🍔∈🌏", s); /// ``` #[stable(feature = "str_mut_extras", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_str_as_mut", issue = "130086")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_str_as_mut", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline(always)] pub const unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { @@ -385,7 +386,8 @@ impl str { /// It is your responsibility to make sure that the string slice only gets /// modified in a way that it remains valid UTF-8. #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_str_as_mut", issue = "130086")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_str_as_mut", since = "CURRENT_RUSTC_VERSION")] #[rustc_never_returns_null_ptr] #[must_use] #[inline(always)] diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 65560dfcf9d..f7ea7e06e9c 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -626,7 +626,6 @@ impl Duration { /// ``` #[stable(feature = "duration_abs_diff", since = "1.81.0")] #[rustc_const_stable(feature = "duration_abs_diff", since = "1.81.0")] - #[rustc_allow_const_fn_unstable(const_option)] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -847,7 +846,7 @@ impl Duration { #[stable(feature = "duration_float", since = "1.38.0")] #[must_use] #[inline] - #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] + #[rustc_const_stable(feature = "duration_consts_float", since = "CURRENT_RUSTC_VERSION")] pub const fn as_secs_f64(&self) -> f64 { (self.secs as f64) + (self.nanos.0 as f64) / (NANOS_PER_SEC as f64) } @@ -866,7 +865,7 @@ impl Duration { #[stable(feature = "duration_float", since = "1.38.0")] #[must_use] #[inline] - #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] + #[rustc_const_stable(feature = "duration_consts_float", since = "CURRENT_RUSTC_VERSION")] pub const fn as_secs_f32(&self) -> f32 { (self.secs as f32) + (self.nanos.0 as f32) / (NANOS_PER_SEC as f32) } @@ -886,7 +885,7 @@ impl Duration { #[unstable(feature = "duration_millis_float", issue = "122451")] #[must_use] #[inline] - #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] + #[rustc_const_unstable(feature = "duration_millis_float", issue = "122451")] pub const fn as_millis_f64(&self) -> f64 { (self.secs as f64) * (MILLIS_PER_SEC as f64) + (self.nanos.0 as f64) / (NANOS_PER_MILLI as f64) @@ -907,7 +906,7 @@ impl Duration { #[unstable(feature = "duration_millis_float", issue = "122451")] #[must_use] #[inline] - #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] + #[rustc_const_unstable(feature = "duration_millis_float", issue = "122451")] pub const fn as_millis_f32(&self) -> f32 { (self.secs as f32) * (MILLIS_PER_SEC as f32) + (self.nanos.0 as f32) / (NANOS_PER_MILLI as f32) @@ -1087,7 +1086,7 @@ impl Duration { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] + #[rustc_const_stable(feature = "duration_consts_float", since = "CURRENT_RUSTC_VERSION")] pub const fn div_duration_f64(self, rhs: Duration) -> f64 { let self_nanos = (self.secs as f64) * (NANOS_PER_SEC as f64) + (self.nanos.0 as f64); let rhs_nanos = (rhs.secs as f64) * (NANOS_PER_SEC as f64) + (rhs.nanos.0 as f64); @@ -1108,7 +1107,7 @@ impl Duration { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")] + #[rustc_const_stable(feature = "duration_consts_float", since = "CURRENT_RUSTC_VERSION")] pub const fn div_duration_f32(self, rhs: Duration) -> f32 { let self_nanos = (self.secs as f32) * (NANOS_PER_SEC as f32) + (self.nanos.0 as f32); let rhs_nanos = (rhs.secs as f32) * (NANOS_PER_SEC as f32) + (rhs.nanos.0 as f32); diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index db2e3ddd754..cba53bf5054 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -331,14 +331,14 @@ pub mod grapheme_extend { #[rustfmt::skip] pub mod lowercase { - const BITSET_CHUNKS_MAP: &'static [u8; 123] = &[ + static BITSET_CHUNKS_MAP: [u8; 123] = [ 14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 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, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 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, 19, 0, 3, 18, 0, 7, ]; - const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 20] = &[ + static BITSET_INDEX_CHUNKS: [[u8; 16]; 20] = [ [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, 61, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 56, 0], @@ -360,7 +360,7 @@ pub mod lowercase { [16, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [65, 41, 55, 12, 77, 63, 18, 1, 7, 64, 76, 20, 73, 74, 4, 45], ]; - const BITSET_CANONICAL: &'static [u64; 56] = &[ + static BITSET_CANONICAL: [u64; 56] = [ 0b0000000000000000000000000000000000000000000000000000000000000000, 0b1111111111111111110000000000000000000000000011111111111111111111, 0b1010101010101010101010101010101010101010101010101010100000000010, @@ -418,7 +418,7 @@ pub mod lowercase { 0b1110011001010001001011010010101001001110001001000011000100101001, 0b1110101111000000000000000000000000001111111111111111111111111100, ]; - const BITSET_MAPPING: &'static [(u8, u8); 22] = &[ + static BITSET_MAPPING: [(u8, u8); 22] = [ (0, 64), (1, 188), (1, 186), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), (1, 70), (1, 77), (2, 146), (2, 144), (2, 83), (3, 93), (3, 147), (3, 133), (4, 12), (4, 6), (5, 187), (6, 78), (7, 132), @@ -471,14 +471,14 @@ pub mod n { #[rustfmt::skip] pub mod uppercase { - const BITSET_CHUNKS_MAP: &'static [u8; 125] = &[ + static BITSET_CHUNKS_MAP: [u8; 125] = [ 12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6, 6, 6, 9, 6, 3, ]; - const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 17] = &[ + static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [ [44, 44, 5, 35, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 5, 1], [44, 44, 5, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], [44, 44, 40, 44, 44, 44, 44, 44, 17, 17, 63, 17, 43, 29, 24, 23], @@ -497,7 +497,7 @@ pub mod uppercase { [58, 19, 2, 18, 10, 48, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], [58, 38, 17, 27, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], ]; - const BITSET_CANONICAL: &'static [u64; 44] = &[ + static BITSET_CANONICAL: [u64; 44] = [ 0b0000011111111111111111111111111000000000000000000000000000000000, 0b0000000000111111111111111111111111111111111111111111111111111111, 0b0101010101010101010101010101010101010101010101010101010000000001, @@ -543,7 +543,7 @@ pub mod uppercase { 0b1111011111111111000000000000000000000000000000000000000000000000, 0b1111111100000000111111110000000000111111000000001111111100000000, ]; - const BITSET_MAPPING: &'static [(u8, u8); 25] = &[ + static BITSET_MAPPING: [(u8, u8); 25] = [ (0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121), (0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164), (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 3d3f8ac10c6..ce09ee507f1 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -481,9 +481,25 @@ fn ascii_ctype_const() { } #[test] -fn test_ascii_display() { - assert_eq!(b"foo'bar".escape_ascii().to_string(), r#"foo\'bar"#); - assert_eq!(b"\0\xff".escape_ascii().to_string(), r#"\x00\xff"#); +fn test_escape_ascii() { + let mut buf = [0u8; 0x1F + 7]; // 0..=0x1F plus two quotes, slash, \x7F, \x80, \xFF + for idx in 0..=0x1F { + buf[idx] = idx as u8; + } + buf[0x20] = b'\''; + buf[0x21] = b'"'; + buf[0x22] = b'\\'; + buf[0x23] = 0x7F; + buf[0x24] = 0x80; + buf[0x25] = 0xff; + assert_eq!( + buf.escape_ascii().to_string(), + r#"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\'\"\\\x7f\x80\xff"# + ); +} + +#[test] +fn test_escape_ascii_iter() { let mut it = b"\0fastpath\xffremainder\xff".escape_ascii(); let _ = it.advance_by(4); let _ = it.advance_back_by(4); diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs index 03826fc4c92..bf91e9e5df0 100644 --- a/library/core/tests/hash/mod.rs +++ b/library/core/tests/hash/mod.rs @@ -164,7 +164,7 @@ fn test_indirect_hasher() { } #[test] -fn test_build_hasher_object_safe() { +fn test_build_hasher_dyn_compatible() { use std::hash::{DefaultHasher, RandomState}; let _: &dyn BuildHasher<Hasher = DefaultHasher> = &RandomState::new(); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4f2190f78bf..37e7db1157c 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -16,34 +16,23 @@ #![feature(clone_to_uninit)] #![feature(const_align_of_val_raw)] #![feature(const_align_offset)] -#![feature(const_array_from_ref)] #![feature(const_black_box)] #![feature(const_hash)] #![feature(const_heap)] -#![feature(const_ip)] -#![feature(const_ipv4)] -#![feature(const_ipv6)] #![feature(const_likely)] #![feature(const_nonnull_new)] -#![feature(const_option)] #![feature(const_option_ext)] #![feature(const_pin)] #![feature(const_pointer_is_aligned)] -#![feature(const_ptr_as_ref)] -#![feature(const_ptr_write)] -#![feature(const_result)] -#![feature(const_slice_from_ref)] #![feature(const_three_way_compare)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] -#![feature(debug_more_non_exhaustive)] #![feature(dec2flt)] #![feature(duration_constants)] #![feature(duration_constructors)] -#![feature(duration_consts_float)] #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extern_types)] @@ -58,6 +47,7 @@ #![feature(hashmap_internals)] #![feature(int_roundings)] #![feature(ip)] +#![feature(ip_from)] #![feature(is_ascii_octdigit)] #![feature(isqrt)] #![feature(iter_advance_by)] diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs index a10b51c550d..707f9a160e1 100644 --- a/library/core/tests/net/ip_addr.rs +++ b/library/core/tests/net/ip_addr.rs @@ -494,6 +494,7 @@ fn ipv6_properties() { let octets = &[$($octet),*]; assert_eq!(&ip!($s).octets(), octets); assert_eq!(Ipv6Addr::from(*octets), ip!($s)); + assert_eq!(Ipv6Addr::from_octets(*octets), ip!($s)); let unspecified: u32 = 1 << 0; let loopback: u32 = 1 << 1; @@ -846,15 +847,19 @@ fn ipv6_from_constructors() { #[test] fn ipv4_from_octets() { - assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) + assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)); + assert_eq!(Ipv4Addr::from_octets([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)); } #[test] fn ipv6_from_segments() { let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u16s_explicit = + Ipv6Addr::from_segments([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); assert_eq!(new, from_u16s); + assert_eq!(new, from_u16s_explicit); } #[test] @@ -865,7 +870,15 @@ fn ipv6_from_octets() { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]); + let from_u16s_explicit = + Ipv6Addr::from_segments([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u8s_explicit = Ipv6Addr::from_octets([ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, + ]); assert_eq!(from_u16s, from_u8s); + assert_eq!(from_u16s, from_u16s_explicit); + assert_eq!(from_u16s_explicit, from_u8s_explicit); } #[test] @@ -915,6 +928,9 @@ fn ipv4_const() { const OCTETS: [u8; 4] = IP_ADDRESS.octets(); assert_eq!(OCTETS, [127, 0, 0, 1]); + const FROM_OCTETS: Ipv4Addr = Ipv4Addr::from_octets(OCTETS); + assert_eq!(IP_ADDRESS, FROM_OCTETS); + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); assert!(!IS_UNSPECIFIED); @@ -971,9 +987,15 @@ fn ipv6_const() { const SEGMENTS: [u16; 8] = IP_ADDRESS.segments(); assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]); + const FROM_SEGMENTS: Ipv6Addr = Ipv6Addr::from_segments(SEGMENTS); + assert_eq!(IP_ADDRESS, FROM_SEGMENTS); + const OCTETS: [u8; 16] = IP_ADDRESS.octets(); assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); + const FROM_OCTETS: Ipv6Addr = Ipv6Addr::from_octets(OCTETS); + assert_eq!(IP_ADDRESS, FROM_OCTETS); + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); assert!(!IS_UNSPECIFIED); diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 7197f3812e5..9ae2bcc8526 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1802,57 +1802,6 @@ fn brute_force_rotate_test_1() { #[test] #[cfg(not(target_arch = "wasm32"))] -fn sort_unstable() { - use rand::Rng; - - // Miri is too slow (but still need to `chain` to make the types match) - let lens = if cfg!(miri) { (2..20).chain(0..0) } else { (2..25).chain(500..510) }; - let rounds = if cfg!(miri) { 1 } else { 100 }; - - let mut v = [0; 600]; - let mut tmp = [0; 600]; - let mut rng = crate::test_rng(); - - for len in lens { - let v = &mut v[0..len]; - let tmp = &mut tmp[0..len]; - - for &modulus in &[5, 10, 100, 1000] { - for _ in 0..rounds { - for i in 0..len { - v[i] = rng.gen::<i32>() % modulus; - } - - // Sort in default order. - tmp.copy_from_slice(v); - tmp.sort_unstable(); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Sort in ascending order. - tmp.copy_from_slice(v); - tmp.sort_unstable_by(|a, b| a.cmp(b)); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Sort in descending order. - tmp.copy_from_slice(v); - tmp.sort_unstable_by(|a, b| b.cmp(a)); - assert!(tmp.windows(2).all(|w| w[0] >= w[1])); - } - } - } - - // Should not panic. - [0i32; 0].sort_unstable(); - [(); 10].sort_unstable(); - [(); 100].sort_unstable(); - - let mut v = [0xDEADBEEFu64]; - v.sort_unstable(); - assert!(v == [0xDEADBEEF]); -} - -#[test] -#[cfg(not(target_arch = "wasm32"))] #[cfg_attr(miri, ignore)] // Miri is too slow fn select_nth_unstable() { use core::cmp::Ordering::{Equal, Greater, Less}; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 5522d556a59..72b597a8083 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1166,7 +1166,7 @@ impl fmt::Debug for Ident { } } -/// A literal string (`"hello"`), byte string (`b"hello"`), +/// A literal string (`"hello"`), byte string (`b"hello"`), C string (`c"hello"`), /// character (`'a'`), byte character (`b'a'`), an integer or floating point number /// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). /// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 63c65b8ef39..358bd25ff1b 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.130" } +compiler_builtins = { version = "0.1.133" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ @@ -39,7 +39,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false } addr2line = { version = "0.22.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.156", default-features = false, features = [ +libc = { version = "0.2.159", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } diff --git a/library/std/build.rs b/library/std/build.rs index 7d37d4e9d7d..032326556bd 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -7,6 +7,7 @@ fn main() { let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").expect("CARGO_CFG_TARGET_VENDOR was not set"); let target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV was not set"); + let target_abi = env::var("CARGO_CFG_TARGET_ABI").expect("CARGO_CFG_TARGET_ABI was not set"); let target_pointer_width: u32 = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set") .parse() @@ -101,7 +102,7 @@ fn main() { // Unsupported <https://github.com/llvm/llvm-project/issues/94434> ("arm64ec", _) => false, // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> - ("x86_64", "windows") if target_env == "gnu" => false, + ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981> ("csky", _) => false, ("hexagon", _) => false, @@ -129,7 +130,7 @@ fn main() { // ABI unsupported <https://github.com/llvm/llvm-project/issues/41838> ("sparc", _) => false, // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> - ("x86_64", "windows") if target_env == "gnu" => false, + ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // 64-bit Linux is about the only platform to have f128 symbols by default (_, "linux") if target_pointer_width == 64 => true, // Almost all OSs are missing symbol. compiler-builtins will have to add them. diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 124ef121b18..675140ff18f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -394,7 +394,8 @@ impl File { /// /// # Errors /// - /// This function will return an error if `path` does not already exist. + /// This function will return an error if `path` does not already exist, + /// or if memory allocation fails for the new buffer. /// Other errors may also be returned according to [`OpenOptions::open`]. /// /// # Examples diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index dd6458c38c6..8fedcb241d0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2382,8 +2382,6 @@ pub trait BufRead: Read { /// about Ferris from a binary string, skipping the fun fact: /// /// ``` - /// #![feature(bufread_skip_until)] - /// /// use std::io::{self, BufRead}; /// /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0"); @@ -2407,7 +2405,7 @@ pub trait BufRead: Read { /// assert_eq!(num_bytes, 11); /// assert_eq!(animal, b"Crustacean\0"); /// ``` - #[unstable(feature = "bufread_skip_until", issue = "111735")] + #[stable(feature = "bufread_skip_until", since = "CURRENT_RUSTC_VERSION")] fn skip_until(&mut self, byte: u8) -> Result<usize> { skip_until(self, byte) } diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index bf242e715bd..35b38ed783f 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -370,7 +370,12 @@ impl Stdin { /// Locks this handle and reads a line of input, appending it to the specified buffer. /// /// For detailed semantics of this method, see the documentation on - /// [`BufRead::read_line`]. + /// [`BufRead::read_line`]. In particular: + /// * Previous content of the buffer will be preserved. To avoid appending + /// to the buffer, you need to [`clear`] it first. + /// * The trailing newline character, if any, is included in the buffer. + /// + /// [`clear`]: String::clear /// /// # Examples /// diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 9f4d244b547..453b2708daa 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2349,12 +2349,13 @@ mod async_keyword {} /// [`async`]: ../std/keyword.async.html mod await_keyword {} +// FIXME(dyn_compat_renaming): Update URL and link text. #[doc(keyword = "dyn")] // /// `dyn` is a prefix of a [trait object]'s type. /// /// 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 'object safe'. +/// are [dynamically dispatched]. To use the trait this way, it must be 'dyn-compatible'[^1]. /// /// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that /// is being passed. That is, the type has been [erased]. @@ -2382,6 +2383,7 @@ mod await_keyword {} /// [ref-trait-obj]: ../reference/types/trait-object.html /// [ref-obj-safety]: ../reference/items/traits.html#object-safety /// [erased]: https://en.wikipedia.org/wiki/Type_erasure +/// [^1]: Formerly known as 'object safe'. mod dyn_keyword {} #[doc(keyword = "union")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 65a9aa66c7c..057a57f7997 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -414,9 +414,6 @@ // tidy-alphabetical-start #![feature(const_collections_with_hasher)] #![feature(const_hash)] -#![feature(const_ip)] -#![feature(const_ipv4)] -#![feature(const_ipv6)] #![feature(thread_local_internals)] // tidy-alphabetical-end // diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs index 33b50c9e53b..2ee6aa46600 100644 --- a/library/std/src/os/wasi/mod.rs +++ b/library/std/src/os/wasi/mod.rs @@ -36,6 +36,8 @@ pub mod ffi; pub mod fs; pub mod io; + +#[cfg(all(target_os = "wasi", target_env = "p1"))] pub mod net; /// A prelude for conveniently writing platform-specific code. diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 0a841f07e3b..80e7c3c026b 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -102,9 +102,24 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { sys::init(argc, argv, sigpipe) }; - // Set up the current thread to give it the right name. - let thread = Thread::new_main(); - thread::set_current(thread); + // Set up the current thread handle to give it the right name. + // + // When code running before main uses `ReentrantLock` (for example by + // using `println!`), the thread ID can become initialized before we + // create this handle. Since `set_current` fails when the ID of the + // handle does not match the current ID, we should attempt to use the + // current thread ID here instead of unconditionally creating a new + // one. Also see #130210. + let thread = Thread::new_main(thread::current_id()); + if let Err(_thread) = thread::set_current(thread) { + // `thread::current` will create a new handle if none has been set yet. + // Thus, if someone uses it before main, this call will fail. That's a + // bad idea though, as we then cannot set the main thread name here. + // + // FIXME: detect the main thread in `thread::current` and use the + // correct name there. + rtabort!("code running before main must not use thread::current"); + } } /// Clean up the thread-local runtime state. This *should* be run after all other diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/pal/sgx/net.rs index 44913ffe3a9..c966886d163 100644 --- a/library/std/src/sys/pal/sgx/net.rs +++ b/library/std/src/sys/pal/sgx/net.rs @@ -78,9 +78,8 @@ fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> { } } -fn addr_to_sockaddr(addr: &Option<String>) -> io::Result<SocketAddr> { - addr.as_ref() - .ok_or(io::ErrorKind::AddrNotAvailable)? +fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> { + addr.ok_or(io::ErrorKind::AddrNotAvailable)? .to_socket_addrs() // unwrap OK: if an iterator is returned, we're guaranteed to get exactly one entry .map(|mut it| it.next().unwrap()) @@ -161,11 +160,11 @@ impl TcpStream { } pub fn peer_addr(&self) -> io::Result<SocketAddr> { - addr_to_sockaddr(&self.peer_addr) + addr_to_sockaddr(self.peer_addr.as_deref()) } pub fn socket_addr(&self) -> io::Result<SocketAddr> { - addr_to_sockaddr(&self.inner.local_addr) + addr_to_sockaddr(self.inner.local_addr.as_deref()) } pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { @@ -255,13 +254,14 @@ impl TcpListener { } pub fn socket_addr(&self) -> io::Result<SocketAddr> { - addr_to_sockaddr(&self.inner.local_addr) + addr_to_sockaddr(self.inner.local_addr.as_deref()) } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { let (fd, local_addr, peer_addr) = usercalls::accept_stream(self.inner.inner.raw())?; let peer_addr = Some(peer_addr); - let ret_peer = addr_to_sockaddr(&peer_addr).unwrap_or_else(|_| ([0; 4], 0).into()); + let ret_peer = + addr_to_sockaddr(peer_addr.as_deref()).unwrap_or_else(|_| ([0; 4], 0).into()); Ok((TcpStream { inner: Socket::new(fd, local_addr), peer_addr }, ret_peer)) } diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 39aabf0b2d6..567577b2b4d 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -899,7 +899,7 @@ impl DirEntry { target_os = "android", target_os = "hurd" ), - not(miri) + not(miri) // no dirfd on Miri ))] pub fn metadata(&self) -> io::Result<FileAttr> { let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?; @@ -1538,7 +1538,7 @@ impl fmt::Debug for File { Some(PathBuf::from(OsString::from_vec(buf))) } - #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] + #[cfg(target_os = "freebsd")] fn get_path(fd: c_int) -> Option<PathBuf> { let info = Box::<libc::kinfo_file>::new_zeroed(); let mut info = unsafe { info.assume_init() }; @@ -1566,7 +1566,7 @@ impl fmt::Debug for File { #[cfg(not(any( target_os = "linux", target_os = "vxworks", - all(target_os = "freebsd", target_arch = "x86_64"), + target_os = "freebsd", target_os = "netbsd", target_os = "illumos", target_os = "solaris", diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs index d9c41d43487..13290fed762 100644 --- a/library/std/src/sys/pal/unix/process/process_common.rs +++ b/library/std/src/sys/pal/unix/process/process_common.rs @@ -312,8 +312,8 @@ impl Command { } #[allow(dead_code)] - pub fn get_cwd(&self) -> &Option<CString> { - &self.cwd + pub fn get_cwd(&self) -> Option<&CStr> { + self.cwd.as_deref() } #[allow(dead_code)] pub fn get_uid(&self) -> Option<uid_t> { diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 5d30f388da1..4551d49e841 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -335,7 +335,7 @@ impl Command { cvt(libc::setuid(u as uid_t))?; } } - if let Some(ref cwd) = *self.get_cwd() { + if let Some(cwd) = self.get_cwd() { cvt(libc::chdir(cwd.as_ptr()))?; } diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs index 2d9a304c495..38daf6af918 100644 --- a/library/std/src/sys/pal/unix/process/process_vxworks.rs +++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs @@ -57,7 +57,7 @@ impl Command { t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))); } - if let Some(ref cwd) = *self.get_cwd() { + if let Some(cwd) = self.get_cwd() { t!(cvt(libc::chdir(cwd.as_ptr()))); } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 2f2d6e6add3..04024661836 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -117,13 +117,15 @@ impl Thread { pub fn set_name(name: &CStr) { const PR_SET_NAME: libc::c_int = 15; unsafe { - libc::prctl( + let res = libc::prctl( PR_SET_NAME, name.as_ptr(), 0 as libc::c_ulong, 0 as libc::c_ulong, 0 as libc::c_ulong, ); + // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. + debug_assert_eq!(res, 0); } } diff --git a/library/std/src/sys/pal/wasip2/net.rs b/library/std/src/sys/pal/wasip2/net.rs index c40eb229ba9..06e623df843 100644 --- a/library/std/src/sys/pal/wasip2/net.rs +++ b/library/std/src/sys/pal/wasip2/net.rs @@ -2,13 +2,12 @@ use libc::{c_int, c_void, size_t}; -use super::fd::WasiFd; use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; -use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::unsupported; -use crate::sys_common::net::{TcpListener, getsockopt, setsockopt, sockaddr_to_addr}; +use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::{Duration, Instant}; use crate::{cmp, mem, str}; @@ -71,7 +70,9 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { pub fn init() {} -pub struct Socket(WasiFd); +pub struct WasiSocket(OwnedFd); + +pub struct Socket(WasiSocket); impl Socket { pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { @@ -327,53 +328,90 @@ impl Socket { } } -impl AsInner<WasiFd> for Socket { +impl AsInner<OwnedFd> for WasiSocket { #[inline] - fn as_inner(&self) -> &WasiFd { + fn as_inner(&self) -> &OwnedFd { &self.0 } } -impl IntoInner<WasiFd> for Socket { - fn into_inner(self) -> WasiFd { +impl IntoInner<OwnedFd> for WasiSocket { + fn into_inner(self) -> OwnedFd { self.0 } } -impl FromInner<WasiFd> for Socket { - fn from_inner(inner: WasiFd) -> Socket { - Socket(inner) +impl FromInner<OwnedFd> for WasiSocket { + fn from_inner(owned_fd: OwnedFd) -> Self { + Self(owned_fd) } } -impl AsFd for Socket { +impl AsFd for WasiSocket { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } } -impl AsRawFd for Socket { +impl AsRawFd for WasiSocket { #[inline] fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } } -impl IntoRawFd for Socket { +impl IntoRawFd for WasiSocket { fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() } } -impl FromRawFd for Socket { +impl FromRawFd for WasiSocket { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } } } -impl AsInner<Socket> for TcpListener { +impl AsInner<WasiSocket> for Socket { + #[inline] + fn as_inner(&self) -> &WasiSocket { + &self.0 + } +} + +impl IntoInner<WasiSocket> for Socket { + fn into_inner(self) -> WasiSocket { + self.0 + } +} + +impl FromInner<WasiSocket> for Socket { + fn from_inner(sock: WasiSocket) -> Socket { + Socket(sock) + } +} + +impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for Socket { #[inline] - fn as_inner(&self) -> &Socket { - &self.socket() + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for Socket { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } } } diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index b65ad7dbe8c..9ce3e912caf 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -175,9 +175,9 @@ extern "system" { pub fn WakeByAddressAll(address: *const c_void); } +// These are loaded by `load_synch_functions`. #[cfg(target_vendor = "win7")] compat_fn_optional! { - crate::sys::compat::load_synch_functions(); pub fn WaitOnAddress( address: *const c_void, compareaddress: *const c_void, diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index c8e25dd0c94..42999da1664 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -198,11 +198,10 @@ macro_rules! compat_fn_with_fallback { /// Optionally loaded functions. /// -/// Actual loading of the function defers to $load_functions. +/// Relies on the functions being pre-loaded elsewhere. #[cfg(target_vendor = "win7")] macro_rules! compat_fn_optional { - ($load_functions:expr; - $( + ($( $(#[$meta:meta])* $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) $(-> $rettype:ty)?; )+) => ( @@ -221,9 +220,6 @@ macro_rules! compat_fn_optional { #[inline(always)] pub fn option() -> Option<F> { - // Miri does not understand the way we do preloading - // therefore load the function here instead. - #[cfg(miri)] $load_functions; NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) }) } } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 1ea253e5e52..a9886012e8e 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -346,7 +346,6 @@ pub fn abort_internal() -> ! { } } -// miri is sensitive to changes here so check that miri is happy if touching this #[cfg(miri)] pub fn abort_internal() -> ! { crate::intrinsics::abort(); diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs index 6849cacf88e..d0c998a5597 100644 --- a/library/std/src/sys/sync/condvar/mod.rs +++ b/library/std/src/sys/sync/condvar/mod.rs @@ -12,7 +12,10 @@ cfg_if::cfg_if! { ))] { mod futex; pub use futex::Condvar; - } else if #[cfg(target_family = "unix")] { + } else if #[cfg(any( + target_family = "unix", + target_os = "teeos", + ))] { mod pthread; pub use pthread::Condvar; } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] { @@ -24,9 +27,6 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "solid_asp3")] { mod itron; pub use itron::Condvar; - } else if #[cfg(target_os = "teeos")] { - mod teeos; - pub use teeos::Condvar; } else if #[cfg(target_os = "xous")] { mod xous; pub use xous::Condvar; diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs index 5b5e7770b06..986cd0cb7d1 100644 --- a/library/std/src/sys/sync/condvar/pthread.rs +++ b/library/std/src/sys/sync/condvar/pthread.rs @@ -2,31 +2,25 @@ use crate::cell::UnsafeCell; use crate::ptr; use crate::sync::atomic::AtomicPtr; use crate::sync::atomic::Ordering::Relaxed; -use crate::sys::sync::{Mutex, mutex}; +use crate::sys::sync::{Mutex, OnceBox}; #[cfg(not(target_os = "nto"))] use crate::sys::time::TIMESPEC_MAX; #[cfg(target_os = "nto")] use crate::sys::time::TIMESPEC_MAX_CAPPED; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>); pub struct Condvar { - inner: LazyBox<AllocatedCondvar>, + inner: OnceBox<AllocatedCondvar>, mutex: AtomicPtr<libc::pthread_mutex_t>, } -#[inline] -fn raw(c: &Condvar) -> *mut libc::pthread_cond_t { - c.inner.0.get() -} - unsafe impl Send for AllocatedCondvar {} unsafe impl Sync for AllocatedCondvar {} -impl LazyInit for AllocatedCondvar { - fn init() -> Box<Self> { +impl AllocatedCondvar { + fn new() -> Box<Self> { let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER))); cfg_if::cfg_if! { @@ -37,7 +31,7 @@ impl LazyInit for AllocatedCondvar { target_vendor = "apple", ))] { // `pthread_condattr_setclock` is unfortunately not supported on these platforms. - } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { + } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "teeos"))] { // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet // So on that platform, init() should always be called // Moreover, that platform does not have pthread_condattr_setclock support, @@ -82,7 +76,11 @@ impl Drop for AllocatedCondvar { impl Condvar { pub const fn new() -> Condvar { - Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } + Condvar { inner: OnceBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } + } + + fn get(&self) -> *mut libc::pthread_cond_t { + self.inner.get_or_init(AllocatedCondvar::new).0.get() } #[inline] @@ -98,21 +96,21 @@ impl Condvar { #[inline] pub fn notify_one(&self) { - let r = unsafe { libc::pthread_cond_signal(raw(self)) }; + let r = unsafe { libc::pthread_cond_signal(self.get()) }; debug_assert_eq!(r, 0); } #[inline] pub fn notify_all(&self) { - let r = unsafe { libc::pthread_cond_broadcast(raw(self)) }; + let r = unsafe { libc::pthread_cond_broadcast(self.get()) }; debug_assert_eq!(r, 0); } #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = mutex::raw(mutex); + let mutex = mutex.get_assert_locked(); self.verify(mutex); - let r = libc::pthread_cond_wait(raw(self), mutex); + let r = libc::pthread_cond_wait(self.get(), mutex); debug_assert_eq!(r, 0); } @@ -129,7 +127,7 @@ impl Condvar { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use crate::sys::time::Timespec; - let mutex = mutex::raw(mutex); + let mutex = mutex.get_assert_locked(); self.verify(mutex); #[cfg(not(target_os = "nto"))] @@ -144,7 +142,7 @@ impl Condvar { .and_then(|t| t.to_timespec_capped()) .unwrap_or(TIMESPEC_MAX_CAPPED); - let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout); + let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout); assert!(r == libc::ETIMEDOUT || r == 0); r == 0 } @@ -162,7 +160,7 @@ impl Condvar { use crate::sys::time::SystemTime; use crate::time::Instant; - let mutex = mutex::raw(mutex); + let mutex = mutex.get_assert_locked(); self.verify(mutex); // OSX implementation of `pthread_cond_timedwait` is buggy @@ -188,7 +186,7 @@ impl Condvar { .and_then(|t| t.to_timespec()) .unwrap_or(TIMESPEC_MAX); - let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout); + let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout); debug_assert!(r == libc::ETIMEDOUT || r == 0); // ETIMEDOUT is not a totally reliable method of determining timeout due diff --git a/library/std/src/sys/sync/condvar/sgx.rs b/library/std/src/sys/sync/condvar/sgx.rs index ecb5872f60d..e60715e4b59 100644 --- a/library/std/src/sys/sync/condvar/sgx.rs +++ b/library/std/src/sys/sync/condvar/sgx.rs @@ -1,44 +1,39 @@ use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable}; -use crate::sys::sync::Mutex; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; +use crate::sys::sync::{Mutex, OnceBox}; use crate::time::Duration; -/// FIXME: `UnsafeList` is not movable. -struct AllocatedCondvar(SpinMutex<WaitVariable<()>>); - pub struct Condvar { - inner: LazyBox<AllocatedCondvar>, -} - -impl LazyInit for AllocatedCondvar { - fn init() -> Box<Self> { - Box::new(AllocatedCondvar(SpinMutex::new(WaitVariable::new(())))) - } + // FIXME: `UnsafeList` is not movable. + inner: OnceBox<SpinMutex<WaitVariable<()>>>, } impl Condvar { pub const fn new() -> Condvar { - Condvar { inner: LazyBox::new() } + Condvar { inner: OnceBox::new() } + } + + fn get(&self) -> &SpinMutex<WaitVariable<()>> { + self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(())))) } #[inline] pub fn notify_one(&self) { - let _ = WaitQueue::notify_one(self.inner.0.lock()); + let _ = WaitQueue::notify_one(self.get().lock()); } #[inline] pub fn notify_all(&self) { - let _ = WaitQueue::notify_all(self.inner.0.lock()); + let _ = WaitQueue::notify_all(self.get().lock()); } pub unsafe fn wait(&self, mutex: &Mutex) { - let guard = self.inner.0.lock(); + let guard = self.get().lock(); WaitQueue::wait(guard, || unsafe { mutex.unlock() }); mutex.lock() } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let success = WaitQueue::wait_timeout(&self.inner.0, dur, || unsafe { mutex.unlock() }); + let success = WaitQueue::wait_timeout(self.get(), dur, || unsafe { mutex.unlock() }); mutex.lock(); success } diff --git a/library/std/src/sys/sync/condvar/teeos.rs b/library/std/src/sys/sync/condvar/teeos.rs deleted file mode 100644 index 943867cd761..00000000000 --- a/library/std/src/sys/sync/condvar/teeos.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::ptr; -use crate::sync::atomic::AtomicPtr; -use crate::sync::atomic::Ordering::Relaxed; -use crate::sys::sync::mutex::{self, Mutex}; -use crate::sys::time::TIMESPEC_MAX; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; -use crate::time::Duration; - -extern "C" { - pub fn pthread_cond_timedwait( - cond: *mut libc::pthread_cond_t, - lock: *mut libc::pthread_mutex_t, - adstime: *const libc::timespec, - ) -> libc::c_int; -} - -struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>); - -pub struct Condvar { - inner: LazyBox<AllocatedCondvar>, - mutex: AtomicPtr<libc::pthread_mutex_t>, -} - -#[inline] -fn raw(c: &Condvar) -> *mut libc::pthread_cond_t { - c.inner.0.get() -} - -unsafe impl Send for AllocatedCondvar {} -unsafe impl Sync for AllocatedCondvar {} - -impl LazyInit for AllocatedCondvar { - fn init() -> Box<Self> { - let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER))); - - let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) }; - assert_eq!(r, 0); - - condvar - } -} - -impl Drop for AllocatedCondvar { - #[inline] - fn drop(&mut self) { - let r = unsafe { libc::pthread_cond_destroy(self.0.get()) }; - debug_assert_eq!(r, 0); - } -} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } - } - - #[inline] - fn verify(&self, mutex: *mut libc::pthread_mutex_t) { - match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) { - Ok(_) => {} // Stored the address - Err(n) if n == mutex => {} // Lost a race to store the same address - _ => panic!("attempted to use a condition variable with two mutexes"), - } - } - - #[inline] - pub fn notify_one(&self) { - let r = unsafe { libc::pthread_cond_signal(raw(self)) }; - debug_assert_eq!(r, 0); - } - - #[inline] - pub fn notify_all(&self) { - let r = unsafe { libc::pthread_cond_broadcast(raw(self)) }; - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = unsafe { mutex::raw(mutex) }; - self.verify(mutex); - let r = unsafe { libc::pthread_cond_wait(raw(self), mutex) }; - debug_assert_eq!(r, 0); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use crate::sys::time::Timespec; - - let mutex = unsafe { mutex::raw(mutex) }; - self.verify(mutex); - - let timeout = Timespec::now(libc::CLOCK_MONOTONIC) - .checked_add_duration(&dur) - .and_then(|t| t.to_timespec()) - .unwrap_or(TIMESPEC_MAX); - - let r = unsafe { pthread_cond_timedwait(raw(self), mutex, &timeout) }; - assert!(r == libc::ETIMEDOUT || r == 0); - r == 0 - } -} diff --git a/library/std/src/sys/sync/mod.rs b/library/std/src/sys/sync/mod.rs index 52fac5902a2..0691e967851 100644 --- a/library/std/src/sys/sync/mod.rs +++ b/library/std/src/sys/sync/mod.rs @@ -1,11 +1,14 @@ mod condvar; mod mutex; mod once; +mod once_box; mod rwlock; mod thread_parking; pub use condvar::Condvar; pub use mutex::Mutex; pub use once::{Once, OnceState}; +#[allow(unused)] // Only used on some platforms. +use once_box::OnceBox; pub use rwlock::RwLock; pub use thread_parking::Parker; diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs index 73d9bd273de..360df3fc4b5 100644 --- a/library/std/src/sys/sync/mutex/mod.rs +++ b/library/std/src/sys/sync/mutex/mod.rs @@ -19,7 +19,7 @@ cfg_if::cfg_if! { target_os = "teeos", ))] { mod pthread; - pub use pthread::{Mutex, raw}; + pub use pthread::Mutex; } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] { mod windows7; pub use windows7::{Mutex, raw}; diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs index 1c407bc2537..87c95f45f96 100644 --- a/library/std/src/sys/sync/mutex/pthread.rs +++ b/library/std/src/sys/sync/mutex/pthread.rs @@ -2,24 +2,19 @@ use crate::cell::UnsafeCell; use crate::io::Error; use crate::mem::{MaybeUninit, forget}; use crate::sys::cvt_nz; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; +use crate::sys::sync::OnceBox; struct AllocatedMutex(UnsafeCell<libc::pthread_mutex_t>); pub struct Mutex { - inner: LazyBox<AllocatedMutex>, -} - -#[inline] -pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { - m.inner.0.get() + inner: OnceBox<AllocatedMutex>, } unsafe impl Send for AllocatedMutex {} unsafe impl Sync for AllocatedMutex {} -impl LazyInit for AllocatedMutex { - fn init() -> Box<Self> { +impl AllocatedMutex { + fn new() -> Box<Self> { let mutex = Box::new(AllocatedMutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))); // Issue #33770 @@ -60,24 +55,6 @@ impl LazyInit for AllocatedMutex { mutex } - - fn destroy(mutex: Box<Self>) { - // We're not allowed to pthread_mutex_destroy a locked mutex, - // so check first if it's unlocked. - if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } { - unsafe { libc::pthread_mutex_unlock(mutex.0.get()) }; - drop(mutex); - } else { - // The mutex is locked. This happens if a MutexGuard is leaked. - // In this case, we just leak the Mutex too. - forget(mutex); - } - } - - fn cancel_init(_: Box<Self>) { - // In this case, we can just drop it without any checks, - // since it cannot have been locked yet. - } } impl Drop for AllocatedMutex { @@ -99,11 +76,33 @@ impl Drop for AllocatedMutex { impl Mutex { #[inline] pub const fn new() -> Mutex { - Mutex { inner: LazyBox::new() } + Mutex { inner: OnceBox::new() } + } + + /// Gets access to the pthread mutex under the assumption that the mutex is + /// locked. + /// + /// This allows skipping the initialization check, as the mutex can only be + /// locked if it is already initialized, and allows relaxing the ordering + /// on the pointer load, since the allocation cannot have been modified + /// since the `lock` and the lock must have occurred on the current thread. + /// + /// # Safety + /// Causes undefined behaviour if the mutex is not locked. + #[inline] + pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t { + unsafe { self.inner.get_unchecked().0.get() } } #[inline] - pub unsafe fn lock(&self) { + fn get(&self) -> *mut libc::pthread_mutex_t { + // If initialization fails, the mutex is destroyed. This is always sound, + // however, as the mutex cannot have been locked yet. + self.inner.get_or_init(AllocatedMutex::new).0.get() + } + + #[inline] + pub fn lock(&self) { #[cold] #[inline(never)] fn fail(r: i32) -> ! { @@ -111,7 +110,7 @@ impl Mutex { panic!("failed to lock mutex: {error}"); } - let r = libc::pthread_mutex_lock(raw(self)); + let r = unsafe { libc::pthread_mutex_lock(self.get()) }; // As we set the mutex type to `PTHREAD_MUTEX_NORMAL` above, we expect // the lock call to never fail. Unfortunately however, some platforms // (Solaris) do not conform to the standard, and instead always provide @@ -126,13 +125,29 @@ impl Mutex { #[inline] pub unsafe fn unlock(&self) { - let r = libc::pthread_mutex_unlock(raw(self)); + let r = libc::pthread_mutex_unlock(self.get_assert_locked()); debug_assert_eq!(r, 0); } #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(raw(self)) == 0 + pub fn try_lock(&self) -> bool { + unsafe { libc::pthread_mutex_trylock(self.get()) == 0 } + } +} + +impl Drop for Mutex { + fn drop(&mut self) { + let Some(mutex) = self.inner.take() else { return }; + // We're not allowed to pthread_mutex_destroy a locked mutex, + // so check first if it's unlocked. + if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } { + unsafe { libc::pthread_mutex_unlock(mutex.0.get()) }; + drop(mutex); + } else { + // The mutex is locked. This happens if a MutexGuard is leaked. + // In this case, we just leak the Mutex too. + forget(mutex); + } } } diff --git a/library/std/src/sys/sync/mutex/sgx.rs b/library/std/src/sys/sync/mutex/sgx.rs index 65d1e880f7b..8529e857970 100644 --- a/library/std/src/sys/sync/mutex/sgx.rs +++ b/library/std/src/sys/sync/mutex/sgx.rs @@ -1,28 +1,24 @@ use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable, try_lock_or_false}; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; - -/// FIXME: `UnsafeList` is not movable. -struct AllocatedMutex(SpinMutex<WaitVariable<bool>>); +use crate::sys::sync::OnceBox; pub struct Mutex { - inner: LazyBox<AllocatedMutex>, -} - -impl LazyInit for AllocatedMutex { - fn init() -> Box<Self> { - Box::new(AllocatedMutex(SpinMutex::new(WaitVariable::new(false)))) - } + // FIXME: `UnsafeList` is not movable. + inner: OnceBox<SpinMutex<WaitVariable<bool>>>, } // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28 impl Mutex { pub const fn new() -> Mutex { - Mutex { inner: LazyBox::new() } + Mutex { inner: OnceBox::new() } + } + + fn get(&self) -> &SpinMutex<WaitVariable<bool>> { + self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(false)))) } #[inline] pub fn lock(&self) { - let mut guard = self.inner.0.lock(); + let mut guard = self.get().lock(); if *guard.lock_var() { // Another thread has the lock, wait WaitQueue::wait(guard, || {}) @@ -35,7 +31,9 @@ impl Mutex { #[inline] pub unsafe fn unlock(&self) { - let guard = self.inner.0.lock(); + // SAFETY: the mutex was locked by the current thread, so it has been + // initialized already. + let guard = unsafe { self.inner.get_unchecked().lock() }; if let Err(mut guard) = WaitQueue::notify_one(guard) { // No other waiters, unlock *guard.lock_var_mut() = false; @@ -46,7 +44,7 @@ impl Mutex { #[inline] pub fn try_lock(&self) -> bool { - let mut guard = try_lock_or_false!(self.inner.0); + let mut guard = try_lock_or_false!(self.get()); if *guard.lock_var() { // Another thread has the lock false diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs new file mode 100644 index 00000000000..1422b5a1721 --- /dev/null +++ b/library/std/src/sys/sync/once_box.rs @@ -0,0 +1,82 @@ +//! A racily-initialized alternative to `OnceLock<Box<T>>`. +//! +//! This is used to implement synchronization primitives that need allocation, +//! like the pthread versions. + +#![allow(dead_code)] // Only used on some platforms. + +use crate::mem::replace; +use crate::ptr::null_mut; +use crate::sync::atomic::AtomicPtr; +use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed}; + +pub(crate) struct OnceBox<T> { + ptr: AtomicPtr<T>, +} + +impl<T> OnceBox<T> { + #[inline] + pub const fn new() -> Self { + Self { ptr: AtomicPtr::new(null_mut()) } + } + + /// Gets access to the value, assuming it is already initialized and this + /// initialization has been observed by the current thread. + /// + /// Since all modifications to the pointer have already been observed, the + /// pointer load in this function can be performed with relaxed ordering, + /// potentially allowing the optimizer to turn code like this: + /// ```rust, ignore + /// once_box.get_or_init(|| Box::new(42)); + /// unsafe { once_box.get_unchecked() } + /// ``` + /// into + /// ```rust, ignore + /// once_box.get_or_init(|| Box::new(42)) + /// ``` + /// + /// # Safety + /// This causes undefined behaviour if the assumption above is violated. + #[inline] + pub unsafe fn get_unchecked(&self) -> &T { + unsafe { &*self.ptr.load(Relaxed) } + } + + #[inline] + pub fn get_or_init(&self, f: impl FnOnce() -> Box<T>) -> &T { + let ptr = self.ptr.load(Acquire); + match unsafe { ptr.as_ref() } { + Some(val) => val, + None => self.initialize(f), + } + } + + #[inline] + pub fn take(&mut self) -> Option<Box<T>> { + let ptr = replace(self.ptr.get_mut(), null_mut()); + if !ptr.is_null() { Some(unsafe { Box::from_raw(ptr) }) } else { None } + } + + #[cold] + fn initialize(&self, f: impl FnOnce() -> Box<T>) -> &T { + let new_ptr = Box::into_raw(f()); + match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) { + Ok(_) => unsafe { &*new_ptr }, + Err(ptr) => { + // Lost the race to another thread. + // Drop the value we created, and use the one from the other thread instead. + drop(unsafe { Box::from_raw(new_ptr) }); + unsafe { &*ptr } + } + } + } +} + +unsafe impl<T: Send> Send for OnceBox<T> {} +unsafe impl<T: Send + Sync> Sync for OnceBox<T> {} + +impl<T> Drop for OnceBox<T> { + fn drop(&mut self) { + self.take(); + } +} diff --git a/library/std/src/sys/sync/rwlock/teeos.rs b/library/std/src/sys/sync/rwlock/teeos.rs index ef9b1ab5154..76343022383 100644 --- a/library/std/src/sys/sync/rwlock/teeos.rs +++ b/library/std/src/sys/sync/rwlock/teeos.rs @@ -14,22 +14,22 @@ impl RwLock { #[inline] pub fn read(&self) { - unsafe { self.inner.lock() }; + self.inner.lock() } #[inline] pub fn try_read(&self) -> bool { - unsafe { self.inner.try_lock() } + self.inner.try_lock() } #[inline] pub fn write(&self) { - unsafe { self.inner.lock() }; + self.inner.lock() } #[inline] pub unsafe fn try_write(&self) -> bool { - unsafe { self.inner.try_lock() } + self.inner.try_lock() } #[inline] diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs index 0ebc5e093ee..f4d8fa0a58c 100644 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -23,6 +23,7 @@ cfg_if::cfg_if! { mod windows7; pub use windows7::Parker; } else if #[cfg(all(target_vendor = "apple", not(miri)))] { + // Doesn't work in Miri, see <https://github.com/rust-lang/miri/issues/2589>. mod darwin; pub use darwin::Parker; } else if #[cfg(target_os = "xous")] { diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs deleted file mode 100644 index b45b05f63ba..00000000000 --- a/library/std/src/sys_common/lazy_box.rs +++ /dev/null @@ -1,88 +0,0 @@ -#![allow(dead_code)] // Only used on some platforms. - -// This is used to wrap pthread {Mutex, Condvar, RwLock} in. - -use crate::marker::PhantomData; -use crate::ops::{Deref, DerefMut}; -use crate::ptr::null_mut; -use crate::sync::atomic::AtomicPtr; -use crate::sync::atomic::Ordering::{AcqRel, Acquire}; - -pub(crate) struct LazyBox<T: LazyInit> { - ptr: AtomicPtr<T>, - _phantom: PhantomData<T>, -} - -pub(crate) trait LazyInit { - /// This is called before the box is allocated, to provide the value to - /// move into the new box. - /// - /// It might be called more than once per LazyBox, as multiple threads - /// might race to initialize it concurrently, each constructing and initializing - /// their own box. All but one of them will be passed to `cancel_init` right after. - fn init() -> Box<Self>; - - /// Any surplus boxes from `init()` that lost the initialization race - /// are passed to this function for disposal. - /// - /// The default implementation calls destroy(). - fn cancel_init(x: Box<Self>) { - Self::destroy(x); - } - - /// This is called to destroy a used box. - /// - /// The default implementation just drops it. - fn destroy(_: Box<Self>) {} -} - -impl<T: LazyInit> LazyBox<T> { - #[inline] - pub const fn new() -> Self { - Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData } - } - - #[inline] - fn get_pointer(&self) -> *mut T { - let ptr = self.ptr.load(Acquire); - if ptr.is_null() { self.initialize() } else { ptr } - } - - #[cold] - fn initialize(&self) -> *mut T { - let new_ptr = Box::into_raw(T::init()); - match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) { - Ok(_) => new_ptr, - Err(ptr) => { - // Lost the race to another thread. - // Drop the box we created, and use the one from the other thread instead. - T::cancel_init(unsafe { Box::from_raw(new_ptr) }); - ptr - } - } - } -} - -impl<T: LazyInit> Deref for LazyBox<T> { - type Target = T; - #[inline] - fn deref(&self) -> &T { - unsafe { &*self.get_pointer() } - } -} - -impl<T: LazyInit> DerefMut for LazyBox<T> { - #[inline] - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.get_pointer() } - } -} - -impl<T: LazyInit> Drop for LazyBox<T> { - fn drop(&mut self) { - let ptr = *self.ptr.get_mut(); - if !ptr.is_null() { - T::destroy(unsafe { Box::from_raw(ptr) }); - } - } -} diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index aa27886ff6f..4f7a131f6bb 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -22,7 +22,6 @@ mod tests; pub mod fs; pub mod io; -pub mod lazy_box; pub mod process; pub mod wstr; pub mod wtf8; diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs index b38149a0da7..e6eb90c4c30 100644 --- a/library/std/src/thread/current.rs +++ b/library/std/src/thread/current.rs @@ -110,22 +110,24 @@ mod id { } } -/// Sets the thread handle for the current thread. -/// -/// Aborts if the handle or the ID has been set already. -pub(crate) fn set_current(thread: Thread) { - if CURRENT.get() != NONE || id::get().is_some() { - // Using `panic` here can add ~3kB to the binary size. We have complete - // control over where this is called, so just abort if there is a bug. - rtabort!("thread::set_current should only be called once per thread"); +/// Tries to set the thread handle for the current thread. Fails if a handle was +/// already set or if the thread ID of `thread` would change an already-set ID. +pub(crate) fn set_current(thread: Thread) -> Result<(), Thread> { + if CURRENT.get() != NONE { + return Err(thread); } - id::set(thread.id()); + match id::get() { + Some(id) if id == thread.id() => {} + None => id::set(thread.id()), + _ => return Err(thread), + } // Make sure that `crate::rt::thread_cleanup` will be run, which will // call `drop_current`. crate::sys::thread_local::guard::enable(); CURRENT.set(thread.into_raw().cast_mut()); + Ok(()) } /// Gets the id of the thread that invokes it. diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index d1d4eabb9bd..39753888509 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -519,9 +519,14 @@ impl Builder { let f = MaybeDangling::new(f); let main = move || { - // Immediately store the thread handle to avoid setting it or its ID - // twice, which would cause an abort. - set_current(their_thread.clone()); + if let Err(_thread) = set_current(their_thread.clone()) { + // Both the current thread handle and the ID should not be + // initialized yet. Since only the C runtime and some of our + // platform code run before this, this point shouldn't be + // reachable. Use an abort to save binary size (see #123356). + rtabort!("something here is badly broken!"); + } + if let Some(name) = their_thread.cname() { imp::Thread::set_name(name); } @@ -1159,9 +1164,6 @@ pub fn park_timeout(dur: Duration) { pub struct ThreadId(NonZero<u64>); impl ThreadId { - // DO NOT rely on this value. - const MAIN_THREAD: ThreadId = ThreadId(unsafe { NonZero::new_unchecked(1) }); - // Generate a new unique thread ID. pub(crate) fn new() -> ThreadId { #[cold] @@ -1173,7 +1175,7 @@ impl ThreadId { if #[cfg(target_has_atomic = "64")] { use crate::sync::atomic::AtomicU64; - static COUNTER: AtomicU64 = AtomicU64::new(1); + static COUNTER: AtomicU64 = AtomicU64::new(0); let mut last = COUNTER.load(Ordering::Relaxed); loop { @@ -1189,7 +1191,7 @@ impl ThreadId { } else { use crate::sync::{Mutex, PoisonError}; - static COUNTER: Mutex<u64> = Mutex::new(1); + static COUNTER: Mutex<u64> = Mutex::new(0); let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner); let Some(id) = counter.checked_add(1) else { @@ -1326,9 +1328,9 @@ impl Thread { Self::new_inner(id, ThreadName::Unnamed) } - // Used in runtime to construct main thread - pub(crate) fn new_main() -> Thread { - Self::new_inner(ThreadId::MAIN_THREAD, ThreadName::Main) + /// Constructs the thread handle for the main thread. + pub(crate) fn new_main(id: ThreadId) -> Thread { + Self::new_inner(id, ThreadName::Main) } fn new_inner(id: ThreadId, name: ThreadName) -> Thread { diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index dcd5cd7f6b9..dd14c0266aa 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -82,6 +82,7 @@ fn aarch64_linux() { println!("sha2: {}", is_aarch64_feature_detected!("sha2")); println!("sha3: {}", is_aarch64_feature_detected!("sha3")); println!("sm4: {}", is_aarch64_feature_detected!("sm4")); + println!("sme-b16b16: {}", is_aarch64_feature_detected!("sme-b16b16")); println!("sme-f16f16: {}", is_aarch64_feature_detected!("sme-f16f16")); println!("sme-f64f64: {}", is_aarch64_feature_detected!("sme-f64f64")); println!("sme-f8f16: {}", is_aarch64_feature_detected!("sme-f8f16")); diff --git a/library/stdarch b/library/stdarch -Subproject ace72223a0e321c1b0a37b5862aa756fe8ab511 +Subproject c881fe3231b3947a4766aa15a26a93022fbb872 diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 4b2c65cfdf5..30ccfe2af8d 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -650,8 +650,8 @@ fn run_test_in_process( io::set_output_capture(None); let test_result = match result { - Ok(()) => calc_result(&desc, Ok(()), &time_opts, &exec_time), - Err(e) => calc_result(&desc, Err(e.as_ref()), &time_opts, &exec_time), + Ok(()) => calc_result(&desc, Ok(()), time_opts.as_ref(), exec_time.as_ref()), + Err(e) => calc_result(&desc, Err(e.as_ref()), time_opts.as_ref(), exec_time.as_ref()), }; let stdout = data.lock().unwrap_or_else(|e| e.into_inner()).to_vec(); let message = CompletedTest::new(id, desc, test_result, exec_time, stdout); @@ -712,7 +712,8 @@ fn spawn_test_subprocess( formatters::write_stderr_delimiter(&mut test_output, &desc.name); test_output.extend_from_slice(&stderr); - let result = get_result_from_exit_code(&desc, status, &time_opts, &exec_time); + let result = + get_result_from_exit_code(&desc, status, time_opts.as_ref(), exec_time.as_ref()); (result, test_output, exec_time) })(); @@ -724,8 +725,8 @@ fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) - let builtin_panic_hook = panic::take_hook(); let record_result = Arc::new(move |panic_info: Option<&'_ PanicHookInfo<'_>>| { let test_result = match panic_info { - Some(info) => calc_result(&desc, Err(info.payload()), &None, &None), - None => calc_result(&desc, Ok(()), &None, &None), + Some(info) => calc_result(&desc, Err(info.payload()), None, None), + None => calc_result(&desc, Ok(()), None, None), }; // We don't support serializing TrFailedMsg, so just diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index c5f4b03bfc9..79fe07bc1ac 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -42,8 +42,8 @@ pub enum TestResult { pub fn calc_result<'a>( desc: &TestDesc, task_result: Result<(), &'a (dyn Any + 'static + Send)>, - time_opts: &Option<time::TestTimeOptions>, - exec_time: &Option<time::TestExecTime>, + time_opts: Option<&time::TestTimeOptions>, + exec_time: Option<&time::TestExecTime>, ) -> TestResult { let result = match (&desc.should_panic, task_result) { (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk, @@ -96,8 +96,8 @@ pub fn calc_result<'a>( pub fn get_result_from_exit_code( desc: &TestDesc, status: ExitStatus, - time_opts: &Option<time::TestTimeOptions>, - exec_time: &Option<time::TestExecTime>, + time_opts: Option<&time::TestTimeOptions>, + exec_time: Option<&time::TestExecTime>, ) -> TestResult { let result = match status.code() { Some(TR_OK) => TestResult::TrOk, diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 46026324d2f..5a476d5843b 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -3,11 +3,10 @@ #![feature(link_cfg)] #![feature(staged_api)] #![feature(strict_provenance)] -#![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] #![cfg_attr(not(target_env = "msvc"), feature(libc))] #![cfg_attr( all(target_family = "wasm", not(target_os = "emscripten")), - feature(link_llvm_intrinsics) + feature(simd_wasm64, wasm_exception_handling_intrinsics) )] #![allow(internal_features)] diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs index f4ffac1ba16..2d36a8be004 100644 --- a/library/unwind/src/wasm.rs +++ b/library/unwind/src/wasm.rs @@ -40,29 +40,25 @@ pub unsafe fn _Unwind_DeleteException(exception: *mut _Unwind_Exception) { } pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code { - #[cfg(panic = "unwind")] - extern "C" { - /// LLVM lowers this intrinsic to the `throw` instruction. - // FIXME(coolreader18): move to stdarch - #[link_name = "llvm.wasm.throw"] - fn wasm_throw(tag: i32, ptr: *mut u8) -> !; - } - // The wasm `throw` instruction takes a "tag", which differentiates certain // types of exceptions from others. LLVM currently just identifies these // via integers, with 0 corresponding to C++ exceptions and 1 to C setjmp()/longjmp(). // Ideally, we'd be able to choose something unique for Rust, but for now, // we pretend to be C++ and implement the Itanium exception-handling ABI. cfg_if::cfg_if! { - // for now, unless we're -Zbuild-std with panic=unwind, never codegen a throw. + // panic=abort is default for wasm targets. Because an unknown instruction is a load-time + // error on wasm, instead of a runtime error like on traditional architectures, we never + // want to codegen a `throw` instruction, as that would break users using runtimes that + // don't yet support exceptions. The only time this first branch would be selected is if + // the user explicitly opts in to wasm exceptions, via -Zbuild-std with -Cpanic=unwind. if #[cfg(panic = "unwind")] { - wasm_throw(0, exception.cast()) + // corresponds with llvm::WebAssembly::Tag::CPP_EXCEPTION + // in llvm-project/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h + const CPP_EXCEPTION_TAG: i32 = 0; + core::arch::wasm::throw::<CPP_EXCEPTION_TAG>(exception.cast()) } else { let _ = exception; - #[cfg(target_arch = "wasm32")] - core::arch::wasm32::unreachable(); - #[cfg(target_arch = "wasm64")] - core::arch::wasm64::unreachable(); + core::arch::wasm::unreachable() } } } diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 0ac58645d2d..f036603ee70 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -182,10 +182,8 @@ Some general areas that you may be interested in modifying are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/src/core/sanity.rs`. -If you make a major change on bootstrap configuration, please remember to: - -+ Update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs`. -* Update `change-id = {pull-request-id}` in `config.example.toml`. +If you make a major change on bootstrap configuration, please add a new entry to +`CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs`. A 'major change' includes diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index b9df7336cca..e9ec79e417b 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -14,6 +14,7 @@ use bootstrap::{ Build, CONFIG_CHANGE_HISTORY, Config, Flags, Subcommand, find_recent_config_change_ids, human_readable_changes, t, }; +use build_helper::ci::CiEnv; fn main() { let args = env::args().skip(1).collect::<Vec<_>>(); @@ -54,9 +55,12 @@ fn main() { }; } - // check_version warnings are not printed during setup - let changelog_suggestion = - if matches!(config.cmd, Subcommand::Setup { .. }) { None } else { check_version(&config) }; + // check_version warnings are not printed during setup, or during CI + let changelog_suggestion = if matches!(config.cmd, Subcommand::Setup { .. }) || CiEnv::is_ci() { + None + } else { + check_version(&config) + }; // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the // changelog warning, not the `x.py setup` message. diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index d04e2fbeb78..18f5a1a58db 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -95,7 +95,6 @@ fn main() { // When statically linking `std` into `rustc_driver`, remove `-C prefer-dynamic` if env::var("RUSTC_LINK_STD_INTO_RUSTC_DRIVER").unwrap() == "1" && crate_name == Some("rustc_driver") - && stage != "0" { if let Some(pos) = args.iter().enumerate().position(|(i, a)| { a == "-C" && args.get(i + 1).map(|a| a == "prefer-dynamic").unwrap_or(false) @@ -137,6 +136,12 @@ fn main() { cmd.args(lint_flags.split_whitespace()); } + // Conditionally pass `-Zon-broken-pipe=kill` to underlying rustc. Not all binaries want + // `-Zon-broken-pipe=kill`, which includes cargo itself. + if env::var_os("FORCE_ON_BROKEN_PIPE_KILL").is_some() { + cmd.arg("-Z").arg("on-broken-pipe=kill"); + } + if target.is_some() { // The stage0 compiler has a special sysroot distinct from what we // actually downloaded, so we just always pass the `--sysroot` option, diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 7671fc7e013..f419bebdc12 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -398,7 +398,14 @@ impl Step for RustAnalyzer { } macro_rules! tool_check_step { - ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => { + ( + $name:ident, + $display_name:literal, + $path:literal, + $($alias:literal, )* + $source_type:path + $(, $default:literal )? + ) => { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { pub target: TargetSelection, @@ -441,7 +448,7 @@ macro_rules! tool_check_step { cargo.arg("--all-targets"); } - let _guard = builder.msg_check(&concat!(stringify!($name), " artifacts").to_lowercase(), target); + let _guard = builder.msg_check(&format!("{} artifacts", $display_name), target); run_cargo( builder, cargo, @@ -468,20 +475,30 @@ macro_rules! tool_check_step { }; } -tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree); +tool_check_step!(Rustdoc, "rustdoc", "src/tools/rustdoc", "src/librustdoc", SourceType::InTree); // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead // of a submodule. Since the SourceType only drives the deny-warnings // behavior, treat it as in-tree so that any new warnings in clippy will be // rejected. -tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree); -tool_check_step!(Miri, "src/tools/miri", SourceType::InTree); -tool_check_step!(CargoMiri, "src/tools/miri/cargo-miri", SourceType::InTree); -tool_check_step!(Rls, "src/tools/rls", SourceType::InTree); -tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree); -tool_check_step!(MiroptTestTools, "src/tools/miropt-test-tools", SourceType::InTree); -tool_check_step!(TestFloatParse, "src/etc/test-float-parse", SourceType::InTree); - -tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false); +tool_check_step!(Clippy, "clippy", "src/tools/clippy", SourceType::InTree); +tool_check_step!(Miri, "miri", "src/tools/miri", SourceType::InTree); +tool_check_step!(CargoMiri, "cargo-miri", "src/tools/miri/cargo-miri", SourceType::InTree); +tool_check_step!(Rls, "rls", "src/tools/rls", SourceType::InTree); +tool_check_step!(Rustfmt, "rustfmt", "src/tools/rustfmt", SourceType::InTree); +tool_check_step!( + MiroptTestTools, + "miropt-test-tools", + "src/tools/miropt-test-tools", + SourceType::InTree +); +tool_check_step!( + TestFloatParse, + "test-float-parse", + "src/etc/test-float-parse", + SourceType::InTree +); + +tool_check_step!(Bootstrap, "bootstrap", "src/bootstrap", SourceType::InTree, false); /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index eaa982d4e2b..27bbc8bd8ff 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1053,8 +1053,19 @@ pub fn rustc_cargo( cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)"); - // If the rustc output is piped to e.g. `head -n1` we want the process to be - // killed, rather than having an error bubble up and cause a panic. + // If the rustc output is piped to e.g. `head -n1` we want the process to be killed, rather than + // having an error bubble up and cause a panic. + // + // FIXME(jieyouxu): this flag is load-bearing for rustc to not ICE on broken pipes, because + // rustc internally sometimes uses std `println!` -- but std `println!` by default will panic on + // broken pipes, and uncaught panics will manifest as an ICE. The compiler *should* handle this + // properly, but this flag is set in the meantime to paper over the I/O errors. + // + // See <https://github.com/rust-lang/rust/issues/131059> for details. + // + // Also see the discussion for properly handling I/O errors related to broken pipes, i.e. safe + // variants of `println!` in + // <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Internal.20lint.20for.20raw.20.60print!.60.20and.20.60println!.60.3F>. cargo.rustflag("-Zon-broken-pipe=kill"); if builder.config.llvm_enzyme { @@ -1923,8 +1934,24 @@ impl Step for Assemble { let src_libdir = builder.sysroot_libdir(build_compiler, host); for f in builder.read_dir(&src_libdir) { let filename = f.file_name().into_string().unwrap(); - if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename) + + let is_proc_macro = proc_macros.contains(&filename); + let is_dylib_or_debug = is_dylib(&filename) || is_debug_info(&filename); + + // If we link statically to stdlib, do not copy the libstd dynamic library file + // FIXME: Also do this for Windows once incremental post-optimization stage0 tests + // work without std.dll (see https://github.com/rust-lang/rust/pull/131188). + let can_be_rustc_dynamic_dep = if builder + .link_std_into_rustc_driver(target_compiler.host) + && !target_compiler.host.is_windows() { + let is_std = filename.starts_with("std-") || filename.starts_with("libstd-"); + !is_std + } else { + true + }; + + if is_dylib_or_debug && can_be_rustc_dynamic_dep && !is_proc_macro { builder.copy_link(&f.path(), &rustc_libdir.join(&filename)); } } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 3d504c3771f..ca2b8742647 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -82,7 +82,7 @@ book!( EditionGuide, "src/doc/edition-guide", "edition-guide", &[], submodule; EmbeddedBook, "src/doc/embedded-book", "embedded-book", &[], submodule; Nomicon, "src/doc/nomicon", "nomicon", &[], submodule; - RustByExample, "src/doc/rust-by-example", "rust-by-example", &["ja"], submodule; + RustByExample, "src/doc/rust-by-example", "rust-by-example", &["ja", "zh"], submodule; RustdocBook, "src/doc/rustdoc", "rustdoc", &[]; StyleGuide, "src/doc/style-guide", "style-guide", &[]; ); @@ -718,6 +718,10 @@ fn doc_std( .arg("--target-dir") .arg(&*target_dir.to_string_lossy()) .arg("-Zskip-rustdoc-fingerprint") + .arg("-Zrustdoc-map") + .rustdocflag("--extern-html-root-url") + .rustdocflag("std_detect=https://docs.rs/std_detect/latest/") + .rustdocflag("--extern-html-root-takes-precedence") .rustdocflag("--resource-suffix") .rustdocflag(&builder.version); for arg in extra_args { diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 952d8d73328..5ca4321d855 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -93,6 +93,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, Str if !verify_rustfmt_version(build) { return Ok(None); } + get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]) } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 30213584157..a2d40f6fbd8 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -20,10 +20,9 @@ use build_helper::git::get_closest_merge_commit; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; -use crate::utils::channel; use crate::utils::exec::command; use crate::utils::helpers::{ - self, HashStamp, exe, get_clang_cl_resource_dir, output, t, unhashed_basename, up_to_date, + self, HashStamp, exe, get_clang_cl_resource_dir, t, unhashed_basename, up_to_date, }; use crate::{CLang, GitRepo, Kind, generate_smart_stamp_hash}; @@ -166,7 +165,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { config.src.join("src/version"), ]) .unwrap() - } else if let Some(info) = channel::read_commit_info_file(&config.src) { + } else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) { info.sha.trim().to_owned() } else { "".to_owned() @@ -242,15 +241,29 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { /// Returns true if we're running in CI with modified LLVM (and thus can't download it) pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { - CiEnv::is_rust_lang_managed_ci_job() && config.rust_info.is_managed_git_subrepository() && { - // We assume we have access to git, so it's okay to unconditionally pass - // `true` here. - let llvm_sha = detect_llvm_sha(config, true); - let head_sha = - output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").as_command_mut()); - let head_sha = head_sha.trim(); - llvm_sha == head_sha + // If not running in a CI environment, return false. + if !CiEnv::is_ci() { + return false; + } + + // In rust-lang/rust managed CI, assert the existence of the LLVM submodule. + if CiEnv::is_rust_lang_managed_ci_job() { + assert!( + config.in_tree_llvm_info.is_managed_git_subrepository(), + "LLVM submodule must be fetched in rust-lang/rust managed CI builders." + ); } + // If LLVM submodule isn't present, skip the change check as it won't work. + else if !config.in_tree_llvm_info.is_managed_git_subrepository() { + return false; + } + + let llvm_sha = detect_llvm_sha(config, true); + let head_sha = crate::output( + helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").as_command_mut(), + ); + let head_sha = head_sha.trim(); + llvm_sha == head_sha } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -1215,6 +1228,9 @@ fn supported_sanitizers( "aarch64-unknown-linux-ohos" => { common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"]) } + "loongarch64-unknown-linux-gnu" | "loongarch64-unknown-linux-musl" => { + common_libs("linux", "loongarch64", &["asan", "lsan", "msan", "tsan"]) + } "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]), "x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]), "x86_64-apple-ios" => darwin_libs("iossim", &["asan", "tsan"]), diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 0ee2cb451f3..51964977933 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -35,21 +35,6 @@ pub enum Profile { static PROFILE_DIR: &str = "src/bootstrap/defaults"; -/// A list of historical hashes of `src/etc/rust_analyzer_settings.json`. -/// New entries should be appended whenever this is updated so we can detect -/// outdated vs. user-modified settings files. -static SETTINGS_HASHES: &[&str] = &[ - "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", - "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", - "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", - "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", - "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", - "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", - "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", - "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", -]; -static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json"); - impl Profile { fn include_path(&self, src_path: &Path) -> PathBuf { PathBuf::from(format!("{}/{PROFILE_DIR}/config.{}.toml", src_path.display(), self)) @@ -533,46 +518,162 @@ undesirable, simply delete the `pre-push` file from .git/hooks." Ok(()) } -/// Sets up or displays `src/etc/rust_analyzer_settings.json` +/// Handles editor-specific setup differences +#[derive(Clone, Debug, Eq, PartialEq)] +enum EditorKind { + Vscode, + Vim, + Emacs, + Helix, +} + +impl EditorKind { + fn prompt_user() -> io::Result<Option<EditorKind>> { + let prompt_str = "Available editors: +1. vscode +2. vim +3. emacs +4. helix + +Select which editor you would like to set up [default: None]: "; + + let mut input = String::new(); + loop { + print!("{}", prompt_str); + io::stdout().flush()?; + input.clear(); + io::stdin().read_line(&mut input)?; + match input.trim().to_lowercase().as_str() { + "1" | "vscode" => return Ok(Some(EditorKind::Vscode)), + "2" | "vim" => return Ok(Some(EditorKind::Vim)), + "3" | "emacs" => return Ok(Some(EditorKind::Emacs)), + "4" | "helix" => return Ok(Some(EditorKind::Helix)), + "" => return Ok(None), + _ => { + eprintln!("ERROR: unrecognized option '{}'", input.trim()); + eprintln!("NOTE: press Ctrl+C to exit"); + } + }; + } + } + + /// A list of historical hashes of each LSP settings file + /// New entries should be appended whenever this is updated so we can detect + /// outdated vs. user-modified settings files. + fn hashes(&self) -> Vec<&str> { + match self { + EditorKind::Vscode | EditorKind::Vim => vec![ + "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", + "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", + "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", + "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", + "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", + "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", + "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", + ], + EditorKind::Emacs => vec![ + "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", + "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", + ], + EditorKind::Helix => { + vec!["2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233"] + } + } + } + + fn settings_path(&self, config: &Config) -> PathBuf { + config.src.join(self.settings_short_path()) + } + + fn settings_short_path(&self) -> PathBuf { + self.settings_folder().join(match self { + EditorKind::Vscode => "settings.json", + EditorKind::Vim => "coc-settings.json", + EditorKind::Emacs => ".dir-locals.el", + EditorKind::Helix => "languages.toml", + }) + } + + fn settings_folder(&self) -> PathBuf { + match self { + EditorKind::Vscode => PathBuf::from(".vscode"), + EditorKind::Vim => PathBuf::from(".vim"), + EditorKind::Emacs => PathBuf::new(), + EditorKind::Helix => PathBuf::from(".helix"), + } + } + + fn settings_template(&self) -> &str { + match self { + EditorKind::Vscode | EditorKind::Vim => { + include_str!("../../../../etc/rust_analyzer_settings.json") + } + EditorKind::Emacs => include_str!("../../../../etc/rust_analyzer_eglot.el"), + EditorKind::Helix => include_str!("../../../../etc/rust_analyzer_helix.toml"), + } + } + + fn backup_extension(&self) -> String { + format!("{}.bak", self.settings_short_path().extension().unwrap().to_str().unwrap()) + } +} + +/// Sets up or displays the LSP config for one of the supported editors #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct Vscode; +pub struct Editor; -impl Step for Vscode { +impl Step for Editor { type Output = (); const DEFAULT: bool = true; + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.alias("vscode") + run.alias("editor") } + fn make_run(run: RunConfig<'_>) { if run.builder.config.dry_run() { return; } if let [cmd] = &run.paths[..] { - if cmd.assert_single_path().path.as_path().as_os_str() == "vscode" { - run.builder.ensure(Vscode); + if cmd.assert_single_path().path.as_path().as_os_str() == "editor" { + run.builder.ensure(Editor); } } } + fn run(self, builder: &Builder<'_>) -> Self::Output { let config = &builder.config; if config.dry_run() { return; } - while !t!(create_vscode_settings_maybe(config)) {} + match EditorKind::prompt_user() { + Ok(editor_kind) => { + if let Some(editor_kind) = editor_kind { + while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {} + } else { + println!("Ok, skipping editor setup!"); + } + } + Err(e) => eprintln!("Could not determine the editor: {e}"), + } } } -/// Create a `.vscode/settings.json` file for rustc development, or just print it +/// Create the recommended editor LSP config file for rustc development, or just print it /// If this method should be re-called, it returns `false`. -fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> { - let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap(); - let vscode_settings = config.src.join(".vscode").join("settings.json"); - // If None, no settings.json exists +fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Result<bool> { + let hashes = editor.hashes(); + let (current_hash, historical_hashes) = hashes.split_last().unwrap(); + let settings_path = editor.settings_path(config); + let settings_short_path = editor.settings_short_path(); + let settings_filename = settings_short_path.to_str().unwrap(); + // If None, no settings file exists // If Some(true), is a previous version of settings.json // If Some(false), is not a previous version (i.e. user modified) // If it's up to date we can just skip this let mut mismatched_settings = None; - if let Ok(current) = fs::read_to_string(&vscode_settings) { + if let Ok(current) = fs::read_to_string(&settings_path) { let mut hasher = sha2::Sha256::new(); hasher.update(¤t); let hash = hex_encode(hasher.finalize().as_slice()); @@ -585,20 +686,21 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> { } } println!( - "\nx.py can automatically install the recommended `.vscode/settings.json` file for rustc development" + "\nx.py can automatically install the recommended `{settings_filename}` file for rustc development" ); + match mismatched_settings { - Some(true) => eprintln!( - "WARNING: existing `.vscode/settings.json` is out of date, x.py will update it" - ), + Some(true) => { + eprintln!("WARNING: existing `{settings_filename}` is out of date, x.py will update it") + } Some(false) => eprintln!( - "WARNING: existing `.vscode/settings.json` has been modified by user, x.py will back it up and replace it" + "WARNING: existing `{settings_filename}` has been modified by user, x.py will back it up and replace it" ), _ => (), } - let should_create = match prompt_user( - "Would you like to create/update settings.json? (Press 'p' to preview values): [y/N]", - )? { + let should_create = match prompt_user(&format!( + "Would you like to create/update `{settings_filename}`? (Press 'p' to preview values): [y/N]" + ))? { Some(PromptResult::Yes) => true, Some(PromptResult::Print) => false, _ => { @@ -607,9 +709,9 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> { } }; if should_create { - let path = config.src.join(".vscode"); - if !path.exists() { - fs::create_dir(&path)?; + let settings_folder_path = config.src.join(editor.settings_folder()); + if !settings_folder_path.exists() { + fs::create_dir(settings_folder_path)?; } let verb = match mismatched_settings { // exists but outdated, we can replace this @@ -617,18 +719,21 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> { // exists but user modified, back it up Some(false) => { // exists and is not current version or outdated, so back it up - let mut backup = vscode_settings.clone(); - backup.set_extension("json.bak"); - eprintln!("WARNING: copying `settings.json` to `settings.json.bak`"); - fs::copy(&vscode_settings, &backup)?; + let backup = settings_path.clone().with_extension(editor.backup_extension()); + eprintln!( + "WARNING: copying `{}` to `{}`", + settings_path.file_name().unwrap().to_str().unwrap(), + backup.file_name().unwrap().to_str().unwrap(), + ); + fs::copy(&settings_path, &backup)?; "Updated" } _ => "Created", }; - fs::write(&vscode_settings, RUST_ANALYZER_SETTINGS)?; - println!("{verb} `.vscode/settings.json`"); + fs::write(&settings_path, editor.settings_template())?; + println!("{verb} `{}`", settings_filename); } else { - println!("\n{RUST_ANALYZER_SETTINGS}"); + println!("\n{}", editor.settings_template()); } Ok(should_create) } diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs index 3552224f33b..f3d4b6aa4db 100644 --- a/src/bootstrap/src/core/build_steps/setup/tests.rs +++ b/src/bootstrap/src/core/build_steps/setup/tests.rs @@ -1,16 +1,17 @@ use sha2::Digest; -use super::{RUST_ANALYZER_SETTINGS, SETTINGS_HASHES}; +use super::EditorKind; use crate::utils::helpers::hex_encode; #[test] fn check_matching_settings_hash() { + let editor = EditorKind::Vscode; let mut hasher = sha2::Sha256::new(); - hasher.update(&RUST_ANALYZER_SETTINGS); + hasher.update(&editor.settings_template()); let hash = hex_encode(hasher.finalize().as_slice()); assert_eq!( &hash, - SETTINGS_HASHES.last().unwrap(), - "Update `SETTINGS_HASHES` with the new hash of `src/etc/rust_analyzer_settings.json`" + editor.hashes().last().unwrap(), + "Update `EditorKind::hashes()` with the new hash of `src/etc/rust_analyzer_settings.json`" ); } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7283b0e9574..e25b571acba 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1394,12 +1394,6 @@ default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" }); default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" }); -default_test!(RunPassValgrind { - path: "tests/run-pass-valgrind", - mode: "run-pass-valgrind", - suite: "run-pass-valgrind" -}); - default_test!(Codegen { path: "tests/codegen", mode: "codegen", suite: "codegen" }); default_test!(CodegenUnits { @@ -1703,7 +1697,11 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the builder.ensure(TestHelpers { target: compiler.host }); // ensure that `libproc_macro` is available on the host. - builder.ensure(compile::Std::new(compiler, compiler.host)); + if suite == "mir-opt" { + builder.ensure(compile::Std::new_for_mir_opt_tests(compiler, compiler.host)); + } else { + builder.ensure(compile::Std::new(compiler, compiler.host)); + } // As well as the target if suite != "mir-opt" { @@ -2088,7 +2086,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } if builder.config.profiler_enabled(target) { - cmd.arg("--profiler-support"); + cmd.arg("--profiler-runtime"); } cmd.env("RUST_TEST_TMPDIR", builder.tempdir()); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 64dfe054d9c..a01497c2bb9 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -209,11 +209,28 @@ pub fn prepare_tool_cargo( // See https://github.com/rust-lang/rust/issues/116538 cargo.rustflag("-Zunstable-options"); - // `-Zon-broken-pipe=kill` breaks cargo tests + // NOTE: The root cause of needing `-Zon-broken-pipe=kill` in the first place is because `rustc` + // and `rustdoc` doesn't gracefully handle I/O errors due to usages of raw std `println!` macros + // which panics upon encountering broken pipes. `-Zon-broken-pipe=kill` just papers over that + // and stops rustc/rustdoc ICEing on e.g. `rustc --print=sysroot | false`. + // + // cargo explicitly does not want the `-Zon-broken-pipe=kill` paper because it does actually use + // variants of `println!` that handles I/O errors gracefully. It's also a breaking change for a + // spawn process not written in Rust, especially if the language default handler is not + // `SIG_IGN`. Thankfully cargo tests will break if we do set the flag. + // + // For the cargo discussion, see + // <https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/Applying.20.60-Zon-broken-pipe.3Dkill.60.20flags.20in.20bootstrap.3F>. + // + // For the rustc discussion, see + // <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Internal.20lint.20for.20raw.20.60print!.60.20and.20.60println!.60.3F> + // for proper solutions. if !path.ends_with("cargo") { - // If the output is piped to e.g. `head -n1` we want the process to be killed, - // rather than having an error bubble up and cause a panic. - cargo.rustflag("-Zon-broken-pipe=kill"); + // Use an untracked env var `FORCE_ON_BROKEN_PIPE_KILL` here instead of `RUSTFLAGS`. + // `RUSTFLAGS` is tracked by cargo. Conditionally omitting `-Zon-broken-pipe=kill` from + // `RUSTFLAGS` causes unnecessary tool rebuilds due to cache invalidation from building e.g. + // cargo *without* `-Zon-broken-pipe=kill` but then rustdoc *with* `-Zon-broken-pipe=kill`. + cargo.env("FORCE_ON_BROKEN_PIPE_KILL", "-Zon-broken-pipe=kill"); } cargo @@ -872,8 +889,11 @@ impl Step for LlvmBitcodeLinker { fn run(self, builder: &Builder<'_>) -> PathBuf { let bin_name = "llvm-bitcode-linker"; - builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); - builder.ensure(compile::Rustc::new(self.compiler, self.target)); + // If enabled, use ci-rustc and skip building the in-tree compiler. + if !builder.download_rustc() { + builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); + builder.ensure(compile::Rustc::new(self.compiler, self.target)); + } let cargo = prepare_tool_cargo( builder, diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index c35384ce3c0..9ac0b0a01f7 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -72,36 +72,40 @@ impl<'a> Deref for Builder<'a> { } pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { - /// `PathBuf` when directories are created or to return a `Compiler` once - /// it's been assembled. + /// Result type of `Step::run`. type Output: Clone; - /// Whether this step is run by default as part of its respective phase. - /// `true` here can still be overwritten by `should_run` calling `default_condition`. + /// Whether this step is run by default as part of its respective phase, as defined by the `describe` + /// macro in [`Builder::get_step_descriptions`]. + /// + /// Note: Even if set to `true`, it can still be overridden with [`ShouldRun::default_condition`] + /// by `Step::should_run`. const DEFAULT: bool = false; /// If true, then this rule should be skipped if --target was specified, but --host was not const ONLY_HOSTS: bool = false; - /// Primary function to execute this rule. Can call `builder.ensure()` - /// with other steps to run those. + /// Primary function to implement `Step` logic. + /// + /// This function can be triggered in two ways: + /// 1. Directly from [`Builder::execute_cli`]. + /// 2. Indirectly by being called from other `Step`s using [`Builder::ensure`]. /// - /// This gets called twice during a normal `./x.py` execution: first - /// with `dry_run() == true`, and then for real. + /// When called with [`Builder::execute_cli`] (as done by `Build::build`), this function executed twice: + /// - First in "dry-run" mode to validate certain things (like cyclic Step invocations, + /// directory creation, etc) super quickly. + /// - Then it's called again to run the actual, very expensive process. + /// + /// When triggered indirectly from other `Step`s, it may still run twice (as dry-run and real mode) + /// depending on the `Step::run` implementation of the caller. fn run(self, builder: &Builder<'_>) -> Self::Output; - /// When bootstrap is passed a set of paths, this controls whether this rule - /// will execute. However, it does not get called in a "default" context - /// when we are not passed any paths; in that case, `make_run` is called - /// directly. + /// Determines if this `Step` should be run when given specific paths (e.g., `x build $path`). fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_>; - /// Builds up a "root" rule, either as a default rule or from a path passed - /// to us. - /// - /// When path is `None`, we are executing in a context where no paths were - /// passed. When `./x.py build` is run, for example, this rule could get - /// called if it is in the correct list below with a path of `None`. + /// Called directly by the bootstrap `Step` handler when not triggered indirectly by other `Step`s using [`Builder::ensure`]. + /// For example, `./x.py test bootstrap` runs this for `test::Bootstrap`. Similarly, `./x.py test` runs it for every step + /// that is listed by the `describe` macro in [`Builder::get_step_descriptions`]. fn make_run(_run: RunConfig<'_>) { // It is reasonable to not have an implementation of make_run for rules // who do not want to get called from the root context. This means that @@ -327,7 +331,6 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ "tests/mir-opt", "tests/pretty", "tests/run-make", - "tests/run-pass-valgrind", "tests/rustdoc", "tests/rustdoc-gui", "tests/rustdoc-js", @@ -415,6 +418,15 @@ impl StepDescription { .map(|desc| (desc.should_run)(ShouldRun::new(builder, desc.kind))) .collect::<Vec<_>>(); + if builder.download_rustc() && (builder.kind == Kind::Dist || builder.kind == Kind::Install) + { + eprintln!( + "ERROR: '{}' subcommand is incompatible with `rust.download-rustc`.", + builder.kind.as_str() + ); + crate::exit!(1); + } + // sanity checks on rules for (desc, should_run) in v.iter().zip(&should_runs) { assert!( @@ -852,7 +864,6 @@ impl<'a> Builder<'a> { test::Tidy, test::Ui, test::Crashes, - test::RunPassValgrind, test::Coverage, test::CoverageMap, test::CoverageRun, @@ -1000,7 +1011,9 @@ impl<'a> Builder<'a> { run::GenerateWindowsSys, run::GenerateCompletions, ), - Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode), + Kind::Setup => { + describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor) + } Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() @@ -1685,10 +1698,24 @@ impl<'a> Builder<'a> { match mode { Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {} Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { - // Build proc macros both for the host and the target + // Build proc macros both for the host and the target unless proc-macros are not + // supported by the target. if target != compiler.host && cmd_kind != Kind::Check { - cargo.arg("-Zdual-proc-macros"); - rustflags.arg("-Zdual-proc-macros"); + let error = command(self.rustc(compiler)) + .arg("--target") + .arg(target.rustc_target_arg()) + .arg("--print=file-names") + .arg("--crate-type=proc-macro") + .arg("-") + .run_capture(self) + .stderr(); + let not_supported = error + .lines() + .any(|line| line.contains("unsupported crate type `proc-macro`")); + if !not_supported { + cargo.arg("-Zdual-proc-macros"); + rustflags.arg("-Zdual-proc-macros"); + } } } } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index bd81dc930be..695a66834d4 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -212,6 +212,39 @@ fn alias_and_path_for_library() { assert_eq!(first(cache.all::<doc::Std>()), &[doc_std!(A => A, stage = 0)]); } +#[test] +fn ci_rustc_if_unchanged_logic() { + let config = Config::parse_inner( + Flags::parse(&[ + "build".to_owned(), + "--dry-run".to_owned(), + "--set=rust.download-rustc='if-unchanged'".to_owned(), + ]), + |&_| Ok(Default::default()), + ); + + let build = Build::new(config.clone()); + let builder = Builder::new(&build); + + if config.out.exists() { + fs::remove_dir_all(&config.out).unwrap(); + } + + builder.run_step_descriptions(&Builder::get_step_descriptions(config.cmd.kind()), &[]); + + // Make sure "if-unchanged" logic doesn't try to use CI rustc while there are changes + // in compiler and/or library. + if config.download_rustc_commit.is_some() { + let has_changes = + config.last_modified_commit(&["compiler", "library"], "download-rustc", true).is_none(); + + assert!( + !has_changes, + "CI-rustc can't be used with 'if-unchanged' while there are changes in compiler and/or library." + ); + } +} + mod defaults { use pretty_assertions::assert_eq; diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 07460b81412..f768470c4ff 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -4,7 +4,7 @@ //! how the build runs. use std::cell::{Cell, RefCell}; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::{self, Display}; use std::io::IsTerminal; use std::path::{Path, PathBuf, absolute}; @@ -13,6 +13,7 @@ use std::str::FromStr; use std::sync::OnceLock; use std::{cmp, env, fs}; +use build_helper::ci::CiEnv; use build_helper::exit; use build_helper::git::{GitConfig, get_closest_merge_commit, output_result}; use serde::{Deserialize, Deserializer}; @@ -22,6 +23,7 @@ use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::llvm; pub use crate::core::config::flags::Subcommand; use crate::core::config::flags::{Color, Flags, Warnings}; +use crate::core::download::is_download_ci_available; use crate::utils::cache::{INTERNER, Interned}; use crate::utils::channel::{self, GitInfo}; use crate::utils::helpers::{self, exe, output, t}; @@ -287,6 +289,7 @@ pub struct Config { pub rust_profile_generate: Option<String>, pub rust_lto: RustcLto, pub rust_validate_mir_opts: Option<u32>, + pub rust_std_features: BTreeSet<String>, pub llvm_profile_use: Option<String>, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option<LlvmLibunwind>, @@ -1152,6 +1155,7 @@ define_config! { download_rustc: Option<StringOrBool> = "download-rustc", lto: Option<String> = "lto", validate_mir_opts: Option<u32> = "validate-mir-opts", + std_features: Option<BTreeSet<String>> = "std-features", } } @@ -1625,9 +1629,11 @@ impl Config { config.mandir = mandir.map(PathBuf::from); } + config.llvm_assertions = + toml.llvm.as_ref().map_or(false, |llvm| llvm.assertions.unwrap_or(false)); + // Store off these values as options because if they're not provided // we'll infer default values for them later - let mut llvm_assertions = None; let mut llvm_tests = None; let mut llvm_enzyme = None; let mut llvm_plugins = None; @@ -1645,6 +1651,7 @@ impl Config { let mut optimize = None; let mut omit_git_hash = None; let mut lld_enabled = None; + let mut std_features = None; let mut is_user_configured_rust_channel = false; @@ -1703,12 +1710,14 @@ impl Config { stack_protector, strip, lld_mode, + std_features: std_features_toml, } = rust; is_user_configured_rust_channel = channel.is_some(); set(&mut config.channel, channel.clone()); - config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc); + config.download_rustc_commit = + config.download_ci_rustc_commit(download_rustc, config.llvm_assertions); debug = debug_toml; debug_assertions = debug_assertions_toml; @@ -1722,6 +1731,7 @@ impl Config { debuginfo_level_tools = debuginfo_level_tools_toml; debuginfo_level_tests = debuginfo_level_tests_toml; lld_enabled = lld_enabled_toml; + std_features = std_features_toml; optimize = optimize_toml; omit_git_hash = omit_git_hash_toml; @@ -1843,7 +1853,7 @@ impl Config { optimize: optimize_toml, thin_lto, release_debuginfo, - assertions, + assertions: _, tests, enzyme, plugins, @@ -1877,7 +1887,6 @@ impl Config { Some(StringOrBool::Bool(false)) | None => {} } set(&mut config.ninja_in_file, ninja); - llvm_assertions = assertions; llvm_tests = tests; llvm_enzyme = enzyme; llvm_plugins = plugins; @@ -1906,8 +1915,8 @@ impl Config { config.llvm_enable_warnings = enable_warnings.unwrap_or(false); config.llvm_build_config = build_config.clone().unwrap_or(Default::default()); - let asserts = llvm_assertions.unwrap_or(false); - config.llvm_from_ci = config.parse_download_ci_llvm(download_ci_llvm, asserts); + config.llvm_from_ci = + config.parse_download_ci_llvm(download_ci_llvm, config.llvm_assertions); if config.llvm_from_ci { let warn = |option: &str| { @@ -2075,7 +2084,6 @@ impl Config { // Now that we've reached the end of our configuration, infer the // default values for all options that we haven't otherwise stored yet. - config.llvm_assertions = llvm_assertions.unwrap_or(false); config.llvm_tests = llvm_tests.unwrap_or(false); config.llvm_enzyme = llvm_enzyme.unwrap_or(false); config.llvm_plugins = llvm_plugins.unwrap_or(false); @@ -2118,6 +2126,9 @@ impl Config { ); } + let default_std_features = BTreeSet::from([String::from("panic-unwind")]); + config.rust_std_features = std_features.unwrap_or(default_std_features); + let default = debug == Some(true); config.rust_debug_assertions = debug_assertions.unwrap_or(default); config.rust_debug_assertions_std = @@ -2388,6 +2399,20 @@ impl Config { Some(commit) => { self.download_ci_rustc(commit); + // CI-rustc can't be used without CI-LLVM. If `self.llvm_from_ci` is false, it means the "if-unchanged" + // logic has detected some changes in the LLVM submodule (download-ci-llvm=false can't happen here as + // we don't allow it while parsing the configuration). + if !self.llvm_from_ci { + // This happens when LLVM submodule is updated in CI, we should disable ci-rustc without an error + // to not break CI. For non-CI environments, we should return an error. + if CiEnv::is_ci() { + println!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled."); + return None; + } else { + panic!("ERROR: LLVM submodule has changes, `download-rustc` can't be used."); + } + } + if let Some(config_path) = &self.config { let ci_config_toml = match self.get_builder_toml("ci-rustc") { Ok(ci_config_toml) => ci_config_toml, @@ -2411,8 +2436,9 @@ impl Config { ci_config_toml, ); - let disable_ci_rustc_if_incompatible = - env::var_os("DISABLE_CI_RUSTC_IF_INCOMPATIBLE") + // Primarily used by CI runners to avoid handling download-rustc incompatible + // options one by one on shell scripts. + let disable_ci_rustc_if_incompatible = env::var_os("DISABLE_CI_RUSTC_IF_INCOMPATIBLE") .is_some_and(|s| s == "1" || s == "true"); if disable_ci_rustc_if_incompatible && res.is_err() { @@ -2703,7 +2729,15 @@ impl Config { } /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. - fn download_ci_rustc_commit(&self, download_rustc: Option<StringOrBool>) -> Option<String> { + fn download_ci_rustc_commit( + &self, + download_rustc: Option<StringOrBool>, + llvm_assertions: bool, + ) -> Option<String> { + if !is_download_ci_available(&self.build.triple, llvm_assertions) { + return None; + } + // If `download-rustc` is not set, default to rebuilding. let if_unchanged = match download_rustc { None | Some(StringOrBool::Bool(false)) => return None, @@ -2714,9 +2748,18 @@ impl Config { } }; + let files_to_track = &[ + self.src.join("compiler"), + self.src.join("library"), + self.src.join("src/version"), + self.src.join("src/stage0"), + self.src.join("src/ci/channel"), + ]; + // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap(); + let commit = + get_closest_merge_commit(Some(&self.src), &self.git_config(), files_to_track).unwrap(); if commit.is_empty() { println!("ERROR: could not find commit hash for downloading rustc"); println!("HELP: maybe your repository history is too shallow?"); @@ -2725,11 +2768,24 @@ impl Config { crate::exit!(1); } + if CiEnv::is_ci() && { + let head_sha = + output(helpers::git(Some(&self.src)).arg("rev-parse").arg("HEAD").as_command_mut()); + let head_sha = head_sha.trim(); + commit == head_sha + } { + 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." + ); + return None; + } + // Warn if there were changes to the compiler or standard library since the ancestor commit. let has_changes = !t!(helpers::git(Some(&self.src)) .args(["diff-index", "--quiet", &commit]) .arg("--") - .args([self.src.join("compiler"), self.src.join("library")]) + .args(files_to_track) .as_command_mut() .status()) .success(); @@ -3016,6 +3072,7 @@ fn check_incompatible_options_for_ci_rustc( description, incremental, default_linker, + std_features, // Rest of the options can simply be ignored. debug: _, @@ -3077,6 +3134,7 @@ fn check_incompatible_options_for_ci_rustc( err!(current_rust_config.default_linker, default_linker); err!(current_rust_config.stack_protector, stack_protector); err!(current_rust_config.lto, lto); + err!(current_rust_config.std_features, std_features); warn!(current_rust_config.channel, channel); warn!(current_rust_config.description, description); diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 87db5f93fb0..3aefe517a5b 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -447,14 +447,14 @@ Arguments: The profile is optional and you will be prompted interactively if it is not given. The following profiles are available: {} - To only set up the git hook, VS Code config or toolchain link, you may use + To only set up the git hook, editor config or toolchain link, you may use ./x.py setup hook - ./x.py setup vscode + ./x.py setup editor ./x.py setup link", Profile::all_for_help(" ").trim_end()))] Setup { /// Either the profile for `config.toml` or another setup action. /// May be omitted to set up interactively - #[arg(value_name = "<PROFILE>|hook|vscode|link")] + #[arg(value_name = "<PROFILE>|hook|editor|link")] profile: Option<PathBuf>, }, /// Suggest a subset of tests to run, based on modified files diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index e38d4eac051..2611b6cf51b 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeSet; use std::env; use std::fs::{File, remove_file}; use std::io::Write; @@ -9,9 +10,10 @@ use serde::Deserialize; use super::flags::Flags; use super::{ChangeIdWrapper, Config}; use crate::core::build_steps::clippy::get_clippy_rules_in_order; +use crate::core::build_steps::llvm; use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig}; -fn parse(config: &str) -> Config { +pub(crate) fn parse(config: &str) -> Config { Config::parse_inner( Flags::parse(&["check".to_string(), "--config=/does/not/exist".to_string()]), |&_| toml::from_str(&config), @@ -20,29 +22,32 @@ fn parse(config: &str) -> Config { #[test] fn download_ci_llvm() { - if crate::core::build_steps::llvm::is_ci_llvm_modified(&parse("")) { - eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change"); - return; + let config = parse(""); + let is_available = llvm::is_ci_llvm_available(&config, config.llvm_assertions); + if is_available { + assert!(config.llvm_from_ci); } - let parse_llvm = |s| parse(s).llvm_from_ci; - let if_unchanged = parse_llvm("llvm.download-ci-llvm = \"if-unchanged\""); + let config = parse("llvm.download-ci-llvm = true"); + let is_available = llvm::is_ci_llvm_available(&config, config.llvm_assertions); + if is_available { + assert!(config.llvm_from_ci); + } - assert!(parse_llvm("llvm.download-ci-llvm = true")); - assert!(!parse_llvm("llvm.download-ci-llvm = false")); - assert_eq!(parse_llvm(""), if_unchanged); - assert_eq!(parse_llvm("rust.channel = \"dev\""), if_unchanged); - assert!(parse_llvm("rust.channel = \"stable\"")); - assert_eq!(parse_llvm("build.build = \"x86_64-unknown-linux-gnu\""), if_unchanged); - assert_eq!( - parse_llvm( - "llvm.assertions = true \r\n build.build = \"x86_64-unknown-linux-gnu\" \r\n llvm.download-ci-llvm = \"if-unchanged\"" - ), - if_unchanged - ); - assert!(!parse_llvm( - "llvm.assertions = true \r\n build.build = \"aarch64-apple-darwin\" \r\n llvm.download-ci-llvm = \"if-unchanged\"" - )); + let config = parse("llvm.download-ci-llvm = false"); + assert!(!config.llvm_from_ci); + + let if_unchanged_config = parse("llvm.download-ci-llvm = \"if-unchanged\""); + if if_unchanged_config.llvm_from_ci { + let has_changes = if_unchanged_config + .last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true) + .is_none(); + + assert!( + !has_changes, + "CI LLVM can't be enabled with 'if-unchanged' while there are changes in LLVM submodule." + ); + } } // FIXME(onur-ozkan): extend scope of the test @@ -326,3 +331,24 @@ fn verbose_tests_default_value() { let config = Config::parse(Flags::parse(&["build".into(), "compiler".into(), "-v".into()])); assert_eq!(config.verbose_tests, true); } + +#[test] +fn parse_rust_std_features() { + let config = parse("rust.std-features = [\"panic-unwind\", \"backtrace\"]"); + let expected_features: BTreeSet<String> = + ["panic-unwind", "backtrace"].into_iter().map(|s| s.to_string()).collect(); + assert_eq!(config.rust_std_features, expected_features); +} + +#[test] +fn parse_rust_std_features_empty() { + let config = parse("rust.std-features = []"); + let expected_features: BTreeSet<String> = BTreeSet::new(); + assert_eq!(config.rust_std_features, expected_features); +} + +#[test] +#[should_panic] +fn parse_rust_std_features_invalid() { + parse("rust.std-features = \"backtrace\""); +} diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 444b75876f2..db1f5b08338 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -832,3 +832,43 @@ fn path_is_dylib(path: &Path) -> bool { // The .so is not necessarily the extension, it might be libLLVM.so.18.1 path.to_str().map_or(false, |path| path.contains(".so")) } + +/// Checks whether the CI rustc is available for the given target triple. +pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: bool) -> bool { + // All tier 1 targets and tier 2 targets with host tools. + const SUPPORTED_PLATFORMS: &[&str] = &[ + "aarch64-apple-darwin", + "aarch64-pc-windows-msvc", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "armv7-unknown-linux-gnueabihf", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "loongarch64-unknown-linux-gnu", + "powerpc-unknown-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "riscv64gc-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-freebsd", + "x86_64-unknown-illumos", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-netbsd", + ]; + + const SUPPORTED_PLATFORMS_WITH_ASSERTIONS: &[&str] = + &["x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]; + + if llvm_assertions { + SUPPORTED_PLATFORMS_WITH_ASSERTIONS.contains(&target_triple) + } else { + SUPPORTED_PLATFORMS.contains(&target_triple) + } +} diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 888ba8e2a3f..6fbdd76ed5b 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -13,8 +13,6 @@ use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use std::{env, fs}; -use build_helper::git::warn_old_master_branch; - use crate::Build; #[cfg(not(feature = "bootstrap-self-test"))] use crate::builder::Builder; @@ -37,6 +35,9 @@ pub struct Finder { const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "armv7-rtems-eabihf", + "riscv32e-unknown-none-elf", + "riscv32em-unknown-none-elf", + "riscv32emc-unknown-none-elf", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM @@ -379,6 +380,4 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake if let Some(ref s) = build.config.ccache { cmd_finder.must_have(s); } - - warn_old_master_branch(&build.config.git_config(), &build.config.src); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 75659f46431..3924a6d714e 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -17,7 +17,7 @@ //! also check out the `src/bootstrap/README.md` file for more information. use std::cell::{Cell, RefCell}; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::Display; use std::fs::{self, File}; use std::path::{Path, PathBuf}; @@ -470,7 +470,7 @@ impl Build { crate::core::metadata::build(&mut build); } - // Make a symbolic link so we can use a consistent directory in the documentation. + // Create symbolic link to use host sysroot from a consistent path (e.g., in the rust-analyzer config file). let build_triple = build.out.join(build.build); t!(fs::create_dir_all(&build_triple)); let host = build.out.join("host"); @@ -645,28 +645,31 @@ impl Build { &self.config.rust_info } - /// Gets the space-separated set of activated features for the standard - /// library. + /// Gets the space-separated set of activated features for the standard library. + /// This can be configured with the `std-features` key in config.toml. fn std_features(&self, target: TargetSelection) -> String { - let mut features = " panic-unwind".to_string(); + let mut features: BTreeSet<&str> = + self.config.rust_std_features.iter().map(|s| s.as_str()).collect(); match self.config.llvm_libunwind(target) { - LlvmLibunwind::InTree => features.push_str(" llvm-libunwind"), - LlvmLibunwind::System => features.push_str(" system-llvm-libunwind"), - LlvmLibunwind::No => {} - } + LlvmLibunwind::InTree => features.insert("llvm-libunwind"), + LlvmLibunwind::System => features.insert("system-llvm-libunwind"), + LlvmLibunwind::No => false, + }; + if self.config.backtrace { - features.push_str(" backtrace"); + features.insert("backtrace"); } if self.config.profiler_enabled(target) { - features.push_str(" profiler"); + features.insert("profiler"); } // Generate memcpy, etc. FIXME: Remove this once compiler-builtins // automatically detects this target. if target.contains("zkvm") { - features.push_str(" compiler-builtins-mem"); + features.insert("compiler-builtins-mem"); } - features + + features.into_iter().collect::<Vec<_>>().join(" ") } /// Gets the space-separated set of activated features for the compiler. @@ -1572,9 +1575,11 @@ Executed at: {executed_at}"#, fn rust_version(&self) -> String { let mut version = self.rust_info().version(self, &self.version); if let Some(ref s) = self.config.description { - version.push_str(" ("); - version.push_str(s); - version.push(')'); + if !s.is_empty() { + version.push_str(" ("); + version.push_str(s); + version.push(')'); + } } version } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index e6f7f105fa2..b37786496cb 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -270,4 +270,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "If `llvm.download-ci-llvm` is not defined, it defaults to `true`.", }, + ChangeInfo { + change_id: 131075, + severity: ChangeSeverity::Info, + summary: "New option `./x setup editor` added, replacing `./x setup vscode` and adding support for vim, emacs and helix.", + }, ]; diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 7150c84313c..6d3c276cc05 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -49,6 +49,8 @@ pub fn exe(name: &str, target: &str) -> String { format!("{name}.exe") } else if target.contains("uefi") { format!("{name}.efi") + } else if target.contains("wasm") { + format!("{name}.wasm") } else { name.to_string() } 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 865a9e32fa9..71eb72686b0 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile @@ -47,6 +47,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-extended \ --enable-full-tools \ --enable-profiler \ + --enable-sanitizers \ --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $TARGETS 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 62dbfaaa673..5081f25e567 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile @@ -29,6 +29,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-extended \ --enable-full-tools \ --enable-profiler \ + --enable-sanitizers \ --disable-docs \ --set target.loongarch64-unknown-linux-musl.crt-static=false \ --musl-root-loongarch64=/x-tools/loongarch64-unknown-linux-musl/loongarch64-unknown-linux-musl/sysroot/usr diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 571378774be..0f8ebb987c3 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -46,7 +46,8 @@ ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 # 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 python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ +ENV SCRIPT \ + python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/check-default-config-profiles.sh && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py clippy bootstrap -Dwarnings && \ 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 ba3e8bdb687..0cae83a85b3 100644 --- a/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile @@ -58,6 +58,9 @@ RUN mkdir -p $RUST_INSTALL_DIR/etc # Fuchsia only supports LLVM. ENV CODEGEN_BACKENDS llvm +# download-rustc is not allowed for `x install` +ENV NO_DOWNLOAD_CI_RUSTC 1 + ENV RUST_CONFIGURE_ARGS \ --prefix=$RUST_INSTALL_DIR \ --sysconfdir=etc \ @@ -70,6 +73,7 @@ ENV RUST_CONFIGURE_ARGS \ --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 + 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-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 6a09ab3065f..17fc1a57492 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 @@ -84,6 +84,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-new-symbol-mangling ENV HOST_TARGET x86_64-unknown-linux-gnu +ENV FORCE_CI_RUSTC 1 COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/ COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ @@ -100,4 +101,4 @@ RUN /scripts/build-gccjit.sh /scripts # the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ - python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--no-sandbox --jobs 1'" + python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index fad4b5af095..28487bce482 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -343,6 +343,7 @@ docker \ --env PR_CI_JOB \ --env OBJDIR_ON_HOST="$objdir" \ --env CODEGEN_BACKENDS \ + --env DISABLE_CI_RUSTC_IF_INCOMPATIBLE="$DISABLE_CI_RUSTC_IF_INCOMPATIBLE" \ --init \ --rm \ rust-ci \ diff --git a/src/ci/docker/scripts/emscripten.sh b/src/ci/docker/scripts/emscripten.sh index 3f5e2c6ff1d..8b2b39ee162 100644 --- a/src/ci/docker/scripts/emscripten.sh +++ b/src/ci/docker/scripts/emscripten.sh @@ -20,5 +20,5 @@ exit 1 git clone https://github.com/emscripten-core/emsdk.git /emsdk-portable cd /emsdk-portable -hide_output ./emsdk install 2.0.5 -./emsdk activate 2.0.5 +hide_output ./emsdk install 3.1.68 +./emsdk activate 3.1.68 diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 8011e07e92e..27dbfc6040c 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,7 @@ set -euo pipefail -LINUX_VERSION=4c7864e81d8bbd51036dacf92fb0a400e13aaeee +LINUX_VERSION=v6.12-rc2 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm.sh b/src/ci/docker/scripts/x86_64-gnu-llvm.sh index 98290f5a72c..dea38b6fd2a 100755 --- a/src/ci/docker/scripts/x86_64-gnu-llvm.sh +++ b/src/ci/docker/scripts/x86_64-gnu-llvm.sh @@ -2,6 +2,22 @@ set -ex +if [ "$READ_ONLY_SRC" = "0" ]; then + # `core::builder::tests::ci_rustc_if_unchanged_logic` bootstrap test ensures that + # "download-rustc=if-unchanged" logic don't use CI rustc while there are changes on + # compiler and/or library. Here we are adding a dummy commit on compiler and running + # that test to make sure we never download CI rustc with a change on the compiler tree. + echo "" >> ../compiler/rustc/src/main.rs + git config --global user.email "dummy@dummy.com" + git config --global user.name "dummy" + git add ../compiler/rustc/src/main.rs + git commit -m "test commit for rust.download-rustc=if-unchanged logic" + DISABLE_CI_RUSTC_IF_INCOMPATIBLE=0 ../x.py test bootstrap \ + -- core::builder::tests::ci_rustc_if_unchanged_logic + # Revert the dummy commit + git reset --hard HEAD~1 +fi + # Only run the stage 1 tests on merges, not on PR CI jobs. if [[ -z "${PR_CI_JOB}" ]]; then ../x.py --stage 1 test --skip src/tools/tidy diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 6379f1ade1c..8f49f623afa 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -92,6 +92,8 @@ pr: - image: x86_64-gnu-llvm-18 env: ENABLE_GCC_CODEGEN: "1" + # We are adding (temporarily) a dummy commit on the compiler + READ_ONLY_SRC: "0" <<: *job-linux-16c - image: x86_64-gnu-tools <<: *job-linux-16c @@ -259,6 +261,7 @@ auto: - image: x86_64-gnu-llvm-18 env: RUST_BACKTRACE: 1 + READ_ONLY_SRC: "0" <<: *job-linux-8c - image: x86_64-gnu-nopt diff --git a/src/ci/run.sh b/src/ci/run.sh index c8201d9bcfd..3962c354c10 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -52,6 +52,13 @@ if [ "$CI" != "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set change-id=99999999" fi +# If runner uses an incompatible option and `FORCE_CI_RUSTC` is not defined, +# switch to in-tree rustc. +if [ "$FORCE_CI_RUSTC" == "" ]; then + echo 'debug: `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` configured.' + DISABLE_CI_RUSTC_IF_INCOMPATIBLE=1 +fi + if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf || \ isCiBranch automation/bors/try; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests" @@ -169,10 +176,16 @@ else if [ "$NO_DOWNLOAD_CI_LLVM" = "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.download-ci-llvm=if-unchanged" else + # CI rustc requires CI LLVM to be enabled (see https://github.com/rust-lang/rust/issues/123586). + NO_DOWNLOAD_CI_RUSTC=1 # When building for CI we want to use the static C++ Standard library # included with LLVM, since a dynamic libstdcpp may not be available. RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.static-libstdcpp" fi + + if [ "$NO_DOWNLOAD_CI_RUSTC" = "" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.download-rustc=if-unchanged" + fi fi if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then diff --git a/src/ci/scripts/setup-upstream-remote.sh b/src/ci/scripts/setup-upstream-remote.sh new file mode 100755 index 00000000000..52b4c98a890 --- /dev/null +++ b/src/ci/scripts/setup-upstream-remote.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# In CI environments, bootstrap is forced to use the remote upstream based +# on "git_repository" and "nightly_branch" values from src/stage0 file. +# This script configures the remote as it may not exist by default. + +set -euo pipefail +IFS=$'\n\t' + +ci_dir=$(cd $(dirname $0) && pwd)/.. +source "$ci_dir/shared.sh" + +git_repository=$(parse_stage0_file_by_key "git_repository") +nightly_branch=$(parse_stage0_file_by_key "nightly_branch") + +# Configure "rust-lang/rust" upstream remote only when it's not origin. +if [ -z "$(git config remote.origin.url | grep $git_repository)" ]; then + echo "Configuring https://github.com/$git_repository remote as upstream." + git remote add upstream "https://github.com/$git_repository" + REMOTE_NAME="upstream" +else + REMOTE_NAME="origin" +fi + +git fetch $REMOTE_NAME $nightly_branch diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 2b0a10e4d08..1e6a008a5de 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -136,3 +136,15 @@ function releaseChannel { echo $RUST_CI_OVERRIDE_RELEASE_CHANNEL fi } + +# Parse values from src/stage0 file by key +function parse_stage0_file_by_key { + local key="$1" + local file="$ci_dir/../stage0" + local value=$(awk -F= '{a[$1]=$2} END {print(a["'$key'"])}' $file) + if [ -z "$value" ]; then + echo "ERROR: Key '$key' not found in '$file'." + exit 1 + fi + echo "$value" +} diff --git a/src/doc/book b/src/doc/book -Subproject 99cf75a5414fa8adbe3974bd0836661ca901708 +Subproject f38ce8baef98cb20229e56f1be2d50e345f1179 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject dbae36bf3f8410aa4313b3bad42e374735d48a9 +Subproject f40a8b420ec4b4505d9489965e261f1d5c28ba2 diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 14649f15d232d509478206ee9ed5105641aa60d +Subproject 456b904f791751892b01282fd2757904993c4c2 diff --git a/src/doc/reference b/src/doc/reference -Subproject 24fb2687cdbc54fa18ae4acf5d879cfceca77b2 +Subproject c64e52a3d306eac0129f3ad6c6d8806ab99ae2e diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject c79ec345f08a1e94494cdc8c999709a90203fd8 +Subproject 8bede1b919a81ab7d0c961f6bbf68d3efa297bd diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 555f3de2fa0d61c4294b74d245f1cbad6fcbf58 +Subproject 07bc9ca9eb1cd6d9fbbf758c2753b748804a134 diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 207eb5d6d4f..0ef95ba64a1 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -388,6 +388,7 @@ target | std | host | notes [`x86_64-unknown-hermit`](platform-support/hermit.md) | ✓ | | x86_64 Hermit `x86_64-unknown-l4re-uclibc` | ? | | [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD +[`x86_64-unknown-trusty`](platform-support/trusty.md) | ? | | `x86_64-uwp-windows-gnu` | ✓ | | `x86_64-uwp-windows-msvc` | ✓ | | [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 64-bit Windows 7 support @@ -412,5 +413,8 @@ target | std | host | notes [`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 32bit with NuttX [`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX [`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX +[`riscv32e-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32E ISA) +[`riscv32em-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EM ISA) +[`riscv32emc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EMC ISA) [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md index e72bfb8bae7..32e4f855313 100644 --- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md +++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md @@ -80,7 +80,7 @@ cd hello_world ```sh CARGO_TARGET_CSKY_UNKNOWN_LINUX_GNUABIV2_RUNNER=${QEMU_PATH}/bin/qemu-cskyv2 -L ${TOOLCHAIN_PATH}/csky-linux-gnuabiv2/libc \ CARGO_TARGET_CSKY_UNKNOWN_LINUX_GNUABIV2_LINKER=${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc \ -RUSTFLAGS="-C target-features=+crt-static" \ +RUSTFLAGS="-C target-feature=+crt-static" \ cargo +stage2 run --target csky-unknown-linux-gnuabiv2 ``` diff --git a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md index 9a27a568b57..38742143c4b 100644 --- a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md @@ -35,4 +35,4 @@ Rust test-suite on this target. ## Cross-compilation toolchains and C code This target supports C code. If interlinking with C or C++, you may need to use -`riscv64-unknown-elf-gcc` as a linker instead of `rust-lld`. +`riscv32-unknown-elf-gcc` as a linker instead of `rust-lld`. diff --git a/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md new file mode 100644 index 00000000000..69f08774f83 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md @@ -0,0 +1,30 @@ +# `riscv32{e,em,emc}-unknown-none-elf` + +**Tier: 3** + +Bare-metal target for RISC-V CPUs with the RV32E, RV32EM and RV32EMC ISAs. + +## Target maintainers + +* Henri Lunnikivi, <henri.lunnikivi@gmail.com>, [@hegza](https://github.com/hegza) + +## Requirements + +The target is cross-compiled, and uses static linking. No external toolchain is +required and the default `rust-lld` linker works, but you must specify a linker +script. + +## Building the target + +This target is included in Rust and can be installed via `rustup`. + +## Testing + +This is a cross-compiled `no-std` target, which must be run either in a +simulator or by programming them onto suitable hardware. It is not possible to +run the Rust test-suite on this target. + +## Cross-compilation toolchains and C code + +This target supports C code. If interlinking with C or C++, you may need to use +`riscv32-unknown-elf-gcc` as a linker instead of `rust-lld`. diff --git a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md new file mode 100644 index 00000000000..ad795ff9d9b --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md @@ -0,0 +1,22 @@ +# `cfg_boolean_literals` + +The tracking issue for this feature is: [#131204] + +[#131204]: https://github.com/rust-lang/rust/issues/131204 + +------------------------ + +The `cfg_boolean_literals` feature makes it possible to use the `true`/`false` +literal as cfg predicate. They always evaluate to true/false respectively. + +## Examples + +```rust +#![feature(cfg_boolean_literals)] + +#[cfg(true)] +const A: i32 = 5; + +#[cfg(all(false))] +const A: i32 = 58 * 89; +``` diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 2aa0d9f69cc..ba7f2c9fb5d 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -2741,7 +2741,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --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 --error-format --json-output --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 --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --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 --error-format --json-output --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 --help [<PROFILE>|hook|editor|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el index e55d80d98de..7b4309f8e18 100644 --- a/src/etc/rust_analyzer_eglot.el +++ b/src/etc/rust_analyzer_eglot.el @@ -2,28 +2,28 @@ .((eglot-workspace-configuration . (:rust-analyzer ( :check ( :invocationLocation "root" - :invocationStrategy "once" - :overrideCommand ["python3" - "x.py" - "check" - "--json-output"]) - :linkedProjects ["Cargo.toml" - "src/tools/x/Cargo.toml" - "src/bootstrap/Cargo.toml" - "src/tools/rust-analyzer/Cargo.toml" - "compiler/rustc_codegen_cranelift/Cargo.toml" - "compiler/rustc_codegen_gcc/Cargo.toml"] - :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" - "--edition=2021"]) - :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" - :enable t) - :cargo ( :buildScripts ( :enable t - :invocationLocation "root" - :invocationStrategy "once" - :overrideCommand ["python3" - "x.py" - "check" - "--json-output"]) - :sysrootSrc "./library" - :extraEnv (:RUSTC_BOOTSTRAP "1")) - :rustc ( :source "./Cargo.toml" ))))))) + :invocationStrategy "once" + :overrideCommand ["python3" + "x.py" + "check" + "--json-output"]) + :linkedProjects ["Cargo.toml" + "src/tools/x/Cargo.toml" + "src/bootstrap/Cargo.toml" + "src/tools/rust-analyzer/Cargo.toml" + "compiler/rustc_codegen_cranelift/Cargo.toml" + "compiler/rustc_codegen_gcc/Cargo.toml"] + :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" + "--edition=2021"]) + :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + :enable t) + :cargo ( :buildScripts ( :enable t + :invocationLocation "root" + :invocationStrategy "once" + :overrideCommand ["python3" + "x.py" + "check" + "--json-output"]) + :sysrootSrc "./library" + :extraEnv (:RUSTC_BOOTSTRAP "1")) + :rustc ( :source "./Cargo.toml" ))))))) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 26739219085..9255242611a 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -6,7 +6,7 @@ use std::fmt::{self, Write}; use std::{mem, ops}; -use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem}; +use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::FxHashSet; use rustc_feature::Features; use rustc_session::parse::ParseSess; @@ -41,14 +41,18 @@ pub(crate) struct InvalidCfgError { } impl Cfg { - /// Parses a `NestedMetaItem` into a `Cfg`. + /// Parses a `MetaItemInner` into a `Cfg`. fn parse_nested( - nested_cfg: &NestedMetaItem, + nested_cfg: &MetaItemInner, exclude: &FxHashSet<Cfg>, ) -> Result<Option<Cfg>, InvalidCfgError> { match nested_cfg { - NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), - NestedMetaItem::Lit(ref lit) => { + MetaItemInner::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), + MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b { + true => Ok(Some(Cfg::True)), + false => Ok(Some(Cfg::False)), + }, + MetaItemInner::Lit(ref lit) => { Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) } } @@ -120,8 +124,8 @@ impl Cfg { /// /// If the content is not properly formatted, it will return an error indicating what and where /// the error is. - pub(crate) fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> { - Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) + pub(crate) fn parse(cfg: &MetaItemInner) -> Result<Cfg, InvalidCfgError> { + Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) } /// Checks whether the given configuration can be matched in the current session. diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 0ab655103e2..2c62e12c96d 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,4 +1,5 @@ -use rustc_ast::{MetaItemLit, Path, Safety, StrStyle}; +use rustc_ast::ast::LitIntType; +use rustc_ast::{MetaItemInner, MetaItemLit, Path, Safety, StrStyle}; use rustc_span::symbol::{Ident, kw}; use rustc_span::{DUMMY_SP, create_default_session_globals_then}; use thin_vec::thin_vec; @@ -13,52 +14,52 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg { Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value))) } -fn dummy_meta_item_word(name: &str) -> MetaItem { - MetaItem { +fn dummy_lit(symbol: Symbol, kind: LitKind) -> MetaItemInner { + MetaItemInner::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }) +} + +fn dummy_meta_item_word(name: &str) -> MetaItemInner { + MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(name)), kind: MetaItemKind::Word, span: DUMMY_SP, - } + }) } -fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem { +fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItemInner { let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }; - MetaItem { + MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(name)), kind: MetaItemKind::NameValue(lit), span: DUMMY_SP, - } + }) } macro_rules! dummy_meta_item_list { ($name:ident, [$($list:ident),* $(,)?]) => { - MetaItem { + MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(stringify!($name))), kind: MetaItemKind::List(thin_vec![ $( - NestedMetaItem::MetaItem( - dummy_meta_item_word(stringify!($list)), - ), + dummy_meta_item_word(stringify!($list)), )* ]), span: DUMMY_SP, - } + }) }; ($name:ident, [$($list:expr),* $(,)?]) => { - MetaItem { + MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(stringify!($name))), kind: MetaItemKind::List(thin_vec![ - $( - NestedMetaItem::MetaItem($list), - )* + $($list,)* ]), span: DUMMY_SP, - } + }) }; } @@ -251,6 +252,14 @@ fn test_cfg_or() { #[test] fn test_parse_ok() { create_default_session_globals_then(|| { + let r#true = Symbol::intern("true"); + let mi = dummy_lit(r#true, LitKind::Bool(true)); + assert_eq!(Cfg::parse(&mi), Ok(Cfg::True)); + + let r#false = Symbol::intern("false"); + let mi = dummy_lit(r#false, LitKind::Bool(false)); + assert_eq!(Cfg::parse(&mi), Ok(Cfg::False)); + let mi = dummy_meta_item_word("all"); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); @@ -309,6 +318,14 @@ fn test_parse_err() { let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]); assert!(Cfg::parse(&mi).is_err()); + + let c = Symbol::intern("e"); + let mi = dummy_lit(c, LitKind::Char('e')); + assert!(Cfg::parse(&mi).is_err()); + + let five = Symbol::intern("5"); + let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed)); + assert!(Cfg::parse(&mi).is_err()); }) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b79458eaa78..fa73733360c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1828,13 +1828,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T Array(Box::new(clean_ty(ty, cx)), length.into()) } TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()), - TyKind::OpaqueDef(item_id, _) => { - let item = cx.tcx.hir().item(item_id); - if let hir::ItemKind::OpaqueTy(ty) = item.kind { - ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) - } else { - unreachable!() - } + TyKind::OpaqueDef(ty, _) => { + ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) } TyKind::Path(_) => clean_qpath(ty, cx), TyKind::TraitObject(bounds, lifetime, _) => { @@ -2736,9 +2731,6 @@ fn clean_maybe_renamed_item<'tcx>( type_: clean_ty(ty, cx), kind: ConstantKind::Local { body: body_id, def_id }, })), - // clean_ty changes types which reference an OpaqueTy item to instead be - // an ImplTrait, so it's ok to return nothing here. - ItemKind::OpaqueTy(_) => return vec![], ItemKind::TyAlias(hir_ty, generics) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; let rustdoc_ty = clean_ty(hir_ty, cx); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a3277e8ca92..bc5bf4c0583 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -5,10 +5,11 @@ use std::sync::{Arc, OnceLock as OnceCell}; use std::{fmt, iter}; use arrayvec::ArrayVec; +use rustc_ast::MetaItemInner; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; use rustc_const_eval::const_eval::is_unstable_const_fn; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -113,7 +114,7 @@ impl From<DefId> for ItemId { pub(crate) struct Crate { pub(crate) module: Item, /// Only here so that they can be filtered through the rustdoc passes. - pub(crate) external_traits: Box<FxHashMap<DefId, Trait>>, + pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>, } impl Crate { @@ -952,7 +953,7 @@ pub(crate) struct Module { } pub(crate) trait AttributesExt { - type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem> + type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner> where Self: 'a; type Attributes<'a>: Iterator<Item = &'a ast::Attribute> @@ -986,7 +987,7 @@ pub(crate) trait AttributesExt { .peekable(); if doc_cfg.peek().is_some() && doc_cfg_active { doc_cfg - .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .filter_map(|attr| Cfg::parse(&attr).ok()) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else if doc_auto_cfg_active { // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because @@ -1042,7 +1043,7 @@ pub(crate) trait AttributesExt { let mut meta = attr.meta_item().unwrap().clone(); meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); - if let Ok(feat_cfg) = Cfg::parse(&meta) { + if let Ok(feat_cfg) = Cfg::parse(&MetaItemInner::MetaItem(meta)) { cfg &= feat_cfg; } } @@ -1054,7 +1055,7 @@ pub(crate) trait AttributesExt { } impl AttributesExt for [ast::Attribute] { - type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a; + type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a; type Attributes<'a> = impl Iterator<Item = &'a ast::Attribute> + 'a; fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { @@ -1071,7 +1072,7 @@ impl AttributesExt for [ast::Attribute] { impl AttributesExt for [(Cow<'_, ast::Attribute>, Option<DefId>)] { type AttributeIterator<'a> - = impl Iterator<Item = ast::NestedMetaItem> + 'a + = impl Iterator<Item = ast::MetaItemInner> + 'a where Self: 'a; type Attributes<'a> @@ -1105,11 +1106,11 @@ pub(crate) trait NestedAttributesExt { /// Returns `Some(attr)` if the attribute list contains 'attr' /// corresponding to a specific `word` - fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>; + fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>; } -impl<I: Iterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I { - fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> { +impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I { + fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> { self.find(|attr| attr.is_word() && attr.has_name(word)) } } @@ -1156,7 +1157,7 @@ pub(crate) struct Attributes { } impl Attributes { - pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::NestedMetaItem> + '_ { + pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> + '_ { self.other_attrs.lists(name) } @@ -1222,7 +1223,7 @@ impl Attributes { } pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> { - let mut aliases = FxHashSet::default(); + let mut aliases = FxIndexSet::default(); for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { if let Some(values) = attr.meta_item_list() { @@ -1758,7 +1759,7 @@ pub(crate) enum PrimitiveType { Never, } -type SimplifiedTypes = FxHashMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>; +type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>; impl PrimitiveType { pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType { use ast::{FloatTy, IntTy, UintTy}; @@ -1926,10 +1927,10 @@ impl PrimitiveType { /// In particular, if a crate depends on both `std` and another crate that also defines /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked. /// (no_std crates are usually fine unless multiple dependencies define a primitive.) - pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> { - static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new(); + pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> { + static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new(); PRIMITIVE_LOCATIONS.get_or_init(|| { - let mut primitive_locations = FxHashMap::default(); + let mut primitive_locations = FxIndexMap::default(); // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate. // This is a degenerate case that I don't plan to support. for &crate_num in tcx.crates(()) { @@ -2459,7 +2460,7 @@ pub(crate) struct Impl { } impl Impl { - pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> { + pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> { self.trait_ .as_ref() .map(|t| t.def_id()) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 7a37f5c70a5..2cd69474b1c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{fmt, io}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::DiagCtxtHandle; use rustc_session::config::{ self, CodegenOptions, CrateType, ErrorOutputType, Externs, Input, JsonUnusedExterns, @@ -249,7 +249,7 @@ pub(crate) struct RenderOptions { pub(crate) extern_html_root_takes_precedence: bool, /// A map of the default settings (values are as for DOM storage API). Keys should lack the /// `rustdoc-` prefix. - pub(crate) default_settings: FxHashMap<String, String>, + pub(crate) default_settings: FxIndexMap<String, String>, /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages. pub(crate) resource_suffix: String, /// Whether to create an index page in the root of the output directory. If this is true but diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 4c48c075a94..aaf4c80f997 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -2,7 +2,7 @@ use std::sync::atomic::AtomicBool; use std::sync::{Arc, LazyLock}; use std::{io, mem}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; @@ -39,7 +39,7 @@ pub(crate) struct DocContext<'tcx> { /// Most of this logic is copied from rustc_lint::late. pub(crate) param_env: ParamEnv<'tcx>, /// Later on moved through `clean::Crate` into `cache` - pub(crate) external_traits: FxHashMap<DefId, clean::Trait>, + pub(crate) external_traits: FxIndexMap<DefId, clean::Trait>, /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. pub(crate) active_extern_traits: DefIdSet, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 4e7571a4803..d5bc2a93fa8 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -14,7 +14,7 @@ use std::{panic, str}; pub(crate) use make::DocTestBuilder; pub(crate) use markdown::test as test_markdown; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_errors::{ColorConfig, DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LOCAL_CRATE; @@ -213,12 +213,13 @@ pub(crate) fn run( let unused_extern_reports: Vec<_> = std::mem::take(&mut unused_extern_reports.lock().unwrap()); if unused_extern_reports.len() == compiling_test_count { - let extern_names = externs.iter().map(|(name, _)| name).collect::<FxHashSet<&String>>(); + let extern_names = + externs.iter().map(|(name, _)| name).collect::<FxIndexSet<&String>>(); let mut unused_extern_names = unused_extern_reports .iter() - .map(|uexts| uexts.unused_extern_names.iter().collect::<FxHashSet<&String>>()) + .map(|uexts| uexts.unused_extern_names.iter().collect::<FxIndexSet<&String>>()) .fold(extern_names, |uextsa, uextsb| { - uextsa.intersection(&uextsb).copied().collect::<FxHashSet<&String>>() + uextsa.intersection(&uextsb).copied().collect::<FxIndexSet<&String>>() }) .iter() .map(|v| (*v).clone()) @@ -253,7 +254,7 @@ pub(crate) fn run_tests( rustdoc_options: &Arc<RustdocOptions>, unused_extern_reports: &Arc<Mutex<Vec<UnusedExterns>>>, mut standalone_tests: Vec<test::TestDescAndFn>, - mergeable_tests: FxHashMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>, + mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>, ) { let mut test_args = Vec::with_capacity(rustdoc_options.test_args.len() + 1); test_args.insert(0, "rustdoctest".to_string()); @@ -775,7 +776,7 @@ pub(crate) trait DocTestVisitor { struct CreateRunnableDocTests { standalone_tests: Vec<test::TestDescAndFn>, - mergeable_tests: FxHashMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>, + mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>, rustdoc_options: Arc<RustdocOptions>, opts: GlobalTestOptions, @@ -790,7 +791,7 @@ impl CreateRunnableDocTests { let can_merge_doctests = rustdoc_options.edition >= Edition::Edition2024; CreateRunnableDocTests { standalone_tests: Vec::new(), - mergeable_tests: FxHashMap::default(), + mergeable_tests: FxIndexMap::default(), rustdoc_options: Arc::new(rustdoc_options), opts, visited_tests: FxHashMap::default(), diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 326ca4ee1e6..942ec8d9936 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -1,6 +1,6 @@ use std::fmt::Write; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_span::edition::Edition; use crate::doctest::{ @@ -11,7 +11,7 @@ use crate::html::markdown::{Ignore, LangString}; /// Convenient type to merge compatible doctests into one. pub(crate) struct DocTestRunner { - crate_attrs: FxHashSet<String>, + crate_attrs: FxIndexSet<String>, ids: String, output: String, supports_color: bool, @@ -21,7 +21,7 @@ pub(crate) struct DocTestRunner { impl DocTestRunner { pub(crate) fn new() -> Self { Self { - crate_attrs: FxHashSet::default(), + crate_attrs: FxIndexSet::default(), ids: String::new(), output: String::new(), supports_color: true, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index db1a0bd0af9..ff0d537b19f 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; @@ -42,7 +42,7 @@ pub(crate) struct Cache { /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information /// necessary. - pub(crate) paths: FxHashMap<DefId, (Vec<Symbol>, ItemType)>, + pub(crate) paths: FxIndexMap<DefId, (Vec<Symbol>, ItemType)>, /// Similar to `paths`, but only holds external paths. This is only used for /// generating explicit hyperlinks to other crates. @@ -64,18 +64,18 @@ pub(crate) struct Cache { /// Implementations of a crate should inherit the documentation of the /// parent trait if no extra documentation is specified, and default methods /// should show up in documentation about trait implementations. - pub(crate) traits: FxHashMap<DefId, clean::Trait>, + pub(crate) traits: FxIndexMap<DefId, clean::Trait>, /// When rendering traits, it's often useful to be able to list all /// implementors of the trait, and this mapping is exactly, that: a mapping /// of trait ids to the list of known implementors of the trait - pub(crate) implementors: FxHashMap<DefId, Vec<Impl>>, + pub(crate) implementors: FxIndexMap<DefId, Vec<Impl>>, /// Cache of where external crate documentation can be found. - pub(crate) extern_locations: FxHashMap<CrateNum, ExternalLocation>, + pub(crate) extern_locations: FxIndexMap<CrateNum, ExternalLocation>, /// Cache of where documentation for primitives can be found. - pub(crate) primitive_locations: FxHashMap<clean::PrimitiveType, DefId>, + pub(crate) primitive_locations: FxIndexMap<clean::PrimitiveType, DefId>, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -118,7 +118,7 @@ pub(crate) struct Cache { // crawl. In order to prevent crashes when looking for notable traits or // when gathering trait documentation on a type, hold impls here while // folding and add them to the cache later on if we find the trait. - orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>, + orphan_trait_impls: Vec<(DefId, FxIndexSet<DefId>, Impl)>, /// All intra-doc links resolved so far. /// @@ -376,7 +376,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { // Figure out the id of this impl. This may map to a // primitive rather than always to a struct/enum. // Note: matching twice to restrict the lifetime of the `i` borrow. - let mut dids = FxHashSet::default(); + let mut dids = FxIndexSet::default(); match i.for_ { clean::Type::Path { ref path } | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => { diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs index 691f86847b5..31a2701f06a 100644 --- a/src/librustdoc/html/escape.rs +++ b/src/librustdoc/html/escape.rs @@ -108,7 +108,17 @@ impl<'a> fmt::Display for EscapeBodyTextWithWbr<'a> { || pk.map_or(true, |(_, t)| t.chars().any(|c| c.is_uppercase())); let next_is_underscore = || pk.map_or(true, |(_, t)| t.contains('_')); let next_is_colon = || pk.map_or(true, |(_, t)| t.contains(':')); - if i - last > 3 && is_uppercase() && !next_is_uppercase() { + // Check for CamelCase. + // + // `i - last > 3` avoids turning FmRadio into Fm<wbr>Radio, which is technically + // correct, but needlessly bloated. + // + // is_uppercase && !next_is_uppercase checks for camelCase. HTTPSProxy, + // for example, should become HTTPS<wbr>Proxy. + // + // !next_is_underscore avoids turning TEST_RUN into TEST<wbr>_<wbr>RUN, which is also + // needlessly bloated. + if i - last > 3 && is_uppercase() && !next_is_uppercase() && !next_is_underscore() { EscapeBodyText(&text[last..i]).fmt(fmt)?; fmt.write_str("<wbr>")?; last = i; diff --git a/src/librustdoc/html/escape/tests.rs b/src/librustdoc/html/escape/tests.rs index a09649e9e18..de702e16063 100644 --- a/src/librustdoc/html/escape/tests.rs +++ b/src/librustdoc/html/escape/tests.rs @@ -24,6 +24,10 @@ fn escape_body_text_with_wbr() { assert_eq!(&E("first:second").to_string(), "first:<wbr>second"); assert_eq!(&E("first::second").to_string(), "first::<wbr>second"); assert_eq!(&E("MY_CONSTANT").to_string(), "MY_<wbr>CONSTANT"); + assert_eq!( + &E("_SIDD_MASKED_NEGATIVE_POLARITY").to_string(), + "_SIDD_<wbr>MASKED_<wbr>NEGATIVE_<wbr>POLARITY" + ); // a string won't get wrapped if it's less than 8 bytes assert_eq!(&E("HashSet").to_string(), "HashSet"); // an individual word won't get wrapped if it's less than 4 bytes diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 69b3421f888..b68b7295096 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -8,7 +8,7 @@ use std::collections::VecDeque; use std::fmt::{Display, Write}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_lexer::{Cursor, LiteralKind, TokenKind}; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; @@ -34,7 +34,7 @@ pub(crate) struct HrefContext<'a, 'tcx> { /// Decorations are represented as a map from CSS class to vector of character ranges. /// Each range will be wrapped in a span with that class. #[derive(Default)] -pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>); +pub(crate) struct DecorationInfo(pub(crate) FxIndexMap<&'static str, Vec<(u32, u32)>>); #[derive(Eq, PartialEq, Clone, Copy)] pub(crate) enum Tooltip { @@ -845,6 +845,7 @@ impl<'src> Classifier<'src> { // Number literals. LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number, }, + TokenKind::GuardedStrPrefix => return no_highlight(sink), TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => { self.in_macro = true; sink(Highlight::EnterSpan { class: Class::Macro(self.new_span(before, text)) }); diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 75328e724fe..fd5275189d6 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,5 +1,5 @@ use expect_test::expect_file; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_span::create_default_session_globals_then; use super::{DecorationInfo, write_code}; @@ -73,7 +73,7 @@ fn test_decorations() { let y = 2; let z = 3; let a = 4;"; - let mut decorations = FxHashMap::default(); + let mut decorations = FxIndexMap::default(); decorations.insert("example", vec![(0, 10), (11, 21)]); decorations.insert("example2", vec![(22, 32)]); diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 3684dc42ac7..31ccfeb3873 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use rinja::Template; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use super::static_files::{STATIC_FILES, StaticFiles}; use crate::externalfiles::ExternalHtml; @@ -13,7 +13,7 @@ pub(crate) struct Layout { pub(crate) logo: String, pub(crate) favicon: String, pub(crate) external_html: ExternalHtml, - pub(crate) default_settings: FxHashMap<String, String>, + pub(crate) default_settings: FxIndexMap<String, String>, pub(crate) krate: String, pub(crate) krate_version: String, /// The given user css file which allow to customize the generated diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8ae5484feda..5dacabd031e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -35,10 +35,9 @@ use std::str::{self, CharIndices}; use std::sync::OnceLock; use pulldown_cmark::{ - BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, - Parser, Tag, TagEnd, html, + BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, TagEnd, html, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Diag, DiagMessage}; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::TyCtxt; @@ -651,12 +650,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> { /// references. struct Footnotes<'a, I> { inner: I, - footnotes: FxHashMap<String, (Vec<Event<'a>>, u16)>, + footnotes: FxIndexMap<String, (Vec<Event<'a>>, u16)>, } impl<'a, I> Footnotes<'a, I> { fn new(iter: I) -> Self { - Footnotes { inner: iter, footnotes: FxHashMap::default() } + Footnotes { inner: iter, footnotes: FxIndexMap::default() } } fn get_entry(&mut self, key: &str) -> &mut (Vec<Event<'a>>, u16) { @@ -694,7 +693,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> { Some(e) => return Some(e), None => { if !self.footnotes.is_empty() { - let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect(); + let mut v: Vec<_> = self.footnotes.drain(..).map(|(_, x)| x).collect(); v.sort_by(|a, b| a.1.cmp(&b.1)); let mut ret = String::from("<div class=\"footnotes\"><hr><ol>"); for (mut content, id) in v { @@ -1686,7 +1685,6 @@ pub(crate) fn html_text_from_events<'a>( pub(crate) struct MarkdownLink { pub kind: LinkType, pub link: String, - pub display_text: Option<String>, pub range: MarkdownLinkRange, } @@ -1848,23 +1846,9 @@ pub(crate) fn markdown_links<'md, R>( LinkType::Autolink | LinkType::Email => unreachable!(), }; - let display_text = if matches!( - link_type, - LinkType::Inline - | LinkType::ReferenceUnknown - | LinkType::Reference - | LinkType::Shortcut - | LinkType::ShortcutUnknown - ) { - collect_link_data(&mut event_iter) - } else { - None - }; - if let Some(link) = preprocess_link(MarkdownLink { kind: link_type, link: dest_url.into_string(), - display_text, range, }) { links.push(link); @@ -1877,37 +1861,6 @@ pub(crate) fn markdown_links<'md, R>( links } -/// Collects additional data of link. -fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( - event_iter: &mut OffsetIter<'input, F>, -) -> Option<String> { - let mut display_text: Option<String> = None; - let mut append_text = |text: CowStr<'_>| { - if let Some(display_text) = &mut display_text { - display_text.push_str(&text); - } else { - display_text = Some(text.to_string()); - } - }; - - while let Some((event, _span)) = event_iter.next() { - match event { - Event::Text(text) => { - append_text(text); - } - Event::Code(code) => { - append_text(code); - } - Event::End(_) => { - break; - } - _ => {} - } - } - - display_text -} - #[derive(Debug)] pub(crate) struct RustCodeBlock { /// The range in the markdown that the code block occupies. Note that this includes the fences diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index bce3f218908..dc4d45e592e 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use std::sync::mpsc::{Receiver, channel}; use rinja::Template; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -69,16 +69,16 @@ pub(crate) struct Context<'tcx> { /// `true`. pub(crate) include_sources: bool, /// Collection of all types with notable traits referenced in the current module. - pub(crate) types_with_notable_traits: FxHashSet<clean::Type>, + pub(crate) types_with_notable_traits: FxIndexSet<clean::Type>, /// Field used during rendering, to know if we're inside an inlined item. pub(crate) is_inside_inlined_module: bool, } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. #[cfg(all(not(windows), target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 160); +rustc_data_structures::static_assert_size!(Context<'_>, 184); #[cfg(all(windows, target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 168); +rustc_data_structures::static_assert_size!(Context<'_>, 192); /// Shared mutable state used in [`Context`] and elsewhere. pub(crate) struct SharedContext<'tcx> { @@ -90,7 +90,7 @@ pub(crate) struct SharedContext<'tcx> { /// creation of the context (contains info like the favicon and added html). pub(crate) layout: layout::Layout, /// The local file sources we've emitted and their respective url-paths. - pub(crate) local_sources: FxHashMap<PathBuf, String>, + pub(crate) local_sources: FxIndexMap<PathBuf, String>, /// Show the memory layout of types in the docs. pub(super) show_type_layout: bool, /// The base-URL of the issue tracker for when an item has been tagged with @@ -567,7 +567,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { deref_id_map: Default::default(), shared: Rc::new(scx), include_sources, - types_with_notable_traits: FxHashSet::default(), + types_with_notable_traits: FxIndexSet::default(), is_inside_inlined_module: false, }; @@ -591,7 +591,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { id_map: IdMap::new(), shared: Rc::clone(&self.shared), include_sources: self.include_sources, - types_with_notable_traits: FxHashSet::default(), + types_with_notable_traits: FxIndexSet::default(), is_inside_inlined_module: self.is_inside_inlined_module, } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 227df0c5f39..399730a01c8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -47,7 +47,7 @@ use std::{fs, str}; use rinja::Template; use rustc_attr::{ConstStability, DeprecatedSince, Deprecation, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::Mutability; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::print::PrintTraitRefExt; @@ -328,24 +328,24 @@ impl Ord for ItemEntry { #[derive(Debug)] struct AllTypes { - structs: FxHashSet<ItemEntry>, - enums: FxHashSet<ItemEntry>, - unions: FxHashSet<ItemEntry>, - primitives: FxHashSet<ItemEntry>, - traits: FxHashSet<ItemEntry>, - macros: FxHashSet<ItemEntry>, - functions: FxHashSet<ItemEntry>, - type_aliases: FxHashSet<ItemEntry>, - statics: FxHashSet<ItemEntry>, - constants: FxHashSet<ItemEntry>, - attribute_macros: FxHashSet<ItemEntry>, - derive_macros: FxHashSet<ItemEntry>, - trait_aliases: FxHashSet<ItemEntry>, + structs: FxIndexSet<ItemEntry>, + enums: FxIndexSet<ItemEntry>, + unions: FxIndexSet<ItemEntry>, + primitives: FxIndexSet<ItemEntry>, + traits: FxIndexSet<ItemEntry>, + macros: FxIndexSet<ItemEntry>, + functions: FxIndexSet<ItemEntry>, + type_aliases: FxIndexSet<ItemEntry>, + statics: FxIndexSet<ItemEntry>, + constants: FxIndexSet<ItemEntry>, + attribute_macros: FxIndexSet<ItemEntry>, + derive_macros: FxIndexSet<ItemEntry>, + trait_aliases: FxIndexSet<ItemEntry>, } impl AllTypes { fn new() -> AllTypes { - let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default()); + let new_set = |cap| FxIndexSet::with_capacity_and_hasher(cap, Default::default()); AllTypes { structs: new_set(100), enums: new_set(100), @@ -437,7 +437,7 @@ impl AllTypes { } fn print(self, f: &mut Buffer) { - fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, kind: ItemSection) { + fn print_entries(f: &mut Buffer, e: &FxIndexSet<ItemEntry>, kind: ItemSection) { if !e.is_empty() { let mut e: Vec<&ItemEntry> = e.iter().collect(); e.sort(); @@ -1151,7 +1151,7 @@ fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Con #[derive(Copy, Clone)] enum AssocItemLink<'a> { Anchor(Option<&'a str>), - GotoSource(ItemId, &'a FxHashSet<Symbol>), + GotoSource(ItemId, &'a FxIndexSet<Symbol>), } impl<'a> AssocItemLink<'a> { @@ -1494,7 +1494,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { for it in &impl_.items { if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind { out.push_str("<div class=\"where\"> "); - let empty_set = FxHashSet::default(); + let empty_set = FxIndexSet::default(); let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set); assoc_type( &mut out, @@ -2526,7 +2526,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c })() .unwrap_or(DUMMY_SP); - let mut decoration_info = FxHashMap::default(); + let mut decoration_info = FxIndexMap::default(); decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]); decoration_info.insert("highlight", byte_ranges); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 38276e4d20c..3c96f873681 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use itertools::Itertools; use rinja::Template; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; @@ -932,7 +932,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let cloned_shared = Rc::clone(&cx.shared); let cache = &cloned_shared.cache; - let mut extern_crates = FxHashSet::default(); + let mut extern_crates = FxIndexSet::default(); if !t.is_object_safe(cx.tcx()) { write_section_heading( diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 660ca3b2594..c958458b662 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -774,7 +774,7 @@ pub(crate) fn get_function_type_for_search<'tcx>( fn get_index_type( clean_type: &clean::Type, generics: Vec<RenderType>, - rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>, + rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>, ) -> RenderType { RenderType { id: get_index_type_id(clean_type, rgen), @@ -785,7 +785,7 @@ fn get_index_type( fn get_index_type_id( clean_type: &clean::Type, - rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>, + rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>, ) -> Option<RenderTypeId> { use rustc_hir::def::{DefKind, Res}; match *clean_type { @@ -854,7 +854,7 @@ fn simplify_fn_type<'a, 'tcx>( tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec<RenderType>, - rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>, + rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>, is_return: bool, cache: &Cache, ) { @@ -1198,7 +1198,7 @@ fn simplify_fn_constraint<'a, 'tcx>( tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec<(RenderTypeId, Vec<RenderType>)>, - rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>, + rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>, is_return: bool, cache: &Cache, ) { @@ -1285,7 +1285,7 @@ fn get_fn_inputs_and_outputs<'tcx>( ) -> (Vec<RenderType>, Vec<RenderType>, Vec<Vec<RenderType>>) { let decl = &func.decl; - let mut rgen: FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default(); + let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default(); let combined_generics; let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics { diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 2143f1ff236..b314b060368 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; @@ -44,7 +44,7 @@ pub(crate) fn collect_spans_and_sources( src_root: &Path, include_sources: bool, generate_link_to_definition: bool, -) -> (FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) { +) -> (FxIndexMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) { let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; if include_sources { @@ -243,7 +243,6 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { | ItemKind::ExternCrate(_) | ItemKind::ForeignMod { .. } | ItemKind::GlobalAsm(_) - | ItemKind::OpaqueTy(_) // We already have "visit_mod" above so no need to check it here. | ItemKind::Mod(_) => {} } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index af94b1042c0..12b63460056 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -28,7 +28,7 @@ use indexmap::IndexMap; use itertools::Itertools; use regex::Regex; use rustc_data_structures::flock; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_span::Symbol; @@ -505,8 +505,8 @@ createSrcSidebar();", struct Hierarchy { parent: Weak<Self>, elem: OsString, - children: RefCell<FxHashMap<OsString, Rc<Self>>>, - elems: RefCell<FxHashSet<OsString>>, + children: RefCell<FxIndexMap<OsString, Rc<Self>>>, + elems: RefCell<FxIndexSet<OsString>>, } impl Hierarchy { @@ -961,8 +961,8 @@ impl Serialize for AliasSerializableImpl { fn get_path_parts<T: CciPart>( dst: &Path, crates_info: &[CrateInfo], -) -> FxHashMap<PathBuf, Vec<String>> { - let mut templates: FxHashMap<PathBuf, Vec<String>> = FxHashMap::default(); +) -> FxIndexMap<PathBuf, Vec<String>> { + let mut templates: FxIndexMap<PathBuf, Vec<String>> = FxIndexMap::default(); crates_info .iter() .map(|crate_info| T::from_crate_info(crate_info).parts.iter()) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 7be9cc0b885..f4a0ef01c25 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use std::{fmt, fs}; use rinja::Template; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -39,15 +39,15 @@ pub(crate) fn collect_local_sources<'tcx>( tcx: TyCtxt<'tcx>, src_root: &Path, krate: &clean::Crate, -) -> FxHashMap<PathBuf, String> { - let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root }; +) -> FxIndexMap<PathBuf, String> { + let mut lsc = LocalSourcesCollector { tcx, local_sources: FxIndexMap::default(), src_root }; lsc.visit_crate(krate); lsc.local_sources } struct LocalSourcesCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, - local_sources: FxHashMap<PathBuf, String>, + local_sources: FxIndexMap<PathBuf, String>, src_root: &'a Path, } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index beac7e73c62..df9776ff5f8 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -230,6 +230,9 @@ h4.code-header { padding: 0; white-space: pre-wrap; } +.structfield { + margin: 0.6em 0; +} #crate-search, h1, h2, h3, h4, h5, h6, @@ -961,10 +964,13 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { } .docblock li { - margin-bottom: .8em; + margin-bottom: .4em; } -.docblock li p { - margin-bottom: .1em; +.docblock li p:not(:last-child) { + /* This margin is voluntarily smaller than `.docblock li` to keep the visual + list element items separated while also having a visual separation (although + smaller) for paragraphs. */ + margin-bottom: .3em; } /* "where ..." clauses with block display are also smaller */ @@ -2432,7 +2438,7 @@ in src-script.js and main.js } /* Position of the "[-]" element. */ - details.toggle:not(.top-doc) > summary { + details.toggle:not(.top-doc) > summary, .impl-items > section { margin-left: 10px; } .impl-items > details.toggle > summary:not(.hideme)::before, diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index b411f9a1a52..b8791c9918b 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -4,20 +4,17 @@ #![allow(rustc::default_hash_types)] -use std::fmt; - use rustc_ast::ast; use rustc_attr::DeprecatedSince; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::DefId; use rustc_metadata::rendered_const; -use rustc_middle::bug; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::symbol::sym; -use rustc_span::{Pos, Symbol}; +use rustc_middle::{bug, ty}; +use rustc_span::{Pos, Symbol, sym}; use rustc_target::spec::abi::Abi as RustcAbi; use rustdoc_json_types::*; +use super::FullItemId; use crate::clean::{self, ItemId}; use crate::formats::FormatRenderer; use crate::formats::item_type::ItemType; @@ -40,7 +37,7 @@ impl JsonRenderer<'_> { Some(UrlFragment::UserWritten(_)) | None => *page_id, }; - (String::from(&**link), id_from_item_default(id.into(), self.tcx)) + (String::from(&**link), self.id_from_item_default(id.into())) }) .collect(); let docs = item.opt_doc_value(); @@ -48,7 +45,7 @@ impl JsonRenderer<'_> { let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::Item { name, item_id, .. } = item; - let id = id_from_item(&item, self.tcx); + let id = self.id_from_item(&item); let inner = match item.kind { clean::KeywordItem => return None, clean::StrippedItem(ref inner) => { @@ -59,12 +56,12 @@ impl JsonRenderer<'_> { clean::ModuleItem(_) if self.imported_items.contains(&item_id.expect_def_id()) => { - from_clean_item(item, self.tcx) + from_clean_item(item, self) } _ => return None, } } - _ => from_clean_item(item, self.tcx), + _ => from_clean_item(item, self), }; Some(Item { id, @@ -105,37 +102,116 @@ impl JsonRenderer<'_> { Some(ty::Visibility::Public) => Visibility::Public, Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate, Some(ty::Visibility::Restricted(did)) => Visibility::Restricted { - parent: id_from_item_default(did.into(), self.tcx), + parent: self.id_from_item_default(did.into()), path: self.tcx.def_path(did).to_string_no_crate_verbose(), }, } } + + pub(crate) fn id_from_item_default(&self, item_id: ItemId) -> Id { + self.id_from_item_inner(item_id, None, None) + } + + pub(crate) fn id_from_item_inner( + &self, + item_id: ItemId, + name: Option<Symbol>, + extra: Option<Id>, + ) -> Id { + let make_part = |def_id: DefId, name: Option<Symbol>, extra: Option<Id>| { + let name = match name { + Some(name) => Some(name), + None => { + // We need this workaround because primitive types' DefId actually refers to + // their parent module, which isn't present in the output JSON items. So + // instead, we directly get the primitive symbol + if matches!(self.tcx.def_kind(def_id), DefKind::Mod) + && let Some(prim) = self + .tcx + .get_attrs(def_id, sym::rustc_doc_primitive) + .find_map(|attr| attr.value_str()) + { + Some(prim) + } else { + self.tcx.opt_item_name(def_id) + } + } + }; + + FullItemId { def_id, name, extra } + }; + + let key = match item_id { + ItemId::DefId(did) => (make_part(did, name, extra), None), + ItemId::Blanket { for_, impl_id } => { + (make_part(impl_id, None, None), Some(make_part(for_, name, extra))) + } + ItemId::Auto { for_, trait_ } => { + (make_part(trait_, None, None), Some(make_part(for_, name, extra))) + } + }; + + let mut interner = self.id_interner.borrow_mut(); + let len = interner.len(); + *interner + .entry(key) + .or_insert_with(|| Id(len.try_into().expect("too many items in a crate"))) + } + + pub(crate) fn id_from_item(&self, item: &clean::Item) -> Id { + match item.kind { + clean::ItemKind::ImportItem(ref import) => { + let extra = + import.source.did.map(ItemId::from).map(|i| self.id_from_item_default(i)); + self.id_from_item_inner(item.item_id, item.name, extra) + } + _ => self.id_from_item_inner(item.item_id, item.name, None), + } + } + + fn ids(&self, items: impl IntoIterator<Item = clean::Item>) -> Vec<Id> { + items + .into_iter() + .filter(|x| !x.is_stripped() && !x.is_keyword()) + .map(|i| self.id_from_item(&i)) + .collect() + } + + fn ids_keeping_stripped( + &self, + items: impl IntoIterator<Item = clean::Item>, + ) -> Vec<Option<Id>> { + items + .into_iter() + .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(&i))) + .collect() + } } -pub(crate) trait FromWithTcx<T> { - fn from_tcx(f: T, tcx: TyCtxt<'_>) -> Self; +pub(crate) trait FromClean<T> { + fn from_clean(f: T, renderer: &JsonRenderer<'_>) -> Self; } -pub(crate) trait IntoWithTcx<T> { - fn into_tcx(self, tcx: TyCtxt<'_>) -> T; +pub(crate) trait IntoJson<T> { + fn into_json(self, renderer: &JsonRenderer<'_>) -> T; } -impl<T, U> IntoWithTcx<U> for T +impl<T, U> IntoJson<U> for T where - U: FromWithTcx<T>, + U: FromClean<T>, { - fn into_tcx(self, tcx: TyCtxt<'_>) -> U { - U::from_tcx(self, tcx) + fn into_json(self, renderer: &JsonRenderer<'_>) -> U { + U::from_clean(self, renderer) } } -impl<I, T, U> FromWithTcx<I> for Vec<U> +impl<I, T, U> FromClean<I> for Vec<U> where I: IntoIterator<Item = T>, - U: FromWithTcx<T>, + U: FromClean<T>, { - fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec<U> { - f.into_iter().map(|x| x.into_tcx(tcx)).collect() + fn from_clean(f: I, renderer: &JsonRenderer<'_>) -> Vec<U> { + f.into_iter().map(|x| x.into_json(renderer)).collect() } } @@ -150,37 +226,38 @@ pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecat Deprecation { since, note: note.map(|s| s.to_string()) } } -impl FromWithTcx<clean::GenericArgs> for GenericArgs { - fn from_tcx(args: clean::GenericArgs, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::GenericArgs> for GenericArgs { + fn from_clean(args: clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericArgs::*; match args { AngleBracketed { args, constraints } => GenericArgs::AngleBracketed { - args: args.into_vec().into_tcx(tcx), - constraints: constraints.into_tcx(tcx), + args: args.into_vec().into_json(renderer), + constraints: constraints.into_json(renderer), }, Parenthesized { inputs, output } => GenericArgs::Parenthesized { - inputs: inputs.into_vec().into_tcx(tcx), - output: output.map(|a| (*a).into_tcx(tcx)), + inputs: inputs.into_vec().into_json(renderer), + output: output.map(|a| (*a).into_json(renderer)), }, } } } -impl FromWithTcx<clean::GenericArg> for GenericArg { - fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::GenericArg> for GenericArg { + fn from_clean(arg: clean::GenericArg, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericArg::*; match arg { Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)), - Type(t) => GenericArg::Type(t.into_tcx(tcx)), - Const(box c) => GenericArg::Const(c.into_tcx(tcx)), + Type(t) => GenericArg::Type(t.into_json(renderer)), + Const(box c) => GenericArg::Const(c.into_json(renderer)), Infer => GenericArg::Infer, } } } -impl FromWithTcx<clean::Constant> for Constant { +impl FromClean<clean::Constant> for Constant { // FIXME(generic_const_items): Add support for generic const items. - fn from_tcx(constant: clean::Constant, tcx: TyCtxt<'_>) -> Self { + fn from_clean(constant: clean::Constant, renderer: &JsonRenderer<'_>) -> Self { + let tcx = renderer.tcx; let expr = constant.expr(tcx); let value = constant.value(tcx); let is_literal = constant.is_literal(tcx); @@ -188,9 +265,10 @@ impl FromWithTcx<clean::Constant> for Constant { } } -impl FromWithTcx<clean::ConstantKind> for Constant { +impl FromClean<clean::ConstantKind> for Constant { // FIXME(generic_const_items): Add support for generic const items. - fn from_tcx(constant: clean::ConstantKind, tcx: TyCtxt<'_>) -> Self { + fn from_clean(constant: clean::ConstantKind, renderer: &JsonRenderer<'_>) -> Self { + let tcx = renderer.tcx; let expr = constant.expr(tcx); let value = constant.value(tcx); let is_literal = constant.is_literal(tcx); @@ -198,147 +276,62 @@ impl FromWithTcx<clean::ConstantKind> for Constant { } } -impl FromWithTcx<clean::AssocItemConstraint> for AssocItemConstraint { - fn from_tcx(constraint: clean::AssocItemConstraint, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::AssocItemConstraint> for AssocItemConstraint { + fn from_clean(constraint: clean::AssocItemConstraint, renderer: &JsonRenderer<'_>) -> Self { AssocItemConstraint { name: constraint.assoc.name.to_string(), - args: constraint.assoc.args.into_tcx(tcx), - binding: constraint.kind.into_tcx(tcx), + args: constraint.assoc.args.into_json(renderer), + binding: constraint.kind.into_json(renderer), } } } -impl FromWithTcx<clean::AssocItemConstraintKind> for AssocItemConstraintKind { - fn from_tcx(kind: clean::AssocItemConstraintKind, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::AssocItemConstraintKind> for AssocItemConstraintKind { + fn from_clean(kind: clean::AssocItemConstraintKind, renderer: &JsonRenderer<'_>) -> Self { use clean::AssocItemConstraintKind::*; match kind { - Equality { term } => AssocItemConstraintKind::Equality(term.into_tcx(tcx)), - Bound { bounds } => AssocItemConstraintKind::Constraint(bounds.into_tcx(tcx)), - } - } -} - -#[inline] -pub(crate) fn id_from_item_default(item_id: ItemId, tcx: TyCtxt<'_>) -> Id { - id_from_item_inner(item_id, tcx, None, None) -} - -/// It generates an ID as follows: -/// -/// `CRATE_ID:ITEM_ID[:NAME_ID][-EXTRA]`: -/// * If there is no `name`, `NAME_ID` is not generated. -/// * If there is no `extra`, `EXTRA` is not generated. -/// -/// * `name` is the item's name if available (it's not for impl blocks for example). -/// * `extra` is used for reexports: it contains the ID of the reexported item. It is used to allow -/// to have items with the same name but different types to both appear in the generated JSON. -pub(crate) fn id_from_item_inner( - item_id: ItemId, - tcx: TyCtxt<'_>, - name: Option<Symbol>, - extra: Option<&Id>, -) -> Id { - struct DisplayDefId<'a, 'b>(DefId, TyCtxt<'a>, Option<&'b Id>, Option<Symbol>); - - impl<'a, 'b> fmt::Display for DisplayDefId<'a, 'b> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let DisplayDefId(def_id, tcx, extra, name) = self; - // We need this workaround because primitive types' DefId actually refers to - // their parent module, which isn't present in the output JSON items. So - // instead, we directly get the primitive symbol and convert it to u32 to - // generate the ID. - let s; - let extra = if let Some(e) = extra { - s = format!("-{}", e.0); - &s - } else { - "" - }; - let name = match name { - Some(name) => format!(":{}", name.as_u32()), - None => { - // We need this workaround because primitive types' DefId actually refers to - // their parent module, which isn't present in the output JSON items. So - // instead, we directly get the primitive symbol and convert it to u32 to - // generate the ID. - if matches!(tcx.def_kind(def_id), DefKind::Mod) - && let Some(prim) = tcx - .get_attrs(*def_id, sym::rustc_doc_primitive) - .find_map(|attr| attr.value_str()) - { - format!(":{}", prim.as_u32()) - } else { - tcx.opt_item_name(*def_id) - .map(|n| format!(":{}", n.as_u32())) - .unwrap_or_default() - } - } - }; - write!(f, "{}:{}{name}{extra}", def_id.krate.as_u32(), u32::from(def_id.index)) - } - } - - match item_id { - ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did, tcx, extra, name))), - ItemId::Blanket { for_, impl_id } => Id(format!( - "b:{}-{}", - DisplayDefId(impl_id, tcx, None, None), - DisplayDefId(for_, tcx, extra, name) - )), - ItemId::Auto { for_, trait_ } => Id(format!( - "a:{}-{}", - DisplayDefId(trait_, tcx, None, None), - DisplayDefId(for_, tcx, extra, name) - )), - } -} - -pub(crate) fn id_from_item(item: &clean::Item, tcx: TyCtxt<'_>) -> Id { - match item.kind { - clean::ItemKind::ImportItem(ref import) => { - let extra = - import.source.did.map(ItemId::from).map(|i| id_from_item_inner(i, tcx, None, None)); - id_from_item_inner(item.item_id, tcx, item.name, extra.as_ref()) + Equality { term } => AssocItemConstraintKind::Equality(term.into_json(renderer)), + Bound { bounds } => AssocItemConstraintKind::Constraint(bounds.into_json(renderer)), } - _ => id_from_item_inner(item.item_id, tcx, item.name, None), } } -fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { +fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum { use clean::ItemKind::*; let name = item.name; let is_crate = item.is_crate(); - let header = item.fn_header(tcx); + let header = item.fn_header(renderer.tcx); match item.inner.kind { ModuleItem(m) => { - ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx), is_stripped: false }) - } - ImportItem(i) => ItemEnum::Use(i.into_tcx(tcx)), - StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)), - UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)), - StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)), - EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)), - VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)), - FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), tcx)), + ItemEnum::Module(Module { is_crate, items: renderer.ids(m.items), is_stripped: false }) + } + ImportItem(i) => ItemEnum::Use(i.into_json(renderer)), + StructItem(s) => ItemEnum::Struct(s.into_json(renderer)), + UnionItem(u) => ItemEnum::Union(u.into_json(renderer)), + StructFieldItem(f) => ItemEnum::StructField(f.into_json(renderer)), + EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)), + VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)), + FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), renderer)), ForeignFunctionItem(f, _) => { - ItemEnum::Function(from_function(f, false, header.unwrap(), tcx)) - } - TraitItem(t) => ItemEnum::Trait((*t).into_tcx(tcx)), - TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), - MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), tcx)), - TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), tcx)), - ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)), - StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), - ForeignStaticItem(s, _) => ItemEnum::Static(s.into_tcx(tcx)), + ItemEnum::Function(from_function(f, false, header.unwrap(), renderer)) + } + TraitItem(t) => ItemEnum::Trait((*t).into_json(renderer)), + TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)), + MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)), + TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), renderer)), + ImplItem(i) => ItemEnum::Impl((*i).into_json(renderer)), + StaticItem(s) => ItemEnum::Static(s.into_json(renderer)), + ForeignStaticItem(s, _) => ItemEnum::Static(s.into_json(renderer)), ForeignTypeItem => ItemEnum::ExternType, - TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)), + TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_json(renderer)), // FIXME(generic_const_items): Add support for generic free consts - ConstantItem(ci) => { - ItemEnum::Constant { type_: ci.type_.into_tcx(tcx), const_: ci.kind.into_tcx(tcx) } - } + ConstantItem(ci) => ItemEnum::Constant { + type_: ci.type_.into_json(renderer), + const_: ci.kind.into_json(renderer), + }, MacroItem(m) => ItemEnum::Macro(m.source), - ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)), + ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_json(renderer)), PrimitiveItem(p) => { ItemEnum::Primitive(Primitive { name: p.as_sym().to_string(), @@ -347,19 +340,22 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { } // FIXME(generic_const_items): Add support for generic associated consts. TyAssocConstItem(_generics, ty) => { - ItemEnum::AssocConst { type_: (*ty).into_tcx(tcx), value: None } + ItemEnum::AssocConst { type_: (*ty).into_json(renderer), value: None } } // FIXME(generic_const_items): Add support for generic associated consts. - AssocConstItem(ci) => { - ItemEnum::AssocConst { type_: ci.type_.into_tcx(tcx), value: Some(ci.kind.expr(tcx)) } - } - TyAssocTypeItem(g, b) => { - ItemEnum::AssocType { generics: g.into_tcx(tcx), bounds: b.into_tcx(tcx), type_: None } - } + AssocConstItem(ci) => ItemEnum::AssocConst { + type_: ci.type_.into_json(renderer), + value: Some(ci.kind.expr(renderer.tcx)), + }, + TyAssocTypeItem(g, b) => ItemEnum::AssocType { + generics: g.into_json(renderer), + bounds: b.into_json(renderer), + type_: None, + }, AssocTypeItem(t, b) => ItemEnum::AssocType { - generics: t.generics.into_tcx(tcx), - bounds: b.into_tcx(tcx), - type_: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)), + generics: t.generics.into_json(renderer), + bounds: b.into_json(renderer), + type_: Some(t.item_type.unwrap_or(t.type_).into_json(renderer)), }, // `convert_item` early returns `None` for stripped items and keywords. KeywordItem => unreachable!(), @@ -367,7 +363,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { match *inner { ModuleItem(m) => ItemEnum::Module(Module { is_crate, - items: ids(m.items, tcx), + items: renderer.ids(m.items), is_stripped: true, }), // `convert_item` early returns `None` for stripped items we're not including @@ -381,36 +377,36 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { } } -impl FromWithTcx<clean::Struct> for Struct { - fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Struct> for Struct { + fn from_clean(struct_: clean::Struct, renderer: &JsonRenderer<'_>) -> Self { let has_stripped_fields = struct_.has_stripped_entries(); let clean::Struct { ctor_kind, generics, fields } = struct_; let kind = match ctor_kind { - Some(CtorKind::Fn) => StructKind::Tuple(ids_keeping_stripped(fields, tcx)), + Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(fields)), Some(CtorKind::Const) => { assert!(fields.is_empty()); StructKind::Unit } - None => StructKind::Plain { fields: ids(fields, tcx), has_stripped_fields }, + None => StructKind::Plain { fields: renderer.ids(fields), has_stripped_fields }, }; Struct { kind, - generics: generics.into_tcx(tcx), + generics: generics.into_json(renderer), impls: Vec::new(), // Added in JsonRenderer::item } } } -impl FromWithTcx<clean::Union> for Union { - fn from_tcx(union_: clean::Union, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Union> for Union { + fn from_clean(union_: clean::Union, renderer: &JsonRenderer<'_>) -> Self { let has_stripped_fields = union_.has_stripped_entries(); let clean::Union { generics, fields } = union_; Union { - generics: generics.into_tcx(tcx), + generics: generics.into_json(renderer), has_stripped_fields, - fields: ids(fields, tcx), + fields: renderer.ids(fields), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -444,51 +440,51 @@ fn convert_lifetime(l: clean::Lifetime) -> String { l.0.to_string() } -impl FromWithTcx<clean::Generics> for Generics { - fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Generics> for Generics { + fn from_clean(generics: clean::Generics, renderer: &JsonRenderer<'_>) -> Self { Generics { - params: generics.params.into_tcx(tcx), - where_predicates: generics.where_predicates.into_tcx(tcx), + params: generics.params.into_json(renderer), + where_predicates: generics.where_predicates.into_json(renderer), } } } -impl FromWithTcx<clean::GenericParamDef> for GenericParamDef { - fn from_tcx(generic_param: clean::GenericParamDef, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::GenericParamDef> for GenericParamDef { + fn from_clean(generic_param: clean::GenericParamDef, renderer: &JsonRenderer<'_>) -> Self { GenericParamDef { name: generic_param.name.to_string(), - kind: generic_param.kind.into_tcx(tcx), + kind: generic_param.kind.into_json(renderer), } } } -impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind { - fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::GenericParamDefKind> for GenericParamDefKind { + fn from_clean(kind: clean::GenericParamDefKind, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericParamDefKind::*; match kind { Lifetime { outlives } => GenericParamDefKind::Lifetime { outlives: outlives.into_iter().map(convert_lifetime).collect(), }, Type { bounds, default, synthetic } => GenericParamDefKind::Type { - bounds: bounds.into_tcx(tcx), - default: default.map(|x| (*x).into_tcx(tcx)), + bounds: bounds.into_json(renderer), + default: default.map(|x| (*x).into_json(renderer)), is_synthetic: synthetic, }, Const { ty, default, synthetic: _ } => GenericParamDefKind::Const { - type_: (*ty).into_tcx(tcx), + type_: (*ty).into_json(renderer), default: default.map(|x| *x), }, } } } -impl FromWithTcx<clean::WherePredicate> for WherePredicate { - fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::WherePredicate> for WherePredicate { + fn from_clean(predicate: clean::WherePredicate, renderer: &JsonRenderer<'_>) -> Self { use clean::WherePredicate::*; match predicate { BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate { - type_: ty.into_tcx(tcx), - bounds: bounds.into_tcx(tcx), + type_: ty.into_json(renderer), + bounds: bounds.into_json(renderer), generic_params: bound_params .into_iter() .map(|x| { @@ -503,15 +499,15 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate { GenericParamDefKind::Type { bounds: bounds .into_iter() - .map(|bound| bound.into_tcx(tcx)) + .map(|bound| bound.into_json(renderer)) .collect(), - default: default.map(|ty| (*ty).into_tcx(tcx)), + default: default.map(|ty| (*ty).into_json(renderer)), is_synthetic: synthetic, } } clean::GenericParamDefKind::Const { ty, default, synthetic: _ } => { GenericParamDefKind::Const { - type_: (*ty).into_tcx(tcx), + type_: (*ty).into_json(renderer), default: default.map(|d| *d), } } @@ -530,21 +526,22 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate { }) .collect(), }, - EqPredicate { lhs, rhs } => { - WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) } - } + EqPredicate { lhs, rhs } => WherePredicate::EqPredicate { + lhs: lhs.into_json(renderer), + rhs: rhs.into_json(renderer), + }, } } } -impl FromWithTcx<clean::GenericBound> for GenericBound { - fn from_tcx(bound: clean::GenericBound, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::GenericBound> for GenericBound { + fn from_clean(bound: clean::GenericBound, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericBound::*; match bound { TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { GenericBound::TraitBound { - trait_: trait_.into_tcx(tcx), - generic_params: generic_params.into_tcx(tcx), + trait_: trait_.into_json(renderer), + generic_params: generic_params.into_json(renderer), modifier: from_trait_bound_modifier(modifier), } } @@ -572,73 +569,75 @@ pub(crate) fn from_trait_bound_modifier( } } -impl FromWithTcx<clean::Type> for Type { - fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Type> for Type { + fn from_clean(ty: clean::Type, renderer: &JsonRenderer<'_>) -> Self { use clean::Type::{ Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath, RawPointer, SelfTy, Slice, Tuple, }; match ty { - clean::Type::Path { path } => Type::ResolvedPath(path.into_tcx(tcx)), + clean::Type::Path { path } => Type::ResolvedPath(path.into_json(renderer)), clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { lifetime: lt.map(convert_lifetime), - traits: bounds.into_tcx(tcx), + traits: bounds.into_json(renderer), }), Generic(s) => Type::Generic(s.to_string()), // FIXME: add dedicated variant to json Type? SelfTy => Type::Generic("Self".to_owned()), Primitive(p) => Type::Primitive(p.as_sym().to_string()), - BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), - Tuple(t) => Type::Tuple(t.into_tcx(tcx)), - Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), - Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() }, + BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_json(renderer))), + Tuple(t) => Type::Tuple(t.into_json(renderer)), + Slice(t) => Type::Slice(Box::new((*t).into_json(renderer))), + Array(t, s) => { + Type::Array { type_: Box::new((*t).into_json(renderer)), len: s.to_string() } + } clean::Type::Pat(t, p) => Type::Pat { - type_: Box::new((*t).into_tcx(tcx)), + type_: Box::new((*t).into_json(renderer)), __pat_unstable_do_not_use: p.to_string(), }, - ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)), + ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)), Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { is_mutable: mutability == ast::Mutability::Mut, - type_: Box::new((*type_).into_tcx(tcx)), + type_: Box::new((*type_).into_json(renderer)), }, BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { lifetime: lifetime.map(convert_lifetime), is_mutable: mutability == ast::Mutability::Mut, - type_: Box::new((*type_).into_tcx(tcx)), + type_: Box::new((*type_).into_json(renderer)), }, QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath { name: assoc.name.to_string(), - args: Box::new(assoc.args.into_tcx(tcx)), - self_type: Box::new(self_type.into_tcx(tcx)), - trait_: trait_.map(|trait_| trait_.into_tcx(tcx)), + args: Box::new(assoc.args.into_json(renderer)), + self_type: Box::new(self_type.into_json(renderer)), + trait_: trait_.map(|trait_| trait_.into_json(renderer)), }, } } } -impl FromWithTcx<clean::Path> for Path { - fn from_tcx(path: clean::Path, tcx: TyCtxt<'_>) -> Path { +impl FromClean<clean::Path> for Path { + fn from_clean(path: clean::Path, renderer: &JsonRenderer<'_>) -> Path { Path { name: path.whole_name(), - id: id_from_item_default(path.def_id().into(), tcx), - args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), + id: renderer.id_from_item_default(path.def_id().into()), + args: path.segments.last().map(|args| Box::new(args.clone().args.into_json(renderer))), } } } -impl FromWithTcx<clean::Term> for Term { - fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term { +impl FromClean<clean::Term> for Term { + fn from_clean(term: clean::Term, renderer: &JsonRenderer<'_>) -> Term { match term { - clean::Term::Type(ty) => Term::Type(FromWithTcx::from_tcx(ty, tcx)), - clean::Term::Constant(c) => Term::Constant(FromWithTcx::from_tcx(c, tcx)), + clean::Term::Type(ty) => Term::Type(ty.into_json(renderer)), + clean::Term::Constant(c) => Term::Constant(c.into_json(renderer)), } } } -impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer { - fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::BareFunctionDecl> for FunctionPointer { + fn from_clean(bare_decl: clean::BareFunctionDecl, renderer: &JsonRenderer<'_>) -> Self { let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl; FunctionPointer { header: FunctionHeader { @@ -647,29 +646,30 @@ impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer { is_async: false, abi: convert_abi(abi), }, - generic_params: generic_params.into_tcx(tcx), - sig: decl.into_tcx(tcx), + generic_params: generic_params.into_json(renderer), + sig: decl.into_json(renderer), } } } -impl FromWithTcx<clean::FnDecl> for FunctionSignature { - fn from_tcx(decl: clean::FnDecl, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::FnDecl> for FunctionSignature { + fn from_clean(decl: clean::FnDecl, renderer: &JsonRenderer<'_>) -> Self { let clean::FnDecl { inputs, output, c_variadic } = decl; FunctionSignature { inputs: inputs .values .into_iter() - .map(|arg| (arg.name.to_string(), arg.type_.into_tcx(tcx))) + .map(|arg| (arg.name.to_string(), arg.type_.into_json(renderer))) .collect(), - output: if output.is_unit() { None } else { Some(output.into_tcx(tcx)) }, + output: if output.is_unit() { None } else { Some(output.into_json(renderer)) }, is_c_variadic: c_variadic, } } } -impl FromWithTcx<clean::Trait> for Trait { - fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Trait> for Trait { + fn from_clean(trait_: clean::Trait, renderer: &JsonRenderer<'_>) -> Self { + let tcx = renderer.tcx; let is_auto = trait_.is_auto(tcx); let is_unsafe = trait_.safety(tcx) == rustc_hir::Safety::Unsafe; let is_object_safe = trait_.is_object_safe(tcx); @@ -678,26 +678,29 @@ impl FromWithTcx<clean::Trait> for Trait { is_auto, is_unsafe, is_object_safe, - items: ids(items, tcx), - generics: generics.into_tcx(tcx), - bounds: bounds.into_tcx(tcx), + items: renderer.ids(items), + generics: generics.into_json(renderer), + bounds: bounds.into_json(renderer), implementations: Vec::new(), // Added in JsonRenderer::item } } } -impl FromWithTcx<clean::PolyTrait> for PolyTrait { - fn from_tcx( +impl FromClean<clean::PolyTrait> for PolyTrait { + fn from_clean( clean::PolyTrait { trait_, generic_params }: clean::PolyTrait, - tcx: TyCtxt<'_>, + renderer: &JsonRenderer<'_>, ) -> Self { - PolyTrait { trait_: trait_.into_tcx(tcx), generic_params: generic_params.into_tcx(tcx) } + PolyTrait { + trait_: trait_.into_json(renderer), + generic_params: generic_params.into_json(renderer), + } } } -impl FromWithTcx<clean::Impl> for Impl { - fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self { - let provided_trait_methods = impl_.provided_trait_methods(tcx); +impl FromClean<clean::Impl> for Impl { + fn from_clean(impl_: clean::Impl, renderer: &JsonRenderer<'_>) -> Self { + let provided_trait_methods = impl_.provided_trait_methods(renderer.tcx); let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_; // FIXME: use something like ImplKind in JSON? let (is_synthetic, blanket_impl) = match kind { @@ -711,17 +714,17 @@ impl FromWithTcx<clean::Impl> for Impl { }; Impl { is_unsafe: safety == rustc_hir::Safety::Unsafe, - generics: generics.into_tcx(tcx), + generics: generics.into_json(renderer), provided_trait_methods: provided_trait_methods .into_iter() .map(|x| x.to_string()) .collect(), - trait_: trait_.map(|path| path.into_tcx(tcx)), - for_: for_.into_tcx(tcx), - items: ids(items, tcx), + trait_: trait_.map(|path| path.into_json(renderer)), + for_: for_.into_json(renderer), + items: renderer.ids(items), is_negative, is_synthetic, - blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)), + blanket_impl: blanket_impl.map(|x| x.into_json(renderer)), } } } @@ -730,42 +733,42 @@ pub(crate) fn from_function( function: Box<clean::Function>, has_body: bool, header: rustc_hir::FnHeader, - tcx: TyCtxt<'_>, + renderer: &JsonRenderer<'_>, ) -> Function { let clean::Function { decl, generics } = *function; Function { - sig: decl.into_tcx(tcx), - generics: generics.into_tcx(tcx), + sig: decl.into_json(renderer), + generics: generics.into_json(renderer), header: from_fn_header(&header), has_body, } } -impl FromWithTcx<clean::Enum> for Enum { - fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Enum> for Enum { + fn from_clean(enum_: clean::Enum, renderer: &JsonRenderer<'_>) -> Self { let has_stripped_variants = enum_.has_stripped_entries(); let clean::Enum { variants, generics } = enum_; Enum { - generics: generics.into_tcx(tcx), + generics: generics.into_json(renderer), has_stripped_variants, - variants: ids(variants, tcx), + variants: renderer.ids(variants), impls: Vec::new(), // Added in JsonRenderer::item } } } -impl FromWithTcx<clean::Variant> for Variant { - fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Variant> for Variant { + fn from_clean(variant: clean::Variant, renderer: &JsonRenderer<'_>) -> Self { use clean::VariantKind::*; - let discriminant = variant.discriminant.map(|d| d.into_tcx(tcx)); + let discriminant = variant.discriminant.map(|d| d.into_json(renderer)); let kind = match variant.kind { CLike => VariantKind::Plain, - Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)), + Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(fields)), Struct(s) => VariantKind::Struct { has_stripped_fields: s.has_stripped_entries(), - fields: ids(s.fields, tcx), + fields: renderer.ids(s.fields), }, }; @@ -773,8 +776,9 @@ impl FromWithTcx<clean::Variant> for Variant { } } -impl FromWithTcx<clean::Discriminant> for Discriminant { - fn from_tcx(disr: clean::Discriminant, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Discriminant> for Discriminant { + fn from_clean(disr: clean::Discriminant, renderer: &JsonRenderer<'_>) -> Self { + let tcx = renderer.tcx; Discriminant { // expr is only none if going through the inlining path, which gets // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines @@ -785,8 +789,8 @@ impl FromWithTcx<clean::Discriminant> for Discriminant { } } -impl FromWithTcx<clean::Import> for Use { - fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Import> for Use { + fn from_clean(import: clean::Import, renderer: &JsonRenderer<'_>) -> Self { use clean::ImportKind::*; let (name, is_glob) = match import.kind { Simple(s) => (s.to_string(), false), @@ -798,14 +802,14 @@ impl FromWithTcx<clean::Import> for Use { Use { source: import.source.path.whole_name(), name, - id: import.source.did.map(ItemId::from).map(|i| id_from_item_default(i, tcx)), + id: import.source.did.map(ItemId::from).map(|i| renderer.id_from_item_default(i)), is_glob, } } } -impl FromWithTcx<clean::ProcMacro> for ProcMacro { - fn from_tcx(mac: clean::ProcMacro, _tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::ProcMacro> for ProcMacro { + fn from_clean(mac: clean::ProcMacro, _renderer: &JsonRenderer<'_>) -> Self { ProcMacro { kind: from_macro_kind(mac.kind), helpers: mac.helpers.iter().map(|x| x.to_string()).collect(), @@ -822,17 +826,18 @@ pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind } } -impl FromWithTcx<Box<clean::TypeAlias>> for TypeAlias { - fn from_tcx(type_alias: Box<clean::TypeAlias>, tcx: TyCtxt<'_>) -> Self { +impl FromClean<Box<clean::TypeAlias>> for TypeAlias { + fn from_clean(type_alias: Box<clean::TypeAlias>, renderer: &JsonRenderer<'_>) -> Self { let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = *type_alias; - TypeAlias { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) } + TypeAlias { type_: type_.into_json(renderer), generics: generics.into_json(renderer) } } } -impl FromWithTcx<clean::Static> for Static { - fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self { +impl FromClean<clean::Static> for Static { + fn from_clean(stat: clean::Static, renderer: &JsonRenderer<'_>) -> Self { + let tcx = renderer.tcx; Static { - type_: (*stat.type_).into_tcx(tcx), + type_: (*stat.type_).into_json(renderer), is_mutable: stat.mutability == ast::Mutability::Mut, expr: stat .expr @@ -842,14 +847,17 @@ impl FromWithTcx<clean::Static> for Static { } } -impl FromWithTcx<clean::TraitAlias> for TraitAlias { - fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self { - TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) } +impl FromClean<clean::TraitAlias> for TraitAlias { + fn from_clean(alias: clean::TraitAlias, renderer: &JsonRenderer<'_>) -> Self { + TraitAlias { + generics: alias.generics.into_json(renderer), + params: alias.bounds.into_json(renderer), + } } } -impl FromWithTcx<ItemType> for ItemKind { - fn from_tcx(kind: ItemType, _tcx: TyCtxt<'_>) -> Self { +impl FromClean<ItemType> for ItemKind { + fn from_clean(kind: ItemType, _renderer: &JsonRenderer<'_>) -> Self { use ItemType::*; match kind { Module => ItemKind::Module, @@ -878,25 +886,3 @@ impl FromWithTcx<ItemType> for ItemKind { } } } - -fn ids(items: impl IntoIterator<Item = clean::Item>, tcx: TyCtxt<'_>) -> Vec<Id> { - items - .into_iter() - .filter(|x| !x.is_stripped() && !x.is_keyword()) - .map(|i| id_from_item(&i, tcx)) - .collect() -} - -fn ids_keeping_stripped( - items: impl IntoIterator<Item = clean::Item>, - tcx: TyCtxt<'_>, -) -> Vec<Option<Id>> { - items - .into_iter() - .map( - |i| { - if !i.is_stripped() && !i.is_keyword() { Some(id_from_item(&i, tcx)) } else { None } - }, - ) - .collect() -} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index b7a683eed1c..df97c5ea263 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -16,6 +16,7 @@ use std::rc::Rc; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_span::Symbol; use rustc_span::def_id::LOCAL_CRATE; use rustdoc_json_types as types; // It's important to use the FxHashMap from rustdoc_json_types here, instead of @@ -31,9 +32,17 @@ use crate::docfs::PathError; use crate::error::Error; use crate::formats::FormatRenderer; use crate::formats::cache::Cache; -use crate::json::conversions::{IntoWithTcx, id_from_item, id_from_item_default}; +use crate::json::conversions::IntoJson; use crate::{clean, try_err}; +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +struct FullItemId { + def_id: DefId, + name: Option<Symbol>, + /// Used to distinguish imports of different items with the same name + extra: Option<types::Id>, +} + #[derive(Clone)] pub(crate) struct JsonRenderer<'tcx> { tcx: TyCtxt<'tcx>, @@ -46,6 +55,7 @@ pub(crate) struct JsonRenderer<'tcx> { out_dir: Option<PathBuf>, cache: Rc<Cache>, imported_items: DefIdSet, + id_interner: Rc<RefCell<FxHashMap<(FullItemId, Option<FullItemId>), types::Id>>>, } impl<'tcx> JsonRenderer<'tcx> { @@ -63,7 +73,7 @@ impl<'tcx> JsonRenderer<'tcx> { .map(|i| { let item = &i.impl_item; self.item(item.clone()).unwrap(); - id_from_item(&item, self.tcx) + self.id_from_item(&item) }) .collect() }) @@ -94,7 +104,7 @@ impl<'tcx> JsonRenderer<'tcx> { if item.item_id.is_local() || is_primitive_impl { self.item(item.clone()).unwrap(); - Some(id_from_item(&item, self.tcx)) + Some(self.id_from_item(&item)) } else { None } @@ -145,6 +155,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { out_dir: if options.output_to_stdout { None } else { Some(options.output) }, cache: Rc::new(cache), imported_items, + id_interner: Default::default(), }, krate, )) @@ -243,7 +254,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { debug!("Constructing Output"); let output_crate = types::Crate { - root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())), + root: self.id_from_item_default(e.def_id().into()), crate_version: self.cache.crate_version.clone(), includes_private: self.cache.document_private, index, @@ -253,10 +264,10 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { .iter() .chain(&self.cache.external_paths) .map(|(&k, &(ref path, kind))| { - (id_from_item_default(k.into(), self.tcx), types::ItemSummary { + (self.id_from_item_default(k.into()), types::ItemSummary { crate_id: k.krate.as_u32(), path: path.iter().map(|s| s.to_string()).collect(), - kind: kind.into_tcx(self.tcx), + kind: kind.into_json(self), }) }) .collect(), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2be415e2e0e..10fc0ea9990 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,6 @@ #![warn(rustc::internal)] #![allow(clippy::collapsible_if, clippy::collapsible_else_if)] #![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] extern crate thin_vec; @@ -99,7 +98,7 @@ use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL; /// Commas between elements are required (even if the expression is a block). macro_rules! map { ($( $key: expr => $val: expr ),* $(,)*) => {{ - let mut map = ::rustc_data_structures::fx::FxHashMap::default(); + let mut map = ::rustc_data_structures::fx::FxIndexMap::default(); $( map.insert($key, $val); )* map }} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0dba16cbaf3..db235786cf4 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -9,7 +9,7 @@ use std::ops::Range; use pulldown_cmark::LinkType; use rustc_ast::util::comments::may_have_doc_links; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, Diag, DiagMessage}; use rustc_hir::def::Namespace::*; @@ -778,9 +778,9 @@ fn trait_impls_for<'a>( cx: &mut DocContext<'a>, ty: Ty<'a>, module: DefId, -) -> FxHashSet<(DefId, DefId)> { +) -> FxIndexSet<(DefId, DefId)> { let tcx = cx.tcx; - let mut impls = FxHashSet::default(); + let mut impls = FxIndexSet::default(); for &trait_ in tcx.doc_link_traits_in_scope(module) { tcx.for_each_relevant_impl(trait_, ty, |impl_| { @@ -1040,21 +1040,6 @@ impl LinkCollector<'_, '_> { false, )?; - if ori_link.display_text.is_some() { - self.resolve_display_text( - path_str, - ResolutionInfo { - item_id, - module_id, - dis: disambiguator, - path_str: ori_link.display_text.clone()?.into_boxed_str(), - extra_fragment: extra_fragment.clone(), - }, - &ori_link, - &diag_info, - ); - } - // Check for a primitive which might conflict with a module // Report the ambiguity and require that the user specify which one they meant. // FIXME: could there ever be a primitive not in the type namespace? @@ -1088,7 +1073,7 @@ impl LinkCollector<'_, '_> { // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677 // for discussion on the matter. let kind = self.cx.tcx.def_kind(id); - self.verify_disambiguator(path_str, kind, id, disambiguator, item, &diag_info)?; + self.verify_disambiguator(path_str, kind, id, disambiguator, &diag_info)?; } else { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {} @@ -1117,7 +1102,6 @@ impl LinkCollector<'_, '_> { kind_for_dis, id_for_dis, disambiguator, - item, &diag_info, )?; @@ -1138,7 +1122,6 @@ impl LinkCollector<'_, '_> { kind: DefKind, id: DefId, disambiguator: Option<Disambiguator>, - item: &Item, diag_info: &DiagnosticInfo<'_>, ) -> Option<()> { debug!("intra-doc link to {path_str} resolved to {:?}", (kind, id)); @@ -1165,7 +1148,7 @@ impl LinkCollector<'_, '_> { // item can be non-local e.g. when using `#[rustc_doc_primitive = "pointer"]` if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| { - item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id)) + diag_info.item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id)) }) { if self.cx.tcx.effective_visibilities(()).is_exported(src_id) && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id) @@ -1398,58 +1381,6 @@ impl LinkCollector<'_, '_> { } } } - - /// Resolve display text if the provided link has separated parts of links. - /// - /// For example: - /// Inline link `[display_text](dest_link)` and reference link `[display_text][reference_link]` has - /// separated parts of links. - fn resolve_display_text( - &mut self, - explicit_link: &Box<str>, - display_res_info: ResolutionInfo, - ori_link: &MarkdownLink, - diag_info: &DiagnosticInfo<'_>, - ) { - // Check if explicit resolution's path is same as resolution of original link's display text path, see - // tests/rustdoc-ui/lint/redundant_explicit_links.rs for more cases. - // - // To avoid disambiguator from panicking, we check if display text path is possible to be disambiguated - // into explicit path. - if !matches!( - ori_link.kind, - LinkType::Inline | LinkType::Reference | LinkType::ReferenceUnknown - ) { - return; - } - - // Algorithm to check if display text could possibly be the explicit link: - // - // Consider 2 links which are display text and explicit link, pick the shorter - // one as symbol and longer one as full qualified path, and tries to match symbol - // to the full qualified path's last symbol. - // - // Otherwise, check if 2 links are same, if so, skip the resolve process. - // - // Notice that this algorithm is passive, might possibly miss actual redundant cases. - let explicit_link = explicit_link.to_string(); - let display_text = ori_link.display_text.as_ref().unwrap(); - - if display_text.len() == explicit_link.len() { - // Whether they are same or not, skip the resolve process. - return; - } - - if explicit_link.ends_with(&display_text[..]) || display_text.ends_with(&explicit_link[..]) - { - self.resolve_with_disambiguator_cached( - display_res_info, - diag_info.clone(), // this struct should really be Copy, but Range is not :( - false, - true, - ); - } - } } /// Get the section of a link between the backticks, @@ -1996,11 +1927,22 @@ fn resolution_failure( &diag_info, ); - format!( - "this link resolves to {}, which is not in the {} namespace", - item(res), - expected_ns.descr() - ) + if let Some(disambiguator) = disambiguator + && !matches!(disambiguator, Disambiguator::Namespace(..)) + { + format!( + "this link resolves to {}, which is not {} {}", + item(res), + disambiguator.article(), + disambiguator.descr() + ) + } else { + format!( + "this link resolves to {}, which is not in the {} namespace", + item(res), + expected_ns.descr() + ) + } } }; if let Some(span) = sp { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index b307e84e42e..d1a1f0df3e7 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -219,7 +219,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> panic!("collect-trait-impls can't run"); }; - krate.external_traits.extend(cx.external_traits.drain()); + krate.external_traits.extend(cx.external_traits.drain(..)); krate } diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 848e70a7bdb..e0dc5b4c513 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -145,7 +145,7 @@ struct BufferEmitter { } impl Translate for BufferEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> { + fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { None } @@ -169,7 +169,7 @@ impl Emitter for BufferEmitter { } } - fn source_map(&self) -> Option<&Lrc<SourceMap>> { + fn source_map(&self) -> Option<&SourceMap> { None } } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 9d4d203562c..a59c43bfbf9 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::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::DiagCtxtHandle; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir}; @@ -102,8 +102,8 @@ pub(crate) struct CallData { pub(crate) is_bin: bool, } -pub(crate) type FnCallLocations = FxHashMap<PathBuf, CallData>; -pub(crate) type AllCallLocations = FxHashMap<DefPathHash, FnCallLocations>; +pub(crate) type FnCallLocations = FxIndexMap<PathBuf, CallData>; +pub(crate) type AllCallLocations = FxIndexMap<DefPathHash, FnCallLocations>; /// Visitor for traversing a crate and finding instances of function calls. struct FindCalls<'a, 'tcx> { @@ -293,7 +293,7 @@ pub(crate) fn run( debug!("Scrape examples target_crates: {target_crates:?}"); // Run call-finder on all items - let mut calls = FxHashMap::default(); + let mut calls = FxIndexMap::default(); let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates, bin_crate }; tcx.hir().visit_all_item_likes_in_crate(&mut finder); @@ -332,7 +332,7 @@ pub(crate) fn load_call_locations( with_examples: Vec<String>, dcx: DiagCtxtHandle<'_>, ) -> AllCallLocations { - let mut all_calls: AllCallLocations = FxHashMap::default(); + let mut all_calls: AllCallLocations = FxIndexMap::default(); for path in with_examples { let bytes = match fs::read(&path) { Ok(bytes) => bytes, diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs index 409728a8e86..2c00bb7e132 100644 --- a/src/librustdoc/theme.rs +++ b/src/librustdoc/theme.rs @@ -1,10 +1,9 @@ -use std::collections::hash_map::Entry; use std::fs; use std::iter::Peekable; use std::path::Path; use std::str::Chars; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_errors::DiagCtxtHandle; #[cfg(test)] @@ -12,8 +11,8 @@ mod tests; #[derive(Debug)] pub(crate) struct CssPath { - pub(crate) rules: FxHashMap<String, String>, - pub(crate) children: FxHashMap<String, CssPath>, + pub(crate) rules: FxIndexMap<String, String>, + pub(crate) children: FxIndexMap<String, CssPath>, } /// When encountering a `"` or a `'`, returns the whole string, including the quote characters. @@ -120,10 +119,10 @@ fn parse_rules( content: &str, selector: String, iter: &mut Peekable<Chars<'_>>, - paths: &mut FxHashMap<String, CssPath>, + paths: &mut FxIndexMap<String, CssPath>, ) -> Result<(), String> { - let mut rules = FxHashMap::default(); - let mut children = FxHashMap::default(); + let mut rules = FxIndexMap::default(); + let mut children = FxIndexMap::default(); loop { // If the parent isn't a "normal" CSS selector, we only expect sub-selectors and not CSS @@ -146,10 +145,10 @@ fn parse_rules( return Err(format!("Found empty value for rule `{rule}` in selector `{selector}`")); } match rules.entry(rule) { - Entry::Occupied(mut o) => { + IndexEntry::Occupied(mut o) => { *o.get_mut() = value; } - Entry::Vacant(v) => { + IndexEntry::Vacant(v) => { v.insert(value); } } @@ -159,7 +158,7 @@ fn parse_rules( } match paths.entry(selector) { - Entry::Occupied(mut o) => { + IndexEntry::Occupied(mut o) => { let v = o.get_mut(); for (key, value) in rules.into_iter() { v.rules.insert(key, value); @@ -168,7 +167,7 @@ fn parse_rules( v.children.insert(sel, child); } } - Entry::Vacant(v) => { + IndexEntry::Vacant(v) => { v.insert(CssPath { rules, children }); } } @@ -178,7 +177,7 @@ fn parse_rules( pub(crate) fn parse_selectors( content: &str, iter: &mut Peekable<Chars<'_>>, - paths: &mut FxHashMap<String, CssPath>, + paths: &mut FxIndexMap<String, CssPath>, ) -> Result<(), String> { let mut selector = String::new(); @@ -202,17 +201,17 @@ pub(crate) fn parse_selectors( /// The entry point to parse the CSS rules. Every time we encounter a `{`, we then parse the rules /// inside it. -pub(crate) fn load_css_paths(content: &str) -> Result<FxHashMap<String, CssPath>, String> { +pub(crate) fn load_css_paths(content: &str) -> Result<FxIndexMap<String, CssPath>, String> { let mut iter = content.chars().peekable(); - let mut paths = FxHashMap::default(); + let mut paths = FxIndexMap::default(); parse_selectors(content, &mut iter, &mut paths)?; Ok(paths) } pub(crate) fn get_differences( - origin: &FxHashMap<String, CssPath>, - against: &FxHashMap<String, CssPath>, + origin: &FxIndexMap<String, CssPath>, + against: &FxIndexMap<String, CssPath>, v: &mut Vec<String>, ) { for (selector, entry) in origin.iter() { @@ -235,7 +234,7 @@ pub(crate) fn get_differences( pub(crate) fn test_theme_against<P: AsRef<Path>>( f: &P, - origin: &FxHashMap<String, CssPath>, + origin: &FxIndexMap<String, CssPath>, dcx: DiagCtxtHandle<'_>, ) -> (bool, Vec<String>) { let against = match fs::read_to_string(f) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c44e5ecaba8..f789aca7378 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -164,7 +164,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { .unwrap_or(&[]) .iter() .filter_map(|attr| { - Cfg::parse(attr.meta_item()?) + Cfg::parse(attr) .map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg)) .ok() }) @@ -505,21 +505,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::TyAlias(..) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { .. }, - .. - }) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => { self.add_to_current_mod(item, renamed, import_id); } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::FnReturn { .. }, - .. - }) => { - // return-position impl traits are never nameable, and should never be documented. - } hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. diff --git a/src/llvm-project b/src/llvm-project -Subproject 56997739365e8132cc817e00899480746c09d7d +Subproject 3a17f74904a74565c54cfac0d67026362d03869 diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index b3707cf6157..fc64bc98bb9 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 34; +pub const FORMAT_VERSION: u32 = 35; /// The root of the emitted JSON blob. /// @@ -296,9 +296,9 @@ pub enum AssocItemConstraintKind { /// Rustdoc makes no guarantees about the inner value of Id's. Applications /// should treat them as opaque keys to lookup items, and avoid attempting /// to parse them, or otherwise depend on any implementation details. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] // FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types. -pub struct Id(pub String); +pub struct Id(pub u32); /// The fundamental kind of an item. Unlike [`ItemEnum`], this does not carry any aditional info. /// @@ -677,7 +677,7 @@ pub struct FunctionHeader { /// on unwinding for more info. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Abi { - // We only have a concrete listing here for stable ABI's because their are so many + // 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 /// The default ABI, but that can also be written explicitly with `extern "Rust"`. Rust, diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index 10c5476cd8f..2aad5650fa8 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -1,6 +1,8 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use crate::ci::CiEnv; + pub struct GitConfig<'a> { pub git_repository: &'a str, pub nightly_branch: &'a str, @@ -114,8 +116,8 @@ fn git_upstream_merge_base( /// Searches for the nearest merge commit in the repository that also exists upstream. /// -/// If it fails to find the upstream remote, it then looks for the most recent commit made -/// by the merge bot by matching the author's email address with the merge bot's email. +/// It looks for the most recent commit made by the merge bot by matching the author's email +/// address with the merge bot's email. pub fn get_closest_merge_commit( git_dir: Option<&Path>, config: &GitConfig<'_>, @@ -127,7 +129,15 @@ pub fn get_closest_merge_commit( git.current_dir(git_dir); } - let merge_base = git_upstream_merge_base(config, git_dir).unwrap_or_else(|_| "HEAD".into()); + let merge_base = { + if CiEnv::is_ci() { + git_upstream_merge_base(config, git_dir).unwrap() + } else { + // For non-CI environments, ignore rust-lang/rust upstream as it usually gets + // outdated very quickly. + "HEAD".to_string() + } + }; git.args([ "rev-list", @@ -196,67 +206,3 @@ pub fn get_git_untracked_files( .collect(); Ok(Some(files)) } - -/// Print a warning if the branch returned from `updated_master_branch` is old -/// -/// For certain configurations of git repository, this remote will not be -/// updated when running `git pull`. -/// -/// This can result in formatting thousands of files instead of a dozen, -/// so we should warn the user something is wrong. -pub fn warn_old_master_branch(config: &GitConfig<'_>, git_dir: &Path) { - if crate::ci::CiEnv::is_ci() { - // this warning is useless in CI, - // and CI probably won't have the right branches anyway. - return; - } - // this will be overwritten by the actual name, if possible - let mut updated_master = "the upstream master branch".to_string(); - match warn_old_master_branch_(config, git_dir, &mut updated_master) { - Ok(branch_is_old) => { - if !branch_is_old { - return; - } - // otherwise fall through and print the rest of the warning - } - Err(err) => { - eprintln!("warning: unable to check if {updated_master} is old due to error: {err}") - } - } - eprintln!( - "warning: {updated_master} is used to determine if files have been modified\n\ - warning: if it is not updated, this may cause files to be needlessly reformatted" - ); -} - -pub fn warn_old_master_branch_( - config: &GitConfig<'_>, - git_dir: &Path, - updated_master: &mut String, -) -> Result<bool, Box<dyn std::error::Error>> { - use std::time::Duration; - *updated_master = updated_master_branch(config, Some(git_dir))?; - let branch_path = git_dir.join(".git/refs/remotes").join(&updated_master); - const WARN_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 10); - let meta = match std::fs::metadata(&branch_path) { - Ok(meta) => meta, - Err(err) => { - let gcd = git_common_dir(&git_dir)?; - if branch_path.starts_with(&gcd) { - return Err(Box::new(err)); - } - std::fs::metadata(Path::new(&gcd).join("refs/remotes").join(&updated_master))? - } - }; - if meta.modified()?.elapsed()? > WARN_AFTER { - eprintln!("warning: {updated_master} has not been updated in 10 days"); - Ok(true) - } else { - Ok(false) - } -} - -fn git_common_dir(dir: &Path) -> Result<String, String> { - output_result(Command::new("git").arg("-C").arg(dir).arg("rev-parse").arg("--git-common-dir")) - .map(|x| x.trim().to_string()) -} diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 80d82ca22abbee5fb7b51fa1abeb1ae34e99e88 +Subproject 15fbd2f607d4defc87053b8b76bf5038f2483cf diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 40959eccd3a..5d4e864b9b0 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -1,15 +1,15 @@ use super::{ALLOW_ATTRIBUTES_WITHOUT_REASON, Attribute}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use rustc_ast::{MetaItemKind, NestedMetaItem}; +use rustc_ast::{MetaItemInner, MetaItemKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::sym; use rustc_span::symbol::Symbol; -pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMetaItem], attr: &'cx Attribute) { +pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[MetaItemInner], attr: &'cx Attribute) { // Check if the reason is present - if let Some(item) = items.last().and_then(NestedMetaItem::meta_item) + if let Some(item) = items.last().and_then(MetaItemInner::meta_item) && let MetaItemKind::NameValue(_) = &item.kind && item.path == sym::reason { diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 508963a20ea..0baf889faa0 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -1,12 +1,12 @@ use super::BLANKET_CLIPPY_RESTRICTION_LINTS; use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_lint::{LateContext, Level, LintContext}; use rustc_span::symbol::Symbol; use rustc_span::{DUMMY_SP, sym}; -pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) { +pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[MetaItemInner]) { for lint in items { if let Some(lint_name) = extract_clippy_lint(lint) { if lint_name.as_str() == "restriction" && name != sym::allow { diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 888f28fa225..1a34ca99fc2 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -14,7 +14,7 @@ mod utils; use clippy_config::Conf; use clippy_config::msrvs::{self, Msrv}; -use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; +use rustc_ast::{Attribute, MetaItemInner, MetaItemKind}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -456,7 +456,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { return; } for item in items { - if let NestedMetaItem::MetaItem(mi) = &item + if let MetaItemInner::MetaItem(mi) = &item && let MetaItemKind::NameValue(lit) = &mi.kind && mi.has_name(sym::since) { diff --git a/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs index 877025cce4c..7eff5eccfa1 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -1,7 +1,7 @@ use super::{Attribute, NON_MINIMAL_CFG}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::SpanRangeExt; -use rustc_ast::{MetaItemKind, NestedMetaItem}; +use rustc_ast::{MetaItemInner, MetaItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; @@ -14,9 +14,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { } } -fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { +fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[MetaItemInner]) { for item in items { - if let NestedMetaItem::MetaItem(meta) = item { + if let MetaItemInner::MetaItem(meta) = item { if !meta.has_name(sym::any) && !meta.has_name(sym::all) { continue; } diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 12668c616c1..72e6ce59d59 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -2,7 +2,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::{Attribute, USELESS_ATTRIBUTE}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{SpanRangeExt, first_line_of_span}; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LintContext}; @@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) for lint in lint_list { match item.kind { ItemKind::Use(..) => { - if let NestedMetaItem::MetaItem(meta_item) = lint + if let MetaItemInner::MetaItem(meta_item) = lint && meta_item.is_word() && let Some(ident) = meta_item.ident() && matches!( diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index 91ae19acbf7..9b10ae83651 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::{is_panic, macro_backtrace}; -use rustc_ast::{AttrId, NestedMetaItem}; +use rustc_ast::{AttrId, MetaItemInner}; use rustc_hir::{ Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, }; @@ -8,8 +8,8 @@ use rustc_middle::ty; use rustc_span::sym; use rustc_span::symbol::Symbol; -pub(super) fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { - if let NestedMetaItem::MetaItem(mi) = &nmi { +pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool { + if let MetaItemInner::MetaItem(mi) = &nmi { mi.is_word() && mi.has_name(expected) } else { false @@ -74,7 +74,7 @@ fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_> } /// Returns the lint name if it is clippy lint. -pub(super) fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<Symbol> { +pub(super) fn extract_clippy_lint(lint: &MetaItemInner) -> Option<Symbol> { if let Some(meta_item) = lint.meta_item() && meta_item.path.segments.len() > 1 && let tool_name = meta_item.path.segments[0].ident diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs index 884d15cabff..84136a2e6c2 100644 --- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -47,7 +47,7 @@ impl EarlyLintPass for CfgNotTest { } } -fn contains_not_test(list: Option<&[NestedMetaItem]>, not: bool) -> bool { +fn contains_not_test(list: Option<&[MetaItemInner]>, not: bool) -> bool { list.is_some_and(|list| { list.iter().any(|item| { item.ident().is_some_and(|ident| match ident.name { diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index 796af851bac..6ad879b9fe7 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty}; use rustc_hir::{ BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, - PredicateOrigin, Ty, TyKind, WherePredicate, + PredicateOrigin, Ty, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; @@ -199,12 +199,6 @@ impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> { fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { if let Some((def_id, _)) = t.peel_refs().as_generic_param() { self.ty_params.remove(&def_id); - } else if let TyKind::OpaqueDef(id, _) = t.kind { - // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls - // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're - // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked. - let item = self.nested_visit_map().item(id); - walk_item(self, item); } else { walk_ty(self, t); } diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 6794c6cabfe..5f349d78053 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ - AssocItemConstraint, GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, + AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind, WherePredicate, }; use rustc_hir_analysis::lower_ty; @@ -342,11 +342,8 @@ impl<'tcx> LateLintPass<'tcx> for ImpliedBoundsInImpls { } } - fn check_ty(&mut self, cx: &LateContext<'_>, ty: &rustc_hir::Ty<'_>) { - if let TyKind::OpaqueDef(item_id, ..) = ty.kind - && let item = cx.tcx.hir().item(item_id) - && let ItemKind::OpaqueTy(opaque_ty) = item.kind - { + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &rustc_hir::Ty<'tcx>) { + if let TyKind::OpaqueDef(opaque_ty, ..) = ty.kind { check(cx, opaque_ty.bounds); } } diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index 73ebe6aec15..96550c4d1cb 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; use clippy_utils::ty::is_copy; use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::HirId; @@ -133,7 +133,7 @@ fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) { .index_use .iter() .map(|(index, _)| *index) - .collect::<FxHashSet<_>>(); + .collect::<FxIndexSet<_>>(); let value_name = |index| format!("{}_{index}", slice.ident.name); diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 45346cd18a6..311bbce14bd 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -308,11 +308,7 @@ enum LenOutput { fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { if let ty::Alias(_, alias_ty) = ty.kind() - && let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) - && let Item { - kind: ItemKind::OpaqueTy(opaque), - .. - } = item + && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir().get_if_local(alias_ty.def_id) && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds && let Some(segment) = trait_ref.trait_ref.path.segments.last() diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 2eb6d99b761..6ee064a6124 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -1,7 +1,6 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] @@ -27,8 +26,6 @@ unused_qualifications, rustc::internal )] -// Disable this rustc lint for now, as it was also done in rustc -#![allow(rustc::potential_query_instability)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 5c37e735445..ec28671a061 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::trait_ref_of_method; use itertools::Itertools; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::Applicability; use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate, }; use rustc_hir::{ @@ -311,7 +311,7 @@ fn could_use_elision<'tcx>( Some((elidable_lts, usages)) } -fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<LocalDefId> { +fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet<LocalDefId> { named_generics .iter() .filter_map(|par| { @@ -420,11 +420,9 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(item, bounds) => { - let map = self.cx.tcx.hir(); - let item = map.item(item); + TyKind::OpaqueDef(opaque, bounds) => { let len = self.lts.len(); - walk_item(self, item); + self.visit_opaque_ty(opaque); self.lts.truncate(len); self.lts.extend(bounds.iter().filter_map(|bound| match bound { GenericArg::Lifetime(&l) => Some(l), @@ -499,7 +497,7 @@ struct Usage { struct LifetimeChecker<'cx, 'tcx, F> { cx: &'cx LateContext<'tcx>, - map: FxHashMap<LocalDefId, Vec<Usage>>, + map: FxIndexMap<LocalDefId, Vec<Usage>>, where_predicate_depth: usize, generic_args_depth: usize, phantom: std::marker::PhantomData<F>, @@ -621,7 +619,7 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' fn report_elidable_impl_lifetimes<'tcx>( cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>, - map: &FxHashMap<LocalDefId, Vec<Usage>>, + map: &FxIndexMap<LocalDefId, Vec<Usage>>, ) { let single_usages = map .iter() diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 745f070a577..214b8b0f379 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::has_iter_method; use clippy_utils::visitors::is_local_used; use clippy_utils::{SpanlessEq, contains_name, higher, is_integer_const, sugg}; use rustc_ast::ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_expr}; @@ -39,7 +39,7 @@ pub(super) fn check<'tcx>( var: canonical_id, indexed_mut: FxHashSet::default(), indexed_indirectly: FxHashMap::default(), - indexed_directly: FxHashMap::default(), + indexed_directly: FxIndexMap::default(), referenced: FxHashSet::default(), nonindex: false, prefer_mutable: false, @@ -229,7 +229,7 @@ struct VarVisitor<'a, 'tcx> { indexed_indirectly: FxHashMap<Symbol, Option<region::Scope>>, /// subset of `indexed` of vars that are indexed directly: `v[i]` /// this will not contain cases like `v[calc_index(i)]` or `v[(i + 4) % N]` - indexed_directly: FxHashMap<Symbol, (Option<region::Scope>, Ty<'tcx>)>, + indexed_directly: FxIndexMap<Symbol, (Option<region::Scope>, Ty<'tcx>)>, /// Any names that are used outside an index operation. /// Used to detect things like `&mut vec` used together with `vec[i]` referenced: FxHashSet<Symbol>, diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 7097c85156c..81115cffdca 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, - FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, TraitRef, Ty, TyKind, + FnRetTy, GenericArg, GenericBound, ImplItem, Item, LifetimeName, Node, TraitRef, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -105,9 +105,7 @@ fn future_trait_ref<'tcx>( cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>, ) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> { - if let TyKind::OpaqueDef(item_id, bounds) = ty.kind - && let item = cx.tcx.hir().item(item_id) - && let ItemKind::OpaqueTy(opaque) = &item.kind + if let TyKind::OpaqueDef(opaque, bounds) = ty.kind && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { if let GenericBound::Trait(poly, _) = bound { Some(&poly.trait_ref) diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 7372f52e1e5..2ce6a8a85a5 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -7,6 +7,7 @@ use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{get_attr, is_lint_allowed}; use itertools::Itertools; use rustc_ast::Mutability; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; @@ -475,19 +476,19 @@ impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> { struct ArmSigDropHelper<'a, 'tcx> { sig_drop_checker: SigDropChecker<'a, 'tcx>, - found_sig_drop_spans: FxHashSet<Span>, + found_sig_drop_spans: FxIndexSet<Span>, } impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> { fn new(cx: &'a LateContext<'tcx>) -> ArmSigDropHelper<'a, 'tcx> { ArmSigDropHelper { sig_drop_checker: SigDropChecker::new(cx), - found_sig_drop_spans: FxHashSet::<Span>::default(), + found_sig_drop_spans: FxIndexSet::<Span>::default(), } } } -fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxHashSet<Span> { +fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxIndexSet<Span> { let mut helper = ArmSigDropHelper::new(cx); for arm in arms { helper.visit_expr(arm); 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 b40d7eba15e..c56a4014b34 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 @@ -8,7 +8,7 @@ use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, hash_expr, higher}; use rustc_ast::{LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; -use rustc_data_structures::unhash::UnhashMap; +use rustc_data_structures::unhash::UnindexMap; use rustc_errors::{Applicability, Diag}; use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -226,7 +226,7 @@ fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> { } /// Checks if the expression is an index into a slice and adds it to `indexes` -fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnhashMap<u64, Vec<IndexEntry<'hir>>>) { +fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnindexMap<u64, Vec<IndexEntry<'hir>>>) { if let ExprKind::Index(slice, index_lit, _) = expr.kind && cx.typeck_results().expr_ty_adjusted(slice).peel_refs().is_slice() && let Some(index) = upper_index_expr(index_lit) @@ -274,7 +274,7 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh } /// Checks if the expression is an `assert!` expression and adds it to `asserts` -fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnhashMap<u64, Vec<IndexEntry<'hir>>>) { +fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnindexMap<u64, Vec<IndexEntry<'hir>>>) { if let Some((comparison, asserted_len, slice)) = assert_len_expr(cx, expr) { let hash = hash_expr(cx, slice); let indexes = map.entry(hash).or_default(); @@ -311,7 +311,7 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un /// Inspects indexes and reports lints. /// /// Called at the end of this lint after all indexing and `assert!` expressions have been collected. -fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>>) { +fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap<u64, Vec<IndexEntry<'_>>>) { for bucket in map.values() { for entry in bucket { let Some(full_span) = entry @@ -403,7 +403,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>> impl LateLintPass<'_> for MissingAssertsForIndexing { fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { - let mut map = UnhashMap::default(); + let mut map = UnindexMap::default(); for_each_expr_without_closures(body.value, |expr| { check_index(cx, expr, &mut map); diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 64fc1a8a1a5..007bcebdff6 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -193,8 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::OpaqueTy(..) => {}, + | hir::ItemKind::Union(..) => {} hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index d342be4545c..f95a0f63fab 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -130,7 +130,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::TyAlias(..) | hir::ItemKind::Union(..) - | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs index e9c5f64a255..676d608eb31 100644 --- a/src/tools/clippy/clippy_lints/src/module_style.rs +++ b/src/tools/clippy/clippy_lints/src/module_style.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LOCAL_CRATE; @@ -87,7 +87,7 @@ impl EarlyLintPass for ModStyle { // `folder_segments` is all unique folder path segments `path/to/foo.rs` gives // `[path, to]` but not foo - let mut folder_segments = FxHashSet::default(); + let mut folder_segments = FxIndexSet::default(); // `mod_folders` is all the unique folder names that contain a mod.rs file let mut mod_folders = FxHashSet::default(); // `file_map` maps file names to the full path including the file name @@ -144,7 +144,7 @@ impl EarlyLintPass for ModStyle { /// is `mod.rs` we add it's parent folder to `mod_folders`. fn process_paths_for_mod_files<'a>( path: &'a Path, - folder_segments: &mut FxHashSet<&'a OsStr>, + folder_segments: &mut FxIndexSet<&'a OsStr>, mod_folders: &mut FxHashSet<&'a OsStr>, ) { let mut comp = path.components().rev().peekable(); diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index c2facb2fcf6..5c631a176c4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -5,7 +5,7 @@ use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr; use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; use core::ops::ControlFlow; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -101,7 +101,7 @@ fn check_closures<'tcx>( ctx: &mut MutablyUsedVariablesCtxt<'tcx>, cx: &LateContext<'tcx>, checked_closures: &mut FxHashSet<LocalDefId>, - closures: FxHashSet<LocalDefId>, + closures: FxIndexSet<LocalDefId>, ) { let hir = cx.tcx.hir(); for closure in closures { @@ -196,7 +196,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { prev_bind: None, prev_move_to_closure: HirIdSet::default(), aliases: HirIdMap::default(), - async_closures: FxHashSet::default(), + async_closures: FxIndexSet::default(), tcx: cx.tcx, }; euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx) @@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // We retrieve all the closures declared in the function because they will not be found // by `euv::Delegate`. - let mut closures: FxHashSet<LocalDefId> = FxHashSet::default(); + let mut closures: FxIndexSet<LocalDefId> = FxIndexSet::default(); for_each_expr(cx, body, |expr| { if let ExprKind::Closure(closure) = expr.kind { closures.insert(closure.def_id); @@ -307,7 +307,7 @@ struct MutablyUsedVariablesCtxt<'tcx> { /// use of a variable. prev_move_to_closure: HirIdSet, aliases: HirIdMap<HirId>, - async_closures: FxHashSet<LocalDefId>, + async_closures: FxIndexSet<LocalDefId>, tcx: TyCtxt<'tcx>, } diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 1f223048ce5..662745e4b5d 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -7,7 +7,7 @@ use clippy_utils::{ path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_errors::Applicability; use rustc_hir::LangItem::ResultErr; use rustc_hir::intravisit::FnKind; @@ -407,7 +407,7 @@ fn check_final_expr<'tcx>( } } - if ret_span.from_expansion() { + if ret_span.from_expansion() || is_from_proc_macro(cx, expr) { return; } @@ -421,7 +421,7 @@ fn check_final_expr<'tcx>( if matches!(Level::from_attr(attr), Some(Level::Expect(_))) && let metas = attr.meta_item_list() && let Some(lst) = metas - && let [NestedMetaItem::MetaItem(meta_item), ..] = lst.as_slice() + && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice() && let [tool, lint_name] = meta_item.path.segments.as_slice() && tool.ident.name == sym::clippy && matches!( diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index a3145c4647c..6cba560393d 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -6,9 +6,9 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core}; use itertools::Itertools; +use rustc_data_structures::fx::FxIndexSet; use rustc_hir::intravisit::{Visitor, walk_expr}; -use crate::FxHashSet; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -334,7 +334,7 @@ struct IndexBinding<'a, 'tcx> { impl<'tcx> IndexBinding<'_, 'tcx> { fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String { - let mut bindings = FxHashSet::default(); + let mut bindings = FxIndexSet::default(); for expr in exprs { bindings.insert(self.snippet_index_binding(expr)); } diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 00277593622..3c3973857e7 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -5,7 +5,7 @@ use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; use core::hash::{Hash, Hasher}; use itertools::Itertools; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, IndexEntry}; use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -16,7 +16,6 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Span}; -use std::collections::hash_map::Entry; declare_clippy_lint! { /// ### What it does @@ -427,7 +426,7 @@ fn rollup_traits( bounds: &[GenericBound<'_>], msg: &'static str, ) -> Vec<(ComparableTraitRef, Span)> { - let mut map = FxHashMap::default(); + let mut map = FxIndexMap::default(); let mut repeated_res = false; let only_comparable_trait_refs = |bound: &GenericBound<'_>| { @@ -442,8 +441,8 @@ fn rollup_traits( for bound in bounds.iter().filter_map(only_comparable_trait_refs) { let (comparable_bound, span_direct) = bound; match map.entry(comparable_bound) { - Entry::Occupied(_) => repeated_res = true, - Entry::Vacant(e) => { + IndexEntry::Occupied(_) => repeated_res = true, + IndexEntry::Vacant(e) => { e.insert((span_direct, i)); i += 1; }, diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 08449de79b3..f5cf4a586fd 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -85,10 +85,6 @@ const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element"; impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) { - if matches!(item.kind, ItemKind::OpaqueTy(_)) { - // skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>` - return; - } // We push the self types of `impl`s on a stack here. Only the top type on the stack is // relevant for linting, since this is the self type of the `impl` we're currently in. To // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that @@ -130,10 +126,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { self.stack.push(stack_item); } - fn check_item_post(&mut self, _: &LateContext<'_>, item: &Item<'_>) { - if !matches!(item.kind, ItemKind::OpaqueTy(_)) { - self.stack.pop(); - } + fn check_item_post(&mut self, _: &LateContext<'_>, _: &Item<'_>) { + self.stack.pop(); } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 9143d292f67..bfb3a76ad25 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -141,62 +141,89 @@ fn path_search_pat(path: &Path<'_>) -> (Pat, Pat) { /// Get the search patterns to use for the given expression fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { - match e.kind { - ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), - // Parenthesis are trimmed from the text before the search patterns are matched. - // See: `span_matches_pat` - ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), - ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), - ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1), - ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1), - ExprKind::Lit(lit) => lit_search_pat(&lit.node), - ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), - ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), - ExprKind::Call(first, [.., last]) - | ExprKind::MethodCall(_, first, [.., last], _) - | ExprKind::Binary(_, first, last) - | ExprKind::Tup([first, .., last]) - | ExprKind::Assign(first, last, _) - | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1), - ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e), - ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")), - ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1), - ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")), - ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")), - ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")), - ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")), - ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => { - (Pat::Str("for"), Pat::Str("}")) - }, - ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")), - ExprKind::Match(e, _, MatchSource::TryDesugar(_)) => (expr_search_pat(tcx, e).0, Pat::Str("?")), - ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { - (expr_search_pat(tcx, e).0, Pat::Str("await")) - }, - ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, tcx.hir().body(body).value).1), - ExprKind::Block( - Block { - rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), - .. + fn expr_search_pat_inner(tcx: TyCtxt<'_>, e: &Expr<'_>, outer_span: Span) -> (Pat, Pat) { + // The expression can have subexpressions in different contexts, in which case + // building up a search pattern from the macro expansion would lead to false positives; + // e.g. `return format!(..)` would be considered to be from a proc macro + // if we build up a pattern for the macro expansion and compare it to the invocation `format!()`. + // So instead we return an empty pattern such that `span_matches_pat` always returns true. + if !e.span.eq_ctxt(outer_span) { + return (Pat::Str(""), Pat::Str("")); + } + + match e.kind { + ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), + // Parenthesis are trimmed from the text before the search patterns are matched. + // See: `span_matches_pat` + ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), + ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Lit(lit) => lit_search_pat(&lit.node), + ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), + ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => { + (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("(")) }, - None, - ) => (Pat::Str("unsafe"), Pat::Str("}")), - ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")), - ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)), - ExprKind::Index(e, _, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")), - ExprKind::Path(ref path) => qpath_search_pat(path), - ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1), - ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")), - ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)), - ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1), - ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")), - ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)), - ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")), - ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1), - ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")), - ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1), - _ => (Pat::Str(""), Pat::Str("")), + ExprKind::Call(first, [.., last]) + | ExprKind::MethodCall(_, first, [.., last], _) + | ExprKind::Binary(_, first, last) + | ExprKind::Tup([first, .., last]) + | ExprKind::Assign(first, last, _) + | ExprKind::AssignOp(_, first, last) => ( + expr_search_pat_inner(tcx, first, outer_span).0, + expr_search_pat_inner(tcx, last, outer_span).1, + ), + ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat_inner(tcx, e, outer_span), + ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("")), + ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat_inner(tcx, let_expr.init, outer_span).1), + ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")), + ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => { + (Pat::Str("for"), Pat::Str("}")) + }, + ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")), + ExprKind::Match(e, _, MatchSource::TryDesugar(_)) => { + (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("?")) + }, + ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { + (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("await")) + }, + ExprKind::Closure(&Closure { body, .. }) => ( + Pat::Str(""), + expr_search_pat_inner(tcx, tcx.hir().body(body).value, outer_span).1, + ), + ExprKind::Block( + Block { + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), + .. + }, + None, + ) => (Pat::Str("unsafe"), Pat::Str("}")), + ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")), + ExprKind::Field(e, name) => (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Sym(name.name)), + ExprKind::Index(e, _, _) => (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("]")), + ExprKind::Path(ref path) => qpath_search_pat(path), + ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")), + ExprKind::Break(Destination { label: Some(name), .. }, None) => { + (Pat::Str("break"), Pat::Sym(name.ident.name)) + }, + ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")), + ExprKind::Continue(Destination { label: Some(name), .. }) => { + (Pat::Str("continue"), Pat::Sym(name.ident.name)) + }, + ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")), + ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")), + ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat_inner(tcx, e, outer_span).1), + _ => (Pat::Str(""), Pat::Str("")), + } } + + expr_search_pat_inner(tcx, e, e.span) } fn fn_header_search_pat(header: FnHeader) -> Pat { @@ -220,7 +247,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")), - ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")), + ItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")), ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")), ItemKind::Struct(VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 514ec70a40b..10e258444a6 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,6 +1,5 @@ #![feature(array_chunks)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 4ad7575e720..eecbfb3936a 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -287,6 +287,7 @@ impl SourceFileRange { self.sf .src .as_ref() + .map(|src| src.as_str()) .or_else(|| self.sf.external_src.get().and_then(|src| src.get_source())) .and_then(|x| x.get(self.range.clone())) } diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed index baf939af24e..cdb8fa0454c 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed @@ -86,6 +86,7 @@ mod issue9612 { util(); } + #[allow(unconditional_panic)] fn util() { let _a: u8 = 4.try_into().unwrap(); let _a: u8 = 5.try_into().expect(""); diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs index e300ba18c33..e53d53db5f7 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -86,6 +86,7 @@ mod issue9612 { util(); } + #[allow(unconditional_panic)] fn util() { let _a: u8 = 4.try_into().unwrap(); let _a: u8 = 5.try_into().expect(""); diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr index 320578bfabc..b58ce9b8af3 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -274,7 +274,7 @@ LL | let _ = &boxed_slice[1]; | ~~~~~~~~~~~~~~~ error: called `.get().unwrap()` on a slice - --> tests/ui-toml/unwrap_used/unwrap_used.rs:93:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:94:17 | LL | let _ = Box::new([0]).get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/crashes/ice-12284.rs b/src/tools/clippy/tests/ui/crashes/ice-12284.rs deleted file mode 100644 index 8d1dbface8e..00000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-12284.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -#[repr(C)] -struct Foo { - _: struct { - }, -} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed index e3525191423..bda9221a5e1 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed @@ -1,5 +1,5 @@ #![warn(clippy::dbg_macro)] -#![allow(clippy::unnecessary_operation, clippy::no_effect)] +#![allow(clippy::unnecessary_operation, clippy::no_effect, clippy::unit_arg)] fn foo(n: u32) -> u32 { if let Some(n) = n.checked_sub(4) { n } else { n } diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs index 80606c2db05..8244254026b 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs @@ -1,5 +1,5 @@ #![warn(clippy::dbg_macro)] -#![allow(clippy::unnecessary_operation, clippy::no_effect)] +#![allow(clippy::unnecessary_operation, clippy::no_effect, clippy::unit_arg)] fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index edfffe8fcfe..355f2bc7736 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -3,7 +3,7 @@ #![allow(dead_code, incomplete_features)] #![warn(clippy::doc_markdown)] -#![feature(custom_inner_attributes, generic_const_exprs, const_option)] +#![feature(custom_inner_attributes, generic_const_exprs)] #![rustfmt::skip] /// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there) diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 3c0f6913e32..9ced2677622 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -3,7 +3,7 @@ #![allow(dead_code, incomplete_features)] #![warn(clippy::doc_markdown)] -#![feature(custom_inner_attributes, generic_const_exprs, const_option)] +#![feature(custom_inner_attributes, generic_const_exprs)] #![rustfmt::skip] /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed index 62beb195939..2dd3c30a4e2 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.fixed +++ b/src/tools/clippy/tests/ui/get_unwrap.fixed @@ -70,6 +70,7 @@ fn main() { mod issue9909 { #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)] + #[allow(unconditional_panic)] fn reduced() { let f = &[1, 2, 3]; diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs index 1e09ff5c67e..94226564cac 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.rs +++ b/src/tools/clippy/tests/ui/get_unwrap.rs @@ -70,6 +70,7 @@ fn main() { mod issue9909 { #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)] + #[allow(unconditional_panic)] fn reduced() { let f = &[1, 2, 3]; diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr index 0f8b279da1e..8eacb249c60 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.stderr +++ b/src/tools/clippy/tests/ui/get_unwrap.stderr @@ -266,7 +266,7 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:77:24 + --> tests/ui/get_unwrap.rs:78:24 | LL | let _x: &i32 = f.get(1 + 2).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL | let _x: &i32 = &f[1 + 2]; | ~~~~~~~~~ error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:80:18 + --> tests/ui/get_unwrap.rs:81:18 | LL | let _x = f.get(1 + 2).unwrap().to_string(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ LL | let _x = f[1 + 2].to_string(); | ~~~~~~~~ error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:83:18 + --> tests/ui/get_unwrap.rs:84:18 | LL | let _x = f.get(1 + 2).unwrap().abs(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ LL | let _x = f[1 + 2].abs(); | ~~~~~~~~ error: called `.get_mut().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:100:33 + --> tests/ui/get_unwrap.rs:101:33 | LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index ca422e605d6..aa2a274525b 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -1,3 +1,4 @@ +//@aux-build:proc_macros.rs #![feature(yeet_expr)] #![allow(unused)] #![allow( @@ -9,6 +10,9 @@ )] #![warn(clippy::needless_return)] +extern crate proc_macros; +use proc_macros::with_span; + use std::cell::RefCell; macro_rules! the_answer { @@ -359,6 +363,10 @@ fn issue12907() -> String { "".split("").next().unwrap().to_string() } +fn issue13458() { + with_span!(span return); +} + fn main() {} fn a(x: Option<u8>) -> Option<u8> { diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index aad6e13136f..bf67cfd3698 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -1,3 +1,4 @@ +//@aux-build:proc_macros.rs #![feature(yeet_expr)] #![allow(unused)] #![allow( @@ -9,6 +10,9 @@ )] #![warn(clippy::needless_return)] +extern crate proc_macros; +use proc_macros::with_span; + use std::cell::RefCell; macro_rules! the_answer { @@ -369,6 +373,10 @@ fn issue12907() -> String { return "".split("").next().unwrap().to_string(); } +fn issue13458() { + with_span!(span return); +} + fn main() {} fn a(x: Option<u8>) -> Option<u8> { diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index da0fa220d8c..d3c2a6badc0 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> tests/ui/needless_return.rs:25:5 + --> tests/ui/needless_return.rs:29:5 | LL | return true; | ^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:29:5 + --> tests/ui/needless_return.rs:33:5 | LL | return true; | ^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:34:5 + --> tests/ui/needless_return.rs:38:5 | LL | return true;;; | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:39:5 + --> tests/ui/needless_return.rs:43:5 | LL | return true;; ; ; | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:44:9 + --> tests/ui/needless_return.rs:48:9 | LL | return true; | ^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:46:9 + --> tests/ui/needless_return.rs:50:9 | LL | return false; | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + false | error: unneeded `return` statement - --> tests/ui/needless_return.rs:52:17 + --> tests/ui/needless_return.rs:56:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | true => false, | ~~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:54:13 + --> tests/ui/needless_return.rs:58:13 | LL | return true; | ^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:61:9 + --> tests/ui/needless_return.rs:65:9 | LL | return true; | ^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:63:16 + --> tests/ui/needless_return.rs:67:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | let _ = || true; | ~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:67:5 + --> tests/ui/needless_return.rs:71:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:70:21 + --> tests/ui/needless_return.rs:74:21 | LL | fn test_void_fun() { | _____________________^ @@ -146,7 +146,7 @@ LL + fn test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:75:11 + --> tests/ui/needless_return.rs:79:11 | LL | if b { | ___________^ @@ -161,7 +161,7 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:77:13 + --> tests/ui/needless_return.rs:81:13 | LL | } else { | _____________^ @@ -176,7 +176,7 @@ LL + } else { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:85:14 + --> tests/ui/needless_return.rs:89:14 | LL | _ => return, | ^^^^^^ @@ -187,7 +187,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:93:24 + --> tests/ui/needless_return.rs:97:24 | LL | let _ = 42; | ________________________^ @@ -202,7 +202,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:96:14 + --> tests/ui/needless_return.rs:100:14 | LL | _ => return, | ^^^^^^ @@ -213,7 +213,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:109:9 + --> tests/ui/needless_return.rs:113:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL + String::from("test") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:111:9 + --> tests/ui/needless_return.rs:115:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -237,7 +237,7 @@ LL + String::new() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:133:32 + --> tests/ui/needless_return.rs:137:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ @@ -248,7 +248,7 @@ LL | bar.unwrap_or_else(|_| {}) | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:137:21 + --> tests/ui/needless_return.rs:141:21 | LL | let _ = || { | _____________________^ @@ -263,7 +263,7 @@ LL + let _ = || { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:140:20 + --> tests/ui/needless_return.rs:144:20 | LL | let _ = || return; | ^^^^^^ @@ -274,7 +274,7 @@ LL | let _ = || {}; | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:146:32 + --> tests/ui/needless_return.rs:150:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ @@ -285,7 +285,7 @@ LL | res.unwrap_or_else(|_| Foo) | ~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:155:5 + --> tests/ui/needless_return.rs:159:5 | LL | return true; | ^^^^^^^^^^^ @@ -297,7 +297,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:159:5 + --> tests/ui/needless_return.rs:163:5 | LL | return true; | ^^^^^^^^^^^ @@ -309,7 +309,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:164:9 + --> tests/ui/needless_return.rs:168:9 | LL | return true; | ^^^^^^^^^^^ @@ -321,7 +321,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:166:9 + --> tests/ui/needless_return.rs:170:9 | LL | return false; | ^^^^^^^^^^^^ @@ -333,7 +333,7 @@ LL + false | error: unneeded `return` statement - --> tests/ui/needless_return.rs:172:17 + --> tests/ui/needless_return.rs:176:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -344,7 +344,7 @@ LL | true => false, | ~~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:174:13 + --> tests/ui/needless_return.rs:178:13 | LL | return true; | ^^^^^^^^^^^ @@ -356,7 +356,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:181:9 + --> tests/ui/needless_return.rs:185:9 | LL | return true; | ^^^^^^^^^^^ @@ -368,7 +368,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:183:16 + --> tests/ui/needless_return.rs:187:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -379,7 +379,7 @@ LL | let _ = || true; | ~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:187:5 + --> tests/ui/needless_return.rs:191:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -391,7 +391,7 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:190:33 + --> tests/ui/needless_return.rs:194:33 | LL | async fn async_test_void_fun() { | _________________________________^ @@ -406,7 +406,7 @@ LL + async fn async_test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:195:11 + --> tests/ui/needless_return.rs:199:11 | LL | if b { | ___________^ @@ -421,7 +421,7 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:197:13 + --> tests/ui/needless_return.rs:201:13 | LL | } else { | _____________^ @@ -436,7 +436,7 @@ LL + } else { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:205:14 + --> tests/ui/needless_return.rs:209:14 | LL | _ => return, | ^^^^^^ @@ -447,7 +447,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:218:9 + --> tests/ui/needless_return.rs:222:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -459,7 +459,7 @@ LL + String::from("test") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:220:9 + --> tests/ui/needless_return.rs:224:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -471,7 +471,7 @@ LL + String::new() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:236:5 + --> tests/ui/needless_return.rs:240:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -483,7 +483,7 @@ LL + format!("Hello {}", "world!") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:277:9 + --> tests/ui/needless_return.rs:281:9 | LL | return true; | ^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:279:9 + --> tests/ui/needless_return.rs:283:9 | LL | return false; | ^^^^^^^^^^^^ @@ -509,7 +509,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:286:13 + --> tests/ui/needless_return.rs:290:13 | LL | return 10; | ^^^^^^^^^ @@ -524,7 +524,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:289:13 + --> tests/ui/needless_return.rs:293:13 | LL | return 100; | ^^^^^^^^^^ @@ -537,7 +537,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:297:9 + --> tests/ui/needless_return.rs:301:9 | LL | return 0; | ^^^^^^^^ @@ -549,7 +549,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:304:13 + --> tests/ui/needless_return.rs:308:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -564,7 +564,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:306:13 + --> tests/ui/needless_return.rs:310:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -577,7 +577,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:313:20 + --> tests/ui/needless_return.rs:317:20 | LL | let _ = 42; | ____________________^ @@ -594,7 +594,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:320:20 + --> tests/ui/needless_return.rs:324:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -606,7 +606,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:332:9 + --> tests/ui/needless_return.rs:336:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -618,7 +618,7 @@ LL + Ok(format!("ok!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:334:9 + --> tests/ui/needless_return.rs:338:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -630,7 +630,7 @@ LL + Err(format!("err!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:340:9 + --> tests/ui/needless_return.rs:344:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -642,7 +642,7 @@ LL + if true { 1 } else { 2 } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:344:9 + --> tests/ui/needless_return.rs:348:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -654,7 +654,7 @@ LL + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else | error: unneeded `return` statement - --> tests/ui/needless_return.rs:365:5 + --> tests/ui/needless_return.rs:369:5 | LL | return { "a".to_string() } + "b" + { "c" }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -666,7 +666,7 @@ LL + ({ "a".to_string() } + "b" + { "c" }) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:369:5 + --> tests/ui/needless_return.rs:373:5 | LL | return "".split("").next().unwrap().to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed index 83814ca43b9..075a198918a 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed @@ -1,7 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] -#![feature(f128, f128_const)] -#![feature(f16, f16_const)] +#![feature(f128)] +#![feature(f16)] fn float_to_int() { let _: u32 = unsafe { 1f32.to_bits() }; diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs index 64d6e917203..12541b2f7cf 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs @@ -1,7 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] -#![feature(f128, f128_const)] -#![feature(f16, f16_const)] +#![feature(f128)] +#![feature(f16)] fn float_to_int() { let _: u32 = unsafe { std::mem::transmute(1f32) }; diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index e95054a7ccb..617d32d1fa7 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -84,8 +84,11 @@ fn issue_10449() { } // Pointers cannot be cast to integers in const contexts +#[allow(ptr_to_integer_transmute_in_consts, reason = "This is tested in the compiler test suite")] const fn issue_12402<P>(ptr: *const P) { - unsafe { transmute::<*const i32, usize>(&42i32) }; - unsafe { transmute::<fn(*const P), usize>(issue_12402) }; - let _ = unsafe { transmute::<_, usize>(ptr) }; + // This test exists even though the compiler lints against it + // to test that clippy's transmute lints do not trigger on this. + unsafe { std::mem::transmute::<*const i32, usize>(&42i32) }; + unsafe { std::mem::transmute::<fn(*const P), usize>(issue_12402) }; + let _ = unsafe { std::mem::transmute::<_, usize>(ptr) }; } diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index e5fcdef7a1c..d68db3c2deb 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -84,8 +84,11 @@ fn issue_10449() { } // Pointers cannot be cast to integers in const contexts +#[allow(ptr_to_integer_transmute_in_consts, reason = "This is tested in the compiler test suite")] const fn issue_12402<P>(ptr: *const P) { - unsafe { transmute::<*const i32, usize>(&42i32) }; - unsafe { transmute::<fn(*const P), usize>(issue_12402) }; - let _ = unsafe { transmute::<_, usize>(ptr) }; + // This test exists even though the compiler lints against it + // to test that clippy's transmute lints do not trigger on this. + unsafe { std::mem::transmute::<*const i32, usize>(&42i32) }; + unsafe { std::mem::transmute::<fn(*const P), usize>(issue_12402) }; + let _ = unsafe { std::mem::transmute::<_, usize>(ptr) }; } diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs index a4cedbf66e2..4d57907f26f 100644 --- a/src/tools/compiletest/src/command-list.rs +++ b/src/tools/compiletest/src/command-list.rs @@ -42,11 +42,14 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-cdb", "ignore-compare-mode-next-solver", "ignore-compare-mode-polonius", + "ignore-coverage-map", + "ignore-coverage-run", "ignore-cross-compile", "ignore-debug", "ignore-eabi", "ignore-emscripten", "ignore-endian-big", + "ignore-enzyme", "ignore-freebsd", "ignore-fuchsia", "ignore-gdb", @@ -64,23 +67,6 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-loongarch64", "ignore-macabi", "ignore-macos", - "ignore-mode-assembly", - "ignore-mode-codegen", - "ignore-mode-codegen-units", - "ignore-mode-coverage-map", - "ignore-mode-coverage-run", - "ignore-mode-crashes", - "ignore-mode-debuginfo", - "ignore-mode-incremental", - "ignore-mode-js-doc-test", - "ignore-mode-mir-opt", - "ignore-mode-pretty", - "ignore-mode-run-make", - "ignore-mode-run-pass-valgrind", - "ignore-mode-rustdoc", - "ignore-mode-rustdoc-json", - "ignore-mode-ui", - "ignore-mode-ui-fulldeps", "ignore-msp430", "ignore-msvc", "ignore-musl", @@ -144,7 +130,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-git-hash", "needs-llvm-components", "needs-llvm-zstd", - "needs-profiler-support", + "needs-profiler-runtime", "needs-relocation-model-pic", "needs-run-enabled", "needs-rust-lld", @@ -223,6 +209,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "pretty-compare-only", "pretty-expanded", "pretty-mode", + "reference", "regex-error-pattern", "remap-src-base", "revisions", diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index adc89cad72f..a5418ad8384 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -53,7 +53,6 @@ macro_rules! string_enum { string_enum! { #[derive(Clone, Copy, PartialEq, Debug)] pub enum Mode { - RunPassValgrind => "run-pass-valgrind", Pretty => "pretty", DebugInfo => "debuginfo", Codegen => "codegen", @@ -207,13 +206,6 @@ pub struct Config { /// Path to LLVM's bin directory. pub llvm_bin_dir: Option<PathBuf>, - /// The valgrind path. - pub valgrind_path: Option<String>, - - /// Whether to fail if we can't run run-pass-valgrind tests under valgrind - /// (or, alternatively, to silently run them like regular run-pass tests). - pub force_valgrind: bool, - /// The path to the Clang executable to run Clang-based tests with. If /// `None` then these tests will be ignored. pub run_clang_based_tests_with: Option<String>, @@ -393,8 +385,8 @@ pub struct Config { pub git_merge_commit_email: String, /// True if the profiler runtime is enabled for this target. - /// Used by the "needs-profiler-support" header in test files. - pub profiler_support: bool, + /// Used by the "needs-profiler-runtime" directive in test files. + pub profiler_runtime: bool, } impl Config { diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs new file mode 100644 index 00000000000..b605bc813f1 --- /dev/null +++ b/src/tools/compiletest/src/debuggers.rs @@ -0,0 +1,272 @@ +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; +use std::process::Command; +use std::sync::Arc; + +use crate::common::{Config, Debugger}; + +pub(crate) fn configure_cdb(config: &Config) -> Option<Arc<Config>> { + config.cdb.as_ref()?; + + Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) +} + +pub(crate) fn configure_gdb(config: &Config) -> Option<Arc<Config>> { + config.gdb_version?; + + if config.matches_env("msvc") { + return None; + } + + if config.remote_test_client.is_some() && !config.target.contains("android") { + println!( + "WARNING: debuginfo tests are not available when \ + testing with remote" + ); + return None; + } + + if config.target.contains("android") { + println!( + "{} debug-info test uses tcp 5039 port.\ + please reserve it", + config.target + ); + + // android debug-info test uses remote debugger so, we test 1 thread + // at once as they're all sharing the same TCP port to communicate + // over. + // + // we should figure out how to lift this restriction! (run them all + // on different ports allocated dynamically). + env::set_var("RUST_TEST_THREADS", "1"); + } + + Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) +} + +pub(crate) fn configure_lldb(config: &Config) -> Option<Arc<Config>> { + config.lldb_python_dir.as_ref()?; + + if let Some(350) = config.lldb_version { + println!( + "WARNING: The used version of LLDB (350) has a \ + known issue that breaks debuginfo tests. See \ + issue #32520 for more information. Skipping all \ + LLDB-based tests!", + ); + return None; + } + + Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) +} + +/// Returns `true` if the given target is an Android target for the +/// purposes of GDB testing. +pub(crate) fn is_android_gdb_target(target: &str) -> bool { + matches!( + &target[..], + "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" + ) +} + +/// Returns `true` if the given target is a MSVC target for the purposes of CDB testing. +fn is_pc_windows_msvc_target(target: &str) -> bool { + target.ends_with("-pc-windows-msvc") +} + +fn find_cdb(target: &str) -> Option<OsString> { + if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { + return None; + } + + let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; + let cdb_arch = if cfg!(target_arch = "x86") { + "x86" + } else if cfg!(target_arch = "x86_64") { + "x64" + } else if cfg!(target_arch = "aarch64") { + "arm64" + } else if cfg!(target_arch = "arm") { + "arm" + } else { + return None; // No compatible CDB.exe in the Windows 10 SDK + }; + + let mut path = PathBuf::new(); + path.push(pf86); + path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? + path.push(cdb_arch); + path.push(r"cdb.exe"); + + if !path.exists() { + return None; + } + + Some(path.into_os_string()) +} + +/// Returns Path to CDB +pub(crate) fn analyze_cdb( + cdb: Option<String>, + target: &str, +) -> (Option<OsString>, Option<[u16; 4]>) { + let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); + + let mut version = None; + if let Some(cdb) = cdb.as_ref() { + if let Ok(output) = Command::new(cdb).arg("/version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version = extract_cdb_version(&first_line); + } + } + } + + (cdb, version) +} + +pub(crate) fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { + // Example full_version_line: "cdb version 10.0.18362.1" + let version = full_version_line.rsplit(' ').next()?; + let mut components = version.split('.'); + let major: u16 = components.next().unwrap().parse().unwrap(); + let minor: u16 = components.next().unwrap().parse().unwrap(); + let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); + let build: u16 = components.next().unwrap_or("0").parse().unwrap(); + Some([major, minor, patch, build]) +} + +/// Returns (Path to GDB, GDB Version) +pub(crate) fn analyze_gdb( + gdb: Option<String>, + target: &str, + android_cross_path: &PathBuf, +) -> (Option<String>, Option<u32>) { + #[cfg(not(windows))] + const GDB_FALLBACK: &str = "gdb"; + #[cfg(windows)] + const GDB_FALLBACK: &str = "gdb.exe"; + + let fallback_gdb = || { + if is_android_gdb_target(target) { + let mut gdb_path = match android_cross_path.to_str() { + Some(x) => x.to_owned(), + None => panic!("cannot find android cross path"), + }; + gdb_path.push_str("/bin/gdb"); + gdb_path + } else { + GDB_FALLBACK.to_owned() + } + }; + + let gdb = match gdb { + None => fallback_gdb(), + Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb + Some(ref s) => s.to_owned(), + }; + + let mut version_line = None; + if let Ok(output) = Command::new(&gdb).arg("--version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version_line = Some(first_line.to_string()); + } + } + + let version = match version_line { + Some(line) => extract_gdb_version(&line), + None => return (None, None), + }; + + (Some(gdb), version) +} + +pub(crate) fn extract_gdb_version(full_version_line: &str) -> Option<u32> { + let full_version_line = full_version_line.trim(); + + // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both + // of the ? sections being optional + + // We will parse up to 3 digits for each component, ignoring the date + + // We skip text in parentheses. This avoids accidentally parsing + // the openSUSE version, which looks like: + // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 + // This particular form is documented in the GNU coding standards: + // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion + + let unbracketed_part = full_version_line.split('[').next().unwrap(); + let mut splits = unbracketed_part.trim_end().rsplit(' '); + let version_string = splits.next().unwrap(); + + let mut splits = version_string.split('.'); + let major = splits.next().unwrap(); + let minor = splits.next().unwrap(); + let patch = splits.next(); + + let major: u32 = major.parse().unwrap(); + let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { + None => { + let minor = minor.parse().unwrap(); + let patch: u32 = match patch { + Some(patch) => match patch.find(not_a_digit) { + None => patch.parse().unwrap(), + Some(idx) if idx > 3 => 0, + Some(idx) => patch[..idx].parse().unwrap(), + }, + None => 0, + }; + (minor, patch) + } + // There is no patch version after minor-date (e.g. "4-2012"). + Some(idx) => { + let minor = minor[..idx].parse().unwrap(); + (minor, 0) + } + }; + + Some(((major * 1000) + minor) * 1000 + patch) +} + +/// Returns LLDB version +pub(crate) fn extract_lldb_version(full_version_line: &str) -> Option<u32> { + // Extract the major LLDB version from the given version string. + // LLDB version strings are different for Apple and non-Apple platforms. + // The Apple variant looks like this: + // + // LLDB-179.5 (older versions) + // lldb-300.2.51 (new versions) + // + // We are only interested in the major version number, so this function + // will return `Some(179)` and `Some(300)` respectively. + // + // Upstream versions look like: + // lldb version 6.0.1 + // + // There doesn't seem to be a way to correlate the Apple version + // with the upstream version, and since the tests were originally + // written against Apple versions, we make a fake Apple version by + // multiplying the first number by 100. This is a hack. + + let full_version_line = full_version_line.trim(); + + if let Some(apple_ver) = + full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) + { + if let Some(idx) = apple_ver.find(not_a_digit) { + let version: u32 = apple_ver[..idx].parse().unwrap(); + return Some(version); + } + } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { + if let Some(idx) = lldb_ver.find(not_a_digit) { + let version: u32 = lldb_ver[..idx].parse().ok()?; + return Some(version * 100); + } + } + None +} + +fn not_a_digit(c: char) -> bool { + !c.is_ascii_digit() +} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 83a10c56208..099e620ffe0 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -5,17 +5,17 @@ use std::io::BufReader; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; -use std::sync::OnceLock; -use regex::Regex; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; +use crate::debuggers::{extract_cdb_version, extract_gdb_version}; +use crate::header::auxiliary::{AuxProps, parse_and_update_aux}; use crate::header::cfg::{MatchOutcome, parse_cfg_name_directive}; use crate::header::needs::CachedNeedsConditions; use crate::util::static_regex; -use crate::{extract_cdb_version, extract_gdb_version}; +pub(crate) mod auxiliary; mod cfg; mod needs; #[cfg(test)] @@ -35,9 +35,10 @@ impl HeadersCache { /// the test. #[derive(Default)] pub struct EarlyProps { - pub aux: Vec<String>, - pub aux_bin: Vec<String>, - pub aux_crate: Vec<(String, String)>, + /// Auxiliary crates that should be built and made available to this test. + /// Included in [`EarlyProps`] so that the indicated files can participate + /// in up-to-date checking. Building happens via [`TestProps::aux`] instead. + pub(crate) aux: AuxProps, pub revisions: Vec<String>, } @@ -56,23 +57,9 @@ impl EarlyProps { &mut poisoned, testfile, rdr, - &mut |HeaderLine { directive: ln, .. }| { - config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| { - r.trim().to_string() - }); - config.push_name_value_directive( - ln, - directives::AUX_BIN, - &mut props.aux_bin, - |r| r.trim().to_string(), - ); - config.push_name_value_directive( - ln, - directives::AUX_CRATE, - &mut props.aux_crate, - Config::parse_aux_crate, - ); - config.parse_and_update_revisions(ln, &mut props.revisions); + &mut |DirectiveLine { directive: ln, .. }| { + parse_and_update_aux(config, ln, &mut props.aux); + config.parse_and_update_revisions(testfile, ln, &mut props.revisions); }, ); @@ -100,18 +87,8 @@ pub struct TestProps { // If present, the name of a file that this test should match when // pretty-printed pub pp_exact: Option<PathBuf>, - // Other crates that should be compiled (typically from the same - // directory as the test, but for backwards compatibility reasons - // we also check the auxiliary directory) - pub aux_builds: Vec<String>, - // Auxiliary crates that should be compiled as `#![crate_type = "bin"]`. - pub aux_bins: Vec<String>, - // Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies - // to build and pass with the `--extern` flag. - pub aux_crates: Vec<(String, String)>, - /// Similar to `aux_builds`, but also passes the resulting dylib path to - /// `-Zcodegen-backend`. - pub aux_codegen_backend: Option<String>, + /// Auxiliary crates that should be built and made available to this test. + pub(crate) aux: AuxProps, // Environment settings to use for compiling pub rustc_env: Vec<(String, String)>, // Environment variables to unset prior to compiling. @@ -278,10 +255,7 @@ impl TestProps { run_flags: vec![], doc_flags: vec![], pp_exact: None, - aux_builds: vec![], - aux_bins: vec![], - aux_crates: vec![], - aux_codegen_backend: None, + aux: Default::default(), revisions: vec![], rustc_env: vec![ ("RUSTC_ICE".to_string(), "0".to_string()), @@ -370,7 +344,7 @@ impl TestProps { &mut poisoned, testfile, file, - &mut |HeaderLine { header_revision, directive: ln, .. }| { + &mut |DirectiveLine { header_revision, directive: ln, .. }| { if header_revision.is_some() && header_revision != test_revision { return; } @@ -417,7 +391,7 @@ impl TestProps { has_edition = true; } - config.parse_and_update_revisions(ln, &mut self.revisions); + config.parse_and_update_revisions(testfile, ln, &mut self.revisions); if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS) { self.run_flags.extend(split_flags(&flags)); @@ -456,21 +430,10 @@ impl TestProps { PRETTY_COMPARE_ONLY, &mut self.pretty_compare_only, ); - config.push_name_value_directive(ln, AUX_BUILD, &mut self.aux_builds, |r| { - r.trim().to_string() - }); - config.push_name_value_directive(ln, AUX_BIN, &mut self.aux_bins, |r| { - r.trim().to_string() - }); - config.push_name_value_directive( - ln, - AUX_CRATE, - &mut self.aux_crates, - Config::parse_aux_crate, - ); - if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) { - self.aux_codegen_backend = Some(r.trim().to_owned()); - } + + // Call a helper method to deal with aux-related directives. + parse_and_update_aux(config, ln, &mut self.aux); + config.push_name_value_directive( ln, EXEC_ENV, @@ -717,7 +680,7 @@ impl TestProps { /// Extract an `(Option<line_revision>, directive)` directive from a line if comment is present. /// -/// See [`HeaderLine`] for a diagram. +/// See [`DirectiveLine`] for a diagram. pub fn line_directive<'line>( comment: &str, original_line: &'line str, @@ -775,17 +738,13 @@ const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] = /// ```text /// //@ compile-flags: -O /// ^^^^^^^^^^^^^^^^^ directive -/// ^^^^^^^^^^^^^^^^^^^^^ original_line /// /// //@ [foo] compile-flags: -O /// ^^^ header_revision /// ^^^^^^^^^^^^^^^^^ directive -/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ original_line /// ``` -struct HeaderLine<'ln> { +struct DirectiveLine<'ln> { line_number: usize, - /// Raw line from the test file, including comment prefix and any revision. - original_line: &'ln str, /// Some header directives start with a revision name in square brackets /// (e.g. `[foo]`), and only apply to that revision of the test. /// If present, this field contains the revision name (e.g. `foo`). @@ -797,7 +756,6 @@ struct HeaderLine<'ln> { pub(crate) struct CheckDirectiveResult<'ln> { is_known_directive: bool, - directive_name: &'ln str, trailing_directive: Option<&'ln str>, } @@ -832,11 +790,7 @@ pub(crate) fn check_directive<'a>( } .then_some(trailing); - CheckDirectiveResult { - is_known_directive: is_known(&directive_name), - directive_name: directive_ln, - trailing_directive, - } + CheckDirectiveResult { is_known_directive: is_known(&directive_name), trailing_directive } } fn iter_header( @@ -845,150 +799,119 @@ fn iter_header( poisoned: &mut bool, testfile: &Path, rdr: impl Read, - it: &mut dyn FnMut(HeaderLine<'_>), + it: &mut dyn FnMut(DirectiveLine<'_>), ) { if testfile.is_dir() { return; } - // Coverage tests in coverage-run mode always have these extra directives, - // without needing to specify them manually in every test file. - // (Some of the comments below have been copied over from the old - // `tests/run-make/coverage-reports/Makefile`, which no longer exists.) + // Coverage tests in coverage-run mode always have these extra directives, without needing to + // specify them manually in every test file. (Some of the comments below have been copied over + // from the old `tests/run-make/coverage-reports/Makefile`, which no longer exists.) + // + // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later. if mode == Mode::CoverageRun { let extra_directives: &[&str] = &[ - "needs-profiler-support", - // 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. + "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 in extra_directives { - it(HeaderLine { line_number: 0, original_line: "", header_revision: None, directive }); + it(DirectiveLine { line_number: 0, header_revision: None, directive }); } } + // NOTE(jieyouxu): once we get rid of `Makefile`s we can unconditionally check for `//@`. let comment = if testfile.extension().is_some_and(|e| e == "rs") { "//@" } else { "#" }; let mut rdr = BufReader::with_capacity(1024, rdr); let mut ln = String::new(); let mut line_number = 0; - // Match on error annotations like `//~ERROR`. - static REVISION_MAGIC_COMMENT_RE: OnceLock<Regex> = OnceLock::new(); - let revision_magic_comment_re = - REVISION_MAGIC_COMMENT_RE.get_or_init(|| Regex::new("//(\\[.*\\])?~.*").unwrap()); - loop { line_number += 1; ln.clear(); if rdr.read_line(&mut ln).unwrap() == 0 { break; } - - // Assume that any directives will be found before the first - // module or function. This doesn't seem to be an optimization - // with a warm page cache. Maybe with a cold one. - let original_line = &ln; let ln = ln.trim(); + + // Assume that any directives will be found before the first module or function. This + // doesn't seem to be an optimization with a warm page cache. Maybe with a cold one. + // FIXME(jieyouxu): this will cause `//@` directives in the rest of the test file to + // not be checked. if ln.starts_with("fn") || ln.starts_with("mod") { return; + } - // First try to accept `ui_test` style comments (`//@`) - } else if let Some((header_revision, non_revisioned_directive_line)) = - line_directive(comment, ln) - { - // Perform unknown directive check on Rust files. - if testfile.extension().map(|e| e == "rs").unwrap_or(false) { - let directive_ln = non_revisioned_directive_line.trim(); - - let CheckDirectiveResult { is_known_directive, trailing_directive, .. } = - check_directive(directive_ln, mode, ln); - - if !is_known_directive { - *poisoned = true; - - eprintln!( - "error: detected unknown compiletest test directive `{}` in {}:{}", - directive_ln, - testfile.display(), - line_number, - ); - - return; - } + let Some((header_revision, non_revisioned_directive_line)) = line_directive(comment, ln) + else { + continue; + }; - if let Some(trailing_directive) = &trailing_directive { - *poisoned = true; + // Perform unknown directive check on Rust files. + if testfile.extension().map(|e| e == "rs").unwrap_or(false) { + let directive_ln = non_revisioned_directive_line.trim(); - eprintln!( - "error: detected trailing compiletest test directive `{}` in {}:{}\n \ - help: put the trailing directive in it's own line: `//@ {}`", - trailing_directive, - testfile.display(), - line_number, - trailing_directive, - ); + let CheckDirectiveResult { is_known_directive, trailing_directive } = + check_directive(directive_ln, mode, ln); - return; - } - } + if !is_known_directive { + *poisoned = true; - it(HeaderLine { - line_number, - original_line, - header_revision, - directive: non_revisioned_directive_line, - }); - // Then we try to check for legacy-style candidates, which are not the magic ~ERROR family - // error annotations. - } else if !revision_magic_comment_re.is_match(ln) { - let Some((_, rest)) = line_directive("//", ln) else { - continue; - }; + eprintln!( + "error: detected unknown compiletest test directive `{}` in {}:{}", + directive_ln, + testfile.display(), + line_number, + ); - if rest.trim_start().starts_with(':') { - // This is likely a markdown link: - // `[link_name]: https://example.org` - continue; + return; } - let rest = rest.trim_start(); - - let CheckDirectiveResult { is_known_directive, directive_name, .. } = - check_directive(rest, mode, ln); - - if is_known_directive { + if let Some(trailing_directive) = &trailing_directive { *poisoned = true; + eprintln!( - "error: detected legacy-style directive {} in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead: {:#?}", - directive_name, + "error: detected trailing compiletest test directive `{}` in {}:{}\n \ + help: put the trailing directive in it's own line: `//@ {}`", + trailing_directive, testfile.display(), line_number, - line_directive("//", ln), + trailing_directive, ); + return; } } + + it(DirectiveLine { + line_number, + header_revision, + directive: non_revisioned_directive_line, + }); } } impl Config { - fn parse_aux_crate(r: String) -> (String, String) { - let mut parts = r.trim().splitn(2, '='); - ( - parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), - parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), - ) - } - - fn parse_and_update_revisions(&self, line: &str, existing: &mut Vec<String>) { + fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec<String>) { if let Some(raw) = self.parse_name_value_directive(line, "revisions") { + if self.mode == Mode::RunMake { + panic!("`run-make` tests do not support revisions: {}", testfile.display()); + } + let mut duplicates: HashSet<_> = existing.iter().cloned().collect(); for revision in raw.split_whitespace().map(|r| r.to_string()) { if !duplicates.insert(revision.clone()) { - panic!("Duplicate revision: `{}` in line `{}`", revision, raw); + panic!( + "duplicate revision: `{}` in line `{}`: {}", + revision, + raw, + testfile.display() + ); } existing.push(revision); } @@ -1362,13 +1285,14 @@ pub fn make_test_description<R: Read>( let mut local_poisoned = false; + // Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives. iter_header( config.mode, &config.suite, &mut local_poisoned, path, src, - &mut |HeaderLine { header_revision, original_line, directive: ln, line_number }| { + &mut |DirectiveLine { header_revision, directive: ln, line_number }| { if header_revision.is_some() && header_revision != test_revision { return; } @@ -1393,17 +1317,7 @@ pub fn make_test_description<R: Read>( }; } - if let Some((_, post)) = original_line.trim_start().split_once("//") { - let post = post.trim_start(); - if post.starts_with("ignore-tidy") { - // Not handled by compiletest. - } else { - decision!(cfg::handle_ignore(config, ln)); - } - } else { - decision!(cfg::handle_ignore(config, ln)); - } - + decision!(cfg::handle_ignore(config, ln)); decision!(cfg::handle_only(config, ln)); decision!(needs::handle_needs(&cache.needs, config, ln)); decision!(ignore_llvm(config, ln)); diff --git a/src/tools/compiletest/src/header/auxiliary.rs b/src/tools/compiletest/src/header/auxiliary.rs new file mode 100644 index 00000000000..6f6538ce196 --- /dev/null +++ b/src/tools/compiletest/src/header/auxiliary.rs @@ -0,0 +1,60 @@ +//! Code for dealing with test directives that request an "auxiliary" crate to +//! be built and made available to the test in some way. + +use std::iter; + +use crate::common::Config; +use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE}; + +/// Properties parsed from `aux-*` test directives. +#[derive(Clone, Debug, Default)] +pub(crate) struct AuxProps { + /// Other crates that should be built and made available to this test. + /// These are filenames relative to `./auxiliary/` in the test's directory. + pub(crate) builds: Vec<String>, + /// Auxiliary crates that should be compiled as `#![crate_type = "bin"]`. + pub(crate) bins: Vec<String>, + /// Similar to `builds`, but a list of NAME=somelib.rs of dependencies + /// to build and pass with the `--extern` flag. + pub(crate) crates: Vec<(String, String)>, + /// Similar to `builds`, but also uses the resulting dylib as a + /// `-Zcodegen-backend` when compiling the test file. + pub(crate) codegen_backend: Option<String>, +} + +impl AuxProps { + /// Yields all of the paths (relative to `./auxiliary/`) that have been + /// specified in `aux-*` directives for this test. + pub(crate) fn all_aux_path_strings(&self) -> impl Iterator<Item = &str> { + let Self { builds, bins, crates, codegen_backend } = self; + + iter::empty() + .chain(builds.iter().map(String::as_str)) + .chain(bins.iter().map(String::as_str)) + .chain(crates.iter().map(|(_, path)| path.as_str())) + .chain(codegen_backend.iter().map(String::as_str)) + } +} + +/// If the given test directive line contains an `aux-*` directive, parse it +/// and update [`AuxProps`] accordingly. +pub(super) fn parse_and_update_aux(config: &Config, ln: &str, aux: &mut AuxProps) { + if !ln.starts_with("aux-") { + return; + } + + config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string()); + config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string()); + config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate); + if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) { + aux.codegen_backend = Some(r.trim().to_owned()); + } +} + +fn parse_aux_crate(r: String) -> (String, String) { + let mut parts = r.trim().splitn(2, '='); + ( + parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), + parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), + ) +} diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 948568e63c2..b9314f0abbb 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crate::common::{CompareMode, Config, Debugger, Mode}; +use crate::common::{CompareMode, Config, Debugger}; use crate::header::IgnoreDecision; const EXTRA_ARCHS: &[&str] = &["spirv"]; @@ -166,6 +166,12 @@ pub(super) fn parse_cfg_name_directive<'a>( message: "when the target vendor is Apple" } + condition! { + name: "enzyme", + condition: config.has_enzyme, + message: "when rustc is built with LLVM Enzyme" + } + // Technically the locally built compiler uses the "dev" channel rather than the "nightly" // channel, even though most people don't know or won't care about it. To avoid confusion, we // treat the "dev" channel as the "nightly" channel when processing the directive. @@ -217,13 +223,10 @@ pub(super) fn parse_cfg_name_directive<'a>( } // Coverage tests run the same test file in multiple modes. // If a particular test should not be run in one of the modes, ignore it - // with "ignore-mode-coverage-map" or "ignore-mode-coverage-run". + // with "ignore-coverage-map" or "ignore-coverage-run". condition! { - name: format!("mode-{}", config.mode.to_str()), - allowed_names: ContainsPrefixed { - prefix: "mode-", - inner: Mode::STR_VARIANTS, - }, + name: config.mode.to_str(), + allowed_names: ["coverage-map", "coverage-run"], message: "when the test mode is {name}", } diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index f5dd722ed37..a744fb61b9c 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -100,9 +100,9 @@ pub(super) fn handle_needs( ignore_reason: "ignored on targets without unwinding support", }, Need { - name: "needs-profiler-support", - condition: cache.profiler_support, - ignore_reason: "ignored when profiler support is disabled", + name: "needs-profiler-runtime", + condition: config.profiler_runtime, + ignore_reason: "ignored when the profiler runtime is not available", }, Need { name: "needs-force-clang-based-tests", @@ -220,7 +220,6 @@ pub(super) struct CachedNeedsConditions { sanitizer_memtag: bool, sanitizer_shadow_call_stack: bool, sanitizer_safestack: bool, - profiler_support: bool, xray: bool, rust_lld: bool, dlltool: bool, @@ -247,7 +246,6 @@ impl CachedNeedsConditions { sanitizer_memtag: sanitizers.contains(&Sanitizer::Memtag), sanitizer_shadow_call_stack: sanitizers.contains(&Sanitizer::ShadowCallStack), sanitizer_safestack: sanitizers.contains(&Sanitizer::Safestack), - profiler_support: config.profiler_support, xray: config.target_cfg().xray, // For tests using the `needs-rust-lld` directive (e.g. for `-Clink-self-contained=+linker`), diff --git a/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs b/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs deleted file mode 100644 index 108ca432e13..00000000000 --- a/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs +++ /dev/null @@ -1 +0,0 @@ -// ignore-wasm diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index ae661200c6c..c3c9496c4d2 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -1,6 +1,5 @@ use std::io::Read; use std::path::Path; -use std::str::FromStr; use super::iter_header; use crate::common::{Config, Debugger, Mode}; @@ -70,7 +69,7 @@ struct ConfigBuilder { llvm_version: Option<String>, git_hash: bool, system_llvm: bool, - profiler_support: bool, + profiler_runtime: bool, } impl ConfigBuilder { @@ -114,8 +113,8 @@ impl ConfigBuilder { self } - fn profiler_support(&mut self, s: bool) -> &mut Self { - self.profiler_support = s; + fn profiler_runtime(&mut self, is_available: bool) -> &mut Self { + self.profiler_runtime = is_available; self } @@ -163,8 +162,8 @@ impl ConfigBuilder { if self.system_llvm { args.push("--system-llvm".to_owned()); } - if self.profiler_support { - args.push("--profiler-support".to_owned()); + if self.profiler_runtime { + args.push("--profiler-runtime".to_owned()); } args.push("--rustc-path".to_string()); @@ -243,7 +242,8 @@ fn aux_build() { //@ aux-build: b.rs " ) - .aux, + .aux + .builds, vec!["a.rs", "b.rs"], ); } @@ -369,12 +369,12 @@ fn sanitizers() { } #[test] -fn profiler_support() { - let config: Config = cfg().profiler_support(false).build(); - assert!(check_ignore(&config, "//@ needs-profiler-support")); +fn profiler_runtime() { + let config: Config = cfg().profiler_runtime(false).build(); + assert!(check_ignore(&config, "//@ needs-profiler-runtime")); - let config: Config = cfg().profiler_support(true).build(); - assert!(!check_ignore(&config, "//@ needs-profiler-support")); + let config: Config = cfg().profiler_runtime(true).build(); + assert!(!check_ignore(&config, "//@ needs-profiler-runtime")); } #[test] @@ -423,7 +423,7 @@ fn test_extract_version_range() { } #[test] -#[should_panic(expected = "Duplicate revision: `rpass1` in line ` rpass1 rpass1`")] +#[should_panic(expected = "duplicate revision: `rpass1` in line ` rpass1 rpass1`")] fn test_duplicate_revisions() { let config: Config = cfg().build(); parse_rs(&config, "//@ revisions: rpass1 rpass1"); @@ -573,19 +573,15 @@ fn families() { } #[test] -fn ignore_mode() { - for &mode in Mode::STR_VARIANTS { - // Indicate profiler support so that "coverage-run" tests aren't skipped. - let config: Config = cfg().mode(mode).profiler_support(true).build(); - let other = if mode == "coverage-run" { "coverage-map" } else { "coverage-run" }; +fn ignore_coverage() { + // Indicate profiler runtime availability so that "coverage-run" tests aren't skipped. + let config = cfg().mode("coverage-map").profiler_runtime(true).build(); + assert!(check_ignore(&config, "//@ ignore-coverage-map")); + assert!(!check_ignore(&config, "//@ ignore-coverage-run")); - assert_ne!(mode, other); - assert_eq!(config.mode, Mode::from_str(mode).unwrap()); - assert_ne!(config.mode, Mode::from_str(other).unwrap()); - - assert!(check_ignore(&config, &format!("//@ ignore-mode-{mode}"))); - assert!(!check_ignore(&config, &format!("//@ ignore-mode-{other}"))); - } + let config = cfg().mode("coverage-run").profiler_runtime(true).build(); + assert!(!check_ignore(&config, "//@ ignore-coverage-map")); + assert!(check_ignore(&config, "//@ ignore-coverage-run")); } #[test] @@ -622,17 +618,6 @@ fn test_unknown_directive_check() { } #[test] -fn test_known_legacy_directive_check() { - let mut poisoned = false; - run_path( - &mut poisoned, - Path::new("a.rs"), - include_bytes!("./test-auxillary/known_legacy_directive.rs"), - ); - assert!(poisoned); -} - -#[test] fn test_known_directive_check_no_error() { let mut poisoned = false; run_path( diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a8355ee9590..18000e5602c 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -10,6 +10,7 @@ mod tests; pub mod common; pub mod compute_diff; +mod debuggers; pub mod errors; pub mod header; mod json; @@ -36,8 +37,8 @@ use walkdir::WalkDir; use self::header::{EarlyProps, make_test_description}; use crate::common::{ - Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path, - output_base_dir, output_relative_path, + Config, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path, output_base_dir, + output_relative_path, }; use crate::header::HeadersCache; use crate::util::logv; @@ -53,8 +54,6 @@ pub fn parse_config(args: Vec<String>) -> Config { .reqopt("", "python", "path to python to use for doc tests", "PATH") .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") - .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") - .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") .reqopt("", "src-base", "directory to scan for test files", "PATH") @@ -65,7 +64,7 @@ pub fn parse_config(args: Vec<String>) -> Config { "", "mode", "which sort of compile tests to run", - "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ + "pretty | debug-info | codegen | rustdoc \ | rustdoc-json | codegen-units | incremental | run-make | ui \ | js-doc-test | mir-opt | assembly | crashes", ) @@ -155,7 +154,7 @@ pub fn parse_config(args: Vec<String>) -> Config { .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") .optflag("", "only-modified", "only run tests that result been modified") .optflag("", "nocapture", "") - .optflag("", "profiler-support", "is the profiler runtime enabled for this target") + .optflag("", "profiler-runtime", "is the profiler runtime enabled for this target") .optflag("h", "help", "show this message") .reqopt("", "channel", "current Rust channel", "CHANNEL") .optflag( @@ -206,9 +205,11 @@ pub fn parse_config(args: Vec<String>) -> Config { let target = opt_str2(matches.opt_str("target")); let android_cross_path = opt_path(matches, "android-cross-path"); - let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); - let (gdb, gdb_version) = analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); - let lldb_version = matches.opt_str("lldb-version").as_deref().and_then(extract_lldb_version); + let (cdb, cdb_version) = debuggers::analyze_cdb(matches.opt_str("cdb"), &target); + let (gdb, gdb_version) = + debuggers::analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); + let lldb_version = + matches.opt_str("lldb-version").as_deref().and_then(debuggers::extract_lldb_version); let color = match matches.opt_str("color").as_deref() { Some("auto") | None => ColorConfig::AutoColor, Some("always") => ColorConfig::AlwaysColor, @@ -269,8 +270,6 @@ pub fn parse_config(args: Vec<String>) -> Config { python: matches.opt_str("python").unwrap(), jsondocck_path: matches.opt_str("jsondocck-path"), jsondoclint_path: matches.opt_str("jsondoclint-path"), - valgrind_path: matches.opt_str("valgrind-path"), - force_valgrind: matches.opt_present("force-valgrind"), run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), @@ -359,7 +358,7 @@ pub fn parse_config(args: Vec<String>) -> Config { nightly_branch: matches.opt_str("nightly-branch").unwrap(), git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(), - profiler_support: matches.opt_present("profiler-support"), + profiler_runtime: matches.opt_present("profiler-runtime"), } } @@ -447,9 +446,9 @@ pub fn run_tests(config: Arc<Config>) { if let Mode::DebugInfo = config.mode { // Debugging emscripten code doesn't make sense today if !config.target.contains("emscripten") { - configs.extend(configure_cdb(&config)); - configs.extend(configure_gdb(&config)); - configs.extend(configure_lldb(&config)); + configs.extend(debuggers::configure_cdb(&config)); + configs.extend(debuggers::configure_gdb(&config)); + configs.extend(debuggers::configure_lldb(&config)); } } else { configs.push(config.clone()); @@ -502,62 +501,6 @@ pub fn run_tests(config: Arc<Config>) { } } -fn configure_cdb(config: &Config) -> Option<Arc<Config>> { - config.cdb.as_ref()?; - - Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) -} - -fn configure_gdb(config: &Config) -> Option<Arc<Config>> { - config.gdb_version?; - - if config.matches_env("msvc") { - return None; - } - - if config.remote_test_client.is_some() && !config.target.contains("android") { - println!( - "WARNING: debuginfo tests are not available when \ - testing with remote" - ); - return None; - } - - if config.target.contains("android") { - println!( - "{} debug-info test uses tcp 5039 port.\ - please reserve it", - config.target - ); - - // android debug-info test uses remote debugger so, we test 1 thread - // at once as they're all sharing the same TCP port to communicate - // over. - // - // we should figure out how to lift this restriction! (run them all - // on different ports allocated dynamically). - env::set_var("RUST_TEST_THREADS", "1"); - } - - Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) -} - -fn configure_lldb(config: &Config) -> Option<Arc<Config>> { - config.lldb_python_dir.as_ref()?; - - if let Some(350) = config.lldb_version { - println!( - "WARNING: The used version of LLDB (350) has a \ - known issue that breaks debuginfo tests. See \ - issue #32520 for more information. Skipping all \ - LLDB-based tests!", - ); - return None; - } - - Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) -} - pub fn test_opts(config: &Config) -> test::TestOpts { if env::var("RUST_TEST_NOCAPTURE").is_ok() { eprintln!( @@ -866,7 +809,8 @@ fn files_related_to_test( related.push(testpaths.file.clone()); } - for aux in &props.aux { + for aux in props.aux.all_aux_path_strings() { + // FIXME(Zalathar): Perform all `auxiliary` path resolution in one place. let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); related.push(path); } @@ -984,212 +928,6 @@ fn make_test_closure( })) } -/// Returns `true` if the given target is an Android target for the -/// purposes of GDB testing. -fn is_android_gdb_target(target: &str) -> bool { - matches!( - &target[..], - "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" - ) -} - -/// Returns `true` if the given target is a MSVC target for the purposes of CDB testing. -fn is_pc_windows_msvc_target(target: &str) -> bool { - target.ends_with("-pc-windows-msvc") -} - -fn find_cdb(target: &str) -> Option<OsString> { - if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { - return None; - } - - let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; - let cdb_arch = if cfg!(target_arch = "x86") { - "x86" - } else if cfg!(target_arch = "x86_64") { - "x64" - } else if cfg!(target_arch = "aarch64") { - "arm64" - } else if cfg!(target_arch = "arm") { - "arm" - } else { - return None; // No compatible CDB.exe in the Windows 10 SDK - }; - - let mut path = PathBuf::new(); - path.push(pf86); - path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? - path.push(cdb_arch); - path.push(r"cdb.exe"); - - if !path.exists() { - return None; - } - - Some(path.into_os_string()) -} - -/// Returns Path to CDB -fn analyze_cdb(cdb: Option<String>, target: &str) -> (Option<OsString>, Option<[u16; 4]>) { - let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); - - let mut version = None; - if let Some(cdb) = cdb.as_ref() { - if let Ok(output) = Command::new(cdb).arg("/version").output() { - if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { - version = extract_cdb_version(&first_line); - } - } - } - - (cdb, version) -} - -fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { - // Example full_version_line: "cdb version 10.0.18362.1" - let version = full_version_line.rsplit(' ').next()?; - let mut components = version.split('.'); - let major: u16 = components.next().unwrap().parse().unwrap(); - let minor: u16 = components.next().unwrap().parse().unwrap(); - let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); - let build: u16 = components.next().unwrap_or("0").parse().unwrap(); - Some([major, minor, patch, build]) -} - -/// Returns (Path to GDB, GDB Version) -fn analyze_gdb( - gdb: Option<String>, - target: &str, - android_cross_path: &PathBuf, -) -> (Option<String>, Option<u32>) { - #[cfg(not(windows))] - const GDB_FALLBACK: &str = "gdb"; - #[cfg(windows)] - const GDB_FALLBACK: &str = "gdb.exe"; - - let fallback_gdb = || { - if is_android_gdb_target(target) { - let mut gdb_path = match android_cross_path.to_str() { - Some(x) => x.to_owned(), - None => panic!("cannot find android cross path"), - }; - gdb_path.push_str("/bin/gdb"); - gdb_path - } else { - GDB_FALLBACK.to_owned() - } - }; - - let gdb = match gdb { - None => fallback_gdb(), - Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb - Some(ref s) => s.to_owned(), - }; - - let mut version_line = None; - if let Ok(output) = Command::new(&gdb).arg("--version").output() { - if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { - version_line = Some(first_line.to_string()); - } - } - - let version = match version_line { - Some(line) => extract_gdb_version(&line), - None => return (None, None), - }; - - (Some(gdb), version) -} - -fn extract_gdb_version(full_version_line: &str) -> Option<u32> { - let full_version_line = full_version_line.trim(); - - // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both - // of the ? sections being optional - - // We will parse up to 3 digits for each component, ignoring the date - - // We skip text in parentheses. This avoids accidentally parsing - // the openSUSE version, which looks like: - // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 - // This particular form is documented in the GNU coding standards: - // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion - - let unbracketed_part = full_version_line.split('[').next().unwrap(); - let mut splits = unbracketed_part.trim_end().rsplit(' '); - let version_string = splits.next().unwrap(); - - let mut splits = version_string.split('.'); - let major = splits.next().unwrap(); - let minor = splits.next().unwrap(); - let patch = splits.next(); - - let major: u32 = major.parse().unwrap(); - let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { - None => { - let minor = minor.parse().unwrap(); - let patch: u32 = match patch { - Some(patch) => match patch.find(not_a_digit) { - None => patch.parse().unwrap(), - Some(idx) if idx > 3 => 0, - Some(idx) => patch[..idx].parse().unwrap(), - }, - None => 0, - }; - (minor, patch) - } - // There is no patch version after minor-date (e.g. "4-2012"). - Some(idx) => { - let minor = minor[..idx].parse().unwrap(); - (minor, 0) - } - }; - - Some(((major * 1000) + minor) * 1000 + patch) -} - -/// Returns LLDB version -fn extract_lldb_version(full_version_line: &str) -> Option<u32> { - // Extract the major LLDB version from the given version string. - // LLDB version strings are different for Apple and non-Apple platforms. - // The Apple variant looks like this: - // - // LLDB-179.5 (older versions) - // lldb-300.2.51 (new versions) - // - // We are only interested in the major version number, so this function - // will return `Some(179)` and `Some(300)` respectively. - // - // Upstream versions look like: - // lldb version 6.0.1 - // - // There doesn't seem to be a way to correlate the Apple version - // with the upstream version, and since the tests were originally - // written against Apple versions, we make a fake Apple version by - // multiplying the first number by 100. This is a hack. - - let full_version_line = full_version_line.trim(); - - if let Some(apple_ver) = - full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) - { - if let Some(idx) = apple_ver.find(not_a_digit) { - let version: u32 = apple_ver[..idx].parse().unwrap(); - return Some(version); - } - } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { - if let Some(idx) = lldb_ver.find(not_a_digit) { - let version: u32 = lldb_ver[..idx].parse().ok()?; - return Some(version * 100); - } - } - None -} - -fn not_a_digit(c: char) -> bool { - !c.is_ascii_digit() -} - fn check_overlapping_tests(found_paths: &HashSet<PathBuf>) { let mut collisions = Vec::new(); for path in found_paths { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 7b85e6f80b3..b0f87593f95 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -18,15 +18,11 @@ fn main() { let config = Arc::new(parse_config(env::args().collect())); - if config.valgrind_path.is_none() && config.force_valgrind { - panic!("Can't find Valgrind to run Valgrind tests"); - } - if !config.has_tidy && config.mode == Mode::Rustdoc { eprintln!("warning: `tidy` is not installed; diffs will not be generated"); } - if !config.profiler_support && config.mode == Mode::CoverageRun { + if !config.profiler_runtime && config.mode == Mode::CoverageRun { let actioned = if config.bless { "blessed" } else { "checked" }; eprintln!( r#" diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 74d86d2b521..29f9925de16 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -20,9 +20,9 @@ use tracing::*; use crate::common::{ Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes, DebugInfo, Debugger, FailMode, Incremental, JsDocTest, MirOpt, PassMode, Pretty, RunMake, - RunPassValgrind, Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, - UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, - incremental_dir, output_base_dir, output_base_name, output_testname_unique, + Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, + UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir, + output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; @@ -49,7 +49,6 @@ mod run_make; mod rustdoc; mod rustdoc_json; mod ui; -mod valgrind; // tidy-alphabet-end #[cfg(test)] @@ -253,7 +252,6 @@ impl<'test> TestCx<'test> { self.fatal("cannot use should-ice in a test that is not cfail"); } match self.config.mode { - RunPassValgrind => self.run_valgrind_test(), Pretty => self.run_pretty_test(), DebugInfo => self.run_debuginfo_test(), Codegen => self.run_codegen_test(), @@ -320,10 +318,29 @@ impl<'test> TestCx<'test> { } } - fn check_if_test_should_compile(&self, proc_res: &ProcRes, pm: Option<PassMode>) { - if self.should_compile_successfully(pm) { + fn check_if_test_should_compile( + &self, + fail_mode: Option<FailMode>, + pass_mode: Option<PassMode>, + proc_res: &ProcRes, + ) { + if self.should_compile_successfully(pass_mode) { if !proc_res.status.success() { - self.fatal_proc_rec("test compilation failed although it shouldn't!", proc_res); + match (fail_mode, pass_mode) { + (Some(FailMode::Build), Some(PassMode::Check)) => { + // A `build-fail` test needs to `check-pass`. + self.fatal_proc_rec( + "`build-fail` test is required to pass check build, but check build failed", + proc_res, + ); + } + _ => { + self.fatal_proc_rec( + "test compilation failed although it shouldn't!", + proc_res, + ); + } + } } } else { if proc_res.status.success() { @@ -843,13 +860,13 @@ impl<'test> TestCx<'test> { /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths. fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes { if self.props.build_aux_docs { - for rel_ab in &self.props.aux_builds { + for rel_ab in &self.props.aux.builds { let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab); - let aux_props = + let props_for_aux = self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config); let aux_cx = TestCx { config: self.config, - props: &aux_props, + props: &props_for_aux, testpaths: &aux_testpaths, revision: self.revision, }; @@ -1061,11 +1078,11 @@ impl<'test> TestCx<'test> { fn aux_output_dir(&self) -> PathBuf { let aux_dir = self.aux_output_dir_name(); - if !self.props.aux_builds.is_empty() { + if !self.props.aux.builds.is_empty() { remove_and_create_dir_all(&aux_dir); } - if !self.props.aux_bins.is_empty() { + if !self.props.aux.bins.is_empty() { let aux_bin_dir = self.aux_bin_output_dir_name(); remove_and_create_dir_all(&aux_dir); remove_and_create_dir_all(&aux_bin_dir); @@ -1075,15 +1092,15 @@ impl<'test> TestCx<'test> { } fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) { - for rel_ab in &self.props.aux_builds { + for rel_ab in &self.props.aux.builds { self.build_auxiliary(of, rel_ab, &aux_dir, false /* is_bin */); } - for rel_ab in &self.props.aux_bins { + for rel_ab in &self.props.aux.bins { self.build_auxiliary(of, rel_ab, &aux_dir, true /* is_bin */); } - for (aux_name, aux_path) in &self.props.aux_crates { + for (aux_name, aux_path) in &self.props.aux.crates { let aux_type = self.build_auxiliary(of, &aux_path, &aux_dir, false /* is_bin */); let lib_name = get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), aux_type); @@ -1099,7 +1116,7 @@ impl<'test> TestCx<'test> { // Build any `//@ aux-codegen-backend`, and pass the resulting library // to `-Zcodegen-backend` when compiling the test file. - if let Some(aux_file) = &self.props.aux_codegen_backend { + if let Some(aux_file) = &self.props.aux.codegen_backend { let aux_type = self.build_auxiliary(of, aux_file, aux_dir, false); if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) { let lib_path = aux_dir.join(&lib_name); @@ -1500,8 +1517,7 @@ impl<'test> TestCx<'test> { Crashes => { set_mir_dump_dir(&mut rustc); } - RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake - | CodegenUnits | JsDocTest => { + Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | JsDocTest => { // do not use JSON output } } @@ -1783,58 +1799,14 @@ impl<'test> TestCx<'test> { proc_res.fatal(None, || on_failure(*self)); } - fn get_output_file(&self, extension: &str) -> TargetLocation { - let thin_lto = self.props.compile_flags.iter().any(|s| s.ends_with("lto=thin")); - if thin_lto { - TargetLocation::ThisDirectory(self.output_base_dir()) - } else { - // This works with both `--emit asm` (as default output name for the assembly) - // and `ptx-linker` because the latter can write output at requested location. - let output_path = self.output_base_name().with_extension(extension); - - TargetLocation::ThisFile(output_path.clone()) - } - } - - fn get_filecheck_file(&self, extension: &str) -> PathBuf { - let thin_lto = self.props.compile_flags.iter().any(|s| s.ends_with("lto=thin")); - if thin_lto { - let name = self.testpaths.file.file_stem().unwrap().to_str().unwrap(); - let canonical_name = name.replace('-', "_"); - let mut output_file = None; - for entry in self.output_base_dir().read_dir().unwrap() { - if let Ok(entry) = entry { - let entry_path = entry.path(); - let entry_file = entry_path.file_name().unwrap().to_str().unwrap(); - if entry_file.starts_with(&format!("{}.{}", name, canonical_name)) - && entry_file.ends_with(extension) - { - assert!( - output_file.is_none(), - "thinlto doesn't support multiple cgu tests" - ); - output_file = Some(entry_file.to_string()); - } - } - } - if let Some(output_file) = output_file { - self.output_base_dir().join(output_file) - } else { - self.output_base_name().with_extension(extension) - } - } else { - self.output_base_name().with_extension(extension) - } - } - // codegen tests (using FileCheck) fn compile_test_and_save_ir(&self) -> (ProcRes, PathBuf) { - let output_file = self.get_output_file("ll"); + let output_path = self.output_base_name().with_extension("ll"); let input_file = &self.testpaths.file; let rustc = self.make_compile_args( input_file, - output_file, + TargetLocation::ThisFile(output_path.clone()), Emit::LlvmIr, AllowUnused::No, LinkToAux::Yes, @@ -1842,35 +1814,27 @@ impl<'test> TestCx<'test> { ); let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths); - let output_path = self.get_filecheck_file("ll"); (proc_res, output_path) } fn compile_test_and_save_assembly(&self) -> (ProcRes, PathBuf) { - let output_file = self.get_output_file("s"); + // This works with both `--emit asm` (as default output name for the assembly) + // and `ptx-linker` because the latter can write output at requested location. + let output_path = self.output_base_name().with_extension("s"); let input_file = &self.testpaths.file; - let mut emit = Emit::None; - match self.props.assembly_output.as_ref().map(AsRef::as_ref) { - Some("emit-asm") => { - emit = Emit::Asm; - } - - Some("bpf-linker") => { - emit = Emit::LinkArgsAsm; - } - - Some("ptx-linker") => { - // No extra flags needed. - } - - Some(header) => self.fatal(&format!("unknown 'assembly-output' header: {header}")), - None => self.fatal("missing 'assembly-output' header"), - } + // Use the `//@ assembly-output:` directive to determine how to emit assembly. + let emit = match self.props.assembly_output.as_deref() { + Some("emit-asm") => Emit::Asm, + Some("bpf-linker") => Emit::LinkArgsAsm, + Some("ptx-linker") => Emit::None, // No extra flags needed. + Some(other) => self.fatal(&format!("unknown 'assembly-output' directive: {other}")), + None => self.fatal("missing 'assembly-output' directive"), + }; let rustc = self.make_compile_args( input_file, - output_file, + TargetLocation::ThisFile(output_path.clone()), emit, AllowUnused::No, LinkToAux::Yes, @@ -1878,7 +1842,6 @@ impl<'test> TestCx<'test> { ); let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths); - let output_path = self.get_filecheck_file("s"); (proc_res, output_path) } @@ -2109,6 +2072,10 @@ impl<'test> TestCx<'test> { .collect() } + /// This method is used for `//@ check-test-line-numbers-match`. + /// + /// It checks that doctests line in the displayed doctest "name" matches where they are + /// defined in source code. fn check_rustdoc_test_option(&self, res: ProcRes) { let mut other_files = Vec::new(); let mut files: HashMap<String, Vec<usize>> = HashMap::new(); @@ -2651,33 +2618,6 @@ impl<'test> TestCx<'test> { } } - // FIXME(jieyouxu): `run_rpass_test` is hoisted out here and not in incremental because - // apparently valgrind test falls back to `run_rpass_test` if valgrind isn't available, which - // seems highly questionable to me. - fn run_rpass_test(&self) { - let emit_metadata = self.should_emit_metadata(self.pass_mode()); - let should_run = self.run_if_enabled(); - let proc_res = self.compile_test(should_run, emit_metadata); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - // FIXME(#41968): Move this check to tidy? - if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { - self.fatal("run-pass tests with expected warnings should be moved to ui/"); - } - - if let WillExecute::Disabled = should_run { - return; - } - - let proc_res = self.exec_compiled_test(); - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } - fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> { for e in path.read_dir()? { let entry = e?; diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 36127414ab1..bd0845b4524 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -9,8 +9,8 @@ use tracing::debug; use super::debugger::DebuggerCommands; use super::{Debugger, Emit, ProcRes, TestCx, Truncated, WillExecute}; use crate::common::Config; +use crate::debuggers::{extract_gdb_version, is_android_gdb_target}; use crate::util::logv; -use crate::{extract_gdb_version, is_android_gdb_target}; impl TestCx<'_> { pub(super) fn run_debuginfo_test(&self) { diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index 81b006292e4..591aff0defe 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -1,10 +1,6 @@ -use super::{TestCx, WillExecute}; +use super::{FailMode, TestCx, WillExecute}; use crate::errors; -// FIXME(jieyouxu): `run_rpass_test` got hoisted out of this because apparently valgrind falls back -// to `run_rpass_test` if valgrind isn't available, which is questionable, but keeping it for -// refactoring changes to preserve current behavior. - impl TestCx<'_> { pub(super) fn run_incremental_test(&self) { // Basic plan for a test incremental/foo/bar.rs: @@ -73,10 +69,34 @@ impl TestCx<'_> { } } + fn run_rpass_test(&self) { + let emit_metadata = self.should_emit_metadata(self.pass_mode()); + let should_run = self.run_if_enabled(); + let proc_res = self.compile_test(should_run, emit_metadata); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + // FIXME(#41968): Move this check to tidy? + if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { + self.fatal("run-pass tests with expected warnings should be moved to ui/"); + } + + if let WillExecute::Disabled = should_run { + return; + } + + let proc_res = self.exec_compiled_test(); + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + } + fn run_cfail_test(&self) { let pm = self.pass_mode(); let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); - self.check_if_test_should_compile(&proc_res, pm); + self.check_if_test_should_compile(Some(FailMode::Build), pm, &proc_res); self.check_no_compiler_crash(&proc_res, self.props.should_ice); let output_to_check = self.get_output(&proc_res); @@ -115,12 +135,6 @@ impl TestCx<'_> { let proc_res = self.exec_compiled_test(); - // The value our Makefile configures valgrind to return on failure - const VALGRIND_ERR: i32 = 100; - if proc_res.status.code() == Some(VALGRIND_ERR) { - self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res); - } - let output_to_check = self.get_output(&proc_res); self.check_correct_failure_status(&proc_res); self.check_all_error_patterns(&output_to_check, &proc_res, pm); diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index bd8ef952a86..bb747c68029 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -18,14 +18,14 @@ impl TestCx<'_> { let pm = Some(PassMode::Check); let proc_res = self.compile_test_general(WillExecute::No, Emit::Metadata, pm, Vec::new()); - self.check_if_test_should_compile(&proc_res, pm); + self.check_if_test_should_compile(self.props.fail_mode, pm, &proc_res); } let pm = self.pass_mode(); let should_run = self.should_run(pm); let emit_metadata = self.should_emit_metadata(pm); let proc_res = self.compile_test(should_run, emit_metadata); - self.check_if_test_should_compile(&proc_res, pm); + self.check_if_test_should_compile(self.props.fail_mode, pm, &proc_res); if matches!(proc_res.truncated, Truncated::Yes) && !self.props.dont_check_compiler_stdout && !self.props.dont_check_compiler_stderr diff --git a/src/tools/compiletest/src/runtest/valgrind.rs b/src/tools/compiletest/src/runtest/valgrind.rs deleted file mode 100644 index 8d72c4be9ff..00000000000 --- a/src/tools/compiletest/src/runtest/valgrind.rs +++ /dev/null @@ -1,34 +0,0 @@ -use super::{Emit, TestCx, WillExecute}; - -impl TestCx<'_> { - pub(super) fn run_valgrind_test(&self) { - assert!(self.revision.is_none(), "revisions not relevant here"); - - // FIXME(jieyouxu): does this really make any sense? If a valgrind test isn't testing - // valgrind, what is it even testing? - if self.config.valgrind_path.is_none() { - assert!(!self.config.force_valgrind); - return self.run_rpass_test(); - } - - let should_run = self.run_if_enabled(); - let mut proc_res = self.compile_test(should_run, Emit::None); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - if let WillExecute::Disabled = should_run { - return; - } - - let mut new_config = self.config.clone(); - new_config.runner = new_config.valgrind_path.clone(); - let new_cx = TestCx { config: &new_config, ..*self }; - proc_res = new_cx.exec_compiled_test(); - - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } -} diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 7c2e7b0f023..680579c59ae 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,5 +1,8 @@ -use super::header::extract_llvm_version; -use super::*; +use std::ffi::OsString; + +use crate::debuggers::{extract_gdb_version, extract_lldb_version}; +use crate::header::extract_llvm_version; +use crate::is_test; #[test] fn test_extract_gdb_version() { diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index c779dd0583c..33fac3edccd 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -56,6 +56,7 @@ pub(crate) fn dump_covfun_mappings( expression_resolver.push_operands(lhs, rhs); } + let mut max_counter = None; for i in 0..num_files { let num_mappings = parser.read_uleb128_u32()?; println!("Number of file {i} mappings: {num_mappings}"); @@ -63,6 +64,11 @@ pub(crate) fn dump_covfun_mappings( for _ in 0..num_mappings { let (kind, region) = parser.read_mapping_kind_and_region()?; println!("- {kind:?} at {region:?}"); + kind.for_each_term(|term| { + if let CovTerm::Counter(n) = term { + max_counter = max_counter.max(Some(n)); + } + }); match kind { // Also print expression mappings in resolved form. @@ -83,6 +89,16 @@ pub(crate) fn dump_covfun_mappings( } parser.ensure_empty()?; + + // Printing the highest counter ID seen in the functions mappings makes + // it easier to determine whether a change to coverage instrumentation + // has increased or decreased the number of physical counters needed. + // (It's possible for the generated code to have more counters that + // aren't used by any mappings, but that should hopefully be rare.) + println!("Highest counter ID seen: {}", match max_counter { + Some(id) => format!("c{id}"), + None => "(none)".to_owned(), + }); println!(); } Ok(()) @@ -271,6 +287,32 @@ enum MappingKind { }, } +impl MappingKind { + fn for_each_term(&self, mut callback: impl FnMut(CovTerm)) { + match *self { + Self::Code(term) => callback(term), + Self::Gap(term) => callback(term), + Self::Expansion(_id) => {} + Self::Skip => {} + Self::Branch { r#true, r#false } => { + callback(r#true); + callback(r#false); + } + Self::MCDCBranch { + r#true, + r#false, + condition_id: _, + true_next_id: _, + false_next_id: _, + } => { + callback(r#true); + callback(r#false); + } + Self::MCDCDecision { bitmap_idx: _, conditions_num: _ } => {} + } + } +} + struct MappingRegion { /// Offset of this region's start line, relative to the *start line* of /// the *previous mapping* (or 0). Line numbers are 1-based. diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index b04919bdd3e..f7c752033c5 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -418,7 +418,7 @@ impl<'a> Validator<'a> { } else if !self.missing_ids.contains(id) { self.missing_ids.insert(id); - let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone())); + let sels = json_find::find_selector(&self.krate_json, &Value::Number(id.0.into())); assert_ne!(sels.len(), 0); self.fail(id, ErrorKind::NotFound(sels)) diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs index d15aa7db315..e842e1318db 100644 --- a/src/tools/jsondoclint/src/validator/tests.rs +++ b/src/tools/jsondoclint/src/validator/tests.rs @@ -15,24 +15,20 @@ fn check(krate: &Crate, errs: &[Error]) { assert_eq!(errs, &validator.errs[..]); } -fn id(s: &str) -> Id { - Id(s.to_owned()) -} - #[test] fn errors_on_missing_links() { let k = Crate { - root: id("0"), + root: Id(0), crate_version: None, includes_private: false, - index: FxHashMap::from_iter([(id("0"), Item { + index: FxHashMap::from_iter([(Id(0), Item { name: Some("root".to_owned()), - id: id(""), + id: Id(0), crate_id: 0, span: None, visibility: Visibility::Public, docs: None, - links: FxHashMap::from_iter([("Not Found".to_owned(), id("1"))]), + links: FxHashMap::from_iter([("Not Found".to_owned(), Id(1))]), attrs: vec![], deprecation: None, inner: ItemEnum::Module(Module { is_crate: true, items: vec![], is_stripped: false }), @@ -49,7 +45,7 @@ fn errors_on_missing_links() { SelectorPart::Field("links".to_owned()), SelectorPart::Field("Not Found".to_owned()), ]]), - id: id("1"), + id: Id(1), }]); } @@ -58,28 +54,28 @@ fn errors_on_missing_links() { #[test] fn errors_on_local_in_paths_and_not_index() { let krate = Crate { - root: id("0:0:1572"), + root: Id(0), crate_version: None, includes_private: false, index: FxHashMap::from_iter([ - (id("0:0:1572"), Item { - id: id("0:0:1572"), + (Id(0), Item { + id: Id(0), crate_id: 0, name: Some("microcore".to_owned()), span: None, visibility: Visibility::Public, docs: None, - links: FxHashMap::from_iter([(("prim@i32".to_owned(), id("0:1:1571")))]), + links: FxHashMap::from_iter([(("prim@i32".to_owned(), Id(2)))]), attrs: Vec::new(), deprecation: None, inner: ItemEnum::Module(Module { is_crate: true, - items: vec![id("0:1:717")], + items: vec![Id(1)], is_stripped: false, }), }), - (id("0:1:717"), Item { - id: id("0:1:717"), + (Id(1), Item { + id: Id(1), crate_id: 0, name: Some("i32".to_owned()), span: None, @@ -91,7 +87,7 @@ fn errors_on_local_in_paths_and_not_index() { inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }), }), ]), - paths: FxHashMap::from_iter([(id("0:1:1571"), ItemSummary { + paths: FxHashMap::from_iter([(Id(2), ItemSummary { crate_id: 0, path: vec!["microcore".to_owned(), "i32".to_owned()], kind: ItemKind::Primitive, @@ -101,7 +97,7 @@ fn errors_on_local_in_paths_and_not_index() { }; check(&krate, &[Error { - id: id("0:1:1571"), + id: Id(2), kind: ErrorKind::Custom("Id for local item in `paths` but not in `index`".to_owned()), }]); } @@ -110,11 +106,11 @@ fn errors_on_local_in_paths_and_not_index() { #[should_panic = "LOCAL_CRATE_ID is wrong"] fn checks_local_crate_id_is_correct() { let krate = Crate { - root: id("root"), + root: Id(0), crate_version: None, includes_private: false, - index: FxHashMap::from_iter([(id("root"), Item { - id: id("root"), + index: FxHashMap::from_iter([(Id(0), Item { + id: Id(0), crate_id: LOCAL_CRATE_ID.wrapping_add(1), name: Some("irrelavent".to_owned()), span: None, diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index eb4dfcf57cf..8b9e7efdff9 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -7067e4aee45c18cfa1c6af3bf79bd097684fb294 +17a19e684cdf3ca088af8b4da6a6209d128913f4 diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 5b1bad28c07..475139a3b51 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -473,14 +473,14 @@ pub fn report_leaks<'tcx>( leaks: Vec<(AllocId, MemoryKind, Allocation<Provenance, AllocExtra<'tcx>, MiriAllocBytes>)>, ) { let mut any_pruned = false; - for (id, kind, mut alloc) in leaks { + for (id, kind, alloc) in leaks { let mut title = format!( "memory leaked: {id:?} ({}, size: {:?}, align: {:?})", kind, alloc.size().bytes(), alloc.align.bytes() ); - let Some(backtrace) = alloc.extra.backtrace.take() else { + let Some(backtrace) = alloc.extra.backtrace else { ecx.tcx.dcx().err(title); continue; }; diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 75dce211dd4..9f93f151668 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -473,7 +473,7 @@ pub fn eval_entry<'tcx>( } // Check for memory leaks. info!("Additional static roots: {:?}", ecx.machine.static_roots); - let leaks = ecx.find_leaked_allocations(&ecx.machine.static_roots); + let leaks = ecx.take_leaked_allocations(|ecx| &ecx.machine.static_roots); if !leaks.is_empty() { report_leaks(&ecx, leaks); tcx.dcx().note("set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check"); diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 665dd7c441a..13eac60f911 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -295,6 +295,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } + "fmuladdf32" => { + let [a, b, c] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f32()?; + let b = this.read_scalar(b)?.to_f32()?; + let c = this.read_scalar(c)?.to_f32()?; + let fuse: bool = this.machine.rng.get_mut().gen(); + #[allow(clippy::arithmetic_side_effects)] // float ops don't overflow + let res = if fuse { + // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 + a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + } else { + ((a * b).value + c).value + }; + let res = this.adjust_nan(res, &[a, b, c]); + this.write_scalar(res, dest)?; + } + "fmuladdf64" => { + let [a, b, c] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f64()?; + let b = this.read_scalar(b)?.to_f64()?; + let c = this.read_scalar(c)?.to_f64()?; + let fuse: bool = this.machine.rng.get_mut().gen(); + #[allow(clippy::arithmetic_side_effects)] // float ops don't overflow + let res = if fuse { + // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 + a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + } else { + ((a * b).value + c).value + }; + let res = this.adjust_nan(res, &[a, b, c]); + this.write_scalar(res, dest)?; + } + "powf32" => { let [f1, f2] = check_arg_count(args)?; let f1 = this.read_scalar(f1)?.to_f32()?; diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 330147c8f1c..f089d1e1bcc 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,6 +1,5 @@ #![feature(rustc_private)] #![feature(cell_update)] -#![feature(const_option)] #![feature(float_gamma)] #![feature(map_try_insert)] #![feature(never_type)] diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 0d28a4ed3e4..af0ca00a0c0 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -321,7 +321,7 @@ impl ProvenanceExtra { } /// Extra per-allocation data -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct AllocExtra<'tcx> { /// Global state of the borrow tracker, if enabled. pub borrow_tracker: Option<borrow_tracker::AllocState>, @@ -338,6 +338,14 @@ pub struct AllocExtra<'tcx> { pub backtrace: Option<Vec<FrameInfo<'tcx>>>, } +// We need a `Clone` impl because the machine passes `Allocation` through `Cow`... +// but that should never end up actually cloning our `AllocExtra`. +impl<'tcx> Clone for AllocExtra<'tcx> { + fn clone(&self) -> Self { + panic!("our allocations should never be cloned"); + } +} + impl VisitProvenance for AllocExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _ } = self; diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 6ab18a5345e..853d3e80517 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -30,6 +30,7 @@ fn main() { libm(); test_fast(); test_algebraic(); + test_fmuladd(); } trait Float: Copy + PartialEq + Debug { @@ -1041,3 +1042,20 @@ fn test_algebraic() { test_operations_f32(11., 2.); test_operations_f32(10., 15.); } + +fn test_fmuladd() { + use std::intrinsics::{fmuladdf32, fmuladdf64}; + + #[inline(never)] + pub fn test_operations_f32(a: f32, b: f32, c: f32) { + assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c); + } + + #[inline(never)] + pub fn test_operations_f64(a: f64, b: f64, c: f64) { + assert_approx_eq!(unsafe { fmuladdf64(a, b, c) }, a * b + c); + } + + test_operations_f32(0.1, 0.2, 0.3); + test_operations_f64(1.1, 1.2, 1.3); +} diff --git a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs new file mode 100644 index 00000000000..b46cf1ddf65 --- /dev/null +++ b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs @@ -0,0 +1,44 @@ +#![feature(core_intrinsics)] +use std::intrinsics::{fmuladdf32, fmuladdf64}; + +fn main() { + let mut saw_zero = false; + let mut saw_nonzero = false; + for _ in 0..50 { + let a = std::hint::black_box(0.1_f64); + let b = std::hint::black_box(0.2); + let c = std::hint::black_box(-a * b); + // It is unspecified whether the following operation is fused or not. The + // following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused. + let x = unsafe { fmuladdf64(a, b, c) }; + if x == 0.0 { + saw_zero = true; + } else { + saw_nonzero = true; + } + } + assert!( + saw_zero && saw_nonzero, + "`fmuladdf64` failed to be evaluated as both fused and unfused" + ); + + let mut saw_zero = false; + let mut saw_nonzero = false; + for _ in 0..50 { + let a = std::hint::black_box(0.1_f32); + let b = std::hint::black_box(0.2); + let c = std::hint::black_box(-a * b); + // It is unspecified whether the following operation is fused or not. The + // following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused. + let x = unsafe { fmuladdf32(a, b, c) }; + if x == 0.0 { + saw_zero = true; + } else { + saw_nonzero = true; + } + } + assert!( + saw_zero && saw_nonzero, + "`fmuladdf32` failed to be evaluated as both fused and unfused" + ); +} diff --git a/src/tools/miri/tests/pass/underscore_pattern.rs b/src/tools/miri/tests/pass/underscore_pattern.rs index f0afe558954..f59bb9f5c82 100644 --- a/src/tools/miri/tests/pass/underscore_pattern.rs +++ b/src/tools/miri/tests/pass/underscore_pattern.rs @@ -1,5 +1,7 @@ // Various tests ensuring that underscore patterns really just construct the place, but don't check its contents. #![feature(strict_provenance)] +#![feature(never_type)] + use std::ptr; fn main() { @@ -9,6 +11,7 @@ fn main() { invalid_let(); dangling_let_type_annotation(); invalid_let_type_annotation(); + never(); } fn dangling_match() { @@ -34,6 +37,13 @@ fn invalid_match() { _ => {} } } + + unsafe { + let x: Uninit<!> = Uninit { uninit: () }; + match x.value { + _ => {} + } + } } fn dangling_let() { @@ -41,6 +51,11 @@ fn dangling_let() { let ptr = ptr::without_provenance::<bool>(0x40); let _ = *ptr; } + + unsafe { + let ptr = ptr::without_provenance::<!>(0x40); + let _ = *ptr; + } } fn invalid_let() { @@ -49,6 +64,12 @@ fn invalid_let() { let ptr = ptr::addr_of!(val).cast::<bool>(); let _ = *ptr; } + + unsafe { + let val = 3u8; + let ptr = ptr::addr_of!(val).cast::<!>(); + let _ = *ptr; + } } // Adding a type annotation used to change how MIR is generated, make sure we cover both cases. @@ -57,6 +78,11 @@ fn dangling_let_type_annotation() { let ptr = ptr::without_provenance::<bool>(0x40); let _: bool = *ptr; } + + unsafe { + let ptr = ptr::without_provenance::<!>(0x40); + let _: ! = *ptr; + } } fn invalid_let_type_annotation() { @@ -65,7 +91,28 @@ fn invalid_let_type_annotation() { let ptr = ptr::addr_of!(val).cast::<bool>(); let _: bool = *ptr; } + + unsafe { + let val = 3u8; + let ptr = ptr::addr_of!(val).cast::<!>(); + let _: ! = *ptr; + } } -// FIXME: we should also test `!`, not just `bool` -- but that s currently buggy: -// https://github.com/rust-lang/rust/issues/117288 +// Regression test from <https://github.com/rust-lang/rust/issues/117288>. +fn never() { + unsafe { + let x = 3u8; + let x: *const ! = &x as *const u8 as *const _; + let _: ! = *x; + } + + // Without a type annotation, make sure we don't implicitly coerce `!` to `()` + // when we do the noop `*x` (as that would require a `!` *value*, creating + // which is UB). + unsafe { + let x = 3u8; + let x: *const ! = &x as *const u8 as *const _; + let _ = *x; + } +} diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 82c393d34a6..e401554640c 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -96,7 +96,6 @@ llvm-config = "{llvm_config}" "tests/incremental", "tests/mir-opt", "tests/pretty", - "tests/run-pass-valgrind", "tests/ui", "tests/crashes", ]; diff --git a/src/tools/run-make-support/src/diff/tests.rs b/src/tools/run-make-support/src/diff/tests.rs index 286548bef61..6096560ca52 100644 --- a/src/tools/run-make-support/src/diff/tests.rs +++ b/src/tools/run-make-support/src/diff/tests.rs @@ -1,28 +1,23 @@ -#[cfg(test)] -mod tests { - use crate::*; - - #[test] - fn test_diff() { - let expected = "foo\nbar\nbaz\n"; - let actual = "foo\nbar\nbaz\n"; +use crate::diff; + +#[test] +fn test_diff() { + let expected = "foo\nbar\nbaz\n"; + let actual = "foo\nbar\nbaz\n"; + diff().expected_text("EXPECTED_TEXT", expected).actual_text("ACTUAL_TEXT", actual).run(); +} + +#[test] +fn test_should_panic() { + let expected = "foo\nbar\nbaz\n"; + let actual = "foo\nbaz\nbar\n"; + + let output = std::panic::catch_unwind(|| { diff().expected_text("EXPECTED_TEXT", expected).actual_text("ACTUAL_TEXT", actual).run(); - } - - #[test] - fn test_should_panic() { - let expected = "foo\nbar\nbaz\n"; - let actual = "foo\nbaz\nbar\n"; - - let output = std::panic::catch_unwind(|| { - diff() - .expected_text("EXPECTED_TEXT", expected) - .actual_text("ACTUAL_TEXT", actual) - .run(); - }) - .unwrap_err(); - - let expected_output = "\ + }) + .unwrap_err(); + + let expected_output = "\ test failed: `EXPECTED_TEXT` is different from `ACTUAL_TEXT` --- EXPECTED_TEXT @@ -34,28 +29,27 @@ test failed: `EXPECTED_TEXT` is different from `ACTUAL_TEXT` -baz "; - assert_eq!(output.downcast_ref::<String>().unwrap(), expected_output); - } + assert_eq!(output.downcast_ref::<String>().unwrap(), expected_output); +} - #[test] - fn test_normalize() { - let expected = " +#[test] +fn test_normalize() { + let expected = " running 2 tests .. test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME "; - let actual = " + let actual = " running 2 tests .. test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s "; - diff() - .expected_text("EXPECTED_TEXT", expected) - .actual_text("ACTUAL_TEXT", actual) - .normalize(r#"finished in \d+\.\d+s"#, "finished in $$TIME") - .run(); - } + diff() + .expected_text("EXPECTED_TEXT", expected) + .actual_text("ACTUAL_TEXT", actual) + .normalize(r#"finished in \d+\.\d+s"#, "finished in $$TIME") + .run(); } diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs index f7fe4f54223..cc3d1281d0a 100644 --- a/src/tools/run-make-support/src/macros.rs +++ b/src/tools/run-make-support/src/macros.rs @@ -70,6 +70,30 @@ macro_rules! impl_common_helpers { self } + /// Configuration for the child process’s standard input (stdin) handle. + /// + /// See [`std::process::Command::stdin`]. + pub fn stdin<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self { + self.cmd.stdin(cfg); + self + } + + /// Configuration for the child process’s standard output (stdout) handle. + /// + /// See [`std::process::Command::stdout`]. + pub fn stdout<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self { + self.cmd.stdout(cfg); + self + } + + /// Configuration for the child process’s standard error (stderr) handle. + /// + /// See [`std::process::Command::stderr`]. + pub fn stderr<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self { + self.cmd.stderr(cfg); + self + } + /// Inspect what the underlying [`Command`] is up to the /// current construction. pub fn inspect<I>(&mut self, inspector: I) -> &mut Self diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index e11d6e15d10..39ac652de0f 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -16,7 +16,7 @@ env: RUSTFLAGS: "-D warnings -W unreachable-pub" RUSTUP_MAX_RETRIES: 10 FETCH_DEPTH: 0 # pull in the tags for the version string - MACOSX_DEPLOYMENT_TARGET: 10.15 + MACOSX_DEPLOYMENT_TARGET: 13.0 CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc @@ -43,10 +43,10 @@ jobs: - os: ubuntu-20.04 target: arm-unknown-linux-gnueabihf code-target: linux-armhf - - os: macos-12 + - os: macos-13 target: x86_64-apple-darwin code-target: darwin-x64 - - os: macos-12 + - os: macos-13 target: aarch64-apple-darwin code-target: darwin-arm64 diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index dc820fcb28d..7891edc2447 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -145,9 +145,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.10" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +dependencies = [ + "shlex", +] [[package]] name = "cfg" @@ -1853,6 +1856,12 @@ dependencies = [ ] [[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index b4587a37961..0b3d6e2a1ef 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"] resolver = "2" [workspace.package] -rust-version = "1.80" +rust-version = "1.81" edition = "2021" license = "MIT OR Apache-2.0" authors = ["rust-analyzer team"] diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index e9daaf7de3c..c2d40086056 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -49,6 +49,10 @@ impl CfgOptions { cfg.fold(&|atom| self.enabled.contains(atom)) } + pub fn check_atom(&self, cfg: &CfgAtom) -> bool { + self.enabled.contains(cfg) + } + pub fn insert_atom(&mut self, key: Symbol) { self.enabled.insert(CfgAtom::Flag(key)); } 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 85fb90fdfb6..d568f6faa72 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 @@ -36,7 +36,7 @@ macro_rules! f { } struct#0:1@58..64#1# MyTraitMap2#0:2@31..42#0# {#0:1@72..73#1# - map#0:1@86..89#1#:#0:1@89..90#1# #0:1@89..90#1#::#0:1@91..92#1#std#0:1@93..96#1#::#0:1@96..97#1#collections#0:1@98..109#1#::#0:1@109..110#1#HashSet#0:1@111..118#1#<#0:1@118..119#1#(#0:1@119..120#1#)#0:1@120..121#1#>#0:1@121..122#1#,#0:1@122..123#1# + map#0:1@86..89#1#:#0:1@89..90#1# #0:1@89..90#1#::#0:1@91..93#1#std#0:1@93..96#1#::#0:1@96..98#1#collections#0:1@98..109#1#::#0:1@109..111#1#HashSet#0:1@111..118#1#<#0:1@118..119#1#(#0:1@119..120#1#)#0:1@120..121#1#>#0:1@121..122#1#,#0:1@122..123#1# }#0:1@132..133#1# "#]], ); 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 e09ef4f205d..7f1d19719da 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 @@ -6,7 +6,7 @@ use std::{cmp::Ordering, iter, mem, ops::Not}; use base_db::{CrateId, CrateOrigin, Dependency, LangCrateOrigin}; -use cfg::{CfgExpr, CfgOptions}; +use cfg::{CfgAtom, CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ attrs::{Attr, AttrId}, @@ -1324,13 +1324,21 @@ impl DefCollector<'_> { }; // Skip #[test]/#[bench] expansion, which would merely result in more memory usage - // due to duplicating functions into macro expansions + // due to duplicating functions into macro expansions, but only if `cfg(test)` is active, + // otherwise they are expanded to nothing and this can impact e.g. diagnostics (due to things + // being cfg'ed out). + // Ideally we will just expand them to nothing here. But we are only collecting macro calls, + // not expanding them, so we have no way to do that. if matches!( def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_test() || expander.is_bench() ) { - return recollect_without(self); + let test_is_active = + self.cfg_options.check_atom(&CfgAtom::Flag(sym::test.clone())); + if test_is_active { + return recollect_without(self); + } } let call_id = || { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/attr_macro.rs index b9afc666f75..2a8691b461c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/attr_macro.rs @@ -4,6 +4,8 @@ use span::{MacroCallId, Span}; use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallKind}; +use super::quote; + macro_rules! register_builtin { ($(($name:ident, $variant:ident) => $expand:ident),* ) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -52,15 +54,15 @@ impl BuiltinAttrExpander { } register_builtin! { - (bench, Bench) => dummy_attr_expand, + (bench, Bench) => dummy_gate_test_expand, (cfg_accessible, CfgAccessible) => dummy_attr_expand, (cfg_eval, CfgEval) => dummy_attr_expand, (derive, Derive) => derive_expand, // derive const is equivalent to derive for our proposes. (derive_const, DeriveConst) => derive_expand, (global_allocator, GlobalAllocator) => dummy_attr_expand, - (test, Test) => dummy_attr_expand, - (test_case, TestCase) => dummy_attr_expand + (test, Test) => dummy_gate_test_expand, + (test_case, TestCase) => dummy_gate_test_expand } pub fn find_builtin_attr(ident: &name::Name) -> Option<BuiltinAttrExpander> { @@ -76,6 +78,19 @@ fn dummy_attr_expand( ExpandResult::ok(tt.clone()) } +fn dummy_gate_test_expand( + _db: &dyn ExpandDatabase, + _id: MacroCallId, + tt: &tt::Subtree, + span: Span, +) -> ExpandResult<tt::Subtree> { + let result = quote::quote! { span=> + #[cfg(test)] + #tt + }; + ExpandResult::ok(result) +} + /// We generate a very specific expansion here, as we do not actually expand the `#[derive]` attribute /// itself in name res, but we do want to expand it to something for the IDE layer, so that the input /// derive attributes can be downmapped, and resolved as proper paths. 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 584f9631e34..484a8662eb1 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -16,7 +16,10 @@ use crate::{ cfg_process, declarative::DeclarativeMacroExpander, fixup::{self, SyntaxFixupUndoInfo}, - hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt}, + hygiene::{ + span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt, + SyntaxContextExt as _, + }, proc_macro::ProcMacros, span_map::{RealSpanMap, SpanMap, SpanMapRef}, tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, @@ -300,14 +303,16 @@ pub fn expand_speculative( token_tree_to_syntax_node(&speculative_expansion.value, expand_to, loc.def.edition); let syntax_node = node.syntax_node(); - let token = rev_tmap + let (token, _) = rev_tmap .ranges_with_span(span_map.span_for_range(token_to_map.text_range())) - .filter_map(|range| syntax_node.covering_element(range).into_token()) - .min_by_key(|t| { - // prefer tokens of the same kind and text + .filter_map(|(range, ctx)| syntax_node.covering_element(range).into_token().zip(Some(ctx))) + .min_by_key(|(t, ctx)| { + // prefer tokens of the same kind and text, as well as non opaque marked ones // Note the inversion of the score here, as we want to prefer the first token in case // of all tokens having the same score - (t.kind() != token_to_map.kind()) as u8 + 2 * ((t.text() != token_to_map.text()) as u8) + ctx.is_opaque(db) as u8 + + 2 * (t.kind() != token_to_map.kind()) as u8 + + 4 * ((t.text() != token_to_map.text()) as u8) })?; Some((node.syntax_node(), token)) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index cc02332207d..5e1448f7950 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -151,6 +151,7 @@ pub trait SyntaxContextExt { fn remove_mark(&mut self, db: &dyn ExpandDatabase) -> (Option<MacroCallId>, Transparency); fn outer_mark(self, db: &dyn ExpandDatabase) -> (Option<MacroCallId>, Transparency); fn marks(self, db: &dyn ExpandDatabase) -> Vec<(MacroCallId, Transparency)>; + fn is_opaque(self, db: &dyn ExpandDatabase) -> bool; } impl SyntaxContextExt for SyntaxContextId { @@ -177,6 +178,9 @@ impl SyntaxContextExt for SyntaxContextId { marks.reverse(); marks } + fn is_opaque(self, db: &dyn ExpandDatabase) -> bool { + !self.is_root() && db.lookup_intern_syntax_context(self).outer_transparency.is_opaque() + } } // FIXME: Make this a SyntaxContextExt method once we have RPIT 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 95380979492..56cb5fd375c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -25,6 +25,7 @@ mod prettify_macro_expansion_; use attrs::collect_attrs; use rustc_hash::FxHashMap; +use stdx::TupleExt; use triomphe::Arc; use std::hash::Hash; @@ -772,14 +773,15 @@ impl ExpansionInfo { /// Maps the passed in file range down into a macro expansion if it is the input to a macro call. /// /// Note this does a linear search through the entire backing vector of the spanmap. + // FIXME: Consider adding a reverse map to ExpansionInfo to get rid of the linear search which + // potentially results in quadratic look ups (notably this might improve semantic highlighting perf) pub fn map_range_down_exact( &self, span: Span, - ) -> Option<InMacroFile<impl Iterator<Item = SyntaxToken> + '_>> { - let tokens = self - .exp_map - .ranges_with_span_exact(span) - .flat_map(move |range| self.expanded.value.covering_element(range).into_token()); + ) -> Option<InMacroFile<impl Iterator<Item = (SyntaxToken, SyntaxContextId)> + '_>> { + let tokens = self.exp_map.ranges_with_span_exact(span).flat_map(move |(range, ctx)| { + self.expanded.value.covering_element(range).into_token().zip(Some(ctx)) + }); Some(InMacroFile::new(self.expanded.file_id, tokens)) } @@ -791,11 +793,10 @@ impl ExpansionInfo { pub fn map_range_down( &self, span: Span, - ) -> Option<InMacroFile<impl Iterator<Item = SyntaxToken> + '_>> { - let tokens = self - .exp_map - .ranges_with_span(span) - .flat_map(move |range| self.expanded.value.covering_element(range).into_token()); + ) -> Option<InMacroFile<impl Iterator<Item = (SyntaxToken, SyntaxContextId)> + '_>> { + let tokens = self.exp_map.ranges_with_span(span).flat_map(move |(range, ctx)| { + self.expanded.value.covering_element(range).into_token().zip(Some(ctx)) + }); Some(InMacroFile::new(self.expanded.file_id, tokens)) } @@ -845,7 +846,8 @@ impl ExpansionInfo { self.arg.file_id, arg_map .ranges_with_span_exact(span) - .filter(|range| range.intersect(arg_range).is_some()) + .filter(|(range, _)| range.intersect(arg_range).is_some()) + .map(TupleExt::head) .collect(), ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index e74e3d78988..f7bacbd49b3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -382,8 +382,9 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { } fn is_object_safe(&self, trait_id: chalk_ir::TraitId<Interner>) -> bool { + // FIXME: When cargo is updated, change to dyn_compatibility let trait_ = from_chalk_trait_id(trait_id); - crate::object_safety::object_safety(self.db, trait_).is_none() + crate::dyn_compatibility::dyn_compatibility(self.db, trait_).is_none() } fn closure_kind( 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 ce5a821ea2b..5620d80adb5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -20,11 +20,11 @@ use triomphe::Arc; use crate::{ chalk_db, consteval::ConstEvalError, + dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, lower::{GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, - object_safety::ObjectSafetyViolation, Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner, PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, }; @@ -108,8 +108,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { #[salsa::invoke(crate::layout::target_data_layout_query)] fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>; - #[salsa::invoke(crate::object_safety::object_safety_of_trait_query)] - fn object_safety_of_trait(&self, trait_: TraitId) -> Option<ObjectSafetyViolation>; + #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] + fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation>; #[salsa::invoke(crate::lower::ty_query)] #[salsa::cycle(crate::lower::ty_recover)] @@ -280,8 +280,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { } #[test] -fn hir_database_is_object_safe() { - fn _assert_object_safe(_: &dyn HirDatabase) {} +fn hir_database_is_dyn_compatible() { + fn _assert_dyn_compatible(_: &dyn HirDatabase) {} } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 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 82517e69917..7f6b7e392b3 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 @@ -58,7 +58,7 @@ impl fmt::Display for CaseType { let repr = match self { CaseType::LowerSnakeCase => "snake_case", CaseType::UpperSnakeCase => "UPPER_SNAKE_CASE", - CaseType::UpperCamelCase => "CamelCase", + CaseType::UpperCamelCase => "UpperCamelCase", }; repr.fmt(f) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs index cbe1af15703..aa0c9e30be1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs @@ -111,7 +111,7 @@ mod tests { check(to_lower_snake_case, "lower_snake_case", expect![[""]]); check(to_lower_snake_case, "UPPER_SNAKE_CASE", expect![["upper_snake_case"]]); check(to_lower_snake_case, "Weird_Case", expect![["weird_case"]]); - check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]); + check(to_lower_snake_case, "UpperCamelCase", expect![["upper_camel_case"]]); check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]); check(to_lower_snake_case, "a", expect![[""]]); check(to_lower_snake_case, "abc", expect![[""]]); @@ -121,8 +121,8 @@ mod tests { #[test] fn test_to_camel_case() { - check(to_camel_case, "CamelCase", expect![[""]]); - check(to_camel_case, "CamelCase_", expect![[""]]); + check(to_camel_case, "UpperCamelCase", expect![[""]]); + check(to_camel_case, "UpperCamelCase_", expect![[""]]); check(to_camel_case, "_CamelCase", expect![[""]]); check(to_camel_case, "lowerCamelCase", expect![["LowerCamelCase"]]); check(to_camel_case, "lower_snake_case", expect![["LowerSnakeCase"]]); @@ -143,7 +143,7 @@ mod tests { check(to_upper_snake_case, "UPPER_SNAKE_CASE", expect![[""]]); check(to_upper_snake_case, "lower_snake_case", expect![["LOWER_SNAKE_CASE"]]); check(to_upper_snake_case, "Weird_Case", expect![["WEIRD_CASE"]]); - check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]); + check(to_upper_snake_case, "UpperCamelCase", expect![["UPPER_CAMEL_CASE"]]); check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]); check(to_upper_snake_case, "A", expect![[""]]); check(to_upper_snake_case, "ABC", expect![[""]]); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index a4c66268555..e0d1758210e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -1,4 +1,4 @@ -//! Compute the object-safety of a trait +//! Compute the dyn-compatibility of a trait use std::ops::ControlFlow; @@ -28,14 +28,14 @@ use crate::{ }; #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ObjectSafetyViolation { +pub enum DynCompatibilityViolation { SizedSelf, SelfReferential, Method(FunctionId, MethodViolationCode), AssocConst(ConstId), GAT(TypeAliasId), // This doesn't exist in rustc, but added for better visualization - HasNonSafeSuperTrait(TraitId), + HasNonCompatibleSuperTrait(TraitId), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -50,70 +50,73 @@ pub enum MethodViolationCode { UndispatchableReceiver, } -pub fn object_safety(db: &dyn HirDatabase, trait_: TraitId) -> Option<ObjectSafetyViolation> { +pub fn dyn_compatibility( + db: &dyn HirDatabase, + trait_: TraitId, +) -> Option<DynCompatibilityViolation> { for super_trait in all_super_traits(db.upcast(), trait_).into_iter().skip(1).rev() { - if db.object_safety_of_trait(super_trait).is_some() { - return Some(ObjectSafetyViolation::HasNonSafeSuperTrait(super_trait)); + if db.dyn_compatibility_of_trait(super_trait).is_some() { + return Some(DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait)); } } - db.object_safety_of_trait(trait_) + db.dyn_compatibility_of_trait(trait_) } -pub fn object_safety_with_callback<F>( +pub fn dyn_compatibility_with_callback<F>( db: &dyn HirDatabase, trait_: TraitId, cb: &mut F, ) -> ControlFlow<()> where - F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>, + F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>, { for super_trait in all_super_traits(db.upcast(), trait_).into_iter().skip(1).rev() { - if db.object_safety_of_trait(super_trait).is_some() { - cb(ObjectSafetyViolation::HasNonSafeSuperTrait(trait_))?; + if db.dyn_compatibility_of_trait(super_trait).is_some() { + cb(DynCompatibilityViolation::HasNonCompatibleSuperTrait(trait_))?; } } - object_safety_of_trait_with_callback(db, trait_, cb) + dyn_compatibility_of_trait_with_callback(db, trait_, cb) } -pub fn object_safety_of_trait_with_callback<F>( +pub fn dyn_compatibility_of_trait_with_callback<F>( db: &dyn HirDatabase, trait_: TraitId, cb: &mut F, ) -> ControlFlow<()> where - F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>, + F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>, { // Check whether this has a `Sized` bound if generics_require_sized_self(db, trait_.into()) { - cb(ObjectSafetyViolation::SizedSelf)?; + cb(DynCompatibilityViolation::SizedSelf)?; } // Check if there exist bounds that referencing self if predicates_reference_self(db, trait_) { - cb(ObjectSafetyViolation::SelfReferential)?; + cb(DynCompatibilityViolation::SelfReferential)?; } if bounds_reference_self(db, trait_) { - cb(ObjectSafetyViolation::SelfReferential)?; + cb(DynCompatibilityViolation::SelfReferential)?; } // rustc checks for non-lifetime binders here, but we don't support HRTB yet let trait_data = db.trait_data(trait_); for (_, assoc_item) in &trait_data.items { - object_safety_violation_for_assoc_item(db, trait_, *assoc_item, cb)?; + dyn_compatibility_violation_for_assoc_item(db, trait_, *assoc_item, cb)?; } ControlFlow::Continue(()) } -pub fn object_safety_of_trait_query( +pub fn dyn_compatibility_of_trait_query( db: &dyn HirDatabase, trait_: TraitId, -) -> Option<ObjectSafetyViolation> { +) -> Option<DynCompatibilityViolation> { let mut res = None; - object_safety_of_trait_with_callback(db, trait_, &mut |osv| { + dyn_compatibility_of_trait_with_callback(db, trait_, &mut |osv| { res = Some(osv); ControlFlow::Break(()) }); @@ -321,14 +324,14 @@ fn contains_illegal_self_type_reference<T: TypeVisitable<Interner>>( t.visit_with(visitor.as_dyn(), outer_binder).is_break() } -fn object_safety_violation_for_assoc_item<F>( +fn dyn_compatibility_violation_for_assoc_item<F>( db: &dyn HirDatabase, trait_: TraitId, item: AssocItemId, cb: &mut F, ) -> ControlFlow<()> where - F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>, + F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>, { // Any item that has a `Self : Sized` requisite is otherwise // exempt from the regulations. @@ -337,10 +340,10 @@ where } match item { - AssocItemId::ConstId(it) => cb(ObjectSafetyViolation::AssocConst(it)), + AssocItemId::ConstId(it) => cb(DynCompatibilityViolation::AssocConst(it)), AssocItemId::FunctionId(it) => { virtual_call_violations_for_method(db, trait_, it, &mut |mvc| { - cb(ObjectSafetyViolation::Method(it, mvc)) + cb(DynCompatibilityViolation::Method(it, mvc)) }) } AssocItemId::TypeAliasId(it) => { @@ -350,7 +353,7 @@ where } else { let generic_params = db.generic_params(item.into()); if !generic_params.is_empty() { - cb(ObjectSafetyViolation::GAT(it)) + cb(DynCompatibilityViolation::GAT(it)) } else { ControlFlow::Continue(()) } @@ -469,7 +472,7 @@ fn receiver_is_dispatchable( return false; }; - // `self: Self` can't be dispatched on, but this is already considered object safe. + // `self: Self` can't be dispatched on, but this is already considered dyn compatible // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437 if sig .skip_binders() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index c2a9117c5be..3f3e68eeb1c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -5,29 +5,29 @@ use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ToSmolStr; use test_fixture::WithFixture; -use crate::{object_safety::object_safety_with_callback, test_db::TestDB}; +use crate::{dyn_compatibility::dyn_compatibility_with_callback, test_db::TestDB}; use super::{ + DynCompatibilityViolation, MethodViolationCode::{self, *}, - ObjectSafetyViolation, }; -use ObjectSafetyViolationKind::*; +use DynCompatibilityViolationKind::*; #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum ObjectSafetyViolationKind { +enum DynCompatibilityViolationKind { SizedSelf, SelfReferential, Method(MethodViolationCode), AssocConst, GAT, - HasNonSafeSuperTrait, + HasNonCompatibleSuperTrait, } -fn check_object_safety<'a>( +fn check_dyn_compatibility<'a>( ra_fixture: &str, - expected: impl IntoIterator<Item = (&'a str, Vec<ObjectSafetyViolationKind>)>, + expected: impl IntoIterator<Item = (&'a str, Vec<DynCompatibilityViolationKind>)>, ) { let mut expected: FxHashMap<_, _> = expected.into_iter().map(|(id, osvs)| (id, FxHashSet::from_iter(osvs))).collect(); @@ -53,18 +53,20 @@ fn check_object_safety<'a>( continue; }; let mut osvs = FxHashSet::default(); - object_safety_with_callback(&db, trait_id, &mut |osv| { + dyn_compatibility_with_callback(&db, trait_id, &mut |osv| { osvs.insert(match osv { - ObjectSafetyViolation::SizedSelf => SizedSelf, - ObjectSafetyViolation::SelfReferential => SelfReferential, - ObjectSafetyViolation::Method(_, mvc) => Method(mvc), - ObjectSafetyViolation::AssocConst(_) => AssocConst, - ObjectSafetyViolation::GAT(_) => GAT, - ObjectSafetyViolation::HasNonSafeSuperTrait(_) => HasNonSafeSuperTrait, + DynCompatibilityViolation::SizedSelf => SizedSelf, + DynCompatibilityViolation::SelfReferential => SelfReferential, + DynCompatibilityViolation::Method(_, mvc) => Method(mvc), + DynCompatibilityViolation::AssocConst(_) => AssocConst, + DynCompatibilityViolation::GAT(_) => GAT, + DynCompatibilityViolation::HasNonCompatibleSuperTrait(_) => { + HasNonCompatibleSuperTrait + } }); ControlFlow::Continue(()) }); - assert_eq!(osvs, expected, "Object safety violations for `{name}` do not match;"); + assert_eq!(osvs, expected, "Dyn Compatibility violations for `{name}` do not match;"); } let remains: Vec<_> = expected.keys().collect(); @@ -73,7 +75,7 @@ fn check_object_safety<'a>( #[test] fn item_bounds_can_reference_self() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: eq pub trait Foo { @@ -88,7 +90,7 @@ pub trait Foo { #[test] fn associated_consts() { - check_object_safety( + check_dyn_compatibility( r#" trait Bar { const X: usize; @@ -100,7 +102,7 @@ trait Bar { #[test] fn bounds_reference_self() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: eq trait X { @@ -113,7 +115,7 @@ trait X { #[test] fn by_value_self() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Bar { @@ -135,7 +137,7 @@ trait Quux { #[test] fn generic_methods() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Bar { @@ -157,7 +159,7 @@ trait Qax { #[test] fn mentions_self() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Bar { @@ -182,7 +184,7 @@ trait Quux { #[test] fn no_static() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Foo { @@ -195,7 +197,7 @@ trait Foo { #[test] fn sized_self() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Bar: Sized { @@ -205,7 +207,7 @@ trait Bar: Sized { [("Bar", vec![SizedSelf])], ); - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Bar @@ -220,7 +222,7 @@ trait Bar #[test] fn supertrait_gat() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait GatTrait { @@ -229,13 +231,13 @@ trait GatTrait { trait SuperTrait<T>: GatTrait {} "#, - [("GatTrait", vec![GAT]), ("SuperTrait", vec![HasNonSafeSuperTrait])], + [("GatTrait", vec![GAT]), ("SuperTrait", vec![HasNonCompatibleSuperTrait])], ); } #[test] fn supertrait_mentions_self() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Bar<T> { @@ -251,7 +253,7 @@ trait Baz : Bar<Self> { #[test] fn rustc_issue_19538() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Foo { @@ -260,13 +262,13 @@ trait Foo { trait Bar: Foo {} "#, - [("Foo", vec![Method(Generic)]), ("Bar", vec![HasNonSafeSuperTrait])], + [("Foo", vec![Method(Generic)]), ("Bar", vec![HasNonCompatibleSuperTrait])], ); } #[test] fn rustc_issue_22040() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: fmt, eq, dispatch_from_dyn use core::fmt::Debug; @@ -281,7 +283,7 @@ trait Expr: Debug + PartialEq { #[test] fn rustc_issue_102762() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: future, send, sync, dispatch_from_dyn, deref use core::pin::Pin; @@ -313,7 +315,7 @@ pub trait Fetcher: Send + Sync { #[test] fn rustc_issue_102933() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: future, dispatch_from_dyn, deref use core::future::Future; @@ -351,7 +353,7 @@ pub trait B2: Service<Response = i32> + B1 { #[test] fn rustc_issue_106247() { - check_object_safety( + check_dyn_compatibility( r#" //- minicore: sync, dispatch_from_dyn pub trait Trait { @@ -363,8 +365,8 @@ pub trait Trait { } #[test] -fn std_error_is_object_safe() { - check_object_safety( +fn std_error_is_dyn_compatible() { + check_dyn_compatibility( r#" //- minicore: fmt, dispatch_from_dyn trait Erased<'a>: 'a {} @@ -380,14 +382,14 @@ pub trait Error: core::fmt::Debug + core::fmt::Display { } #[test] -fn lifetime_gat_is_object_unsafe() { - check_object_safety( +fn lifetime_gat_is_dyn_incompatible() { + check_dyn_compatibility( r#" //- minicore: dispatch_from_dyn trait Foo { type Bar<'a>; } "#, - [("Foo", vec![ObjectSafetyViolationKind::GAT])], + [("Foo", vec![DynCompatibilityViolationKind::GAT])], ); } 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 5ed41b99ba3..ef570a20556 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -38,11 +38,11 @@ pub mod consteval; pub mod db; pub mod diagnostics; pub mod display; +pub mod dyn_compatibility; pub mod lang_items; pub mod layout; pub mod method_resolution; pub mod mir; -pub mod object_safety; pub mod primitive; pub mod traits; 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 878d584a4ef..9830fa1ca7b 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 @@ -386,82 +386,91 @@ fn ever_initialized_map( fn dfs( db: &dyn HirDatabase, body: &MirBody, - b: BasicBlockId, l: LocalId, + stack: &mut Vec<BasicBlockId>, result: &mut ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>>, ) { - let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs - let block = &body.basic_blocks[b]; - for statement in &block.statements { - match &statement.kind { - StatementKind::Assign(p, _) => { - if p.projection.lookup(&body.projection_store).is_empty() && p.local == l { - is_ever_initialized = true; + while let Some(b) = stack.pop() { + let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs + let block = &body.basic_blocks[b]; + for statement in &block.statements { + match &statement.kind { + StatementKind::Assign(p, _) => { + if p.projection.lookup(&body.projection_store).is_empty() && p.local == l { + is_ever_initialized = true; + } } - } - StatementKind::StorageDead(p) => { - if *p == l { - is_ever_initialized = false; + StatementKind::StorageDead(p) => { + if *p == l { + is_ever_initialized = false; + } } + StatementKind::Deinit(_) + | StatementKind::FakeRead(_) + | StatementKind::Nop + | StatementKind::StorageLive(_) => (), } - StatementKind::Deinit(_) - | StatementKind::FakeRead(_) - | StatementKind::Nop - | StatementKind::StorageLive(_) => (), - } - } - let Some(terminator) = &block.terminator else { - never!( - "Terminator should be none only in construction.\nThe body:\n{}", - body.pretty_print(db) - ); - return; - }; - let mut process = |target, is_ever_initialized| { - if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized { - result[target].insert(l, is_ever_initialized); - dfs(db, body, target, l, result); - } - }; - match &terminator.kind { - TerminatorKind::Goto { target } => process(*target, is_ever_initialized), - TerminatorKind::SwitchInt { targets, .. } => { - targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized)); } - TerminatorKind::UnwindResume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable => (), - TerminatorKind::Call { target, cleanup, destination, .. } => { - if destination.projection.lookup(&body.projection_store).is_empty() - && destination.local == l - { - is_ever_initialized = true; + let Some(terminator) = &block.terminator else { + never!( + "Terminator should be none only in construction.\nThe body:\n{}", + body.pretty_print(db) + ); + return; + }; + let mut process = |target, is_ever_initialized| { + if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized { + result[target].insert(l, is_ever_initialized); + stack.push(target); + } + }; + match &terminator.kind { + TerminatorKind::Goto { target } => process(*target, is_ever_initialized), + TerminatorKind::SwitchInt { targets, .. } => { + targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized)); + } + TerminatorKind::UnwindResume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable => (), + TerminatorKind::Call { target, cleanup, destination, .. } => { + if destination.projection.lookup(&body.projection_store).is_empty() + && destination.local == l + { + is_ever_initialized = true; + } + target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized)); + } + TerminatorKind::Drop { target, unwind, place: _ } => { + iter::once(target) + .chain(unwind) + .for_each(|&it| process(it, is_ever_initialized)); + } + TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::CoroutineDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => { + never!("We don't emit these MIR terminators yet"); } - target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized)); - } - TerminatorKind::Drop { target, unwind, place: _ } => { - iter::once(target).chain(unwind).for_each(|&it| process(it, is_ever_initialized)); - } - TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::CoroutineDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { - never!("We don't emit these MIR terminators yet"); } } } + let mut stack = Vec::new(); for &l in &body.param_locals { result[body.start_block].insert(l, true); - dfs(db, body, body.start_block, l, &mut result); + stack.clear(); + stack.push(body.start_block); + dfs(db, body, l, &mut stack, &mut result); } for l in body.locals.iter().map(|it| it.0) { db.unwind_if_cancelled(); if !result[body.start_block].contains_idx(l) { result[body.start_block].insert(l, false); - dfs(db, body, body.start_block, l, &mut result); + stack.clear(); + stack.push(body.start_block); + dfs(db, body, l, &mut stack, &mut result); } } result diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 8f5db32f957..30e023e1a47 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -144,9 +144,9 @@ pub use { hir_ty::{ consteval::ConstEvalError, display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, + dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, layout::LayoutError, mir::{MirEvalError, MirLowerError}, - object_safety::{MethodViolationCode, ObjectSafetyViolation}, CastError, FnAbi, PointerCast, Safety, }, // FIXME: Properly encapsulate mir @@ -497,10 +497,9 @@ impl Module { /// Finds a parent module. pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> { - // FIXME: handle block expressions as modules (their parent is in a different DefMap) let def_map = self.id.def_map(db.upcast()); - let parent_id = def_map[self.id.local_id].parent?; - Some(Module { id: def_map.module_id(parent_id) }) + let parent_id = def_map.containing_module(self.id.local_id)?; + Some(Module { id: parent_id }) } /// Finds nearest non-block ancestor `Module` (`self` included). @@ -557,7 +556,7 @@ impl Module { acc: &mut Vec<AnyDiagnostic>, style_lints: bool, ) { - let _p = tracing::info_span!("Module::diagnostics", name = ?self.name(db)).entered(); + let _p = tracing::info_span!("diagnostics", name = ?self.name(db)).entered(); let edition = db.crate_graph()[self.id.krate()].edition; let def_map = self.id.def_map(db.upcast()); for diag in def_map.diagnostics() { @@ -2690,8 +2689,8 @@ impl Trait { .count() } - pub fn object_safety(&self, db: &dyn HirDatabase) -> Option<ObjectSafetyViolation> { - hir_ty::object_safety::object_safety(db, self.id) + pub fn dyn_compatibility(&self, db: &dyn HirDatabase) -> Option<DynCompatibilityViolation> { + hir_ty::dyn_compatibility::dyn_compatibility(db, self.id) } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index fa14b53dbc3..b27f1fbb5db 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -24,6 +24,7 @@ use hir_expand::{ builtin::{BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, files::InRealFile, + hygiene::SyntaxContextExt as _, inert_attr_macro::find_builtin_attr_idx, name::AsName, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt, @@ -32,13 +33,13 @@ use intern::Symbol; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; -use span::{EditionedFileId, FileId, HirFileIdRepr}; +use span::{EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId}; use stdx::TupleExt; use syntax::{ algo::skip_trivia_token, - ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody, IsString as _}, - match_ast, AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, - TextRange, TextSize, + ast::{self, HasAttrs as _, HasGenericParams, IsString as _}, + AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, + TextSize, }; use crate::{ @@ -608,7 +609,7 @@ impl<'db> SemanticsImpl<'db> { let quote = string.open_quote_text_range()?; let token = self.wrap_token_infile(string.syntax().clone()).into_real_file().ok()?; - self.descend_into_macros_breakable(token, |token| { + self.descend_into_macros_breakable(token, |token, _| { (|| { let token = token.value; let string = ast::String::cast(token)?; @@ -655,7 +656,7 @@ impl<'db> SemanticsImpl<'db> { let original_string = ast::String::cast(original_token.clone())?; let original_token = self.wrap_token_infile(original_token).into_real_file().ok()?; let quote = original_string.open_quote_text_range()?; - self.descend_into_macros_breakable(original_token, |token| { + self.descend_into_macros_breakable(original_token, |token, _| { (|| { let token = token.value; self.resolve_offset_in_format_args( @@ -718,7 +719,7 @@ impl<'db> SemanticsImpl<'db> { // node is just the token, so descend the token self.descend_into_macros_impl( InRealFile::new(file_id, first), - &mut |InFile { value, .. }| { + &mut |InFile { value, .. }, _ctx| { if let Some(node) = value .parent_ancestors() .take_while(|it| it.text_range() == value.text_range()) @@ -732,7 +733,7 @@ impl<'db> SemanticsImpl<'db> { } else { // Descend first and last token, then zip them to look for the node they belong to let mut scratch: SmallVec<[_; 1]> = smallvec![]; - self.descend_into_macros_impl(InRealFile::new(file_id, first), &mut |token| { + self.descend_into_macros_impl(InRealFile::new(file_id, first), &mut |token, _ctx| { scratch.push(token); CONTINUE_NO_BREAKS }); @@ -740,7 +741,7 @@ impl<'db> SemanticsImpl<'db> { let mut scratch = scratch.into_iter(); self.descend_into_macros_impl( InRealFile::new(file_id, last), - &mut |InFile { value: last, file_id: last_fid }| { + &mut |InFile { value: last, file_id: last_fid }, _ctx| { if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() { if first_fid == last_fid { if let Some(p) = first.parent() { @@ -763,7 +764,9 @@ impl<'db> SemanticsImpl<'db> { res } - fn is_inside_macro_call(token: &SyntaxToken) -> bool { + // FIXME: This isn't quite right wrt to inner attributes + /// Does a syntactic traversal to check whether this token might be inside a macro call + pub fn might_be_inside_macro_call(&self, token: &SyntaxToken) -> bool { token.parent_ancestors().any(|ancestor| { if ast::MacroCall::can_cast(ancestor.kind()) { return true; @@ -781,25 +784,14 @@ impl<'db> SemanticsImpl<'db> { }) } - pub fn descend_into_macros_exact_if_in_macro( - &self, - token: SyntaxToken, - ) -> SmallVec<[SyntaxToken; 1]> { - if Self::is_inside_macro_call(&token) { - self.descend_into_macros_exact(token) - } else { - smallvec![token] - } - } - pub fn descend_into_macros_cb( &self, token: SyntaxToken, - mut cb: impl FnMut(InFile<SyntaxToken>), + mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContextId), ) { if let Ok(token) = self.wrap_token_infile(token).into_real_file() { - self.descend_into_macros_impl(token, &mut |t| { - cb(t); + self.descend_into_macros_impl(token, &mut |t, ctx| { + cb(t, ctx); CONTINUE_NO_BREAKS }); } @@ -808,7 +800,7 @@ impl<'db> SemanticsImpl<'db> { pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { let mut res = smallvec![]; if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_impl(token, &mut |t| { + self.descend_into_macros_impl(token, &mut |t, _ctx| { res.push(t.value); CONTINUE_NO_BREAKS }); @@ -819,10 +811,27 @@ impl<'db> SemanticsImpl<'db> { res } + pub fn descend_into_macros_no_opaque(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { + let mut res = smallvec![]; + if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { + self.descend_into_macros_impl(token, &mut |t, ctx| { + if !ctx.is_opaque(self.db.upcast()) { + // Don't descend into opaque contexts + res.push(t.value); + } + CONTINUE_NO_BREAKS + }); + } + if res.is_empty() { + res.push(token); + } + res + } + pub fn descend_into_macros_breakable<T>( &self, token: InRealFile<SyntaxToken>, - mut cb: impl FnMut(InFile<SyntaxToken>) -> ControlFlow<T>, + mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContextId) -> ControlFlow<T>, ) -> Option<T> { self.descend_into_macros_impl(token.clone(), &mut cb) } @@ -834,10 +843,12 @@ impl<'db> SemanticsImpl<'db> { let text = token.text(); let kind = token.kind(); - self.descend_into_macros_cb(token.clone(), |InFile { value, file_id: _ }| { + self.descend_into_macros_cb(token.clone(), |InFile { value, file_id: _ }, ctx| { let mapped_kind = value.kind(); let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier(); - let matches = (kind == mapped_kind || any_ident_match()) && text == value.text(); + let matches = (kind == mapped_kind || any_ident_match()) + && text == value.text() + && !ctx.is_opaque(self.db.upcast()); if matches { r.push(value); } @@ -854,17 +865,21 @@ impl<'db> SemanticsImpl<'db> { let text = token.text(); let kind = token.kind(); if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_breakable(token.clone(), |InFile { value, file_id: _ }| { - let mapped_kind = value.kind(); - let any_ident_match = - || kind.is_any_identifier() && value.kind().is_any_identifier(); - let matches = (kind == mapped_kind || any_ident_match()) && text == value.text(); - if matches { - ControlFlow::Break(value) - } else { - ControlFlow::Continue(()) - } - }) + self.descend_into_macros_breakable( + token.clone(), + |InFile { value, file_id: _ }, _ctx| { + let mapped_kind = value.kind(); + let any_ident_match = + || kind.is_any_identifier() && value.kind().is_any_identifier(); + let matches = + (kind == mapped_kind || any_ident_match()) && text == value.text(); + if matches { + ControlFlow::Break(value) + } else { + ControlFlow::Continue(()) + } + }, + ) } else { None } @@ -874,7 +889,7 @@ impl<'db> SemanticsImpl<'db> { fn descend_into_macros_impl<T>( &self, InRealFile { value: token, file_id }: InRealFile<SyntaxToken>, - f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<T>, + f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContextId) -> ControlFlow<T>, ) -> Option<T> { let _p = tracing::info_span!("descend_into_macros_impl").entered(); let (sa, span, file_id) = token @@ -898,7 +913,8 @@ impl<'db> SemanticsImpl<'db> { // These are tracked to know which macro calls we still have to look into // the tokens themselves aren't that interesting as the span that is being used to map // things down never changes. - let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![(file_id, smallvec![token])]; + let mut stack: Vec<(_, SmallVec<[_; 2]>)> = + vec![(file_id, smallvec![(token, SyntaxContextId::ROOT)])]; // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { @@ -921,11 +937,11 @@ impl<'db> SemanticsImpl<'db> { // Filters out all tokens that contain the given range (usually the macro call), any such // token is redundant as the corresponding macro call has already been processed let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| { - tokens.retain(|t: &mut SyntaxToken| !range.contains_range(t.text_range())) + tokens.retain(|(t, _): &mut (SyntaxToken, _)| !range.contains_range(t.text_range())) }; while let Some((expansion, ref mut tokens)) = stack.pop() { - while let Some(token) = tokens.pop() { + while let Some((token, ctx)) = tokens.pop() { let was_not_remapped = (|| { // First expand into attribute invocations let containing_attribute_macro_call = self.with_ctx(|ctx| { @@ -1036,7 +1052,7 @@ impl<'db> SemanticsImpl<'db> { let text_range = attr.syntax().text_range(); // remove any other token in this macro input, all their mappings are the // same as this - tokens.retain(|t| { + tokens.retain(|(t, _)| { !text_range.contains_range(t.text_range()) }); return process_expansion_for_token( @@ -1093,7 +1109,7 @@ impl<'db> SemanticsImpl<'db> { .is_none(); if was_not_remapped { - if let ControlFlow::Break(b) = f(InFile::new(expansion, token)) { + if let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx) { return Some(b); } } @@ -1221,26 +1237,10 @@ impl<'db> SemanticsImpl<'db> { ToDef::to_def(self, src.as_ref()) } - pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> { - let text = lifetime.text(); - let label = lifetime.syntax().ancestors().find_map(|syn| { - let label = match_ast! { - match syn { - ast::ForExpr(it) => it.label(), - ast::WhileExpr(it) => it.label(), - ast::LoopExpr(it) => it.label(), - ast::BlockExpr(it) => it.label(), - _ => None, - } - }; - label.filter(|l| { - l.lifetime() - .and_then(|lt| lt.lifetime_ident_token()) - .map_or(false, |lt| lt.text() == text) - }) - })?; - let src = self.wrap_node_infile(label); - ToDef::to_def(self, src.as_ref()) + pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> { + let (parent, label_id) = self + .with_ctx(|ctx| ctx.label_ref_to_def(self.wrap_node_infile(label.clone()).as_ref()))?; + Some(Label { parent, label_id }) } pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> { 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 c1e4e1d1e27..fd6d52d6c9d 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 @@ -92,7 +92,7 @@ use hir_def::{ keys::{self, Key}, DynMap, }, - hir::{BindingId, LabelId}, + hir::{BindingId, Expr, LabelId}, AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, Lookup, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId, @@ -343,6 +343,20 @@ impl SourceToDefCtx<'_, '_> { Some((container, label_id)) } + pub(super) fn label_ref_to_def( + &mut self, + src: InFile<&ast::Lifetime>, + ) -> Option<(DefWithBodyId, 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 break_or_continue = source_map.node_expr(src.with_value(&break_or_continue))?; + let (Expr::Break { label, .. } | Expr::Continue { label }) = body[break_or_continue] else { + return None; + }; + Some((container, label?)) + } + pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option<MacroCallId> { let map = self.dyn_map(src)?; map[keys::ATTR_MACRO_CALL].get(&AstPtr::new(src.value)).copied() 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 a43a4b5e1a0..61dc72e0b33 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 @@ -1,8 +1,12 @@ use hir::TypeInfo; use ide_db::syntax_helpers::suggest_name; use syntax::{ - ast::{self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasName}, - ted, NodeOrToken, + ast::{ + self, edit::IndentLevel, edit_in_place::Indent, make, syntax_factory::SyntaxFactory, + AstNode, + }, + syntax_editor::Position, + NodeOrToken, SyntaxKind::{BLOCK_EXPR, BREAK_EXPR, COMMENT, LOOP_EXPR, MATCH_GUARD, PATH_EXPR, RETURN_EXPR}, SyntaxNode, T, }; @@ -105,39 +109,46 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op ), }; + let make = SyntaxFactory::new(); + 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)); + + if let Some(cap) = ctx.config.snippet_cap { + let tabstop = edit.make_tabstop_before(cap); + editor.add_annotation(pat_name.syntax().clone(), tabstop); + } + let ident_pat = match parent { Some(ast::Expr::RefExpr(expr)) if expr.mut_token().is_some() => { - make::ident_pat(false, true, make::name(&var_name)) + make.ident_pat(false, true, pat_name) } _ if needs_adjust && !needs_ref && ty.as_ref().is_some_and(|ty| ty.is_mutable_reference()) => { - make::ident_pat(false, true, make::name(&var_name)) + make.ident_pat(false, true, pat_name) } - _ => make::ident_pat(false, false, make::name(&var_name)), + _ => make.ident_pat(false, false, pat_name), }; let to_extract_no_ref = match ty.as_ref().filter(|_| needs_ref) { Some(receiver_type) if receiver_type.is_mutable_reference() => { - make::expr_ref(to_extract_no_ref, true) + make.expr_ref(to_extract_no_ref, true) } Some(receiver_type) if receiver_type.is_reference() => { - make::expr_ref(to_extract_no_ref, false) + make.expr_ref(to_extract_no_ref, false) } _ => to_extract_no_ref, }; - let expr_replace = edit.make_syntax_mut(expr_replace); - let let_stmt = - make::let_stmt(ident_pat.into(), None, Some(to_extract_no_ref)).clone_for_update(); - let name_expr = make::expr_path(make::ext::ident_path(&var_name)).clone_for_update(); + let let_stmt = make.let_stmt(ident_pat.into(), None, Some(to_extract_no_ref)); match anchor { Anchor::Before(place) => { let prev_ws = place.prev_sibling_or_token().and_then(|it| it.into_token()); let indent_to = IndentLevel::from_node(&place); - let insert_place = edit.make_syntax_mut(place); // Adjust ws to insert depending on if this is all inline or on separate lines let trailing_ws = if prev_ws.is_some_and(|it| it.text().starts_with('\n')) { @@ -146,37 +157,20 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op " ".to_owned() }; - ted::insert_all_raw( - ted::Position::before(insert_place), + editor.insert_all( + Position::before(place), vec![ let_stmt.syntax().clone().into(), make::tokens::whitespace(&trailing_ws).into(), ], ); - ted::replace(expr_replace, name_expr.syntax()); - - if let Some(cap) = ctx.config.snippet_cap { - if let Some(ast::Pat::IdentPat(ident_pat)) = let_stmt.pat() { - if let Some(name) = ident_pat.name() { - edit.add_tabstop_before(cap, name); - } - } - } + editor.replace(expr_replace, name_expr.syntax()); } Anchor::Replace(stmt) => { cov_mark::hit!(test_extract_var_expr_stmt); - let stmt_replace = edit.make_mut(stmt); - ted::replace(stmt_replace.syntax(), let_stmt.syntax()); - - if let Some(cap) = ctx.config.snippet_cap { - if let Some(ast::Pat::IdentPat(ident_pat)) = let_stmt.pat() { - if let Some(name) = ident_pat.name() { - edit.add_tabstop_before(cap, name); - } - } - } + editor.replace(stmt.syntax(), let_stmt.syntax()); } Anchor::WrapInBlock(to_wrap) => { let indent_to = to_wrap.indent_level(); @@ -184,47 +178,22 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let block = if to_wrap.syntax() == &expr_replace { // Since `expr_replace` is the same that needs to be wrapped in a block, // we can just directly replace it with a block - let block = - make::block_expr([let_stmt.into()], Some(name_expr)).clone_for_update(); - ted::replace(expr_replace, block.syntax()); - - block + make.block_expr([let_stmt.into()], Some(name_expr)) } else { - // `expr_replace` is a descendant of `to_wrap`, so both steps need to be - // handled separately, otherwise we wrap the wrong expression - let to_wrap = edit.make_mut(to_wrap); - - // Replace the target expr first so that we don't need to find where - // `expr_replace` is in the wrapped `to_wrap` - ted::replace(expr_replace, name_expr.syntax()); - - // Wrap `to_wrap` in a block - let block = make::block_expr([let_stmt.into()], Some(to_wrap.clone())) - .clone_for_update(); - ted::replace(to_wrap.syntax(), block.syntax()); - - block + // `expr_replace` is a descendant of `to_wrap`, so we just replace it with `name_expr`. + editor.replace(expr_replace, name_expr.syntax()); + make.block_expr([let_stmt.into()], Some(to_wrap.clone())) }; - if let Some(cap) = ctx.config.snippet_cap { - // Adding a tabstop to `name` requires finding the let stmt again, since - // the existing `let_stmt` is not actually added to the tree - let pat = block.statements().find_map(|stmt| { - let ast::Stmt::LetStmt(let_stmt) = stmt else { return None }; - let_stmt.pat() - }); - - if let Some(ast::Pat::IdentPat(ident_pat)) = pat { - if let Some(name) = ident_pat.name() { - edit.add_tabstop_before(cap, name); - } - } - } + editor.replace(to_wrap.syntax(), block.syntax()); // fixup indentation of block block.indent(indent_to); } } + + editor.add_mappings(make.finish_with_mappings()); + edit.add_file_edits(ctx.file_id(), editor); edit.rename(); }, ) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs index 0d403f49b7a..1d05419c96d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs @@ -7,7 +7,7 @@ use hir::ImportPathConfig; use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap}; -use crate::snippet::Snippet; +use crate::{snippet::Snippet, CompletionFieldsToResolve}; #[derive(Clone, Debug, PartialEq, Eq)] pub struct CompletionConfig { @@ -27,6 +27,7 @@ pub struct CompletionConfig { pub prefer_absolute: bool, pub snippets: Vec<Snippet>, pub limit: Option<usize>, + pub fields_to_resolve: CompletionFieldsToResolve, } #[derive(Clone, Debug, PartialEq, Eq)] 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 192f1b43fac..e49a9e3b064 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -7,7 +7,8 @@ mod tests; use std::{iter, ops::ControlFlow}; use hir::{ - HasAttrs, Local, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo, + HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, + TypeInfo, }; use ide_db::{ base_db::SourceDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, FilePosition, @@ -743,7 +744,12 @@ impl<'a> CompletionContext<'a> { } }); - let depth_from_crate_root = iter::successors(module.parent(db), |m| m.parent(db)).count(); + let depth_from_crate_root = iter::successors(Some(module), |m| m.parent(db)) + // `BlockExpr` modules are not count as module depth + .filter(|m| !matches!(m.definition_source(db).value, ModuleSource::BlockExpr(_))) + .count() + // exclude `m` itself + .saturating_sub(1); let complete_semicolon = if config.add_semicolon_to_unit { let inside_closure_ret = token.parent_ancestors().try_for_each(|ancestor| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 58d1fad0950..a78976d3fd8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -37,6 +37,31 @@ pub use crate::{ snippet::{Snippet, SnippetScope}, }; +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct CompletionFieldsToResolve { + pub resolve_label_details: bool, + pub resolve_tags: bool, + pub resolve_detail: bool, + pub resolve_documentation: bool, + pub resolve_filter_text: bool, + pub resolve_text_edit: bool, + pub resolve_command: bool, +} + +impl CompletionFieldsToResolve { + pub const fn empty() -> Self { + Self { + resolve_label_details: false, + resolve_tags: false, + resolve_detail: false, + resolve_documentation: false, + resolve_filter_text: false, + resolve_text_edit: false, + resolve_command: false, + } + } +} + //FIXME: split the following feature into fine-grained features. // Feature: Magic Completions diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 9d77d970071..f371012de3f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -37,8 +37,8 @@ use test_fixture::ChangeFixture; use test_utils::assert_eq_text; use crate::{ - resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionItem, - CompletionItemKind, + resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, + CompletionItem, CompletionItemKind, }; /// Lots of basic item definitions @@ -84,6 +84,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { prefer_absolute: false, snippets: Vec::new(), limit: None, + fields_to_resolve: CompletionFieldsToResolve::empty(), }; pub(crate) fn completion_list(ra_fixture: &str) -> String { 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 abf4438a71f..266109765ab 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 @@ -7081,8 +7081,8 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "object_safe_for_dispatch", - description: r##"# `object_safe_for_dispatch` + label: "dyn_compatible_for_dispatch", + description: r##"# `dyn_compatible_for_dispatch` The tracking issue for this feature is: [#43561] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index 926fae0d317..4c197b45338 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -614,7 +614,7 @@ fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { (Some(_), None) => Ordering::Greater, (None, Some(_)) => Ordering::Less, (Some(a_name), Some(b_name)) => { - // snake_case < CamelCase < UPPER_SNAKE_CASE + // snake_case < UpperCamelCase < UPPER_SNAKE_CASE let a_text = a_name.as_str().trim_start_matches("r#"); let b_text = b_name.as_str().trim_start_matches("r#"); if a_text.starts_with(char::is_lowercase) 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 bb121f4a80a..19d8a15422e 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 @@ -13,6 +13,7 @@ use crate::{ salsa::{Database, ParallelDatabase, Snapshot}, Cancelled, CrateId, SourceDatabase, SourceRootDatabase, }, + symbol_index::SymbolsDatabase, FxIndexMap, RootDatabase, }; @@ -54,11 +55,13 @@ pub fn parallel_prime_caches( let (progress_sender, progress_receiver) = crossbeam_channel::unbounded(); let (work_sender, work_receiver) = crossbeam_channel::unbounded(); let graph = graph.clone(); + let local_roots = db.local_roots(); let prime_caches_worker = move |db: Snapshot<RootDatabase>| { while let Ok((crate_id, crate_name)) = work_receiver.recv() { progress_sender .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?; + // Compute the DefMap and possibly ImportMap let file_id = graph[crate_id].root_file_id; let root_id = db.file_source_root(file_id); if db.source_root(root_id).is_library { @@ -68,6 +71,19 @@ pub fn parallel_prime_caches( db.import_map(crate_id); } + // Compute the symbol search index. + // This primes the cache for `ide_db::symbol_index::world_symbols()`. + // + // We do this for workspace crates only (members of local_roots), because doing it + // for all dependencies could be *very* unnecessarily slow in a large project. + // + // FIXME: We should do it unconditionally if the configuration is set to default to + // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we + // would need to pipe that configuration information down here. + if local_roots.contains(&root_id) { + db.crate_symbols(crate_id.into()); + } + progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?; } 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 4166b08339b..852ee595be4 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -529,9 +529,13 @@ impl<'a> FindUsages<'a> { }) .into_iter() .flat_map(move |token| { - sema.descend_into_macros_exact_if_in_macro(token) - .into_iter() - .filter_map(|it| it.parent()) + if sema.might_be_inside_macro_call(&token) { + sema.descend_into_macros_exact(token) + } else { + <_>::from([token]) + } + .into_iter() + .filter_map(|it| it.parent()) }) } 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 83a1eb44a61..bbdeb7cf085 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 @@ -229,10 +229,10 @@ fn foo() { check_diagnostics( r#" struct non_camel_case_name {} - // ^^^^^^^^^^^^^^^^^^^ 💡 warn: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` + // ^^^^^^^^^^^^^^^^^^^ 💡 warn: Structure `non_camel_case_name` should have UpperCamelCase name, e.g. `NonCamelCaseName` struct SCREAMING_CASE {} - // ^^^^^^^^^^^^^^ 💡 warn: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` + // ^^^^^^^^^^^^^^ 💡 warn: Structure `SCREAMING_CASE` should have UpperCamelCase name, e.g. `ScreamingCase` "#, ); } @@ -261,10 +261,10 @@ struct SomeStruct { SomeField: u8 } check_diagnostics( r#" enum some_enum { Val(u8) } - // ^^^^^^^^^ 💡 warn: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` + // ^^^^^^^^^ 💡 warn: Enum `some_enum` should have UpperCamelCase name, e.g. `SomeEnum` enum SOME_ENUM {} - // ^^^^^^^^^ 💡 warn: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` + // ^^^^^^^^^ 💡 warn: Enum `SOME_ENUM` should have UpperCamelCase name, e.g. `SomeEnum` "#, ); } @@ -283,7 +283,7 @@ enum AABB {} check_diagnostics( r#" enum SomeEnum { SOME_VARIANT(u8) } - // ^^^^^^^^^^^^ 💡 warn: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` + // ^^^^^^^^^^^^ 💡 warn: Variant `SOME_VARIANT` should have UpperCamelCase name, e.g. `SomeVariant` "#, ); } @@ -313,7 +313,7 @@ static some_weird_const: u8 = 10; check_diagnostics( r#" struct someStruct; - // ^^^^^^^^^^ 💡 warn: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` + // ^^^^^^^^^^ 💡 warn: Structure `someStruct` should have UpperCamelCase name, e.g. `SomeStruct` impl someStruct { fn SomeFunc(&self) { @@ -530,11 +530,11 @@ extern { check_diagnostics( r#" trait BAD_TRAIT { - // ^^^^^^^^^ 💡 warn: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` + // ^^^^^^^^^ 💡 warn: Trait `BAD_TRAIT` should have UpperCamelCase name, e.g. `BadTrait` const bad_const: u8; // ^^^^^^^^^ 💡 warn: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST` type BAD_TYPE; - // ^^^^^^^^ 💡 warn: Type alias `BAD_TYPE` should have CamelCase name, e.g. `BadType` + // ^^^^^^^^ 💡 warn: Type alias `BAD_TYPE` should have UpperCamelCase name, e.g. `BadType` fn BAD_FUNCTION(); // ^^^^^^^^^^^^ 💡 warn: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` fn BadFunction(); @@ -552,11 +552,11 @@ trait BAD_TRAIT { check_diagnostics_with_disabled( r#" trait BAD_TRAIT { - // ^^^^^^^^^ 💡 warn: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` + // ^^^^^^^^^ 💡 warn: Trait `BAD_TRAIT` should have UpperCamelCase name, e.g. `BadTrait` const bad_const: u8; // ^^^^^^^^^ 💡 warn: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST` type BAD_TYPE; - // ^^^^^^^^ 💡 warn: Type alias `BAD_TYPE` should have CamelCase name, e.g. `BadType` + // ^^^^^^^^ 💡 warn: Type alias `BAD_TYPE` should have UpperCamelCase name, e.g. `BadType` fn BAD_FUNCTION(BAD_PARAM: u8); // ^^^^^^^^^^^^ 💡 warn: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` // ^^^^^^^^^ 💡 warn: Parameter `BAD_PARAM` should have snake_case name, e.g. `bad_param` @@ -664,7 +664,7 @@ mod CheckNonstandardStyle { mod CheckBadStyle { //^^^^^^^^^^^^^ 💡 error: Module `CheckBadStyle` should have snake_case name, e.g. `check_bad_style` struct fooo; - //^^^^ 💡 error: Structure `fooo` should have CamelCase name, e.g. `Fooo` + //^^^^ 💡 error: Structure `fooo` should have UpperCamelCase name, e.g. `Fooo` } mod F { @@ -676,7 +676,7 @@ mod F { #[deny(non_snake_case, non_camel_case_types)] pub struct some_type { - //^^^^^^^^^ 💡 error: Structure `some_type` should have CamelCase name, e.g. `SomeType` + //^^^^^^^^^ 💡 error: Structure `some_type` should have UpperCamelCase name, e.g. `SomeType` SOME_FIELD: u8, //^^^^^^^^^^ 💡 error: Field `SOME_FIELD` should have snake_case name, e.g. `some_field` SomeField: u16, @@ -693,11 +693,11 @@ pub static SomeStatic: u8 = 10; #[deny(non_snake_case, non_camel_case_types, non_upper_case_globals)] trait BAD_TRAIT { - // ^^^^^^^^^ 💡 error: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` + // ^^^^^^^^^ 💡 error: Trait `BAD_TRAIT` should have UpperCamelCase name, e.g. `BadTrait` const bad_const: u8; // ^^^^^^^^^ 💡 error: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST` type BAD_TYPE; - // ^^^^^^^^ 💡 error: Type alias `BAD_TYPE` should have CamelCase name, e.g. `BadType` + // ^^^^^^^^ 💡 error: Type alias `BAD_TYPE` should have UpperCamelCase name, e.g. `BadType` fn BAD_FUNCTION(BAD_PARAM: u8); // ^^^^^^^^^^^^ 💡 error: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` // ^^^^^^^^^ 💡 error: Parameter `BAD_PARAM` should have snake_case name, e.g. `bad_param` @@ -952,7 +952,7 @@ fn foo() { let FOO; #[allow(non_snake_case)] struct qux; - // ^^^ 💡 warn: Structure `qux` should have CamelCase name, e.g. `Qux` + // ^^^ 💡 warn: Structure `qux` should have UpperCamelCase name, e.g. `Qux` fn BAZ() { // ^^^ 💡 error: Function `BAZ` should have snake_case name, e.g. `baz` diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs index 6ae9dde84be..9dacbd8badf 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs @@ -29,7 +29,7 @@ pub(crate) fn goto_declaration( .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?; let range = original_token.text_range(); let info: Vec<NavigationTarget> = sema - .descend_into_macros(original_token) + .descend_into_macros_no_opaque(original_token) .iter() .filter_map(|token| { let parent = token.parent()?; diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 8836166d969..c61b2ba84f2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -83,7 +83,7 @@ pub(crate) fn goto_definition( } let navs = sema - .descend_into_macros(original_token.clone()) + .descend_into_macros_no_opaque(original_token.clone()) .into_iter() .filter_map(|token| { let parent = token.parent()?; @@ -2661,6 +2661,24 @@ fn foo() { } #[test] + fn label_inside_macro() { + check( + r#" +macro_rules! m { + ($s:stmt) => { $s }; +} + +fn foo() { + 'label: loop { + // ^^^^^^ + m!(continue 'label$0); + } +} +"#, + ); + } + + #[test] fn goto_def_on_return_in_try() { check( r#" diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index ca04b7bb5a9..c7ebd9a3531 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -69,7 +69,7 @@ pub(crate) fn goto_type_definition( } let range = token.text_range(); - sema.descend_into_macros(token) + sema.descend_into_macros_no_opaque(token) .into_iter() .filter_map(|token| { let ty = sema 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 83adf6548a8..01fa316d5fc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -3,9 +3,9 @@ use std::{mem, ops::Not}; use either::Either; use hir::{ - db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, - HirDisplay, Layout, LayoutError, MethodViolationCode, Name, ObjectSafetyViolation, Semantics, - Trait, Type, TypeInfo, + db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, AssocItemContainer, CaptureKind, + DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError, + MethodViolationCode, Name, Semantics, Trait, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -529,10 +529,10 @@ pub(super) fn definition( _ => None, }; - let object_safety_info = if let Definition::Trait(it) = def { - let mut object_safety_info = String::new(); - render_object_safety(db, &mut object_safety_info, it.object_safety(db)); - Some(object_safety_info) + let dyn_compatibility_info = if let Definition::Trait(it) = def { + let mut dyn_compatibility_info = String::new(); + render_dyn_compatibility(db, &mut dyn_compatibility_info, it.dyn_compatibility(db)); + Some(dyn_compatibility_info) } else { None }; @@ -546,8 +546,8 @@ pub(super) fn definition( desc.push_str(&layout_info); desc.push('\n'); } - if let Some(object_safety_info) = object_safety_info { - desc.push_str(&object_safety_info); + if let Some(dyn_compatibility_info) = dyn_compatibility_info { + desc.push_str(&dyn_compatibility_info); desc.push('\n'); } desc.push_str(&label); @@ -813,7 +813,15 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition, edition: Edition) -> if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) { return None; } - def.module(db).map(|module| path(db, module, definition_owner_name(db, def, edition), edition)) + let container: Option<Definition> = + def.as_assoc_item(db).and_then(|assoc| match assoc.container(db) { + AssocItemContainer::Trait(trait_) => Some(trait_.into()), + AssocItemContainer::Impl(impl_) => impl_.self_ty(db).as_adt().map(|adt| adt.into()), + }); + container + .unwrap_or(*def) + .module(db) + .map(|module| path(db, module, definition_owner_name(db, def, edition), edition)) } fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Markup { @@ -980,24 +988,24 @@ fn keyword_hints( } } -fn render_object_safety( +fn render_dyn_compatibility( db: &RootDatabase, buf: &mut String, - safety: Option<ObjectSafetyViolation>, + safety: Option<DynCompatibilityViolation>, ) { let Some(osv) = safety else { - buf.push_str("// Object Safety: Yes"); + buf.push_str("// Dyn Compatible: Yes"); return; }; - buf.push_str("// Object Safety: No\n// - Reason: "); + buf.push_str("// Dyn Compatible: No\n// - Reason: "); match osv { - ObjectSafetyViolation::SizedSelf => { + DynCompatibilityViolation::SizedSelf => { buf.push_str("has a `Self: Sized` bound"); } - ObjectSafetyViolation::SelfReferential => { + DynCompatibilityViolation::SelfReferential => { buf.push_str("has a bound that references `Self`"); } - ObjectSafetyViolation::Method(func, mvc) => { + DynCompatibilityViolation::Method(func, mvc) => { let name = hir::Function::from(func).name(db); format_to!( buf, @@ -1020,7 +1028,7 @@ fn render_object_safety( }; buf.push_str(desc); } - ObjectSafetyViolation::AssocConst(const_) => { + DynCompatibilityViolation::AssocConst(const_) => { let name = hir::Const::from(const_).name(db); if let Some(name) = name { format_to!(buf, "has an associated constant `{}`", name.as_str()); @@ -1028,11 +1036,11 @@ fn render_object_safety( buf.push_str("has an associated constant"); } } - ObjectSafetyViolation::GAT(alias) => { + DynCompatibilityViolation::GAT(alias) => { let name = hir::TypeAlias::from(alias).name(db); format_to!(buf, "has a generic associated type `{}`", name.as_str()); } - ObjectSafetyViolation::HasNonSafeSuperTrait(super_trait) => { + DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => { let name = hir::Trait::from(super_trait).name(db); format_to!(buf, "has a object unsafe supertrait `{}`", name.as_str()); } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index cca62d2181f..e60be577f79 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -7175,7 +7175,7 @@ impl T$0 for () {} ``` ```rust - // Object Safety: Yes + // Dyn Compatible: Yes trait T {} ``` "#]], @@ -7195,7 +7195,7 @@ impl T$0 for () {} ``` ```rust - // Object Safety: Yes + // Dyn Compatible: Yes trait T {} ``` "#]], @@ -7219,7 +7219,7 @@ impl T$0 for () {} ``` ```rust - // Object Safety: No + // Dyn Compatible: No // - Reason: has a method `func` that is non dispatchable because of: // - missing a receiver trait T { /* … */ } @@ -7245,7 +7245,7 @@ impl T$0 for () {} ``` ```rust - // Object Safety: No + // Dyn Compatible: No // - Reason: has a method `func` that is non dispatchable because of: // - missing a receiver trait T { @@ -7275,7 +7275,7 @@ impl T$0 for () {} ``` ```rust - // Object Safety: No + // Dyn Compatible: No // - Reason: has a method `func` that is non dispatchable because of: // - missing a receiver trait T { @@ -7305,7 +7305,7 @@ impl T$0 for () {} ``` ```rust - // Object Safety: No + // Dyn Compatible: No // - Reason: has a method `func` that is non dispatchable because of: // - missing a receiver trait T { @@ -8962,3 +8962,29 @@ fn test_hover_function_with_pat_param() { "#]], ); } + +#[test] +fn hover_path_inside_block_scope() { + check( + r#" +mod m { + const _: () = { + mod m2 { + const C$0: () = (); + } + }; +} +"#, + expect![[r#" + *C* + + ```rust + test::m::m2 + ``` + + ```rust + const C: () = () + ``` + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 547286c3f4d..c46c4c8ce94 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -119,8 +119,8 @@ pub use ide_assists::{ Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve, }; pub use ide_completion::{ - CallableSnippets, CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance, - Snippet, SnippetScope, + CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem, + CompletionItemKind, CompletionRelevance, Snippet, SnippetScope, }; pub use ide_db::{ base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId}, 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 927fdaa178c..961b2a4c938 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -409,7 +409,8 @@ fn traverse( let mut r = 0; sema.descend_into_macros_breakable( InRealFile::new(file_id, token.clone()), - |tok| { + |tok, _ctx| { + // FIXME: Consider checking ctx transparency for being opaque? let tok = tok.value; let tok_kind = tok.kind(); 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 baa45174236..0e1606a6991 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -265,6 +265,11 @@ impl ProjectFolders { entries.push(manifest.to_owned()); } + for buildfile in ws.buildfiles() { + file_set_roots.push(VfsPath::from(buildfile.to_owned())); + entries.push(buildfile.to_owned()); + } + // In case of detached files we do **not** look for a rust-analyzer.toml. if !matches!(ws.kind, ProjectWorkspaceKind::DetachedFile { .. }) { let ws_root = ws.workspace_root(); @@ -521,7 +526,7 @@ mod tests { #[test] fn test_loading_rust_analyzer() { let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); - let cargo_config = CargoConfig::default(); + 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, diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index dceac815e0b..7ea23b4f752 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -187,6 +187,12 @@ impl<'a> Converter<'a> { } rustc_lexer::TokenKind::RawIdent => IDENT, + + rustc_lexer::TokenKind::GuardedStrPrefix => { + err = "Invalid string literal (reserved syntax)"; + ERROR + }, + rustc_lexer::TokenKind::Literal { kind, .. } => { self.extend_literal(token_text.len(), kind); return; diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 7cc21bcf131..2dc6f0357e3 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -100,6 +100,7 @@ pub struct CargoConfig { pub invocation_strategy: InvocationStrategy, /// Optional path to use instead of `target` when building pub target_dir: Option<Utf8PathBuf>, + pub set_test: bool, } pub type Package = Idx<PackageData>; 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 30d1ddb636e..5099697a696 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -35,6 +35,7 @@ fn load_cargo_with_overrides( rustc: Err(None), cargo_config_extra_env: Default::default(), error: None, + set_test: true, }, cfg_overrides, sysroot: Sysroot::empty(), @@ -242,6 +243,7 @@ fn smoke_test_real_sysroot_cargo() { rustc: Err(None), cargo_config_extra_env: Default::default(), error: None, + set_test: true, }, sysroot, rustc_cfg: Vec::new(), diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 17b40a87cda..71b9b61e205 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -78,6 +78,7 @@ pub enum ProjectWorkspaceKind { rustc: Result<Box<(CargoWorkspace, WorkspaceBuildScripts)>, Option<String>>, /// Environment variables set in the `.cargo/config` file. cargo_config_extra_env: FxHashMap<String, String>, + set_test: bool, }, /// Project workspace was specified using a `rust-project.json` file. Json(ProjectJson), @@ -98,6 +99,7 @@ pub enum ProjectWorkspaceKind { cargo: Option<(CargoWorkspace, WorkspaceBuildScripts, Option<Arc<anyhow::Error>>)>, /// Environment variables set in the `.cargo/config` file. cargo_config_extra_env: FxHashMap<String, String>, + set_test: bool, }, } @@ -112,6 +114,7 @@ impl fmt::Debug for ProjectWorkspace { build_scripts, rustc, cargo_config_extra_env, + set_test, } => f .debug_struct("Cargo") .field("root", &cargo.workspace_root().file_name()) @@ -126,6 +129,7 @@ impl fmt::Debug for ProjectWorkspace { .field("toolchain", &toolchain) .field("data_layout", &target_layout) .field("cargo_config_extra_env", &cargo_config_extra_env) + .field("set_test", set_test) .field("build_scripts", &build_scripts.error().unwrap_or("ok")) .finish(), ProjectWorkspaceKind::Json(project) => { @@ -137,12 +141,14 @@ impl fmt::Debug for ProjectWorkspace { .field("toolchain", &toolchain) .field("data_layout", &target_layout) .field("n_cfg_overrides", &cfg_overrides.len()); + debug_struct.finish() } ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, cargo_config_extra_env, + set_test, } => f .debug_struct("DetachedFiles") .field("file", &file) @@ -154,6 +160,7 @@ impl fmt::Debug for ProjectWorkspace { .field("data_layout", &target_layout) .field("n_cfg_overrides", &cfg_overrides.len()) .field("cargo_config_extra_env", &cargo_config_extra_env) + .field("set_test", set_test) .finish(), } } @@ -329,6 +336,7 @@ impl ProjectWorkspace { rustc, cargo_config_extra_env, error: error.map(Arc::new), + set_test: config.set_test, }, sysroot, rustc_cfg, @@ -423,6 +431,7 @@ impl ProjectWorkspace { file: detached_file.to_owned(), cargo: cargo_script, cargo_config_extra_env, + set_test: config.set_test, }, sysroot, rustc_cfg, @@ -539,6 +548,17 @@ impl ProjectWorkspace { } } + pub fn buildfiles(&self) -> Vec<AbsPathBuf> { + match &self.kind { + ProjectWorkspaceKind::Json(project) => project + .crates() + .filter_map(|(_, krate)| krate.build.as_ref().map(|build| build.build_file.clone())) + .map(AbsPathBuf::assert) + .collect(), + _ => vec![], + } + } + pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> { self.sysroot.discover_proc_macro_srv() } @@ -598,6 +618,7 @@ impl ProjectWorkspace { build_scripts, cargo_config_extra_env: _, error: _, + set_test: _, } => { cargo .packages() @@ -739,6 +760,7 @@ impl ProjectWorkspace { build_scripts, cargo_config_extra_env: _, error: _, + set_test, } => ( cargo_to_crate_graph( load, @@ -748,10 +770,11 @@ impl ProjectWorkspace { rustc_cfg.clone(), cfg_overrides, build_scripts, + *set_test, ), sysroot, ), - ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => ( + ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => ( if let Some((cargo, build_scripts, _)) = cargo_script { cargo_to_crate_graph( &mut |path| load(path), @@ -761,6 +784,7 @@ impl ProjectWorkspace { rustc_cfg.clone(), cfg_overrides, build_scripts, + *set_test, ) } else { detached_file_to_crate_graph( @@ -769,6 +793,7 @@ impl ProjectWorkspace { file, sysroot, cfg_overrides, + *set_test, ) }, sysroot, @@ -802,6 +827,7 @@ impl ProjectWorkspace { cargo_config_extra_env, build_scripts: _, error: _, + set_test: _, }, ProjectWorkspaceKind::Cargo { cargo: o_cargo, @@ -809,6 +835,7 @@ impl ProjectWorkspace { cargo_config_extra_env: o_cargo_config_extra_env, build_scripts: _, error: _, + set_test: _, }, ) => { cargo == o_cargo @@ -823,11 +850,13 @@ impl ProjectWorkspace { file, cargo: Some((cargo_script, _, _)), cargo_config_extra_env, + set_test: _, }, ProjectWorkspaceKind::DetachedFile { file: o_file, cargo: Some((o_cargo_script, _, _)), cargo_config_extra_env: o_cargo_config_extra_env, + set_test: _, }, ) => { file == o_file @@ -976,6 +1005,7 @@ fn cargo_to_crate_graph( rustc_cfg: Vec<CfgAtom>, override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, + set_test: bool, ) -> (CrateGraph, ProcMacroPaths) { let _p = tracing::info_span!("cargo_to_crate_graph").entered(); let mut res = (CrateGraph::default(), ProcMacroPaths::default()); @@ -1000,8 +1030,10 @@ fn cargo_to_crate_graph( let mut cfg_options = cfg_options.clone(); if cargo[pkg].is_local { - // Add test cfg for local crates - cfg_options.insert_atom(sym::test.clone()); + if set_test { + // Add test cfg for local crates + cfg_options.insert_atom(sym::test.clone()); + } cfg_options.insert_atom(sym::rust_analyzer.clone()); } @@ -1162,6 +1194,7 @@ fn detached_file_to_crate_graph( detached_file: &ManifestPath, sysroot: &Sysroot, override_cfg: &CfgOverrides, + set_test: bool, ) -> (CrateGraph, ProcMacroPaths) { let _p = tracing::info_span!("detached_file_to_crate_graph").entered(); let mut crate_graph = CrateGraph::default(); @@ -1169,7 +1202,9 @@ fn detached_file_to_crate_graph( sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); let mut cfg_options = CfgOptions::from_iter(rustc_cfg); - cfg_options.insert_atom(sym::test.clone()); + if set_test { + cfg_options.insert_atom(sym::test.clone()); + } cfg_options.insert_atom(sym::rust_analyzer.clone()); override_cfg.apply(&mut cfg_options, ""); let cfg_options = Arc::new(cfg_options); @@ -1415,6 +1450,7 @@ fn sysroot_to_crate_graph( ..Default::default() }, &WorkspaceBuildScripts::default(), + false, ); let mut pub_deps = vec![]; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index 41b42573f08..ecc8333503e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -137,6 +137,7 @@ fn setup_logging(log_file_flag: Option<PathBuf>) -> anyhow::Result<()> { filter: env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_owned()), chalk_filter: env::var("CHALK_DEBUG").ok(), profile_filter: env::var("RA_PROFILE").ok(), + json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(), } .init()?; 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 e899e0e8eea..4844c514ae9 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 @@ -65,6 +65,7 @@ impl flags::AnalysisStats { false => Some(RustLibSource::Discover), }, all_targets: true, + set_test: true, ..Default::default() }; let no_progress = &|_| (); @@ -81,7 +82,13 @@ impl flags::AnalysisStats { with_proc_macro_server: if self.disable_proc_macros { ProcMacroServerChoice::None } else { - ProcMacroServerChoice::Sysroot + match self.proc_macro_srv { + Some(ref path) => { + let path = vfs::AbsPathBuf::assert_utf8(path.to_owned()); + ProcMacroServerChoice::Explicit(path) + } + None => ProcMacroServerChoice::Sysroot, + } }, prefill_caches: false, }; 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 73e71658d17..60d621b214a 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 @@ -76,6 +76,8 @@ xflags::xflags! { optional --disable-build-scripts /// Don't use expand proc macros. optional --disable-proc-macros + /// Run the proc-macro-srv binary at the specified path. + optional --proc-macro-srv path: PathBuf /// Skip body lowering. optional --skip-lowering /// Skip type inference. @@ -120,7 +122,7 @@ xflags::xflags! { optional --disable-build-scripts /// Don't use expand proc macros. optional --disable-proc-macros - /// Run a custom proc-macro-srv binary. + /// Run the proc-macro-srv binary at the specified path. optional --proc-macro-srv path: PathBuf } @@ -133,7 +135,7 @@ xflags::xflags! { optional --disable-build-scripts /// Don't use expand proc macros. optional --disable-proc-macros - /// Run a custom proc-macro-srv binary. + /// Run the proc-macro-srv binary at the specified path. optional --proc-macro-srv path: PathBuf } @@ -233,6 +235,7 @@ pub struct AnalysisStats { pub no_sysroot: bool, pub disable_build_scripts: bool, pub disable_proc_macros: bool, + pub proc_macro_srv: Option<PathBuf>, pub skip_lowering: bool, pub skip_inference: bool, pub skip_mir_stats: bool, 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 e4263a3f667..ca8acf57bff 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 @@ -277,6 +277,7 @@ impl flags::Lsif { let cargo_config = &CargoConfig { sysroot: Some(RustLibSource::Discover), all_targets: true, + set_test: true, ..Default::default() }; let no_progress = &|_| (); 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 f90ebcfdb2e..11534bbeba9 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 @@ -16,6 +16,7 @@ impl flags::RunTests { let cargo_config = CargoConfig { sysroot: Some(RustLibSource::Discover), all_targets: true, + set_test: true, ..Default::default() }; let load_cargo_config = LoadCargoConfig { 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 730f3c08abb..30378db0b38 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 @@ -70,6 +70,7 @@ impl Tester { let cargo_config = CargoConfig { sysroot: Some(RustLibSource::Discover), all_targets: true, + set_test: true, ..Default::default() }; @@ -85,6 +86,7 @@ impl Tester { file: ManifestPath::try_from(tmp_file).unwrap(), cargo: None, cargo_config_extra_env: Default::default(), + set_test: true, }, sysroot, rustc_cfg: vec![], 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 e9198977dea..ff009e69547 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 @@ -24,11 +24,6 @@ impl flags::Scip { let now = Instant::now(); let no_progress = &|s| (eprintln!("rust-analyzer: Loading {s}")); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: true, - with_proc_macro_server: ProcMacroServerChoice::Sysroot, - prefill_caches: true, - }; let root = vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(&self.path)).normalize(); @@ -51,6 +46,11 @@ impl flags::Scip { // FIXME @alibektas : What happens to errors without logging? error!(?error_sink, "Config Error(s)"); } + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: true, + with_proc_macro_server: ProcMacroServerChoice::Sysroot, + prefill_caches: true, + }; let cargo_config = config.cargo(None); let (db, vfs, _) = load_workspace_at( root.as_path().as_ref(), 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 bdca800a0d6..c03688e8009 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 @@ -13,6 +13,7 @@ impl flags::Ssr { let cargo_config = CargoConfig { sysroot: Some(RustLibSource::Discover), all_targets: true, + set_test: true, ..Default::default() }; let load_cargo_config = LoadCargoConfig { @@ -50,7 +51,8 @@ impl flags::Search { pub fn run(self) -> anyhow::Result<()> { use ide_db::base_db::SourceRootDatabase; use ide_db::symbol_index::SymbolsDatabase; - let cargo_config = CargoConfig::default(); + let cargo_config = + CargoConfig { all_targets: true, set_test: true, ..CargoConfig::default() }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro_server: ProcMacroServerChoice::Sysroot, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 4cc60695fe6..ef2e542cf22 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -12,10 +12,10 @@ use std::{ use cfg::{CfgAtom, CfgDiff}; use hir::Symbol; use ide::{ - AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, - GenericParameterHints, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, - InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, - MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId, + AssistConfig, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig, + ExprFillDefaultMode, GenericParameterHints, HighlightConfig, HighlightRelatedConfig, + HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, + MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, @@ -574,6 +574,9 @@ config_data! { /// set to a path relative to the workspace to use that path. cargo_targetDir | rust_analyzerTargetDir: Option<TargetDirectory> = None, + /// Set `cfg(test)` for local crates. Defaults to true. + cfg_setTest: bool = true, + /// Run the check command for diagnostics on save. checkOnSave | checkOnSave_enable: bool = true, @@ -695,7 +698,6 @@ config_data! { workspace_symbol_search_limit: usize = 128, /// Workspace symbol search scope. workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = WorkspaceSymbolSearchScopeDef::Workspace, - } } @@ -1391,6 +1393,7 @@ impl Config { } pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig { + let client_capability_fields = self.completion_resolve_support_properties(); CompletionConfig { enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(), enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned() @@ -1415,6 +1418,15 @@ impl Config { limit: self.completion_limit(source_root).to_owned(), enable_term_search: self.completion_termSearch_enable(source_root).to_owned(), term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64, + fields_to_resolve: CompletionFieldsToResolve { + resolve_label_details: client_capability_fields.contains("labelDetails"), + resolve_tags: client_capability_fields.contains("tags"), + resolve_detail: client_capability_fields.contains("detail"), + resolve_documentation: client_capability_fields.contains("documentation"), + resolve_filter_text: client_capability_fields.contains("filterText"), + resolve_text_edit: client_capability_fields.contains("textEdit"), + resolve_command: client_capability_fields.contains("command"), + }, } } @@ -1859,9 +1871,14 @@ impl Config { extra_args: self.cargo_extraArgs(source_root).clone(), extra_env: self.cargo_extraEnv(source_root).clone(), target_dir: self.target_dir_from_config(source_root), + set_test: *self.cfg_setTest(source_root), } } + pub fn cfg_set_test(&self, source_root: Option<SourceRootId>) -> bool { + *self.cfg_setTest(source_root) + } + pub(crate) fn completion_snippets_default() -> FxHashMap<String, SnippetDef> { serde_json::from_str( r#"{ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs index 7e9162eee6e..96b164228ef 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs @@ -7,6 +7,7 @@ use paths::{AbsPathBuf, Utf8Path, Utf8PathBuf}; use project_model::ProjectJsonData; use serde::{Deserialize, Serialize}; use serde_json::Value; +use tracing::{info_span, span::EnteredSpan}; use crate::command::{CommandHandle, ParseFromLine}; @@ -60,7 +61,10 @@ impl DiscoverCommand { let mut cmd = Command::new(command); cmd.args(args); - Ok(DiscoverHandle { _handle: CommandHandle::spawn(cmd, self.sender.clone())? }) + Ok(DiscoverHandle { + _handle: CommandHandle::spawn(cmd, self.sender.clone())?, + span: info_span!("discover_command").entered(), + }) } } @@ -68,6 +72,8 @@ impl DiscoverCommand { #[derive(Debug)] pub(crate) struct DiscoverHandle { _handle: CommandHandle<DiscoverProjectMessage>, + #[allow(dead_code)] // not accessed, but used to log on drop. + span: EnteredSpan, } /// An enum containing either progress messages, an error, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 89487aa673b..c3142c9cfca 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -46,6 +46,11 @@ pub(crate) struct FetchWorkspaceRequest { pub(crate) force_crate_graph_reload: bool, } +pub(crate) struct FetchWorkspaceResponse { + pub(crate) workspaces: Vec<anyhow::Result<ProjectWorkspace>>, + pub(crate) force_crate_graph_reload: bool, +} + // Enforces drop order pub(crate) struct Handle<H, C> { pub(crate) handle: H, @@ -111,6 +116,9 @@ pub(crate) struct GlobalState { pub(crate) vfs_config_version: u32, pub(crate) vfs_progress_config_version: u32, pub(crate) vfs_done: bool, + // used to track how long VFS loading takes. this can't be on `vfs::loader::Handle`, + // as that handle's lifetime is the same as `GlobalState` itself. + pub(crate) vfs_span: Option<tracing::span::EnteredSpan>, pub(crate) wants_to_switch: Option<Cause>, /// `workspaces` field stores the data we actually use, while the `OpQueue` @@ -143,8 +151,7 @@ pub(crate) struct GlobalState { pub(crate) detached_files: FxHashSet<ManifestPath>, // op queues - pub(crate) fetch_workspaces_queue: - OpQueue<FetchWorkspaceRequest, Option<(Vec<anyhow::Result<ProjectWorkspace>>, bool)>>, + pub(crate) fetch_workspaces_queue: OpQueue<FetchWorkspaceRequest, FetchWorkspaceResponse>, pub(crate) fetch_build_data_queue: OpQueue<(), (Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>, pub(crate) fetch_proc_macros_queue: OpQueue<Vec<ProcMacroPaths>, bool>, @@ -253,6 +260,7 @@ impl GlobalState { vfs: Arc::new(RwLock::new((vfs::Vfs::default(), IntMap::default()))), vfs_config_version: 0, vfs_progress_config_version: 0, + vfs_span: None, vfs_done: true, wants_to_switch: None, @@ -498,7 +506,7 @@ impl GlobalState { mem_docs: self.mem_docs.clone(), semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache), proc_macros_loaded: !self.config.expand_proc_macros() - || *self.fetch_proc_macros_queue.last_op_result(), + || self.fetch_proc_macros_queue.last_op_result().copied().unwrap_or(false), flycheck: self.flycheck.clone(), } } 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 49b1ba32a79..bb03eb3c89b 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 @@ -380,7 +380,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { if id == flycheck.id() { updated = true; match package.filter(|_| { - !world.config.flycheck_workspace(source_root_id) || target.is_some() + !world.config.flycheck_workspace(source_root_id) && target.is_some() }) { Some(package) => flycheck .restart_for_package(package, target.clone().map(TupleExt::head)), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index bcbd970a0d2..9773d8dbce0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -10,9 +10,9 @@ use std::{ use anyhow::Context; use ide::{ - AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange, - HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, - Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit, + AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, + FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, + RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit, }; use ide_db::SymbolKind; use itertools::Itertools; @@ -1019,9 +1019,11 @@ pub(crate) fn handle_completion( let items = to_proto::completion_items( &snap.config, + &completion_config.fields_to_resolve, &line_index, snap.file_version(position.file_id), text_document_position, + completion_trigger_character, items, ); @@ -1054,36 +1056,70 @@ pub(crate) fn handle_completion_resolve( }; let source_root = snap.analysis.source_root_id(file_id)?; - let additional_edits = snap - .analysis - .resolve_completion_edits( - &snap.config.completion(Some(source_root)), - FilePosition { file_id, offset }, - resolve_data - .imports - .into_iter() - .map(|import| (import.full_import_path, import.imported_name)), - )? - .into_iter() - .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) - .collect::<Vec<_>>(); + let mut forced_resolve_completions_config = snap.config.completion(Some(source_root)); + forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty(); - if !all_edits_are_disjoint(&original_completion, &additional_edits) { - return Err(LspError::new( - ErrorCode::InternalError as i32, - "Import edit overlaps with the original completion edits, this is not LSP-compliant" - .into(), - ) - .into()); - } + let position = FilePosition { file_id, offset }; + let Some(resolved_completions) = snap.analysis.completions( + &forced_resolve_completions_config, + position, + resolve_data.trigger_character, + )? + else { + return Ok(original_completion); + }; + let resolved_completions = to_proto::completion_items( + &snap.config, + &forced_resolve_completions_config.fields_to_resolve, + &line_index, + snap.file_version(position.file_id), + resolve_data.position, + resolve_data.trigger_character, + resolved_completions, + ); + let Some(mut resolved_completion) = resolved_completions.into_iter().find(|completion| { + completion.label == original_completion.label + && completion.kind == original_completion.kind + && completion.deprecated == original_completion.deprecated + && completion.preselect == original_completion.preselect + && completion.sort_text == original_completion.sort_text + }) else { + return Ok(original_completion); + }; - if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() { - original_additional_edits.extend(additional_edits) - } else { - original_completion.additional_text_edits = Some(additional_edits); + if !resolve_data.imports.is_empty() { + let additional_edits = snap + .analysis + .resolve_completion_edits( + &forced_resolve_completions_config, + position, + resolve_data + .imports + .into_iter() + .map(|import| (import.full_import_path, import.imported_name)), + )? + .into_iter() + .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) + .collect::<Vec<_>>(); + + if !all_edits_are_disjoint(&resolved_completion, &additional_edits) { + return Err(LspError::new( + ErrorCode::InternalError as i32, + "Import edit overlaps with the original completion edits, this is not LSP-compliant" + .into(), + ) + .into()); + } + + if let Some(original_additional_edits) = resolved_completion.additional_text_edits.as_mut() + { + original_additional_edits.extend(additional_edits) + } else { + resolved_completion.additional_text_edits = Some(additional_edits); + } } - Ok(original_completion) + Ok(resolved_completion) } pub(crate) fn handle_folding_range( 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 118469df730..8946c7acb93 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 @@ -12,7 +12,8 @@ use hir::ChangeWithProcMacros; use ide::{ - AnalysisHost, CallableSnippets, CompletionConfig, DiagnosticsConfig, FilePosition, TextSize, + AnalysisHost, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig, + FilePosition, TextSize, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig}, @@ -36,6 +37,8 @@ fn integrated_highlighting_benchmark() { let cargo_config = CargoConfig { sysroot: Some(project_model::RustLibSource::Discover), + all_targets: true, + set_test: true, ..CargoConfig::default() }; let load_cargo_config = LoadCargoConfig { @@ -102,6 +105,8 @@ fn integrated_completion_benchmark() { let cargo_config = CargoConfig { sysroot: Some(project_model::RustLibSource::Discover), + all_targets: true, + set_test: true, ..CargoConfig::default() }; let load_cargo_config = LoadCargoConfig { @@ -168,6 +173,7 @@ fn integrated_completion_benchmark() { snippets: Vec::new(), limit: None, add_semicolon_to_unit: true, + fields_to_resolve: CompletionFieldsToResolve::empty(), }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; @@ -215,6 +221,7 @@ fn integrated_completion_benchmark() { snippets: Vec::new(), limit: None, add_semicolon_to_unit: true, + fields_to_resolve: CompletionFieldsToResolve::empty(), }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; @@ -260,6 +267,7 @@ fn integrated_completion_benchmark() { snippets: Vec::new(), limit: None, add_semicolon_to_unit: true, + fields_to_resolve: CompletionFieldsToResolve::empty(), }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; @@ -279,6 +287,8 @@ fn integrated_diagnostics_benchmark() { let cargo_config = CargoConfig { sysroot: Some(project_model::RustLibSource::Discover), + all_targets: true, + set_test: true, ..CargoConfig::default() }; let load_cargo_config = LoadCargoConfig { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index 714991e8116..234204695cb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -34,6 +34,7 @@ mod handlers { pub mod tracing { pub mod config; + pub mod json; pub use config::Config; pub mod hprof; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index 9610808c27e..3b19284f241 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -448,7 +448,7 @@ impl ClientCapabilities { .unwrap_or_default() } - pub fn inlay_hint_resolve_support_properties(&self) -> FxHashSet<String> { + pub fn inlay_hint_resolve_support_properties(&self) -> FxHashSet<&str> { self.0 .text_document .as_ref() @@ -457,8 +457,22 @@ impl ClientCapabilities { .map(|inlay_resolve| inlay_resolve.properties.iter()) .into_iter() .flatten() - .cloned() - .collect::<FxHashSet<_>>() + .map(|s| s.as_str()) + .collect() + } + + pub fn completion_resolve_support_properties(&self) -> FxHashSet<&str> { + self.0 + .text_document + .as_ref() + .and_then(|text| text.completion.as_ref()) + .and_then(|completion_caps| completion_caps.completion_item.as_ref()) + .and_then(|completion_item_caps| completion_item_caps.resolve_support.as_ref()) + .map(|resolve_support| resolve_support.properties.iter()) + .into_iter() + .flatten() + .map(|s| s.as_str()) + .collect() } pub fn hover_markdown_support(&self) -> bool { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 618481bbc66..8039f0644ee 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -825,6 +825,7 @@ pub struct CompletionResolveData { pub position: lsp_types::TextDocumentPositionParams, pub imports: Vec<CompletionImport>, pub version: Option<i32>, + pub trigger_character: Option<char>, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index 4902c9f88c1..375b7428c2d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -6,9 +6,9 @@ use std::{ }; use ide::{ - Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem, - CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, - Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, + Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve, + CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, + FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp, SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, @@ -227,9 +227,11 @@ pub(crate) fn snippet_text_edit_vec( pub(crate) fn completion_items( config: &Config, + fields_to_resolve: &CompletionFieldsToResolve, line_index: &LineIndex, version: Option<i32>, tdpp: lsp_types::TextDocumentPositionParams, + completion_trigger_character: Option<char>, mut items: Vec<CompletionItem>, ) -> Vec<lsp_types::CompletionItem> { if config.completion_hide_deprecated() { @@ -239,7 +241,17 @@ pub(crate) fn completion_items( let max_relevance = items.iter().map(|it| it.relevance.score()).max().unwrap_or_default(); let mut res = Vec::with_capacity(items.len()); for item in items { - completion_item(&mut res, config, line_index, version, &tdpp, max_relevance, item); + completion_item( + &mut res, + config, + fields_to_resolve, + line_index, + version, + &tdpp, + max_relevance, + completion_trigger_character, + item, + ); } if let Some(limit) = config.completion(None).limit { @@ -253,21 +265,33 @@ pub(crate) fn completion_items( fn completion_item( acc: &mut Vec<lsp_types::CompletionItem>, config: &Config, + fields_to_resolve: &CompletionFieldsToResolve, line_index: &LineIndex, version: Option<i32>, tdpp: &lsp_types::TextDocumentPositionParams, max_relevance: u32, + completion_trigger_character: Option<char>, item: CompletionItem, ) { let insert_replace_support = config.insert_replace_support().then_some(tdpp.position); let ref_match = item.ref_match(); - let lookup = item.lookup().to_owned(); let mut additional_text_edits = Vec::new(); + let mut something_to_resolve = false; - // LSP does not allow arbitrary edits in completion, so we have to do a - // non-trivial mapping here. - let text_edit = { + let filter_text = if fields_to_resolve.resolve_filter_text { + something_to_resolve = !item.lookup().is_empty(); + None + } else { + Some(item.lookup().to_owned()) + }; + + let text_edit = if fields_to_resolve.resolve_text_edit { + something_to_resolve = true; + None + } else { + // LSP does not allow arbitrary edits in completion, so we have to do a + // non-trivial mapping here. let mut text_edit = None; let source_range = item.source_range; for indel in item.text_edit { @@ -290,25 +314,49 @@ fn completion_item( additional_text_edits.push(text_edit); } } - text_edit.unwrap() + Some(text_edit.unwrap()) }; let insert_text_format = item.is_snippet.then_some(lsp_types::InsertTextFormat::SNIPPET); - let tags = item.deprecated.then(|| vec![lsp_types::CompletionItemTag::DEPRECATED]); + let tags = if fields_to_resolve.resolve_tags { + something_to_resolve = item.deprecated; + None + } else { + item.deprecated.then(|| vec![lsp_types::CompletionItemTag::DEPRECATED]) + }; let command = if item.trigger_call_info && config.client_commands().trigger_parameter_hints { - Some(command::trigger_parameter_hints()) + if fields_to_resolve.resolve_command { + something_to_resolve = true; + None + } else { + Some(command::trigger_parameter_hints()) + } + } else { + None + }; + + let detail = if fields_to_resolve.resolve_detail { + something_to_resolve = item.detail.is_some(); + None } else { + item.detail + }; + + let documentation = if fields_to_resolve.resolve_documentation { + something_to_resolve = item.documentation.is_some(); None + } else { + item.documentation.map(documentation) }; let mut lsp_item = lsp_types::CompletionItem { label: item.label.to_string(), - detail: item.detail, - filter_text: Some(lookup), + detail, + filter_text, kind: Some(completion_item_kind(item.kind)), - text_edit: Some(text_edit), + text_edit, additional_text_edits: Some(additional_text_edits), - documentation: item.documentation.map(documentation), + documentation, deprecated: Some(item.deprecated), tags, command, @@ -317,29 +365,40 @@ fn completion_item( }; if config.completion_label_details_support() { - lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { - detail: item.label_detail.as_ref().map(ToString::to_string), - description: lsp_item.detail.clone(), - }); + if fields_to_resolve.resolve_label_details { + something_to_resolve = true; + } else { + lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { + detail: item.label_detail.as_ref().map(ToString::to_string), + description: lsp_item.detail.clone(), + }); + } } else if let Some(label_detail) = item.label_detail { lsp_item.label.push_str(label_detail.as_str()); } set_score(&mut lsp_item, max_relevance, item.relevance); - if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() { - let imports = item - .import_to_add - .into_iter() - .map(|(import_path, import_name)| lsp_ext::CompletionImport { - full_import_path: import_path, - imported_name: import_name, - }) - .collect::<Vec<_>>(); - if !imports.is_empty() { - let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports, version }; - lsp_item.data = Some(to_value(data).unwrap()); - } + let imports = + if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() { + item.import_to_add + .into_iter() + .map(|(import_path, import_name)| lsp_ext::CompletionImport { + full_import_path: import_path, + imported_name: import_name, + }) + .collect() + } else { + Vec::new() + }; + if something_to_resolve || !imports.is_empty() { + let data = lsp_ext::CompletionResolveData { + position: tdpp.clone(), + imports, + version, + trigger_character: completion_trigger_character, + }; + lsp_item.data = Some(to_value(data).unwrap()); } if let Some((label, indel, relevance)) = ref_match { 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 83559230257..ef289720568 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 @@ -22,7 +22,9 @@ use crate::{ diagnostics::{fetch_native_diagnostics, DiagnosticsGeneration, NativeDiagnosticsFetchKind}, discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage}, flycheck::{self, FlycheckMessage}, - global_state::{file_id_to_url, url_to_file_id, FetchWorkspaceRequest, GlobalState}, + global_state::{ + file_id_to_url, url_to_file_id, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState, + }, hack_recover_crate_name, handlers::dispatch::{NotificationDispatcher, RequestDispatcher}, lsp::{ @@ -695,9 +697,9 @@ impl GlobalState { let (state, msg) = match progress { ProjectWorkspaceProgress::Begin => (Progress::Begin, None), ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), - ProjectWorkspaceProgress::End(workspaces, force_reload_crate_graph) => { - self.fetch_workspaces_queue - .op_completed(Some((workspaces, force_reload_crate_graph))); + ProjectWorkspaceProgress::End(workspaces, force_crate_graph_reload) => { + let resp = FetchWorkspaceResponse { workspaces, force_crate_graph_reload }; + self.fetch_workspaces_queue.op_completed(resp); if let Err(e) = self.fetch_workspace_error() { error!("FetchWorkspaceError: {e}"); } @@ -794,13 +796,20 @@ impl GlobalState { } } vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => { - let _p = tracing::info_span!("GlobalState::handle_vfs_mgs/progress").entered(); + let _p = span!(Level::INFO, "GlobalState::handle_vfs_mgs/progress").entered(); always!(config_version <= self.vfs_config_version); let (n_done, state) = match n_done { - LoadingProgress::Started => (0, Progress::Begin), + LoadingProgress::Started => { + self.vfs_span = + Some(span!(Level::INFO, "vfs_load", total = n_total).entered()); + (0, Progress::Begin) + } LoadingProgress::Progress(n_done) => (n_done.min(n_total), Progress::Report), - LoadingProgress::Finished => (n_total, Progress::End), + LoadingProgress::Finished => { + self.vfs_span = None; + (n_total, Progress::End) + } }; self.vfs_progress_config_version = config_version; @@ -881,6 +890,7 @@ impl GlobalState { .expect("No title could be found; this is a bug"); match message { DiscoverProjectMessage::Finished { project, buildfile } => { + self.discover_handle = None; self.report_progress(&title, Progress::End, None, None, None); self.discover_workspace_queue.op_completed(()); @@ -892,6 +902,7 @@ impl GlobalState { self.report_progress(&title, Progress::Report, Some(message), None, None) } DiscoverProjectMessage::Error { error, source } => { + self.discover_handle = None; let message = format!("Project discovery failed: {error}"); self.discover_workspace_queue.op_completed(()); self.show_and_log_error(message.clone(), source); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs index 5c4c858e150..123f20605ab 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs @@ -27,12 +27,12 @@ pub(crate) type Cause = String; pub(crate) struct OpQueue<Args = (), Output = ()> { op_requested: Option<(Cause, Args)>, op_in_progress: bool, - last_op_result: Output, + last_op_result: Option<Output>, } -impl<Args, Output: Default> Default for OpQueue<Args, Output> { +impl<Args, Output> Default for OpQueue<Args, Output> { fn default() -> Self { - Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() } + Self { op_requested: None, op_in_progress: false, last_op_result: None } } } @@ -56,12 +56,12 @@ impl<Args, Output> OpQueue<Args, Output> { pub(crate) fn op_completed(&mut self, result: Output) { assert!(self.op_in_progress); self.op_in_progress = false; - self.last_op_result = result; + self.last_op_result = Some(result); } /// Get the result of the last operation. - pub(crate) fn last_op_result(&self) -> &Output { - &self.last_op_result + pub(crate) fn last_op_result(&self) -> Option<&Output> { + self.last_op_result.as_ref() } // Is there an operation that has started, but hasn't yet finished? diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index f6765715c5a..60ee0295a3a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -33,7 +33,7 @@ use vfs::{AbsPath, AbsPathBuf, ChangeKind}; use crate::{ config::{Config, FilesWatcher, LinkedProject}, flycheck::{FlycheckConfig, FlycheckHandle}, - global_state::{FetchWorkspaceRequest, GlobalState}, + global_state::{FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState}, lsp_ext, main_loop::{DiscoverProjectParam, Task}, op_queue::Cause, @@ -448,15 +448,15 @@ impl GlobalState { let _p = tracing::info_span!("GlobalState::switch_workspaces").entered(); tracing::info!(%cause, "will switch workspaces"); - let Some((workspaces, force_reload_crate_graph)) = + let Some(FetchWorkspaceResponse { workspaces, force_crate_graph_reload }) = self.fetch_workspaces_queue.last_op_result() else { return; }; - info!(%cause, ?force_reload_crate_graph); + info!(%cause, ?force_crate_graph_reload); if self.fetch_workspace_error().is_err() && !self.workspaces.is_empty() { - if *force_reload_crate_graph { + if *force_crate_graph_reload { self.recreate_crate_graph(cause); } // It only makes sense to switch to a partially broken workspace @@ -474,8 +474,12 @@ impl GlobalState { .all(|(l, r)| l.eq_ignore_build_data(r)); if same_workspaces { - let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result(); - if Arc::ptr_eq(workspaces, &self.workspaces) { + let (workspaces, build_scripts) = match self.fetch_build_data_queue.last_op_result() { + Some((workspaces, build_scripts)) => (workspaces.clone(), build_scripts.as_slice()), + None => (Default::default(), Default::default()), + }; + + if Arc::ptr_eq(&workspaces, &self.workspaces) { info!("set build scripts to workspaces"); let workspaces = workspaces @@ -492,7 +496,7 @@ impl GlobalState { self.workspaces = Arc::new(workspaces); } else { info!("build scripts do not match the version of the active workspace"); - if *force_reload_crate_graph { + if *force_crate_graph_reload { self.recreate_crate_graph(cause); } @@ -739,22 +743,18 @@ impl GlobalState { pub(super) fn fetch_workspace_error(&self) -> Result<(), String> { let mut buf = String::new(); - let Some((last_op_result, _)) = self.fetch_workspaces_queue.last_op_result() else { + let Some(FetchWorkspaceResponse { workspaces, .. }) = + self.fetch_workspaces_queue.last_op_result() + else { return Ok(()); }; - if !self.discover_workspace_queue.op_in_progress() { - if last_op_result.is_empty() { - stdx::format_to!(buf, "rust-analyzer failed to discover workspace"); - } else { - for ws in last_op_result { - if let Err(err) = ws { - stdx::format_to!( - buf, - "rust-analyzer failed to load workspace: {:#}\n", - err - ); - } + if workspaces.is_empty() && self.config.discover_workspace_config().is_none() { + stdx::format_to!(buf, "rust-analyzer failed to fetch workspace"); + } else { + for ws in workspaces { + if let Err(err) = ws { + stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err); } } } @@ -769,7 +769,11 @@ impl GlobalState { pub(super) fn fetch_build_data_error(&self) -> Result<(), String> { let mut buf = String::new(); - for ws in &self.fetch_build_data_queue.last_op_result().1 { + let Some((_, ws)) = &self.fetch_build_data_queue.last_op_result() else { + return Ok(()); + }; + + for ws in ws { match ws { Ok(data) => { if let Some(stderr) = data.error() { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs index f330754f19a..b73f6e77514 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs @@ -1,17 +1,20 @@ //! Simple logger that logs either to stderr or to a file, using `tracing_subscriber` //! filter syntax and `tracing_appender` for non blocking output. -use std::io; +use std::io::{self}; use anyhow::Context; use tracing::level_filters::LevelFilter; use tracing_subscriber::{ - filter::Targets, fmt::MakeWriter, layer::SubscriberExt, util::SubscriberInitExt, Layer, - Registry, + filter::{filter_fn, Targets}, + fmt::MakeWriter, + layer::SubscriberExt, + Layer, Registry, }; use tracing_tree::HierarchicalLayer; use crate::tracing::hprof; +use crate::tracing::json; #[derive(Debug)] pub struct Config<T> { @@ -34,6 +37,12 @@ pub struct Config<T> { /// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 /// ``` pub profile_filter: Option<String>, + + /// Filtering syntax, set in a shell: + /// ``` + /// env RA_PROFILE_JSON=foo|bar|baz + /// ``` + pub json_profile_filter: Option<String>, } impl<T> Config<T> @@ -41,7 +50,7 @@ where T: for<'writer> MakeWriter<'writer> + Send + Sync + 'static, { pub fn init(self) -> anyhow::Result<()> { - let filter: Targets = self + let targets_filter: Targets = self .filter .parse() .with_context(|| format!("invalid log filter: `{}`", self.filter))?; @@ -50,31 +59,60 @@ where let ra_fmt_layer = tracing_subscriber::fmt::layer() .with_target(false) + .with_ansi(false) .with_writer(writer) - .with_filter(filter); - - let mut chalk_layer = None; - if let Some(chalk_filter) = self.chalk_filter { - let level: LevelFilter = - chalk_filter.parse().with_context(|| "invalid chalk log filter")?; - - let chalk_filter = Targets::new() - .with_target("chalk_solve", level) - .with_target("chalk_ir", level) - .with_target("chalk_recursive", level); - chalk_layer = Some( + .with_filter(targets_filter); + + let chalk_layer = match self.chalk_filter { + Some(chalk_filter) => { + let level: LevelFilter = + chalk_filter.parse().with_context(|| "invalid chalk log filter")?; + + let chalk_filter = Targets::new() + .with_target("chalk_solve", level) + .with_target("chalk_ir", level) + .with_target("chalk_recursive", level); + // TODO: remove `.with_filter(LevelFilter::OFF)` on the `None` branch. HierarchicalLayer::default() .with_indent_lines(true) .with_ansi(false) .with_indent_amount(2) .with_writer(io::stderr) - .with_filter(chalk_filter), - ); + .with_filter(chalk_filter) + .boxed() + } + None => None::<HierarchicalLayer>.with_filter(LevelFilter::OFF).boxed(), + }; + + // TODO: remove `.with_filter(LevelFilter::OFF)` on the `None` branch. + let profiler_layer = match self.profile_filter { + Some(spec) => Some(hprof::SpanTree::new(&spec)).with_filter(LevelFilter::INFO), + None => None.with_filter(LevelFilter::OFF), + }; + + let json_profiler_layer = match self.json_profile_filter { + Some(spec) => { + let filter = json::JsonFilter::from_spec(&spec); + let filter = filter_fn(move |metadata| { + let allowed = match &filter.allowed_names { + Some(names) => names.contains(metadata.name()), + None => true, + }; + + allowed && metadata.is_span() + }); + Some(json::TimingLayer::new(std::io::stderr).with_filter(filter)) + } + None => None, }; - let profiler_layer = self.profile_filter.map(|spec| hprof::layer(&spec)); + let subscriber = Registry::default() + .with(ra_fmt_layer) + .with(json_profiler_layer) + .with(profiler_layer) + .with(chalk_layer); - Registry::default().with(ra_fmt_layer).with(chalk_layer).with(profiler_layer).try_init()?; + tracing::subscriber::set_global_default(subscriber)?; Ok(()) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs index 2d1604e70be..cad92962f34 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs @@ -33,6 +33,7 @@ use std::{ fmt::Write, + marker::PhantomData, mem, time::{Duration, Instant}, }; @@ -50,53 +51,42 @@ use tracing_subscriber::{ Layer, Registry, }; -use crate::tracing::hprof; - pub fn init(spec: &str) -> tracing::subscriber::DefaultGuard { - let subscriber = Registry::default().with(layer(spec)); + let subscriber = Registry::default().with(SpanTree::new(spec)); tracing::subscriber::set_default(subscriber) } -pub fn layer<S>(spec: &str) -> impl Layer<S> -where - S: Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>, -{ - let (write_filter, allowed_names) = WriteFilter::from_spec(spec); - - // this filter the first pass for `tracing`: these are all the "profiling" spans, but things like - // span depth or duration are not filtered here: that only occurs at write time. - let profile_filter = filter::filter_fn(move |metadata| { - let allowed = match &allowed_names { - Some(names) => names.contains(metadata.name()), - None => true, - }; - - allowed - && metadata.is_span() - && metadata.level() >= &Level::INFO - && !metadata.target().starts_with("salsa") - && metadata.name() != "compute_exhaustiveness_and_usefulness" - && !metadata.target().starts_with("chalk") - }); - - hprof::SpanTree::default().aggregate(true).spec_filter(write_filter).with_filter(profile_filter) -} - -#[derive(Default, Debug)] -pub(crate) struct SpanTree { +#[derive(Debug)] +pub(crate) struct SpanTree<S> { aggregate: bool, write_filter: WriteFilter, + _inner: PhantomData<fn(S)>, } -impl SpanTree { - /// Merge identical sibling spans together. - pub(crate) fn aggregate(self, yes: bool) -> SpanTree { - SpanTree { aggregate: yes, ..self } - } - - /// Add a write-time filter for span duration or tree depth. - pub(crate) fn spec_filter(self, write_filter: WriteFilter) -> SpanTree { - SpanTree { write_filter, ..self } +impl<S> SpanTree<S> +where + S: Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>, +{ + pub(crate) fn new(spec: &str) -> impl Layer<S> { + let (write_filter, allowed_names) = WriteFilter::from_spec(spec); + + // this filter the first pass for `tracing`: these are all the "profiling" spans, but things like + // span depth or duration are not filtered here: that only occurs at write time. + let profile_filter = filter::filter_fn(move |metadata| { + let allowed = match &allowed_names { + Some(names) => names.contains(metadata.name()), + None => true, + }; + + allowed + && metadata.is_span() + && metadata.level() >= &Level::INFO + && !metadata.target().starts_with("salsa") + && metadata.name() != "compute_exhaustiveness_and_usefulness" + && !metadata.target().starts_with("chalk") + }); + + Self { aggregate: true, write_filter, _inner: PhantomData }.with_filter(profile_filter) } } @@ -136,7 +126,7 @@ impl<'a> Visit for DataVisitor<'a> { } } -impl<S> Layer<S> for SpanTree +impl<S> Layer<S> for SpanTree<S> where S: Subscriber + for<'span> LookupSpan<'span>, { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/json.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/json.rs new file mode 100644 index 00000000000..f540a33b451 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/json.rs @@ -0,0 +1,90 @@ +//! A [tracing_subscriber::layer::Layer] that exports new-line delinated JSON. +//! +//! Usage: +//! +//! ```rust +//! let layer = json::TimingLayer::new(std::io::stderr); +//! Registry::default().with(layer).init(); +//! ``` + +use std::{io::Write as _, marker::PhantomData, time::Instant}; + +use ide_db::FxHashSet; +use tracing::{ + span::{Attributes, Id}, + Event, Subscriber, +}; +use tracing_subscriber::{fmt::MakeWriter, layer::Context, registry::LookupSpan, Layer}; + +struct JsonData { + name: &'static str, + start: std::time::Instant, +} + +impl JsonData { + fn new(name: &'static str) -> Self { + Self { name, start: Instant::now() } + } +} + +#[derive(Debug)] +pub(crate) struct TimingLayer<S, W> { + writer: W, + _inner: PhantomData<fn(S)>, +} + +impl<S, W> TimingLayer<S, W> { + pub(crate) fn new(writer: W) -> Self { + Self { writer, _inner: PhantomData } + } +} + +impl<S, W> Layer<S> for TimingLayer<S, W> +where + S: Subscriber + for<'span> LookupSpan<'span>, + W: for<'writer> MakeWriter<'writer> + Send + Sync + 'static, +{ + fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) { + let span = ctx.span(id).unwrap(); + + let data = JsonData::new(attrs.metadata().name()); + span.extensions_mut().insert(data); + } + + fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, S>) {} + + fn on_close(&self, id: Id, ctx: Context<'_, S>) { + #[derive(serde::Serialize)] + struct JsonDataInner { + name: &'static str, + elapsed_ms: u128, + } + + let span = ctx.span(&id).unwrap(); + let Some(data) = span.extensions_mut().remove::<JsonData>() else { + return; + }; + + let data = JsonDataInner { name: data.name, elapsed_ms: data.start.elapsed().as_millis() }; + let mut out = serde_json::to_string(&data).expect("Unable to serialize data"); + out.push('\n'); + self.writer.make_writer().write_all(out.as_bytes()).expect("Unable to write data"); + } +} + +#[derive(Default, Clone, Debug)] +pub(crate) struct JsonFilter { + pub(crate) allowed_names: Option<FxHashSet<String>>, +} + +impl JsonFilter { + pub(crate) fn from_spec(spec: &str) -> Self { + let allowed_names = if spec == "*" { + None + } else { + Some(FxHashSet::from_iter(spec.split('|').map(String::from))) + }; + + Self { allowed_names } + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 06ce9846818..18aface632d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -103,6 +103,7 @@ impl Project<'_> { filter: std::env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_owned()), chalk_filter: std::env::var("CHALK_DEBUG").ok(), profile_filter: std::env::var("RA_PROFILE").ok(), + json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(), }; }); diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index cb9c092f5fc..3863b3e809c 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -142,3 +142,12 @@ pub enum Transparency { /// Def-site spans in procedural macros, identifiers from `macro` by default use this. Opaque, } + +impl Transparency { + /// Returns `true` if the transparency is [`Opaque`]. + /// + /// [`Opaque`]: Transparency::Opaque + pub fn is_opaque(&self) -> bool { + matches!(self, Self::Opaque) + } +} diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs index f80de05ec65..66bbce18594 100644 --- a/src/tools/rust-analyzer/crates/span/src/map.rs +++ b/src/tools/rust-analyzer/crates/span/src/map.rs @@ -55,7 +55,10 @@ where /// Returns all [`TextRange`]s that correspond to the given span. /// /// Note this does a linear search through the entire backing vector. - pub fn ranges_with_span_exact(&self, span: SpanData<S>) -> impl Iterator<Item = TextRange> + '_ + pub fn ranges_with_span_exact( + &self, + span: SpanData<S>, + ) -> impl Iterator<Item = (TextRange, S)> + '_ where S: Copy, { @@ -64,14 +67,14 @@ where return None; } let start = idx.checked_sub(1).map_or(TextSize::new(0), |prev| self.spans[prev].0); - Some(TextRange::new(start, end)) + Some((TextRange::new(start, end), s.ctx)) }) } /// Returns all [`TextRange`]s whose spans contain the given span. /// /// Note this does a linear search through the entire backing vector. - pub fn ranges_with_span(&self, span: SpanData<S>) -> impl Iterator<Item = TextRange> + '_ + pub fn ranges_with_span(&self, span: SpanData<S>) -> impl Iterator<Item = (TextRange, S)> + '_ where S: Copy, { @@ -83,7 +86,7 @@ where return None; } let start = idx.checked_sub(1).map_or(TextSize::new(0), |prev| self.spans[prev].0); - Some(TextRange::new(start, end)) + Some((TextRange::new(start, end), s.ctx)) }) } diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index 0ccd0886760..3a05b83e497 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -148,6 +148,7 @@ pub fn token_tree_to_syntax_node<Ctx>( ) -> (Parse<SyntaxNode>, SpanMap<Ctx>) where SpanData<Ctx>: Copy + fmt::Debug, + Ctx: PartialEq, { let buffer = match tt { tt::Subtree { @@ -892,6 +893,7 @@ fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> Option<&'static str> { impl<Ctx> TtTreeSink<'_, Ctx> where SpanData<Ctx>: Copy + fmt::Debug, + Ctx: PartialEq, { /// Parses a float literal as if it was a one to two name ref nodes with a dot inbetween. /// This occurs when a float literal is used as a field access. @@ -949,6 +951,7 @@ where } let mut last = self.cursor; + let mut combined_span = None; 'tokens: for _ in 0..n_tokens { let tmp: u8; if self.cursor.eof() { @@ -982,7 +985,10 @@ where format_to!(self.buf, "{lit}"); debug_assert_ne!(self.buf.len() - buf_l, 0); self.text_pos += TextSize::new((self.buf.len() - buf_l) as u32); - self.token_map.push(self.text_pos, lit.span); + combined_span = match combined_span { + None => Some(lit.span), + Some(prev_span) => Some(Self::merge_spans(prev_span, lit.span)), + }; self.cursor = self.cursor.bump(); continue 'tokens; } @@ -1006,9 +1012,13 @@ where }; self.buf += text; self.text_pos += TextSize::of(text); - self.token_map.push(self.text_pos, span); + combined_span = match combined_span { + None => Some(span), + Some(prev_span) => Some(Self::merge_spans(prev_span, span)), + } } + self.token_map.push(self.text_pos, combined_span.expect("expected at least one token")); self.inner.token(kind, self.buf.as_str()); self.buf.clear(); // FIXME: Emitting whitespace for this is really just a hack, we should get rid of it. @@ -1043,4 +1053,22 @@ where fn error(&mut self, error: String) { self.inner.error(error, self.text_pos) } + + fn merge_spans(a: SpanData<Ctx>, b: SpanData<Ctx>) -> SpanData<Ctx> { + // We don't do what rustc does exactly, rustc does something clever when the spans have different syntax contexts + // but this runs afoul of our separation between `span` and `hir-expand`. + SpanData { + range: if a.ctx == b.ctx { + TextRange::new( + std::cmp::min(a.range.start(), b.range.start()), + std::cmp::max(a.range.end(), b.range.end()), + ) + } else { + // Combining ranges make no sense when they come from different syntax contexts. + a.range + }, + anchor: a.anchor, + ctx: a.ctx, + } + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs index 3282bd6eff2..32b1f5f7544 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs @@ -8,6 +8,7 @@ pub mod make; mod node_ext; mod operators; pub mod prec; +pub mod syntax_factory; mod token_ext; mod traits; @@ -166,7 +167,7 @@ mod support { } #[test] -fn assert_ast_is_object_safe() { +fn assert_ast_is_dyn_compatible() { fn _f(_: &dyn AstNode, _: &dyn HasName) {} } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory.rs new file mode 100644 index 00000000000..73bbe49105d --- /dev/null +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory.rs @@ -0,0 +1,45 @@ +//! Builds upon [`crate::ast::make`] constructors to create ast fragments with +//! optional syntax mappings. +//! +//! Instead of forcing make constructors to perform syntax mapping, we instead +//! let [`SyntaxFactory`] handle constructing the mappings. Care must be taken +//! to remember to feed the syntax mappings into a [`SyntaxEditor`](crate::syntax_editor::SyntaxEditor), +//! if applicable. + +mod constructors; + +use std::cell::{RefCell, RefMut}; + +use crate::syntax_editor::SyntaxMapping; + +pub struct SyntaxFactory { + // Stored in a refcell so that the factory methods can be &self + mappings: Option<RefCell<SyntaxMapping>>, +} + +impl SyntaxFactory { + /// Creates a new [`SyntaxFactory`], generating mappings between input nodes and generated nodes. + pub fn new() -> Self { + Self { mappings: Some(RefCell::new(SyntaxMapping::new())) } + } + + /// Creates a [`SyntaxFactory`] without generating mappings. + pub fn without_mappings() -> Self { + Self { mappings: None } + } + + /// Gets all of the tracked syntax mappings, if any. + pub fn finish_with_mappings(self) -> SyntaxMapping { + self.mappings.unwrap_or_default().into_inner() + } + + fn mappings(&self) -> Option<RefMut<'_, SyntaxMapping>> { + self.mappings.as_ref().map(|it| it.borrow_mut()) + } +} + +impl Default for SyntaxFactory { + fn default() -> Self { + Self::without_mappings() + } +} 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 new file mode 100644 index 00000000000..9f88add0f78 --- /dev/null +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -0,0 +1,110 @@ +//! Wrappers over [`make`] constructors +use itertools::Itertools; + +use crate::{ + ast::{self, make, HasName}, + syntax_editor::SyntaxMappingBuilder, + AstNode, +}; + +use super::SyntaxFactory; + +impl SyntaxFactory { + pub fn name(&self, name: &str) -> ast::Name { + make::name(name).clone_for_update() + } + + pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { + let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn block_expr( + &self, + stmts: impl IntoIterator<Item = ast::Stmt>, + tail_expr: Option<ast::Expr>, + ) -> ast::BlockExpr { + let stmts = stmts.into_iter().collect_vec(); + let input = stmts.iter().map(|it| it.syntax().clone()).collect_vec(); + + let ast = make::block_expr(stmts, tail_expr.clone()).clone_for_update(); + + if let Some((mut mapping, stmt_list)) = self.mappings().zip(ast.stmt_list()) { + let mut builder = SyntaxMappingBuilder::new(stmt_list.syntax().clone()); + + builder.map_children( + input.into_iter(), + stmt_list.statements().map(|it| it.syntax().clone()), + ); + + if let Some((input, output)) = tail_expr.zip(stmt_list.tail_expr()) { + builder.map_node(input.syntax().clone(), output.syntax().clone()); + } + + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_path(&self, path: ast::Path) -> ast::Expr { + let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else { + unreachable!() + }; + + 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()); + builder.finish(&mut mapping); + } + + ast.into() + } + + pub fn expr_ref(&self, expr: ast::Expr, exclusive: bool) -> ast::Expr { + let ast::Expr::RefExpr(ast) = make::expr_ref(expr.clone(), exclusive).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.into() + } + + pub fn let_stmt( + &self, + pattern: ast::Pat, + ty: Option<ast::Type>, + initializer: Option<ast::Expr>, + ) -> ast::LetStmt { + let ast = + make::let_stmt(pattern.clone(), ty.clone(), initializer.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone()); + if let Some(input) = ty { + builder.map_node(input.syntax().clone(), ast.ty().unwrap().syntax().clone()); + } + if let Some(input) = initializer { + builder + .map_node(input.syntax().clone(), ast.initializer().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } +} 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 eb114f5e5f1..714f5a99111 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -100,6 +100,10 @@ impl SyntaxEditor { pub fn finish(self) -> SyntaxEdit { edit_algo::apply_edits(self) } + + pub fn add_mappings(&mut self, other: SyntaxMapping) { + self.mappings.merge(other); + } } /// Represents a completed [`SyntaxEditor`] operation. @@ -319,85 +323,14 @@ fn is_ancestor_or_self_of_element(node: &SyntaxElement, ancestor: &SyntaxNode) - #[cfg(test)] mod tests { use expect_test::expect; - use itertools::Itertools; use crate::{ - ast::{self, make, HasName}, + ast::{self, make, syntax_factory::SyntaxFactory}, AstNode, }; use super::*; - fn make_ident_pat( - editor: Option<&mut SyntaxEditor>, - ref_: bool, - mut_: bool, - name: ast::Name, - ) -> ast::IdentPat { - let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update(); - - if let Some(editor) = editor { - let mut mapping = SyntaxMappingBuilder::new(ast.syntax().clone()); - mapping.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); - mapping.finish(editor); - } - - ast - } - - fn make_let_stmt( - editor: Option<&mut SyntaxEditor>, - pattern: ast::Pat, - ty: Option<ast::Type>, - initializer: Option<ast::Expr>, - ) -> ast::LetStmt { - let ast = - make::let_stmt(pattern.clone(), ty.clone(), initializer.clone()).clone_for_update(); - - if let Some(editor) = editor { - let mut mapping = SyntaxMappingBuilder::new(ast.syntax().clone()); - mapping.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone()); - if let Some(input) = ty { - mapping.map_node(input.syntax().clone(), ast.ty().unwrap().syntax().clone()); - } - if let Some(input) = initializer { - mapping - .map_node(input.syntax().clone(), ast.initializer().unwrap().syntax().clone()); - } - mapping.finish(editor); - } - - ast - } - - fn make_block_expr( - editor: Option<&mut SyntaxEditor>, - stmts: impl IntoIterator<Item = ast::Stmt>, - tail_expr: Option<ast::Expr>, - ) -> ast::BlockExpr { - let stmts = stmts.into_iter().collect_vec(); - let input = stmts.iter().map(|it| it.syntax().clone()).collect_vec(); - - let ast = make::block_expr(stmts, tail_expr.clone()).clone_for_update(); - - if let Some((editor, stmt_list)) = editor.zip(ast.stmt_list()) { - let mut mapping = SyntaxMappingBuilder::new(stmt_list.syntax().clone()); - - mapping.map_children( - input.into_iter(), - stmt_list.statements().map(|it| it.syntax().clone()), - ); - - if let Some((input, output)) = tail_expr.zip(stmt_list.tail_expr()) { - mapping.map_node(input.syntax().clone(), output.syntax().clone()); - } - - mapping.finish(editor); - } - - ast - } - #[test] fn basic_usage() { let root = make::match_arm( @@ -417,6 +350,7 @@ mod tests { let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap(); let mut editor = SyntaxEditor::new(root.syntax().clone()); + let make = SyntaxFactory::new(); let name = make::name("var_name"); let name_ref = make::name_ref("var_name").clone_for_update(); @@ -425,21 +359,20 @@ mod tests { editor.add_annotation(name.syntax(), placeholder_snippet); editor.add_annotation(name_ref.syntax(), placeholder_snippet); - let make_ident_pat = make_ident_pat(Some(&mut editor), false, false, name); - let make_let_stmt = make_let_stmt( - Some(&mut editor), - make_ident_pat.into(), - None, - Some(to_replace.clone().into()), - ); - let new_block = make_block_expr( - Some(&mut editor), - [make_let_stmt.into()], + let new_block = make.block_expr( + [make + .let_stmt( + make.ident_pat(false, false, name.clone()).into(), + None, + Some(to_replace.clone().into()), + ) + .into()], Some(to_wrap.clone().into()), ); editor.replace(to_replace.syntax(), name_ref.syntax()); editor.replace(to_wrap.syntax(), new_block.syntax()); + editor.add_mappings(make.finish_with_mappings()); let edit = editor.finish(); @@ -473,11 +406,11 @@ mod tests { let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap(); let mut editor = SyntaxEditor::new(root.syntax().clone()); + let make = SyntaxFactory::without_mappings(); editor.insert( Position::first_child_of(root.stmt_list().unwrap().syntax()), - make_let_stmt( - None, + make.let_stmt( make::ext::simple_ident_pat(make::name("first")).into(), None, Some(make::expr_literal("1").into()), @@ -487,8 +420,7 @@ mod tests { editor.insert( Position::after(second_let.syntax()), - make_let_stmt( - None, + make.let_stmt( make::ext::simple_ident_pat(make::name("third")).into(), None, Some(make::expr_literal("3").into()), @@ -528,19 +460,17 @@ mod tests { let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap(); let mut editor = SyntaxEditor::new(root.syntax().clone()); + let make = SyntaxFactory::new(); - let new_block_expr = - make_block_expr(Some(&mut editor), [], Some(ast::Expr::BlockExpr(inner_block.clone()))); + let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone()))); - let first_let = make_let_stmt( - Some(&mut editor), + let first_let = make.let_stmt( make::ext::simple_ident_pat(make::name("first")).into(), None, Some(make::expr_literal("1").into()), ); - let third_let = make_let_stmt( - Some(&mut editor), + let third_let = make.let_stmt( make::ext::simple_ident_pat(make::name("third")).into(), None, Some(make::expr_literal("3").into()), @@ -552,6 +482,7 @@ mod tests { ); editor.insert(Position::after(second_let.syntax()), third_let.syntax()); editor.replace(inner_block.syntax(), new_block_expr.syntax()); + editor.add_mappings(make.finish_with_mappings()); let edit = editor.finish(); @@ -581,12 +512,11 @@ mod tests { let inner_block = root.clone(); let mut editor = SyntaxEditor::new(root.syntax().clone()); + let make = SyntaxFactory::new(); - let new_block_expr = - make_block_expr(Some(&mut editor), [], Some(ast::Expr::BlockExpr(inner_block.clone()))); + let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone()))); - let first_let = make_let_stmt( - Some(&mut editor), + let first_let = make.let_stmt( make::ext::simple_ident_pat(make::name("first")).into(), None, Some(make::expr_literal("1").into()), @@ -597,6 +527,7 @@ mod tests { first_let.syntax(), ); editor.replace(inner_block.syntax(), new_block_expr.syntax()); + editor.add_mappings(make.finish_with_mappings()); let edit = editor.finish(); diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs index 9bb5e6d9338..16bc55ed2d4 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs @@ -7,8 +7,6 @@ use rustc_hash::FxHashMap; use crate::{SyntaxElement, SyntaxNode}; -use super::SyntaxEditor; - #[derive(Debug, Default)] pub struct SyntaxMapping { // important information to keep track of: @@ -209,7 +207,7 @@ impl SyntaxMapping { Some(output) } - fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) { + pub fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) { let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping; let parent_entry: u32 = self.entry_parents.len().try_into().unwrap(); @@ -257,8 +255,8 @@ impl SyntaxMappingBuilder { } } - pub fn finish(self, editor: &mut SyntaxEditor) { - editor.mappings.add_mapping(self); + pub fn finish(self, mappings: &mut SyntaxMapping) { + mappings.add_mapping(self); } } diff --git a/src/tools/rust-analyzer/crates/vfs/src/loader.rs b/src/tools/rust-analyzer/crates/vfs/src/loader.rs index f24354cb493..c49e4c4322d 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/loader.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/loader.rs @@ -1,4 +1,4 @@ -//! Object safe interface for file watching and reading. +//! Dynamically compatible interface for file watching and reading. use std::fmt; use paths::{AbsPath, AbsPathBuf}; @@ -232,6 +232,6 @@ impl fmt::Debug for Message { } #[test] -fn handle_is_object_safe() { +fn handle_is_dyn_compatible() { fn _assert(_: &dyn Handle) {} } diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md index 002b8ba2a66..12e6d829a08 100644 --- a/src/tools/rust-analyzer/docs/dev/README.md +++ b/src/tools/rust-analyzer/docs/dev/README.md @@ -178,7 +178,15 @@ RA_PROFILE=foo|bar|baz // enabled only selected entries RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms ``` -In particular, I have `export RA_PROFILE='*>10'` in my shell profile. +Some rust-analyzer contributors have `export RA_PROFILE='*>10'` in my shell profile. + +For machine-readable JSON output, we have the `RA_PROFILE_JSON` env variable. We support +filtering only by span name: + +``` +RA_PROFILE=* // dump everything +RA_PROFILE_JSON="vfs_load|parallel_prime_caches|discover_command" // dump selected spans +``` We also have a "counting" profiler which counts number of instances of popular structs. It is enabled by `RA_COUNT=1`. diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/dev/architecture.md index 4f8723a9368..6aa57b2f9be 100644 --- a/src/tools/rust-analyzer/docs/dev/architecture.md +++ b/src/tools/rust-analyzer/docs/dev/architecture.md @@ -42,7 +42,7 @@ The underlying engine makes sure that model is computed lazily (on-demand) and c `crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP. This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it. -`crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. +`crates/rust-analyzer/src/handlers/requests.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. `Analysis` and `AnalysisHost` types define the main API for consumers of IDE services. diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index b7bac4d29fa..7764f7843a0 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ <!--- -lsp/ext.rs hash: 6292ee8d88d4c9ec +lsp/ext.rs hash: 90cf7718d54fe3c2 If you need to change the above hash to make the test pass, please check if you need to adjust this doc as well and ping this issue: diff --git a/src/tools/rust-analyzer/docs/dev/syntax.md b/src/tools/rust-analyzer/docs/dev/syntax.md index 6c4daecc58f..3dcd430cea5 100644 --- a/src/tools/rust-analyzer/docs/dev/syntax.md +++ b/src/tools/rust-analyzer/docs/dev/syntax.md @@ -378,7 +378,7 @@ impl AstNode for AssocItem { } ``` -Shared AST substructures are modeled via (object safe) traits: +Shared AST substructures are modeled via (dynamically compatible) traits: ```rust trait HasVisibility: AstNode { diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index f37fd7f4ab3..708fc2b7891 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -158,6 +158,11 @@ building from locking the `Cargo.lock` at the expense of duplicating build artif Set to `true` to use a subdirectory of the existing target directory or set to a path relative to the workspace to use that path. -- +[[rust-analyzer.cfg.setTest]]rust-analyzer.cfg.setTest (default: `true`):: ++ +-- +Set `cfg(test)` for local crates. Defaults to true. +-- [[rust-analyzer.checkOnSave]]rust-analyzer.checkOnSave (default: `true`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index b66f0a64d57..a823e5bb96c 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -512,6 +512,11 @@ "type": "boolean", "default": false }, + "rust-analyzer.debug.buildBeforeRestart": { + "markdownDescription": "Whether to rebuild the project modules before debugging the same test again", + "type": "boolean", + "default": false + }, "rust-analyzer.debug.engineSettings": { "type": "object", "default": {}, @@ -849,6 +854,16 @@ } }, { + "title": "cfg", + "properties": { + "rust-analyzer.cfg.setTest": { + "markdownDescription": "Set `cfg(test)` for local crates. Defaults to true.", + "default": true, + "type": "boolean" + } + } + }, + { "title": "general", "properties": { "rust-analyzer.checkOnSave": { diff --git a/src/tools/rust-analyzer/editors/code/src/bootstrap.ts b/src/tools/rust-analyzer/editors/code/src/bootstrap.ts index daead47e942..35867f710d5 100644 --- a/src/tools/rust-analyzer/editors/code/src/bootstrap.ts +++ b/src/tools/rust-analyzer/editors/code/src/bootstrap.ts @@ -23,10 +23,11 @@ export async function bootstrap( if (!isValidExecutable(path, config.serverExtraEnv)) { throw new Error( - `Failed to execute ${path} --version.` + config.serverPath - ? `\`config.server.path\` or \`config.serverPath\` has been set explicitly.\ + `Failed to execute ${path} --version.` + + (config.serverPath + ? `\`config.server.path\` or \`config.serverPath\` has been set explicitly.\ Consider removing this config or making a valid server binary available at that path.` - : "", + : ""), ); } diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 1e3dc608095..abb4099f9f5 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -24,6 +24,7 @@ export class Config { "serverPath", "server", "files", + "cfg", ].map((opt) => `${this.rootSection}.${opt}`); private readonly requiresWindowReloadOpts = ["testExplorer"].map( @@ -299,6 +300,7 @@ export class Config { engine: this.get<string>("debug.engine"), engineSettings: this.get<object>("debug.engineSettings") ?? {}, openDebugPane: this.get<boolean>("debug.openDebugPane"), + buildBeforeRestart: this.get<boolean>("debug.buildBeforeRestart"), sourceFileMap: sourceFileMap, }; } diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts index 3aae0f9ce6e..fb7e340e517 100644 --- a/src/tools/rust-analyzer/editors/code/src/debug.ts +++ b/src/tools/rust-analyzer/editors/code/src/debug.ts @@ -5,12 +5,15 @@ import type * as ra from "./lsp_ext"; import { Cargo } from "./toolchain"; import type { Ctx } from "./ctx"; -import { prepareEnv } from "./run"; +import { createTaskFromRunnable, prepareEnv } from "./run"; import { execute, isCargoRunnableArgs, unwrapUndefinable } from "./util"; import type { Config } from "./config"; const debugOutput = vscode.window.createOutputChannel("Debug"); +// Here we want to keep track on everything that's currently running +const activeDebugSessionIds: string[] = []; + export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> { const scope = ctx.activeRustEditor?.document.uri; if (!scope) return; @@ -45,6 +48,8 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis const wsLaunchSection = vscode.workspace.getConfiguration("launch"); const configurations = wsLaunchSection.get<any[]>("configurations") || []; + // The runnable label is the name of the test with the "test prefix" + // e.g. test test_feature_x const index = configurations.findIndex((c) => c.name === runnable.label); if (-1 !== index) { debugConfig = configurations[index]; @@ -168,6 +173,8 @@ async function getDebugConfiguration( if (debugConfig.name === "run binary") { // The LSP side: crates\rust-analyzer\src\main_loop\handlers.rs, // fn to_lsp_runnable(...) with RunnableKind::Bin + // FIXME: Neither crates\rust-analyzer\src\main_loop\handlers.rs + // nor to_lsp_runnable exist anymore debugConfig.name = `run ${path.basename(executable)}`; } @@ -359,3 +366,49 @@ function quote(xs: string[]) { }) .join(" "); } + +async function recompileTestFromDebuggingSession(session: vscode.DebugSession, ctx: Ctx) { + const { cwd, args: sessionArgs }: vscode.DebugConfiguration = session.configuration; + + const args: ra.CargoRunnableArgs = { + cwd: cwd, + cargoArgs: ["test", "--no-run", "--test", "lib"], + + // The first element of the debug configuration args is the test path e.g. "test_bar::foo::test_a::test_b" + executableArgs: sessionArgs, + }; + const runnable: ra.Runnable = { + kind: "cargo", + label: "compile-test", + args, + }; + const task: vscode.Task = await createTaskFromRunnable(runnable, ctx.config); + + // It is not needed to call the language server, since the test path is already resolved in the + // configuration option. We can simply call a debug configuration with the --no-run option to compile + await vscode.tasks.executeTask(task); +} + +export function initializeDebugSessionTrackingAndRebuild(ctx: Ctx) { + vscode.debug.onDidStartDebugSession((session: vscode.DebugSession) => { + if (!activeDebugSessionIds.includes(session.id)) { + activeDebugSessionIds.push(session.id); + } + }); + + vscode.debug.onDidTerminateDebugSession(async (session: vscode.DebugSession) => { + // The id of the session will be the same when pressing restart the restart button + if (activeDebugSessionIds.find((s) => s === session.id)) { + await recompileTestFromDebuggingSession(session, ctx); + } + removeActiveSession(session); + }); +} + +function removeActiveSession(session: vscode.DebugSession) { + const activeSessionId = activeDebugSessionIds.findIndex((id) => id === session.id); + + if (activeSessionId !== -1) { + activeDebugSessionIds.splice(activeSessionId, 1); + } +} diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 4769fdd864a..0ddc5619e99 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -6,6 +6,7 @@ import { type CommandFactory, Ctx, fetchWorkspace } from "./ctx"; import * as diagnostics from "./diagnostics"; import { activateTaskProvider } from "./tasks"; import { setContextValue } from "./util"; +import { initializeDebugSessionTrackingAndRebuild } from "./debug"; const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; @@ -102,6 +103,10 @@ async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> { ctx.subscriptions, ); + if (ctx.config.debug.buildBeforeRestart) { + initializeDebugSessionTrackingAndRebuild(ctx); + } + await ctx.start(); return ctx; } diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index dd0da6b62c8..8a82a5a58cf 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -36,7 +36,7 @@ export async function selectRunnable( if (runnables.length === 0) { // it is the debug case, run always has at least 'cargo check ...' - // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables + // see crates\rust-analyzer\src\handlers\request.rs, handle_runnables await vscode.window.showErrorMessage("There's no debug target!"); quickPick.dispose(); return; diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts index 850a6a55616..e8bab9c3d84 100644 --- a/src/tools/rust-analyzer/editors/code/src/toolchain.ts +++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts @@ -29,7 +29,7 @@ export class Cargo { static artifactSpec(cargoArgs: string[], executableArgs?: string[]): ArtifactSpec { cargoArgs = [...cargoArgs, "--message-format=json"]; // arguments for a runnable from the quick pick should be updated. - // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens + // see crates\rust-analyzer\src\handlers\request.rs, handle_code_lens switch (cargoArgs[0]) { case "run": cargoArgs[0] = "build"; diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 79ed6cc7d74..f217c6a19cb 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -1b5aa96d6016bafe50e071b45d4d2e3c90fd766f +cf24c73141a77db730f4b7fda69dcd7e8b113b51 diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index 8f6626f6296..c5874b4ee02 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -19,7 +19,6 @@ function showHelp() { console.log(" --debug : show extra information about script run"); console.log(" --show-text : render font in pages"); console.log(" --no-headless : disable headless mode"); - console.log(" --no-sandbox : disable sandbox mode"); console.log(" --help : show this message then quit"); console.log(" --tests-folder [PATH] : location of the .GOML tests folder"); console.log(" --jobs [NUMBER] : number of threads to run tests on"); @@ -40,7 +39,6 @@ function parseOptions(args) { "no_headless": false, "jobs": -1, "executable_path": null, - "no_sandbox": false, }; const correspondences = { "--doc-folder": "doc_folder", @@ -49,7 +47,6 @@ function parseOptions(args) { "--show-text": "show_text", "--no-headless": "no_headless", "--executable-path": "executable_path", - "--no-sandbox": "no_sandbox", }; for (let i = 0; i < args.length; ++i) { @@ -80,9 +77,6 @@ function parseOptions(args) { } else if (arg === "--help") { showHelp(); process.exit(0); - } else if (arg === "--no-sandbox") { - console.log("`--no-sandbox` is being used. Be very careful!"); - opts[correspondences[arg]] = true; } else if (correspondences[arg]) { opts[correspondences[arg]] = true; } else { @@ -203,6 +197,7 @@ async function main(argv) { const args = [ "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"), "--enable-fail-on-js-error", "--allow-file-access-from-files", + "--no-sandbox", ]; if (opts["debug"]) { debug = true; @@ -211,9 +206,6 @@ async function main(argv) { if (opts["show_text"]) { args.push("--show-text"); } - if (opts["no_sandbox"]) { - args.push("--no-sandbox"); - } if (opts["no_headless"]) { args.push("--no-headless"); headless = false; @@ -262,19 +254,6 @@ async function main(argv) { console.log(`Running ${files.length} rustdoc-gui ...`); } - // We catch this "event" to display a nicer message in case of unexpected exit (because of a - // missing `--no-sandbox`). - const exitHandling = () => { - if (!opts["no_sandbox"]) { - console.log(""); - console.log( - "`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \ ---no-sandbox` at the end. For example: `x.py test tests/rustdoc-gui --test-args --no-sandbox`"); - console.log(""); - } - }; - process.on("exit", exitHandling); - const originalFilesLen = files.length; const results = createEmptyResults(); const status_bar = char_printer(files.length); @@ -299,9 +278,6 @@ async function main(argv) { Array.prototype.push.apply(results.failed, new_results.failed); Array.prototype.push.apply(results.errored, new_results.errored); - // We don't need this listener anymore. - process.removeListener("exit", exitHandling); - if (debug) { results.successful.sort(by_filename); results.successful.forEach(r => { diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 5c2068b6a22..381c938ae80 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -90,7 +90,7 @@ fn format_derive( let item_spans = attr.meta_item_list().map(|meta_item_list| { meta_item_list .into_iter() - .map(|nested_meta_item| nested_meta_item.span()) + .map(|meta_item_inner| meta_item_inner.span()) })?; let items = itemize_list( @@ -243,17 +243,15 @@ fn rewrite_initial_doc_comments( Ok((0, None)) } -impl Rewrite for ast::NestedMetaItem { +impl Rewrite for ast::MetaItemInner { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> { self.rewrite_result(context, shape).ok() } fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { match self { - ast::NestedMetaItem::MetaItem(ref meta_item) => { - meta_item.rewrite_result(context, shape) - } - ast::NestedMetaItem::Lit(ref l) => { + ast::MetaItemInner::MetaItem(ref meta_item) => meta_item.rewrite_result(context, shape), + ast::MetaItemInner::Lit(ref l) => { rewrite_literal(context, l.as_token_lit(), l.span, shape) } } @@ -535,10 +533,10 @@ pub(crate) trait MetaVisitor<'ast> { fn visit_meta_list( &mut self, _meta_item: &'ast ast::MetaItem, - list: &'ast [ast::NestedMetaItem], + list: &'ast [ast::MetaItemInner], ) { for nm in list { - self.visit_nested_meta_item(nm); + self.visit_meta_item_inner(nm); } } @@ -551,10 +549,10 @@ pub(crate) trait MetaVisitor<'ast> { ) { } - fn visit_nested_meta_item(&mut self, nm: &'ast ast::NestedMetaItem) { + fn visit_meta_item_inner(&mut self, nm: &'ast ast::MetaItemInner) { match nm { - ast::NestedMetaItem::MetaItem(ref meta_item) => self.visit_meta_item(meta_item), - ast::NestedMetaItem::Lit(ref lit) => self.visit_meta_item_lit(lit), + ast::MetaItemInner::MetaItem(ref meta_item) => self.visit_meta_item(meta_item), + ast::MetaItemInner::Lit(ref lit) => self.visit_meta_item_lit(lit), } } diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs index fdc8e23e72b..728adff2c7d 100644 --- a/src/tools/rustfmt/src/overflow.rs +++ b/src/tools/rustfmt/src/overflow.rs @@ -78,7 +78,7 @@ pub(crate) enum OverflowableItem<'a> { Expr(&'a ast::Expr), GenericParam(&'a ast::GenericParam), MacroArg(&'a MacroArg), - NestedMetaItem(&'a ast::NestedMetaItem), + MetaItemInner(&'a ast::MetaItemInner), SegmentParam(&'a SegmentParam<'a>), FieldDef(&'a ast::FieldDef), TuplePatField(&'a TuplePatField<'a>), @@ -123,7 +123,7 @@ impl<'a> OverflowableItem<'a> { OverflowableItem::Expr(expr) => f(*expr), OverflowableItem::GenericParam(gp) => f(*gp), OverflowableItem::MacroArg(macro_arg) => f(*macro_arg), - OverflowableItem::NestedMetaItem(nmi) => f(*nmi), + OverflowableItem::MetaItemInner(nmi) => f(*nmi), OverflowableItem::SegmentParam(sp) => f(*sp), OverflowableItem::FieldDef(sf) => f(*sf), OverflowableItem::TuplePatField(pat) => f(*pat), @@ -138,9 +138,9 @@ impl<'a> OverflowableItem<'a> { OverflowableItem::Expr(expr) => is_simple_expr(expr), OverflowableItem::MacroArg(MacroArg::Keyword(..)) => true, OverflowableItem::MacroArg(MacroArg::Expr(expr)) => is_simple_expr(expr), - OverflowableItem::NestedMetaItem(nested_meta_item) => match nested_meta_item { - ast::NestedMetaItem::Lit(..) => true, - ast::NestedMetaItem::MetaItem(ref meta_item) => { + OverflowableItem::MetaItemInner(meta_item_inner) => match meta_item_inner { + ast::MetaItemInner::Lit(..) => true, + ast::MetaItemInner::MetaItem(ref meta_item) => { matches!(meta_item.kind, ast::MetaItemKind::Word) } }, @@ -184,12 +184,10 @@ impl<'a> OverflowableItem<'a> { MacroArg::Item(..) => len == 1, MacroArg::Keyword(..) => false, }, - OverflowableItem::NestedMetaItem(nested_meta_item) if len == 1 => { - match nested_meta_item { - ast::NestedMetaItem::Lit(..) => false, - ast::NestedMetaItem::MetaItem(..) => true, - } - } + OverflowableItem::MetaItemInner(meta_item_inner) if len == 1 => match meta_item_inner { + ast::MetaItemInner::Lit(..) => false, + ast::MetaItemInner::MetaItem(..) => true, + }, OverflowableItem::SegmentParam(SegmentParam::Type(ty)) => { can_be_overflowed_type(context, ty, len) } @@ -202,7 +200,7 @@ impl<'a> OverflowableItem<'a> { fn special_cases(&self, config: &Config) -> impl Iterator<Item = &(&'static str, usize)> { let base_cases = match self { OverflowableItem::MacroArg(..) => SPECIAL_CASE_MACROS, - OverflowableItem::NestedMetaItem(..) => SPECIAL_CASE_ATTR, + OverflowableItem::MetaItemInner(..) => SPECIAL_CASE_ATTR, _ => &[], }; let additional_cases = match self { @@ -261,7 +259,7 @@ macro_rules! impl_into_overflowable_item_for_rustfmt_types { impl_into_overflowable_item_for_ast_node!( Expr, GenericParam, - NestedMetaItem, + MetaItemInner, FieldDef, Ty, Pat, diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs index 5ee083da539..58c8d21bd7a 100644 --- a/src/tools/rustfmt/src/parse/macros/asm.rs +++ b/src/tools/rustfmt/src/parse/macros/asm.rs @@ -7,5 +7,5 @@ use crate::rewrite::RewriteContext; pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<AsmArgs> { let ts = mac.args.tokens.clone(); let mut parser = super::build_parser(context, ts); - parse_asm_args(&mut parser, mac.span(), false).ok() + parse_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok() } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 9f27a05939e..54ad56ed3f3 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -46,7 +46,7 @@ impl SilentOnIgnoredFilesEmitter { } impl Translate for SilentOnIgnoredFilesEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> { + fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { self.emitter.fluent_bundle() } @@ -56,7 +56,7 @@ impl Translate for SilentOnIgnoredFilesEmitter { } impl Emitter for SilentOnIgnoredFilesEmitter { - fn source_map(&self) -> Option<&Lrc<SourceMap>> { + fn source_map(&self) -> Option<&SourceMap> { None } @@ -344,7 +344,7 @@ mod tests { } impl Translate for TestEmitter { - fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> { + fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { None } @@ -354,7 +354,7 @@ mod tests { } impl Emitter for TestEmitter { - fn source_map(&self) -> Option<&Lrc<SourceMap>> { + fn source_map(&self) -> Option<&SourceMap> { None } diff --git a/src/tools/rustfmt/src/skip.rs b/src/tools/rustfmt/src/skip.rs index d733f7068fd..cd3860d3d7f 100644 --- a/src/tools/rustfmt/src/skip.rs +++ b/src/tools/rustfmt/src/skip.rs @@ -116,8 +116,8 @@ fn get_skip_names(kind: &str, attrs: &[ast::Attribute]) -> Vec<String> { } if let Some(list) = attr.meta_item_list() { - for nested_meta_item in list { - if let Some(name) = nested_meta_item.ident() { + for meta_item_inner in list { + if let Some(name) = meta_item_inner.ident() { skip_names.push(name.to_string()); } } diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index b4424e476ee..555a9240798 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -199,7 +199,7 @@ impl Spanned for MacroArg { } } -impl Spanned for ast::NestedMetaItem { +impl Spanned for ast::MetaItemInner { fn span(&self) -> Span { self.span() } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 07b483b2b37..f75c4f0fad7 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -951,8 +951,6 @@ impl Rewrite for ast::Ty { ast::TyKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1) } - ast::TyKind::AnonStruct(..) => Ok(context.snippet(self.span).to_owned()), - ast::TyKind::AnonUnion(..) => Ok(context.snippet(self.span).to_owned()), ast::TyKind::Path(ref q_self, ref path) => { rewrite_path(context, PathContext::Type, q_self, path, shape) } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index d1cfc6acc49..0ca34a79491 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use rustc_ast::ast::{ - self, Attribute, MetaItem, MetaItemKind, NestedMetaItem, NodeId, Path, Visibility, + self, Attribute, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Visibility, VisibilityKind, }; use rustc_ast::ptr; @@ -257,10 +257,10 @@ fn is_skip(meta_item: &MetaItem) -> bool { } #[inline] -fn is_skip_nested(meta_item: &NestedMetaItem) -> bool { +fn is_skip_nested(meta_item: &MetaItemInner) -> bool { match meta_item { - NestedMetaItem::MetaItem(ref mi) => is_skip(mi), - NestedMetaItem::Lit(_) => false, + MetaItemInner::MetaItem(ref mi) => is_skip(mi), + MetaItemInner::Lit(_) => false, } } diff --git a/src/tools/rustfmt/tests/target/anonymous-types.rs b/src/tools/rustfmt/tests/target/anonymous-types.rs deleted file mode 100644 index e8c2d83878c..00000000000 --- a/src/tools/rustfmt/tests/target/anonymous-types.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Test for issue 85480 -// Pretty print anonymous struct and union types - -// pp-exact -// pretty-compare-only - -struct Foo { - _: union { - _: struct { - a: u8, - b: u16, - }, - c: u32, - }, - d: u64, - e: f32, -} - -// Test for https://github.com/rust-lang/rust/issues/117942 -struct Foo { - _: union { - #[rustfmt::skip] - f: String, - }, - #[rustfmt::skip] - _: struct { - g: i32, - }, -} - -fn main() {} diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 50d21c7ed4c..7a0f98d59f0 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,6 +1,5 @@ run-make/branch-protection-check-IBT/Makefile run-make/cat-and-grep-sanity-check/Makefile -run-make/emit-to-stdout/Makefile run-make/extern-fn-reachable/Makefile run-make/incr-add-rust-src-component/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 1ffad06457f..5163f039a23 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -129,11 +129,14 @@ const EXCEPTIONS_STDARCH: ExceptionList = &[ const EXCEPTIONS_CARGO: ExceptionList = &[ // tidy-alphabetical-start + ("arrayref", "BSD-2-Clause"), ("bitmaps", "MPL-2.0+"), + ("blake3", "CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception"), ("bytesize", "Apache-2.0"), ("ciborium", "Apache-2.0"), ("ciborium-io", "Apache-2.0"), ("ciborium-ll", "Apache-2.0"), + ("constant_time_eq", "CC0-1.0 OR MIT-0 OR Apache-2.0"), ("dunce", "CC0-1.0 OR MIT-0 OR Apache-2.0"), ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"), ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 86cae849b97..66c176c6f44 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -802,7 +802,6 @@ ui/consts/issue-70942-trait-vs-impl-mismatch.rs ui/consts/issue-73976-monomorphic.rs ui/consts/issue-73976-polymorphic.rs ui/consts/issue-76064.rs -ui/consts/issue-77062-large-zst-array.rs ui/consts/issue-78655.rs ui/consts/issue-79137-monomorphic.rs ui/consts/issue-79137-toogeneric.rs @@ -3173,10 +3172,6 @@ ui/nll/user-annotations/issue-55241.rs ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs ui/numbers-arithmetic/issue-8460.rs -ui/object-safety/issue-102762.rs -ui/object-safety/issue-102933.rs -ui/object-safety/issue-106247.rs -ui/object-safety/issue-19538.rs ui/on-unimplemented/issue-104140.rs ui/or-patterns/issue-64879-trailing-before-guard.rs ui/or-patterns/issue-67514-irrefutable-param.rs diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index bfffa1eee60..8097d6a8caf 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -77,7 +77,7 @@ impl RawEmitter { writeln!( &mut self.file, - "const BITSET_CANONICAL: &'static [u64; {}] = &[{}];", + "static BITSET_CANONICAL: [u64; {}] = [{}];", canonicalized.canonical_words.len(), fmt_list(canonicalized.canonical_words.iter().map(|v| Bits(*v))), ) @@ -85,7 +85,7 @@ impl RawEmitter { self.bytes_used += 8 * canonicalized.canonical_words.len(); writeln!( &mut self.file, - "const BITSET_MAPPING: &'static [(u8, u8); {}] = &[{}];", + "static BITSET_MAPPING: [(u8, u8); {}] = [{}];", canonicalized.canonicalized_words.len(), fmt_list(&canonicalized.canonicalized_words), ) @@ -139,7 +139,7 @@ impl RawEmitter { writeln!( &mut self.file, - "const BITSET_CHUNKS_MAP: &'static [u8; {}] = &[{}];", + "static BITSET_CHUNKS_MAP: [u8; {}] = [{}];", chunk_indices.len(), fmt_list(&chunk_indices), ) @@ -147,7 +147,7 @@ impl RawEmitter { self.bytes_used += chunk_indices.len(); writeln!( &mut self.file, - "const BITSET_INDEX_CHUNKS: &'static [[u8; {}]; {}] = &[{}];", + "static BITSET_INDEX_CHUNKS: [[u8; {}]; {}] = [{}];", chunk_length, chunks.len(), fmt_list(chunks.iter()), diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index 49f4e59650e..acdb1aa1ab7 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.9" +wasm-component-ld = "0.5.10" diff --git a/src/version b/src/version index 6b4de0a42b0..bd0f9e6c28f 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.83.0 +1.84.0 diff --git a/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs index 8ee6f6792e9..46e627eaa00 100644 --- a/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs +++ b/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs @@ -5,7 +5,7 @@ #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", // meaning "no prologue whatsoever, no, really, not one instruction." @@ -17,5 +17,5 @@ use std::arch::asm; pub unsafe extern "C" fn _hlt() -> ! { // CHECK-NOT: hint #34 // CHECK: hlt #0x1 - asm!("hlt #1", options(noreturn)) + naked_asm!("hlt #1") } diff --git a/tests/assembly/powerpc64-struct-abi.rs b/tests/assembly/powerpc64-struct-abi.rs index 9a3540d8b41..7052937acf6 100644 --- a/tests/assembly/powerpc64-struct-abi.rs +++ b/tests/assembly/powerpc64-struct-abi.rs @@ -1,4 +1,4 @@ -//@ revisions: elfv1-be elfv2-be elfv2-le +//@ revisions: elfv1-be elfv2-be elfv2-le aix //@ assembly-output: emit-asm //@ compile-flags: -O //@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu @@ -7,8 +7,13 @@ //@[elfv2-be] needs-llvm-components: powerpc //@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu //@[elfv2-le] needs-llvm-components: powerpc +//@[aix] compile-flags: --target powerpc64-ibm-aix +//@[aix] needs-llvm-components: powerpc //@[elfv1-be] filecheck-flags: --check-prefix be //@[elfv2-be] filecheck-flags: --check-prefix be +//@[elfv1-be] filecheck-flags: --check-prefix elf +//@[elfv2-be] filecheck-flags: --check-prefix elf +//@[elfv2-le] filecheck-flags: --check-prefix elf #![feature(no_core, lang_items)] #![no_std] @@ -44,6 +49,10 @@ struct FiveU16s(u16, u16, u16, u16, u16); struct ThreeU8s(u8, u8, u8); // CHECK-LABEL: read_large +// aix: lwz [[REG1:.*]], 16(4) +// aix-NEXT: lxvd2x 0, 0, 4 +// aix-NEXT: stw [[REG1]], 16(3) +// aix-NEXT: stxvd2x 0, 0, 3 // be: lwz [[REG1:.*]], 16(4) // be-NEXT: stw [[REG1]], 16(3) // be-NEXT: ld [[REG2:.*]], 8(4) @@ -61,6 +70,10 @@ extern "C" fn read_large(x: &FiveU32s) -> FiveU32s { } // CHECK-LABEL: read_medium +// aix: lhz [[REG1:.*]], 8(4) +// aix-NEXT: ld [[REG2:.*]], 0(4) +// aix-NEXT: sth [[REG1]], 8(3) +// aix-NEXT: std [[REG2]], 0(3) // elfv1-be: lhz [[REG1:.*]], 8(4) // elfv1-be-NEXT: ld [[REG2:.*]], 0(4) // elfv1-be-NEXT: sth [[REG1]], 8(3) @@ -78,6 +91,10 @@ extern "C" fn read_medium(x: &FiveU16s) -> FiveU16s { } // CHECK-LABEL: read_small +// aix: lbz [[REG1:.*]], 2(4) +// aix-NEXT: lhz [[REG2:.*]], 0(4) +// aix-NEXT: stb [[REG1]], 2(3) +// aix-NEXT: sth [[REG2]], 0(3) // elfv1-be: lbz [[REG1:.*]], 2(4) // elfv1-be-NEXT: lhz [[REG2:.*]], 0(4) // elfv1-be-NEXT: stb [[REG1]], 2(3) @@ -95,9 +112,17 @@ extern "C" fn read_small(x: &ThreeU8s) -> ThreeU8s { } // CHECK-LABEL: write_large -// CHECK: std 3, 0(6) +// aix: std 3, 48(1) +// aix-NEXT: rldicl [[REG1:.*]], 5, 32, 32 +// aix-NEXT: std 5, 64(1) +// aix-NEXT: std 4, 56(1) +// aix-NEXT: stw [[REG1]], 16(6) +// aix-NEXT: addi [[REG2:.*]], 1, 48 +// aix-NEXT: lxvd2x 0, 0, [[REG2]] +// aix-NEXT: stxvd2x 0, 0, 6 +// elf: std 3, 0(6) // be-NEXT: rldicl [[REG1:.*]], 5, 32, 32 -// CHECK-NEXT: std 4, 8(6) +// elf-NEXT: std 4, 8(6) // be-NEXT: stw [[REG1]], 16(6) // elfv2-le-NEXT: stw 5, 16(6) // CHECK-NEXT: blr @@ -107,7 +132,12 @@ extern "C" fn write_large(x: FiveU32s, dest: &mut FiveU32s) { } // CHECK-LABEL: write_medium -// CHECK: std 3, 0(5) +// aix: std 4, 56(1) +// aix-NEXT: rldicl [[REG1:.*]], 4, 16, 48 +// aix-NEXT: std 3, 48(1) +// aix-NEXT: std 3, 0(5) +// aix-NEXT: sth [[REG1]], 8(5) +// elf: std 3, 0(5) // be-NEXT: rldicl [[REG1:.*]], 4, 16, 48 // be-NEXT: sth [[REG1]], 8(5) // elfv2-le-NEXT: sth 4, 8(5) @@ -118,6 +148,11 @@ extern "C" fn write_medium(x: FiveU16s, dest: &mut FiveU16s) { } // CHECK-LABEL: write_small +// aix: std 3, 48(1) +// aix-NEXT: rldicl [[REG1:.*]], 3, 16, 48 +// aix-NEXT: sth 3, 0(4) +// aix-NEXT: lbz 3, 50(1) +// aix-NEXT: stb [[REG1]], 2(4) // be: stb 3, 2(4) // be-NEXT: srwi [[REG1:.*]], 3, 8 // be-NEXT: sth [[REG1]], 0(4) diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 7d1d05e2d55..f26d06a0ecb 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -375,6 +375,15 @@ //@ revisions: riscv32_wrs_vxworks //@ [riscv32_wrs_vxworks] compile-flags: --target riscv32-wrs-vxworks //@ [riscv32_wrs_vxworks] needs-llvm-components: riscv +//@ revisions: riscv32e_unknown_none_elf +//@ [riscv32e_unknown_none_elf] compile-flags: --target riscv32e-unknown-none-elf +//@ [riscv32e_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32em_unknown_none_elf +//@ [riscv32em_unknown_none_elf] compile-flags: --target riscv32em-unknown-none-elf +//@ [riscv32em_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32emc_unknown_none_elf +//@ [riscv32emc_unknown_none_elf] compile-flags: --target riscv32emc-unknown-none-elf +//@ [riscv32emc_unknown_none_elf] needs-llvm-components: riscv //@ revisions: riscv32gc_unknown_linux_gnu //@ [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu //@ [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv @@ -594,6 +603,9 @@ //@ revisions: x86_64_unknown_redox //@ [x86_64_unknown_redox] compile-flags: --target x86_64-unknown-redox //@ [x86_64_unknown_redox] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_trusty +//@ [x86_64_unknown_trusty] compile-flags: --target x86_64-unknown-trusty +//@ [x86_64_unknown_trusty] needs-llvm-components: x86 //@ revisions: x86_64_wrs_vxworks //@ [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks //@ [x86_64_wrs_vxworks] needs-llvm-components: x86 diff --git a/tests/assembly/thin-lto.rs b/tests/assembly/thin-lto.rs deleted file mode 100644 index 7b67b2de1e6..00000000000 --- a/tests/assembly/thin-lto.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ compile-flags: -O -C lto=thin -C prefer-dynamic=no -//@ only-x86_64-unknown-linux-gnu -//@ assembly-output: emit-asm - -// CHECK: main - -pub fn main() {} diff --git a/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs b/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs index a5683874182..54e1d93c68b 100644 --- a/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs +++ b/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs @@ -5,7 +5,7 @@ #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", // meaning "no prologue whatsoever, no, really, not one instruction." @@ -17,7 +17,7 @@ use std::arch::asm; pub unsafe extern "sysv64" fn will_halt() -> ! { // CHECK-NOT: endbr{{32|64}} // CHECK: hlt - asm!("hlt", options(noreturn)) + naked_asm!("hlt") } // what about aarch64? diff --git a/tests/codegen/asm-msp430-clobbers.rs b/tests/codegen/asm-msp430-clobbers.rs new file mode 100644 index 00000000000..c00c04f3088 --- /dev/null +++ b/tests/codegen/asm-msp430-clobbers.rs @@ -0,0 +1,36 @@ +//@ assembly-output: emit-asm +//@ compile-flags: --target msp430-none-elf +//@ needs-llvm-components: msp430 + +#![crate_type = "rlib"] +#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +// CHECK-LABEL: @sr_clobber +// CHECK: call void asm sideeffect "", "~{sr}"() +#[no_mangle] +pub unsafe fn sr_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r11},={r12},={r13},={r14},={r15}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs index 807873ea368..24b69c5f59e 100644 --- a/tests/codegen/cffi/c-variadic-naked.rs +++ b/tests/codegen/cffi/c-variadic-naked.rs @@ -12,8 +12,7 @@ pub unsafe extern "C" fn c_variadic(_: usize, _: ...) { // CHECK-NOT: va_start // CHECK-NOT: alloca - core::arch::asm! { + core::arch::naked_asm! { "ret", - options(noreturn), } } diff --git a/tests/codegen/default-visibility.rs b/tests/codegen/default-visibility.rs index 884d386ec20..88ff9fee254 100644 --- a/tests/codegen/default-visibility.rs +++ b/tests/codegen/default-visibility.rs @@ -31,3 +31,19 @@ pub static tested_symbol: [u8; 6] = *b"foobar"; // PROTECTED: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant // INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant // DEFAULT: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant + +pub fn do_memcmp(left: &[u8], right: &[u8]) -> i32 { + left.cmp(right) as i32 +} + +// CHECK: define {{.*}} @{{.*}}do_memcmp{{.*}} { +// CHECK: } + +// `do_memcmp` should invoke core::intrinsic::compare_bytes which emits a call +// to the C symbol `memcmp` (at least on x86_64-unknown-linux-gnu). This symbol +// should *not* be declared hidden or protected. + +// HIDDEN: declare i32 @memcmp +// PROTECTED: declare i32 @memcmp +// INTERPOSABLE: declare i32 @memcmp +// DEFAULT: declare i32 @memcmp diff --git a/tests/codegen/function-return.rs b/tests/codegen/function-return.rs index 0ca1a41ee86..2b9de4e1478 100644 --- a/tests/codegen/function-return.rs +++ b/tests/codegen/function-return.rs @@ -26,3 +26,9 @@ pub fn foo() { // keep-thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } // thunk-extern-keep-NOT: fn_ret_thunk_extern } + +// unset-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// keep-thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// thunk-extern-keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs index ac36018eed3..bcaa60baeff 100644 --- a/tests/codegen/naked-asan.rs +++ b/tests/codegen/naked-asan.rs @@ -14,7 +14,7 @@ #[no_mangle] pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { unsafe { - core::arch::asm!("ud2", options(noreturn)); + core::arch::naked_asm!("ud2"); } } diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs index d5faac44836..3bbd67981e5 100644 --- a/tests/codegen/naked-fn/aligned.rs +++ b/tests/codegen/naked-fn/aligned.rs @@ -4,7 +4,7 @@ #![crate_type = "lib"] #![feature(naked_functions, fn_align)] -use std::arch::asm; +use std::arch::naked_asm; // CHECK: Function Attrs: naked // CHECK-NEXT: define{{.*}}void @naked_empty() @@ -16,5 +16,5 @@ pub unsafe extern "C" fn naked_empty() { // CHECK-NEXT: start: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - asm!("ret", options(noreturn)); + naked_asm!("ret"); } diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs index 307745a921c..3f7447af599 100644 --- a/tests/codegen/naked-fn/naked-functions.rs +++ b/tests/codegen/naked-fn/naked-functions.rs @@ -4,7 +4,7 @@ #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; // CHECK: Function Attrs: naked // CHECK-NEXT: define{{.*}}void @naked_empty() @@ -14,7 +14,7 @@ pub unsafe extern "C" fn naked_empty() { // CHECK-NEXT: {{.+}}: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - asm!("ret", options(noreturn)); + naked_asm!("ret"); } // CHECK: Function Attrs: naked @@ -25,5 +25,5 @@ pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize // CHECK-NEXT: {{.+}}: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); + naked_asm!("lea rax, [rdi + rsi]", "ret"); } diff --git a/tests/codegen/naked-fn/naked-nocoverage.rs b/tests/codegen/naked-fn/naked-nocoverage.rs index d73c5b7fd26..f63661bcd3a 100644 --- a/tests/codegen/naked-fn/naked-nocoverage.rs +++ b/tests/codegen/naked-fn/naked-nocoverage.rs @@ -6,7 +6,7 @@ //@ compile-flags: -Cinstrument-coverage #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; #[naked] #[no_mangle] @@ -15,5 +15,5 @@ pub unsafe extern "C" fn f() { // CHECK-NEXT: start: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - asm!("", options(noreturn)); + naked_asm!(""); } diff --git a/tests/codegen/naked-fn/naked-noinline.rs b/tests/codegen/naked-fn/naked-noinline.rs index c1e8f368249..6ea36d96783 100644 --- a/tests/codegen/naked-fn/naked-noinline.rs +++ b/tests/codegen/naked-fn/naked-noinline.rs @@ -5,7 +5,7 @@ #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; #[naked] #[no_mangle] @@ -15,7 +15,7 @@ pub unsafe extern "C" fn f() { // CHECK: define {{(dso_local )?}}void @f() unnamed_addr [[ATTR:#[0-9]+]] // CHECK-NEXT: start: // CHECK-NEXT: call void asm - asm!("", options(noreturn)); + naked_asm!(""); } #[no_mangle] diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs index cfa479aa4b2..0edbbac1176 100644 --- a/tests/codegen/option-as-slice.rs +++ b/tests/codegen/option-as-slice.rs @@ -14,7 +14,9 @@ pub fn u64_opt_as_slice(o: &Option<u64>) -> &[u64] { // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp - // CHECK: %[[LEN:.+]] = load i64,{{.+}} !range ![[META_U64:.+]], !noundef + // CHECK: %[[LEN:.+]] = load i64 + // CHECK-SAME: !range ![[META_U64:[0-9]+]], + // CHECK-SAME: !noundef // CHECK-NOT: select // CHECK-NOT: br // CHECK-NOT: switch @@ -51,7 +53,9 @@ pub fn u8_opt_as_slice(o: &Option<u8>) -> &[u8] { // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp - // CHECK: %[[TAG:.+]] = load i8,{{.+}} !range ![[META_U8:.+]], !noundef + // CHECK: %[[TAG:.+]] = load i8 + // CHECK-SAME: !range ![[META_U8:[0-9]+]], + // CHECK-SAME: !noundef // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64 // CHECK-NOT: select // CHECK-NOT: br diff --git a/tests/codegen/thin-lto.rs b/tests/codegen/thin-lto.rs deleted file mode 100644 index 4339d20532e..00000000000 --- a/tests/codegen/thin-lto.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ compile-flags: -O -C lto=thin -C prefer-dynamic=no -//@ only-x86_64-unknown-linux-gnu - -// CHECK: main - -pub fn main() {} diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 15156ec9811..06dce43c3ca 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -34,6 +34,7 @@ Number of file 0 mappings: 13 - Code(Expression(9, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + c2) - Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2) +Highest counter ID seen: c5 Function name: abort::might_abort Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02] @@ -46,4 +47,5 @@ Number of file 0 mappings: 3 - Code(Counter(1)) at (prev + 2, 9) to (start + 1, 36) - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) = (c0 - c1) +Highest counter ID seen: c1 diff --git a/tests/coverage/assert-ne.cov-map b/tests/coverage/assert-ne.cov-map index 6d9906fd7f5..906abcd3c2e 100644 --- a/tests/coverage/assert-ne.cov-map +++ b/tests/coverage/assert-ne.cov-map @@ -10,4 +10,5 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c0 - c1) - Code(Counter(2)) at (prev + 3, 5) to (start + 1, 2) +Highest counter ID seen: c2 diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map index dd413123de7..018fcc2c3db 100644 --- a/tests/coverage/assert.cov-map +++ b/tests/coverage/assert.cov-map @@ -25,6 +25,7 @@ Number of file 0 mappings: 9 - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) +Highest counter ID seen: c4 Function name: assert::might_fail_assert Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02] @@ -37,4 +38,5 @@ Number of file 0 mappings: 3 - Code(Expression(0, Sub)) at (prev + 2, 37) to (start + 0, 61) = (c0 - c1) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/assert_not.cov-map b/tests/coverage/assert_not.cov-map index 788bc5dbf58..401dd6450e9 100644 --- a/tests/coverage/assert_not.cov-map +++ b/tests/coverage/assert_not.cov-map @@ -13,4 +13,5 @@ Number of file 0 mappings: 5 - Code(Counter(3)) at (prev + 1, 5) to (start + 0, 22) - Code(Expression(1, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c3 - Zero) +Highest counter ID seen: c3 diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map index 43b497a1d3f..9a67cefcf98 100644 --- a/tests/coverage/async.cov-map +++ b/tests/coverage/async.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 1) to (start + 0, 25) +Highest counter ID seen: c0 Function name: async::c::{closure#0} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0c, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] @@ -18,6 +19,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: async::d Raw bytes (9): 0x[01, 01, 00, 01, 01, 14, 01, 00, 14] @@ -26,6 +28,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 20, 1) to (start + 0, 20) +Highest counter ID seen: c0 Function name: async::d::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 14, 14, 00, 19] @@ -34,6 +37,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 20, 20) to (start + 0, 25) +Highest counter ID seen: c0 Function name: async::e (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 00, 14] @@ -42,6 +46,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 22, 1) to (start + 0, 20) +Highest counter ID seen: (none) Function name: async::e::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 14, 00, 19] @@ -50,6 +55,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 22, 20) to (start + 0, 25) +Highest counter ID seen: (none) Function name: async::f Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 00, 14] @@ -58,6 +64,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 24, 1) to (start + 0, 20) +Highest counter ID seen: c0 Function name: async::f::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 14, 00, 19] @@ -66,6 +73,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 24, 20) to (start + 0, 25) +Highest counter ID seen: c0 Function name: async::foo (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 01, 00, 1e] @@ -74,6 +82,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 26, 1) to (start + 0, 30) +Highest counter ID seen: (none) Function name: async::foo::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 1e, 00, 2d] @@ -82,6 +91,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 26, 30) to (start + 0, 45) +Highest counter ID seen: (none) Function name: async::g Raw bytes (9): 0x[01, 01, 00, 01, 01, 1c, 01, 00, 17] @@ -90,6 +100,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 28, 1) to (start + 0, 23) +Highest counter ID seen: c0 Function name: async::g::{closure#0} (unused) Raw bytes (59): 0x[01, 01, 00, 0b, 00, 1c, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] @@ -108,6 +119,7 @@ Number of file 0 mappings: 11 - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: (none) Function name: async::h Raw bytes (9): 0x[01, 01, 00, 01, 01, 24, 01, 00, 16] @@ -116,6 +128,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 36, 1) to (start + 0, 22) +Highest counter ID seen: c0 Function name: async::h::{closure#0} (unused) Raw bytes (39): 0x[01, 01, 00, 07, 00, 24, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] @@ -130,6 +143,7 @@ Number of file 0 mappings: 7 - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: (none) Function name: async::i Raw bytes (9): 0x[01, 01, 00, 01, 01, 2d, 01, 00, 13] @@ -138,6 +152,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 45, 1) to (start + 0, 19) +Highest counter ID seen: c0 Function name: async::i::{closure#0} Raw bytes (63): 0x[01, 01, 02, 07, 19, 11, 15, 0b, 01, 2d, 13, 04, 0c, 09, 05, 09, 00, 0a, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 0d, 00, 0e, 00, 17, 1d, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 19, 01, 0e, 00, 10, 03, 02, 01, 00, 02] @@ -159,6 +174,7 @@ Number of file 0 mappings: 11 - Code(Counter(6)) at (prev + 1, 14) to (start + 0, 16) - Code(Expression(0, Add)) at (prev + 2, 1) to (start + 0, 2) = ((c4 + c5) + c6) +Highest counter ID seen: c7 Function name: async::j Raw bytes (58): 0x[01, 01, 02, 07, 0d, 05, 09, 0a, 01, 38, 01, 00, 0d, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02] @@ -179,6 +195,7 @@ Number of file 0 mappings: 10 - Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16) - Code(Expression(0, Add)) at (prev + 2, 1) to (start + 0, 2) = ((c1 + c2) + c3) +Highest counter ID seen: c4 Function name: async::j::c Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 3a, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 02, 0d, 00, 0e, 01, 02, 05, 00, 06] @@ -192,6 +209,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) +Highest counter ID seen: c1 Function name: async::j::d Raw bytes (9): 0x[01, 01, 00, 01, 01, 41, 05, 00, 17] @@ -200,6 +218,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 65, 5) to (start + 0, 23) +Highest counter ID seen: c0 Function name: async::j::f Raw bytes (9): 0x[01, 01, 00, 01, 01, 42, 05, 00, 17] @@ -208,6 +227,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 66, 5) to (start + 0, 23) +Highest counter ID seen: c0 Function name: async::k (unused) Raw bytes (29): 0x[01, 01, 00, 05, 00, 4a, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] @@ -220,6 +240,7 @@ Number of file 0 mappings: 5 - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: (none) Function name: async::l Raw bytes (37): 0x[01, 01, 04, 01, 07, 05, 09, 0f, 02, 09, 05, 05, 01, 52, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] @@ -238,6 +259,7 @@ Number of file 0 mappings: 5 - Code(Counter(2)) at (prev + 1, 14) to (start + 0, 16) - Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2) = ((c2 + c1) + (c0 - (c1 + c2))) +Highest counter ID seen: c2 Function name: async::m Raw bytes (9): 0x[01, 01, 00, 01, 01, 5a, 01, 00, 19] @@ -246,6 +268,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 90, 1) to (start + 0, 25) +Highest counter ID seen: c0 Function name: async::m::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 5a, 19, 00, 22] @@ -254,6 +277,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 90, 25) to (start + 0, 34) +Highest counter ID seen: (none) Function name: async::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 5c, 01, 08, 02] @@ -262,4 +286,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 92, 1) to (start + 8, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map index 3816401ac63..ed61e91efc2 100644 --- a/tests/coverage/async2.cov-map +++ b/tests/coverage/async2.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 16, 1) to (start + 0, 23) +Highest counter ID seen: c0 Function name: async2::async_func::{closure#0} Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02] @@ -16,6 +17,7 @@ Number of file 0 mappings: 4 - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6) - Code(Zero) at (prev + 2, 6) to (start + 0, 7) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: async2::async_func_just_println Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 00, 24] @@ -24,6 +26,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 24, 1) to (start + 0, 36) +Highest counter ID seen: c0 Function name: async2::async_func_just_println::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 24, 02, 02] @@ -32,6 +35,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 24, 36) to (start + 2, 2) +Highest counter ID seen: c0 Function name: async2::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 1c, 01, 07, 02] @@ -40,6 +44,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 28, 1) to (start + 7, 2) +Highest counter ID seen: c0 Function name: async2::non_async_func Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02] @@ -51,4 +56,5 @@ Number of file 0 mappings: 4 - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6) - Code(Zero) at (prev + 2, 6) to (start + 0, 7) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async_block.cov-map index 65f3d821f6e..e3309bd51b4 100644 --- a/tests/coverage/async_block.cov-map +++ b/tests/coverage/async_block.cov-map @@ -12,6 +12,7 @@ Number of file 0 mappings: 6 - Code(Counter(1)) at (prev + 0, 20) to (start + 1, 22) - Code(Counter(1)) at (prev + 7, 10) to (start + 2, 6) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: async_block::main::{closure#0} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0a, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] @@ -25,4 +26,5 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) +Highest counter ID seen: c1 diff --git a/tests/coverage/attr/impl.cov-map b/tests/coverage/attr/impl.cov-map index 9b0deed8b64..4d068c290f4 100644 --- a/tests/coverage/attr/impl.cov-map +++ b/tests/coverage/attr/impl.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 14, 5) to (start + 0, 19) +Highest counter ID seen: (none) Function name: <impl::MyStruct>::on_inherit (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 05, 00, 17] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 22, 5) to (start + 0, 23) +Highest counter ID seen: (none) Function name: <impl::MyStruct>::on_on (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 05, 00, 12] @@ -21,4 +23,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 25, 5) to (start + 0, 18) +Highest counter ID seen: (none) diff --git a/tests/coverage/attr/module.cov-map b/tests/coverage/attr/module.cov-map index 34898eb4ca8..b318ac85a6c 100644 --- a/tests/coverage/attr/module.cov-map +++ b/tests/coverage/attr/module.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 12, 5) to (start + 0, 15) +Highest counter ID seen: (none) Function name: module::on::inherit (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 14, 05, 00, 14] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 20, 5) to (start + 0, 20) +Highest counter ID seen: (none) Function name: module::on::on (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 05, 00, 0f] @@ -21,4 +23,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 23, 5) to (start + 0, 15) +Highest counter ID seen: (none) diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map index 466aec8956e..2bd95325373 100644 --- a/tests/coverage/attr/nested.cov-map +++ b/tests/coverage/attr/nested.cov-map @@ -6,6 +6,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 63, 1) to (start + 1, 15) - Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2) +Highest counter ID seen: c0 Function name: nested::closure_tail Raw bytes (14): 0x[01, 01, 00, 02, 01, 4e, 01, 01, 0f, 01, 11, 05, 01, 02] @@ -15,4 +16,5 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 78, 1) to (start + 1, 15) - Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map index d5fbac6ebf7..ae5c9bd19a2 100644 --- a/tests/coverage/attr/off-on-sandwich.cov-map +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -6,6 +6,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 15, 5) to (start + 2, 18) - Code(Counter(0)) at (prev + 7, 5) to (start + 0, 6) +Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c Raw bytes (14): 0x[01, 01, 00, 02, 01, 21, 09, 02, 17, 01, 0b, 09, 00, 0a] @@ -15,6 +16,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 33, 9) to (start + 2, 23) - Code(Counter(0)) at (prev + 11, 9) to (start + 0, 10) +Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 0d, 02, 1b, 01, 07, 0d, 00, 0e] @@ -24,4 +26,5 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 36, 13) to (start + 2, 27) - Code(Counter(0)) at (prev + 7, 13) to (start + 0, 14) +Highest counter ID seen: c0 diff --git a/tests/coverage/await_ready.cov-map b/tests/coverage/await_ready.cov-map index 38c2cf7b2d3..95dbf68a191 100644 --- a/tests/coverage/await_ready.cov-map +++ b/tests/coverage/await_ready.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 15, 1) to (start + 0, 30) +Highest counter ID seen: c0 Function name: await_ready::await_ready::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 0f, 1e, 03, 0f, 05, 04, 01, 00, 02] @@ -14,4 +15,5 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 15, 30) to (start + 3, 15) - Code(Counter(1)) at (prev + 4, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map index 7eff7f5f02f..2b5399f33bb 100644 --- a/tests/coverage/bad_counter_ids.cov-map +++ b/tests/coverage/bad_counter_ids.cov-map @@ -6,6 +6,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 36, 1) to (start + 2, 31) - Code(Zero) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: bad_counter_ids::eq_bad_message Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 29, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02] @@ -18,6 +19,7 @@ Number of file 0 mappings: 3 - Code(Expression(0, Sub)) at (prev + 2, 32) to (start + 0, 43) = (c0 - Zero) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 1f, 05, 03, 01, 00, 02] @@ -27,6 +29,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 16, 1) to (start + 2, 31) - Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: bad_counter_ids::eq_good_message Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02] @@ -37,6 +40,7 @@ Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15) - Code(Zero) at (prev + 2, 32) to (start + 0, 43) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: bad_counter_ids::ne_bad Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 1f, 00, 03, 01, 00, 02] @@ -46,6 +50,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 46, 1) to (start + 2, 31) - Code(Zero) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad_message Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02] @@ -56,6 +61,7 @@ Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15) - Code(Counter(1)) at (prev + 2, 32) to (start + 0, 43) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: bad_counter_ids::ne_good Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 1a, 01, 02, 1f, 02, 03, 01, 00, 02] @@ -67,6 +73,7 @@ Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 26, 1) to (start + 2, 31) - Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2) = (c0 - Zero) +Highest counter ID seen: c0 Function name: bad_counter_ids::ne_good_message Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02] @@ -79,4 +86,5 @@ Number of file 0 mappings: 3 - Code(Zero) at (prev + 2, 32) to (start + 0, 43) - Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c0 - Zero) +Highest counter ID seen: c0 diff --git a/tests/coverage/bench.cov-map b/tests/coverage/bench.cov-map index aa702a48681..9ee6510f690 100644 --- a/tests/coverage/bench.cov-map +++ b/tests/coverage/bench.cov-map @@ -5,4 +5,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 8, 1) to (start + 0, 39) +Highest counter ID seen: c0 diff --git a/tests/coverage/branch/generics.cov-map b/tests/coverage/branch/generics.cov-map index 2e5668c8b56..656890634ff 100644 --- a/tests/coverage/branch/generics.cov-map +++ b/tests/coverage/branch/generics.cov-map @@ -13,6 +13,7 @@ Number of file 0 mappings: 5 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: generics::print_size::<u32> Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] @@ -29,6 +30,7 @@ Number of file 0 mappings: 5 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: generics::print_size::<u64> Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] @@ -45,4 +47,5 @@ Number of file 0 mappings: 5 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map index d67c3d349a1..0f33ed17a0a 100644 --- a/tests/coverage/branch/guard.cov-map +++ b/tests/coverage/branch/guard.cov-map @@ -29,4 +29,5 @@ Number of file 0 mappings: 13 = (c1 + c2) - Code(Expression(2, Add)) at (prev + 4, 1) to (start + 0, 2) = ((((c1 + c2) + c3) + c4) + c5) +Highest counter ID seen: c7 diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map index 0b098bc6497..380765c7af4 100644 --- a/tests/coverage/branch/if-let.cov-map +++ b/tests/coverage/branch/if-let.cov-map @@ -16,6 +16,7 @@ Number of file 0 mappings: 7 = (c1 - c2) - Code(Counter(2)) at (prev + 2, 12) to (start + 2, 6) - Code(Counter(1)) at (prev + 3, 5) to (start + 1, 2) +Highest counter ID seen: c2 Function name: if_let::if_let_chain Raw bytes (66): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 0d, 09, 01, 10, 00, 17, 0d, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02] @@ -45,4 +46,5 @@ Number of file 0 mappings: 10 = (c1 + c2) - Code(Expression(2, Add)) at (prev + 3, 5) to (start + 1, 2) = ((c1 + c2) + c3) +Highest counter ID seen: c3 diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index 7f4ee980e26..4a8cb664dd8 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -22,6 +22,7 @@ Number of file 0 mappings: 8 = (c3 + (c1 - c2)) - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) = (c4 + (c3 + (c1 - c2))) +Highest counter ID seen: c4 Function name: if::branch_not Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 06, 00, 07, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 05, 01, 01, 00, 02] @@ -66,6 +67,7 @@ Number of file 0 mappings: 18 = (c1 - c5) - Code(Counter(5)) at (prev + 2, 6) to (start + 0, 7) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c5 Function name: if::branch_not_as Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 06, 00, 07, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 06, 00, 07, 05, 01, 01, 00, 02] @@ -101,6 +103,7 @@ Number of file 0 mappings: 14 = (c1 - c4) - Code(Counter(4)) at (prev + 2, 6) to (start + 0, 7) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c4 Function name: if::branch_or Raw bytes (56): 0x[01, 01, 04, 05, 09, 09, 0d, 0f, 11, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0f, 00, 0f, 02, 06, 11, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] @@ -127,4 +130,5 @@ Number of file 0 mappings: 8 - Code(Counter(4)) at (prev + 2, 12) to (start + 2, 6) - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) = ((c2 + c3) + c4) +Highest counter ID seen: c4 diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map index 09ce9137673..c2b6a5b8df2 100644 --- a/tests/coverage/branch/lazy-boolean.cov-map +++ b/tests/coverage/branch/lazy-boolean.cov-map @@ -13,6 +13,7 @@ Number of file 0 mappings: 6 false = (c1 - c2) - Code(Counter(2)) at (prev + 0, 18) to (start + 0, 19) - Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c2 Function name: lazy_boolean::branch_or Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 1b, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 05, 01, 05, 01, 02] @@ -30,6 +31,7 @@ Number of file 0 mappings: 6 - Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c1 - c2) - Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c2 Function name: lazy_boolean::chain Raw bytes (149): 0x[01, 01, 13, 11, 07, 0b, 16, 15, 1a, 09, 0d, 05, 09, 05, 09, 09, 0d, 47, 25, 4b, 21, 19, 1d, 03, 19, 03, 19, 3e, 1d, 03, 19, 3e, 1d, 03, 19, 47, 25, 4b, 21, 19, 1d, 13, 01, 24, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 09, 16, 00, 0d, 00, 12, 09, 00, 16, 00, 1b, 20, 0d, 1a, 00, 16, 00, 1b, 0d, 00, 1f, 00, 24, 20, 11, 15, 00, 1f, 00, 24, 11, 00, 28, 00, 2d, 03, 01, 05, 00, 11, 43, 03, 09, 00, 0a, 03, 00, 0d, 00, 12, 20, 19, 3e, 00, 0d, 00, 12, 3e, 00, 16, 00, 1b, 20, 1d, 3a, 00, 16, 00, 1b, 3a, 00, 1f, 00, 24, 20, 21, 25, 00, 1f, 00, 24, 25, 00, 28, 00, 2d, 43, 01, 05, 01, 02] @@ -94,6 +96,7 @@ Number of file 0 mappings: 19 - Code(Counter(9)) at (prev + 0, 40) to (start + 0, 45) - Code(Expression(16, Add)) at (prev + 1, 5) to (start + 1, 2) = (((c6 + c7) + c8) + c9) +Highest counter ID seen: c9 Function name: lazy_boolean::nested_mixed Raw bytes (155): 0x[01, 01, 16, 33, 1a, 09, 0d, 1e, 0d, 05, 09, 05, 09, 05, 09, 1e, 0d, 05, 09, 09, 0d, 33, 11, 09, 0d, 33, 11, 09, 0d, 19, 57, 1d, 21, 03, 15, 15, 19, 4a, 4e, 15, 19, 03, 15, 19, 57, 1d, 21, 13, 01, 31, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 1e, 00, 0e, 00, 13, 1e, 00, 17, 00, 1d, 20, 0d, 1a, 00, 17, 00, 1d, 33, 00, 23, 00, 28, 20, 11, 2e, 00, 23, 00, 28, 2e, 00, 2c, 00, 33, 03, 01, 05, 00, 11, 53, 03, 09, 00, 0a, 03, 00, 0e, 00, 13, 20, 15, 4e, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 4a, 00, 17, 00, 1c, 47, 00, 22, 00, 28, 20, 1d, 21, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 53, 01, 05, 01, 02] @@ -163,4 +166,5 @@ Number of file 0 mappings: 19 - Code(Counter(7)) at (prev + 0, 44) to (start + 0, 51) - Code(Expression(20, Add)) at (prev + 1, 5) to (start + 1, 2) = (c6 + (c7 + c8)) +Highest counter ID seen: c8 diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map index 07079934464..e6bf7ed6a92 100644 --- a/tests/coverage/branch/let-else.cov-map +++ b/tests/coverage/branch/let-else.cov-map @@ -16,4 +16,5 @@ Number of file 0 mappings: 7 - Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 11) = (c1 - c2) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c2 diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index 1f17f11baaa..fd0366ee818 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -34,6 +34,7 @@ Number of file 0 mappings: 12 = ((((Zero + c2) + c3) + c4) + c5) - Code(Expression(4, Add)) at (prev + 3, 5) to (start + 1, 2) = ((((((((Zero + c2) + c3) + c4) + c5) + c6) + c7) + c8) + c9) +Highest counter ID seen: c10 Function name: match_arms::match_arms Raw bytes (51): 0x[01, 01, 06, 05, 07, 0b, 11, 09, 0d, 13, 02, 17, 09, 11, 0d, 07, 01, 18, 01, 01, 10, 05, 03, 0b, 00, 10, 11, 01, 11, 00, 21, 0d, 01, 11, 00, 21, 09, 01, 11, 00, 21, 02, 01, 11, 00, 21, 0f, 03, 05, 01, 02] @@ -56,6 +57,7 @@ Number of file 0 mappings: 7 = (c1 - ((c2 + c3) + c4)) - Code(Expression(3, Add)) at (prev + 3, 5) to (start + 1, 2) = (((c4 + c3) + c2) + (c1 - ((c2 + c3) + c4))) +Highest counter ID seen: c4 Function name: match_arms::or_patterns Raw bytes (75): 0x[01, 01, 0d, 11, 0d, 05, 2f, 33, 11, 09, 0d, 09, 2a, 05, 2f, 33, 11, 09, 0d, 03, 27, 09, 2a, 05, 2f, 33, 11, 09, 0d, 09, 01, 25, 01, 01, 10, 05, 03, 0b, 00, 10, 11, 01, 11, 00, 12, 0d, 00, 1e, 00, 1f, 03, 00, 24, 00, 2e, 09, 01, 11, 00, 12, 2a, 00, 1e, 00, 1f, 27, 00, 24, 00, 2e, 23, 03, 05, 01, 02] @@ -89,4 +91,5 @@ Number of file 0 mappings: 9 = (c2 + (c1 - ((c2 + c3) + c4))) - Code(Expression(8, Add)) at (prev + 3, 5) to (start + 1, 2) = ((c4 + c3) + (c2 + (c1 - ((c2 + c3) + c4)))) +Highest counter ID seen: c4 diff --git a/tests/coverage/branch/match-trivial.cov-map b/tests/coverage/branch/match-trivial.cov-map index 1136a529b25..6af8ce46f5f 100644 --- a/tests/coverage/branch/match-trivial.cov-map +++ b/tests/coverage/branch/match-trivial.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 22, 1) to (start + 1, 16) +Highest counter ID seen: (none) Function name: match_trivial::trivial Raw bytes (14): 0x[01, 01, 00, 02, 01, 1e, 01, 01, 10, 05, 03, 0b, 05, 02] @@ -14,4 +15,5 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 30, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 3, 11) to (start + 5, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/branch/no-mir-spans.cov-map b/tests/coverage/branch/no-mir-spans.cov-map index cb19211913f..ab12732b1ed 100644 --- a/tests/coverage/branch/no-mir-spans.cov-map +++ b/tests/coverage/branch/no-mir-spans.cov-map @@ -8,6 +8,7 @@ Number of file 0 mappings: 2 - Branch { true: Counter(1), false: Counter(2) } at (prev + 4, 11) to (start + 0, 16) true = c1 false = c2 +Highest counter ID seen: c2 Function name: no_mir_spans::while_cond_not Raw bytes (16): 0x[01, 01, 00, 02, 01, 19, 01, 00, 15, 20, 09, 05, 04, 0b, 00, 14] @@ -19,6 +20,7 @@ Number of file 0 mappings: 2 - Branch { true: Counter(2), false: Counter(1) } at (prev + 4, 11) to (start + 0, 20) true = c2 false = c1 +Highest counter ID seen: c2 Function name: no_mir_spans::while_op_and Raw bytes (25): 0x[01, 01, 01, 09, 0d, 03, 01, 22, 01, 00, 13, 20, 09, 05, 05, 0b, 00, 10, 20, 02, 0d, 00, 14, 00, 19] @@ -34,6 +36,7 @@ Number of file 0 mappings: 3 - Branch { true: Expression(0, Sub), false: Counter(3) } at (prev + 0, 20) to (start + 0, 25) true = (c2 - c3) false = c3 +Highest counter ID seen: c3 Function name: no_mir_spans::while_op_or Raw bytes (25): 0x[01, 01, 01, 09, 0d, 03, 01, 2d, 01, 00, 12, 20, 05, 09, 05, 0b, 00, 10, 20, 0d, 02, 00, 14, 00, 19] @@ -49,4 +52,5 @@ Number of file 0 mappings: 3 - Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 25) true = c3 false = (c2 - c3) +Highest counter ID seen: c3 diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map index fd05bbb69a5..d5840a2c320 100644 --- a/tests/coverage/branch/while.cov-map +++ b/tests/coverage/branch/while.cov-map @@ -14,6 +14,7 @@ Number of file 0 mappings: 6 false = c1 - Code(Counter(2)) at (prev + 0, 17) to (start + 2, 6) - Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c2 Function name: while::while_cond_not Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 15, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 14, 20, 09, 05, 00, 0b, 00, 14, 09, 00, 15, 02, 06, 05, 03, 01, 00, 02] @@ -31,6 +32,7 @@ Number of file 0 mappings: 6 false = c1 - Code(Counter(2)) at (prev + 0, 21) to (start + 2, 6) - Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c2 Function name: while::while_op_and Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 11, 0d, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 11, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 0f, 04, 01, 00, 02] @@ -57,6 +59,7 @@ Number of file 0 mappings: 8 - Code(Counter(2)) at (prev + 0, 26) to (start + 3, 6) - Code(Expression(3, Add)) at (prev + 4, 1) to (start + 0, 2) = (c4 + c3) +Highest counter ID seen: c4 Function name: while::while_op_or Raw bytes (66): 0x[01, 01, 09, 05, 1b, 09, 0d, 03, 09, 03, 09, 22, 0d, 03, 09, 09, 0d, 22, 0d, 03, 09, 08, 01, 29, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 09, 22, 00, 0b, 00, 10, 22, 00, 14, 00, 19, 20, 0d, 1e, 00, 14, 00, 19, 1b, 00, 1a, 03, 06, 1e, 04, 01, 00, 02] @@ -89,4 +92,5 @@ Number of file 0 mappings: 8 = (c2 + c3) - Code(Expression(7, Sub)) at (prev + 4, 1) to (start + 0, 2) = (((c1 + (c2 + c3)) - c2) - c3) +Highest counter ID seen: c3 diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 6edd35921fe..d50f9f8e7af 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -30,6 +30,7 @@ Number of file 0 mappings: 24 - Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2) +Highest counter ID seen: c1 Function name: closure::main::{closure#0} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] @@ -43,6 +44,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +Highest counter ID seen: c1 Function name: closure::main::{closure#10} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21] @@ -51,6 +53,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 155, 7) to (start + 0, 33) +Highest counter ID seen: (none) Function name: closure::main::{closure#11} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 9f, 01, 07, 00, 21] @@ -59,6 +62,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 159, 7) to (start + 0, 33) +Highest counter ID seen: (none) Function name: closure::main::{closure#12} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 01, 00, 17] @@ -67,6 +71,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 167, 1) to (start + 0, 23) +Highest counter ID seen: (none) Function name: closure::main::{closure#13} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, ac, 01, 0d, 02, 0e] @@ -75,6 +80,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 172, 13) to (start + 2, 14) +Highest counter ID seen: (none) Function name: closure::main::{closure#14} Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e] @@ -88,6 +94,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) +Highest counter ID seen: c1 Function name: closure::main::{closure#15} Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] @@ -103,6 +110,7 @@ Number of file 0 mappings: 6 - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +Highest counter ID seen: c1 Function name: closure::main::{closure#16} Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e] @@ -116,6 +124,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) +Highest counter ID seen: c1 Function name: closure::main::{closure#17} Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] @@ -131,6 +140,7 @@ Number of file 0 mappings: 6 - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +Highest counter ID seen: c1 Function name: closure::main::{closure#18} (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 12, 00, 13, 00, 01, 11, 01, 0e] @@ -142,6 +152,7 @@ Number of file 0 mappings: 4 - Code(Zero) at (prev + 2, 29) to (start + 2, 18) - Code(Zero) at (prev + 2, 18) to (start + 0, 19) - Code(Zero) at (prev + 1, 17) to (start + 1, 14) +Highest counter ID seen: (none) Function name: closure::main::{closure#19} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 01, 01, 11, 01, 0e] @@ -155,6 +166,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) +Highest counter ID seen: c1 Function name: closure::main::{closure#1} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] @@ -168,6 +180,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +Highest counter ID seen: c1 Function name: closure::main::{closure#2} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] @@ -181,6 +194,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +Highest counter ID seen: c1 Function name: closure::main::{closure#3} (unused) Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] @@ -192,6 +206,7 @@ Number of file 0 mappings: 4 - Code(Zero) at (prev + 1, 21) to (start + 2, 10) - Code(Zero) at (prev + 2, 10) to (start + 0, 11) - Code(Zero) at (prev + 1, 9) to (start + 1, 6) +Highest counter ID seen: (none) Function name: closure::main::{closure#4} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 89, 01, 35, 00, 43] @@ -200,6 +215,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 137, 53) to (start + 0, 67) +Highest counter ID seen: (none) Function name: closure::main::{closure#5} Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 3d, 00, 4f] @@ -208,6 +224,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 140, 61) to (start + 0, 79) +Highest counter ID seen: c0 Function name: closure::main::{closure#6} Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 41, 00, 57] @@ -216,6 +233,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 141, 65) to (start + 0, 87) +Highest counter ID seen: c0 Function name: closure::main::{closure#7} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 3b, 00, 51] @@ -224,6 +242,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 142, 59) to (start + 0, 81) +Highest counter ID seen: (none) Function name: closure::main::{closure#8} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 93, 01, 3b, 00, 55] @@ -232,6 +251,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 147, 59) to (start + 0, 85) +Highest counter ID seen: (none) Function name: closure::main::{closure#9} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 95, 01, 38, 02, 06] @@ -240,4 +260,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 149, 56) to (start + 2, 6) +Highest counter ID seen: (none) diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map index 32e8db5fb2f..96e1e339e56 100644 --- a/tests/coverage/closure_bug.cov-map +++ b/tests/coverage/closure_bug.cov-map @@ -29,6 +29,7 @@ Number of file 0 mappings: 17 - Code(Expression(3, Sub)) at (prev + 0, 23) to (start + 0, 24) = (c0 - c4) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c4 Function name: closure_bug::main::{closure#0} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] @@ -42,6 +43,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42) +Highest counter ID seen: c1 Function name: closure_bug::main::{closure#1} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] @@ -55,6 +57,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42) +Highest counter ID seen: c1 Function name: closure_bug::main::{closure#2} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] @@ -68,6 +71,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42) +Highest counter ID seen: c1 Function name: closure_bug::main::{closure#3} Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] @@ -81,4 +85,5 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42) +Highest counter ID seen: c1 diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index eb5f94d1080..7c9d3292f98 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: closure_macro::main Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] @@ -21,21 +22,23 @@ Number of file 0 mappings: 6 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: closure_macro::main::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) -- expression 2 operands: lhs = Counter(2), rhs = Zero +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) = (c0 - c1) -- Code(Zero) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) - Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) - = (c1 + (c2 + Zero)) + = (c1 + (c2 + c3)) +Highest counter ID seen: c3 diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 4d0597f58bf..e2a52e57015 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 34, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: closure_macro_async::test Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 01, 00, 2b] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 38, 1) to (start + 0, 43) +Highest counter ID seen: c0 Function name: closure_macro_async::test::{closure#0} Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 26, 2b, 01, 21, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] @@ -29,21 +31,23 @@ Number of file 0 mappings: 6 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: closure_macro_async::test::{closure#0}::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 15, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 15, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) -- expression 2 operands: lhs = Counter(2), rhs = Zero +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 21, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) = (c0 - c1) -- Code(Zero) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) - Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) - = (c1 + (c2 + Zero)) + = (c1 + (c2 + c3)) +Highest counter ID seen: c3 diff --git a/tests/coverage/closure_unit_return.cov-map b/tests/coverage/closure_unit_return.cov-map index c97b4a44dd6..9a66e0b0e77 100644 --- a/tests/coverage/closure_unit_return.cov-map +++ b/tests/coverage/closure_unit_return.cov-map @@ -6,6 +6,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 16) - Code(Counter(0)) at (prev + 5, 5) to (start + 2, 2) +Highest counter ID seen: c0 Function name: closure_unit_return::explicit_unit::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 08, 16, 02, 06] @@ -14,6 +15,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 8, 22) to (start + 2, 6) +Highest counter ID seen: (none) Function name: closure_unit_return::implicit_unit Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 01, 10, 01, 05, 05, 02, 02] @@ -23,6 +25,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 16, 1) to (start + 1, 16) - Code(Counter(0)) at (prev + 5, 5) to (start + 2, 2) +Highest counter ID seen: c0 Function name: closure_unit_return::implicit_unit::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 16, 02, 06] @@ -31,4 +34,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 17, 22) to (start + 2, 6) +Highest counter ID seen: (none) diff --git a/tests/coverage/color.coverage b/tests/coverage/color.coverage index b12f20204b4..4e6ef6b60ce 100644 --- a/tests/coverage/color.coverage +++ b/tests/coverage/color.coverage @@ -1,5 +1,5 @@ LL| |//@ edition: 2021 - LL| |//@ ignore-mode-coverage-map + LL| |//@ ignore-coverage-map LL| |//@ ignore-windows LL| |//@ llvm-cov-flags: --use-color LL| | diff --git a/tests/coverage/color.rs b/tests/coverage/color.rs index 144e798ba5d..bdb81c088f5 100644 --- a/tests/coverage/color.rs +++ b/tests/coverage/color.rs @@ -1,5 +1,5 @@ //@ edition: 2021 -//@ ignore-mode-coverage-map +//@ ignore-coverage-map //@ ignore-windows //@ llvm-cov-flags: --use-color diff --git a/tests/coverage/condition/conditions.cov-map b/tests/coverage/condition/conditions.cov-map index 74726e269fc..208d671919c 100644 --- a/tests/coverage/condition/conditions.cov-map +++ b/tests/coverage/condition/conditions.cov-map @@ -29,6 +29,7 @@ Number of file 0 mappings: 9 false = c4 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = ((c2 + c3) + c4) +Highest counter ID seen: c4 Function name: conditions::assign_3_or_and Raw bytes (73): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 09, 01, 17, 01, 00, 2f, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 22, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 20, 1e, 11, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 20, 09, 0d, 00, 17, 00, 18, 03, 01, 05, 01, 02] @@ -64,6 +65,7 @@ Number of file 0 mappings: 9 false = c3 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = (c1 + ((c2 + c3) + c4)) +Highest counter ID seen: c4 Function name: conditions::assign_and Raw bytes (51): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 07, 01, 0d, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02] @@ -88,6 +90,7 @@ Number of file 0 mappings: 7 false = c3 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = ((c2 + c3) + (c0 - c1)) +Highest counter ID seen: c3 Function name: conditions::assign_or Raw bytes (51): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 07, 01, 12, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02] @@ -113,6 +116,7 @@ Number of file 0 mappings: 7 false = c3 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = ((c1 + c2) + c3) +Highest counter ID seen: c3 Function name: conditions::foo Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] @@ -121,6 +125,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: conditions::func_call Raw bytes (39): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 0d, 00, 0e, 00, 0f, 07, 01, 01, 00, 02] @@ -141,6 +146,7 @@ Number of file 0 mappings: 5 false = c3 - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) = ((c2 + c3) + (c0 - c1)) +Highest counter ID seen: c3 Function name: conditions::simple_assign Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] @@ -149,4 +155,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index 17143775b7b..a392d1b7028 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -260,4 +260,5 @@ Number of file 0 mappings: 68 - Code(Counter(9)) at (prev + 2, 9) to (start + 0, 15) - Code(Expression(137, Add)) at (prev + 2, 1) to (start + 0, 2) = ((c4 + (((c5 + c6) + c7) + c8)) + ((((c9 + c10) + c11) + c12) + ((c0 - c2) - c3))) +Highest counter ID seen: c35 diff --git a/tests/coverage/continue.cov-map b/tests/coverage/continue.cov-map index 810694d7f66..7781d2d2544 100644 --- a/tests/coverage/continue.cov-map +++ b/tests/coverage/continue.cov-map @@ -76,4 +76,5 @@ Number of file 0 mappings: 30 - Code(Counter(16)) at (prev + 3, 9) to (start + 0, 14) - Code(Expression(27, Add)) at (prev + 2, 13) to (start + 1, 2) = (c18 + c17) +Highest counter ID seen: c18 diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index 6ff5ed74a96..2fdc3220c19 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -10,6 +10,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 40) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: coroutine::main Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] @@ -39,6 +40,7 @@ Number of file 0 mappings: 9 = (c5 + c6) - Code(Expression(6, Sub)) at (prev + 2, 1) to (start + 0, 2) = ((c4 - c5) - c6) +Highest counter ID seen: c4 Function name: coroutine::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06] @@ -48,4 +50,5 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 22, 8) to (start + 1, 31) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) +Highest counter ID seen: c1 diff --git a/tests/coverage/coverage_attr_closure.cov-map b/tests/coverage/coverage_attr_closure.cov-map index 5d2c6b00b40..fb861996a0d 100644 --- a/tests/coverage/coverage_attr_closure.cov-map +++ b/tests/coverage/coverage_attr_closure.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 6, 15) to (start + 2, 2) +Highest counter ID seen: c0 Function name: coverage_attr_closure::contains_closures_off::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1d, 13, 02, 06] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 29, 19) to (start + 2, 6) +Highest counter ID seen: (none) Function name: coverage_attr_closure::contains_closures_on Raw bytes (19): 0x[01, 01, 00, 03, 01, 0f, 01, 01, 1a, 01, 05, 09, 00, 1b, 01, 04, 01, 00, 02] @@ -23,6 +25,7 @@ Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 26) - Code(Counter(0)) at (prev + 5, 9) to (start + 0, 27) - Code(Counter(0)) at (prev + 4, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: coverage_attr_closure::contains_closures_on::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 13, 02, 06] @@ -31,4 +34,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 17, 19) to (start + 2, 6) +Highest counter ID seen: (none) diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map index 31599d9072c..b94c6e656ab 100644 --- a/tests/coverage/dead_code.cov-map +++ b/tests/coverage/dead_code.cov-map @@ -10,6 +10,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: dead_code::unused_fn (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] @@ -21,6 +22,7 @@ Number of file 0 mappings: 4 - Code(Zero) at (prev + 7, 16) to (start + 2, 6) - Code(Zero) at (prev + 2, 6) to (start + 0, 7) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: (none) Function name: dead_code::unused_pub_fn_not_in_library (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] @@ -32,4 +34,5 @@ Number of file 0 mappings: 4 - Code(Zero) at (prev + 7, 16) to (start + 2, 6) - Code(Zero) at (prev + 2, 6) to (start + 0, 7) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: (none) diff --git a/tests/coverage/drop_trait.cov-map b/tests/coverage/drop_trait.cov-map index eb9d7d7acfd..a97c0f8794c 100644 --- a/tests/coverage/drop_trait.cov-map +++ b/tests/coverage/drop_trait.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 9, 5) to (start + 2, 6) +Highest counter ID seen: c0 Function name: drop_trait::main Raw bytes (24): 0x[01, 01, 00, 04, 01, 0e, 01, 05, 0c, 05, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02] @@ -16,4 +17,5 @@ Number of file 0 mappings: 4 - Code(Counter(1)) at (prev + 6, 9) to (start + 1, 22) - Code(Zero) at (prev + 2, 6) to (start + 4, 11) - Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/fn_sig_into_try.cov-map b/tests/coverage/fn_sig_into_try.cov-map index 49758954831..374811dba9e 100644 --- a/tests/coverage/fn_sig_into_try.cov-map +++ b/tests/coverage/fn_sig_into_try.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 5, 2) +Highest counter ID seen: c0 Function name: fn_sig_into_try::b Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02] @@ -18,6 +19,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - Zero) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: fn_sig_into_try::c Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02] @@ -31,6 +33,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - Zero) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: fn_sig_into_try::d Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02] @@ -44,4 +47,5 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - Zero) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/generics.cov-map b/tests/coverage/generics.cov-map index 48e191c1156..d082bd54493 100644 --- a/tests/coverage/generics.cov-map +++ b/tests/coverage/generics.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) +Highest counter ID seen: c0 Function name: <generics::Firework<f64>>::set_strength Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) +Highest counter ID seen: c0 Function name: <generics::Firework<i32> as core::ops::drop::Drop>::drop Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] @@ -21,6 +23,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) +Highest counter ID seen: c0 Function name: <generics::Firework<i32>>::set_strength Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] @@ -29,6 +32,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) +Highest counter ID seen: c0 Function name: generics::main Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 01, 08, 0c, 05, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02] @@ -40,4 +44,5 @@ Number of file 0 mappings: 4 - Code(Counter(1)) at (prev + 9, 9) to (start + 1, 22) - Code(Zero) at (prev + 2, 6) to (start + 4, 11) - Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map index 9350bd9a405..3c740d80ea0 100644 --- a/tests/coverage/holes.cov-map +++ b/tests/coverage/holes.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 37, 9) to (start + 0, 29) +Highest counter ID seen: (none) Function name: holes::main Raw bytes (44): 0x[01, 01, 00, 08, 01, 08, 01, 06, 11, 01, 0f, 05, 00, 12, 01, 04, 05, 00, 12, 01, 07, 05, 00, 12, 01, 06, 05, 00, 12, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 01, 02] @@ -20,6 +21,7 @@ Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 6, 5) to (start + 3, 15) - Code(Counter(0)) at (prev + 10, 5) to (start + 3, 15) - Code(Counter(0)) at (prev + 10, 5) to (start + 1, 2) +Highest counter ID seen: c0 Function name: holes::main::_unused_fn (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 05, 00, 17] @@ -28,6 +30,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 25, 5) to (start + 0, 23) +Highest counter ID seen: (none) Function name: holes::main::{closure#0} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a] @@ -36,6 +39,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 18, 9) to (start + 2, 10) +Highest counter ID seen: (none) Function name: holes::main::{closure#1} (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 3d, 09, 02, 0a] @@ -44,4 +48,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 61, 9) to (start + 2, 10) +Highest counter ID seen: (none) diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map index 2b5ae97b406..8f12afac027 100644 --- a/tests/coverage/if.cov-map +++ b/tests/coverage/if.cov-map @@ -10,4 +10,5 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/if_else.cov-map index c2111917e55..194ad6ca71f 100644 --- a/tests/coverage/if_else.cov-map +++ b/tests/coverage/if_else.cov-map @@ -15,4 +15,5 @@ Number of file 0 mappings: 7 - Code(Expression(1, Sub)) at (prev + 7, 5) to (start + 5, 6) = (c0 - c2) - Code(Counter(0)) at (prev + 6, 1) to (start + 0, 2) +Highest counter ID seen: c2 diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map index 9e11ed787a8..a2c276b7bb7 100644 --- a/tests/coverage/if_not.cov-map +++ b/tests/coverage/if_not.cov-map @@ -20,4 +20,5 @@ Number of file 0 mappings: 10 = (c0 - c3) - Code(Counter(3)) at (prev + 2, 12) to (start + 2, 6) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c3 diff --git a/tests/coverage/ignore_map.coverage b/tests/coverage/ignore_map.coverage index a796a7375a7..466f9e29815 100644 --- a/tests/coverage/ignore_map.coverage +++ b/tests/coverage/ignore_map.coverage @@ -1,4 +1,4 @@ - LL| |//@ ignore-mode-coverage-map + LL| |//@ ignore-coverage-map LL| | LL| 1|fn main() {} diff --git a/tests/coverage/ignore_map.rs b/tests/coverage/ignore_map.rs index deee6e27d99..95df6cbbf0d 100644 --- a/tests/coverage/ignore_map.rs +++ b/tests/coverage/ignore_map.rs @@ -1,3 +1,3 @@ -//@ ignore-mode-coverage-map +//@ ignore-coverage-map fn main() {} diff --git a/tests/coverage/ignore_run.cov-map b/tests/coverage/ignore_run.cov-map index 9865efae0a1..c8ad3821e16 100644 --- a/tests/coverage/ignore_run.cov-map +++ b/tests/coverage/ignore_run.cov-map @@ -5,4 +5,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) +Highest counter ID seen: c0 diff --git a/tests/coverage/ignore_run.rs b/tests/coverage/ignore_run.rs index 0363524d369..2d67ebe6f3a 100644 --- a/tests/coverage/ignore_run.rs +++ b/tests/coverage/ignore_run.rs @@ -1,3 +1,3 @@ -//@ ignore-mode-coverage-run +//@ ignore-coverage-run fn main() {} diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map index 96b907cbe15..411f16725bb 100644 --- a/tests/coverage/inline-dead.cov-map +++ b/tests/coverage/inline-dead.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 23, 1) to (start + 2, 2) +Highest counter ID seen: (none) Function name: inline_dead::live::<false> Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 0e, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] @@ -18,6 +19,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - Zero) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: inline_dead::main Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0a, 01, 06, 05, 01, 02] @@ -27,6 +29,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 4, 1) to (start + 3, 10) - Code(Counter(0)) at (prev + 6, 5) to (start + 1, 2) +Highest counter ID seen: c0 Function name: inline_dead::main::{closure#0} Raw bytes (23): 0x[01, 01, 02, 00, 06, 01, 00, 03, 01, 07, 17, 01, 16, 00, 01, 17, 00, 18, 03, 01, 05, 00, 06] @@ -40,4 +43,5 @@ Number of file 0 mappings: 3 - Code(Zero) at (prev + 1, 23) to (start + 0, 24) - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 6) = (Zero + (c0 - Zero)) +Highest counter ID seen: c0 diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map index 2366a3bc534..ab3a505e925 100644 --- a/tests/coverage/inline.cov-map +++ b/tests/coverage/inline.cov-map @@ -11,6 +11,7 @@ Number of file 0 mappings: 5 = (c0 + c1) - Code(Counter(1)) at (prev + 0, 17) to (start + 2, 6) - Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +Highest counter ID seen: c1 Function name: inline::error Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 14] @@ -19,6 +20,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 49, 1) to (start + 1, 20) +Highest counter ID seen: c0 Function name: inline::length::<char> Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 02, 02] @@ -27,6 +29,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 30, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: inline::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 05, 01, 02, 02] @@ -35,6 +38,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 5, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: inline::permutate::<char> Raw bytes (52): 0x[01, 01, 04, 01, 05, 02, 0d, 05, 0f, 09, 0d, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 11, 01, 0d, 00, 0e, 06, 00, 12, 00, 16, 11, 00, 17, 04, 0a, 0d, 05, 0c, 02, 06, 0b, 03, 01, 00, 02] @@ -57,6 +61,7 @@ Number of file 0 mappings: 8 - Code(Counter(3)) at (prev + 5, 12) to (start + 2, 6) - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) = (c1 + (c2 + c3)) +Highest counter ID seen: c4 Function name: inline::permutations::<char> Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 03, 02] @@ -65,6 +70,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 3, 2) +Highest counter ID seen: c0 Function name: inline::swap::<char> Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 04, 02] @@ -73,4 +79,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 35, 1) to (start + 4, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map index 6ccc3f0bafc..16e86b2cade 100644 --- a/tests/coverage/inner_items.cov-map +++ b/tests/coverage/inner_items.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 9) to (start + 3, 10) +Highest counter ID seen: c0 Function name: <inner_items::main::InStruct as inner_items::main::InTrait>::trait_func Raw bytes (9): 0x[01, 01, 00, 01, 01, 28, 09, 03, 0a] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 40, 9) to (start + 3, 10) +Highest counter ID seen: c0 Function name: inner_items::main Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 06, 00, 07, 01, 02, 09, 05, 02] @@ -31,6 +33,7 @@ Number of file 0 mappings: 7 - Code(Expression(1, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c2) - Code(Counter(0)) at (prev + 2, 9) to (start + 5, 2) +Highest counter ID seen: c2 Function name: inner_items::main::in_func Raw bytes (9): 0x[01, 01, 00, 01, 01, 12, 05, 04, 06] @@ -39,4 +42,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 18, 5) to (start + 4, 6) +Highest counter ID seen: c0 diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index f2447e3c92c..c188cca1b51 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -9,4 +9,5 @@ Number of file 0 mappings: 3 - Code(Counter(1)) at (prev + 3, 9) to (start + 1, 28) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2) = (c1 - c2) +Highest counter ID seen: c1 diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index d3c4671e0ba..a8ad17574ba 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -10,6 +10,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: c1 Function name: issue_84561::main Raw bytes (10): 0x[01, 01, 00, 01, 01, b4, 01, 01, 04, 02] @@ -18,6 +19,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 180, 1) to (start + 4, 2) +Highest counter ID seen: c0 Function name: issue_84561::test1 Raw bytes (50): 0x[01, 01, 00, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 01, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 01, 01, 01, 00, 02] @@ -34,6 +36,7 @@ Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 1, 5) to (start + 3, 11) - Code(Counter(4)) at (prev + 3, 12) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c4 Function name: issue_84561::test2 Raw bytes (20): 0x[01, 01, 00, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 01, 01, 01, 00, 02] @@ -44,6 +47,7 @@ Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 176, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: issue_84561::test2::call_print Raw bytes (10): 0x[01, 01, 00, 01, 01, a7, 01, 09, 02, 0a] @@ -52,6 +56,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10) +Highest counter ID seen: c0 Function name: issue_84561::test3 Raw bytes (375): 0x[01, 01, 31, 05, 09, 0d, 00, 15, 19, 12, 00, 15, 19, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 7a, 55, 51, 00, 7a, 55, 51, 00, 77, 5d, 7a, 55, 51, 00, 77, 61, 7a, 55, 51, 00, 72, 65, 77, 61, 7a, 55, 51, 00, 75, be, 01, c2, 01, 79, 69, 6d, 69, 6d, 69, 6d, c2, 01, 00, 69, 6d, c2, 01, 79, 69, 6d, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, b6, 01, 00, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 77, 03, 05, 00, 0f, 77, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 56, 02, 0d, 00, 13, 72, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 6e, 02, 0d, 00, 13, bb, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, c2, 01, 02, 0d, 00, 17, c2, 01, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 92, 01, 02, 15, 00, 1b, be, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, b6, 01, 02, 05, 00, 0f, b2, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] @@ -182,4 +187,5 @@ Number of file 0 mappings: 51 - Code(Zero) at (prev + 2, 5) to (start + 0, 15) - Code(Zero) at (prev + 3, 9) to (start + 0, 44) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c31 diff --git a/tests/coverage/issue-85461.cov-map b/tests/coverage/issue-85461.cov-map index d1c449b9a35..349bc2cab80 100644 --- a/tests/coverage/issue-85461.cov-map +++ b/tests/coverage/issue-85461.cov-map @@ -5,4 +5,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/issue-93054.cov-map b/tests/coverage/issue-93054.cov-map index 024ef519fcf..38cb70a3f97 100644 --- a/tests/coverage/issue-93054.cov-map +++ b/tests/coverage/issue-93054.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 21, 1) to (start + 0, 29) +Highest counter ID seen: (none) Function name: issue_93054::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 0d] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 29, 1) to (start + 0, 13) +Highest counter ID seen: c0 Function name: issue_93054::make (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02] @@ -21,4 +23,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 25, 1) to (start + 2, 2) +Highest counter ID seen: (none) diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map index 8dca205d33f..fcb9d8f1ff5 100644 --- a/tests/coverage/lazy_boolean.cov-map +++ b/tests/coverage/lazy_boolean.cov-map @@ -46,4 +46,5 @@ Number of file 0 mappings: 28 - Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6) = (c0 - c9) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c9 diff --git a/tests/coverage/let_else_loop.cov-map b/tests/coverage/let_else_loop.cov-map index 13d0d08adb1..04451596eae 100644 --- a/tests/coverage/let_else_loop.cov-map +++ b/tests/coverage/let_else_loop.cov-map @@ -7,6 +7,7 @@ Number of file 0 mappings: 3 - Code(Zero) at (prev + 22, 1) to (start + 1, 12) - Code(Zero) at (prev + 1, 15) to (start + 0, 22) - Code(Zero) at (prev + 0, 32) to (start + 0, 39) +Highest counter ID seen: (none) Function name: let_else_loop::_loop_either_way (unused) Raw bytes (19): 0x[01, 01, 00, 03, 00, 0f, 01, 01, 14, 00, 01, 1c, 00, 23, 00, 01, 05, 00, 0c] @@ -17,6 +18,7 @@ Number of file 0 mappings: 3 - Code(Zero) at (prev + 15, 1) to (start + 1, 20) - Code(Zero) at (prev + 1, 28) to (start + 0, 35) - Code(Zero) at (prev + 1, 5) to (start + 0, 12) +Highest counter ID seen: (none) Function name: let_else_loop::loopy Raw bytes (19): 0x[01, 01, 00, 03, 01, 09, 01, 01, 14, 00, 01, 1c, 00, 23, 05, 01, 01, 00, 02] @@ -27,4 +29,5 @@ Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 9, 1) to (start + 1, 20) - Code(Zero) at (prev + 1, 28) to (start + 0, 35) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/long_and_wide.cov-map b/tests/coverage/long_and_wide.cov-map index 97aebf9b18a..032b7fe102e 100644 --- a/tests/coverage/long_and_wide.cov-map +++ b/tests/coverage/long_and_wide.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 150, 1) to (start + 0, 21) +Highest counter ID seen: c0 Function name: long_and_wide::long_function Raw bytes (10): 0x[01, 01, 00, 01, 01, 10, 01, 84, 01, 02] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 16, 1) to (start + 132, 2) +Highest counter ID seen: c0 Function name: long_and_wide::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 01, 04, 02] @@ -21,6 +23,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 7, 1) to (start + 4, 2) +Highest counter ID seen: c0 Function name: long_and_wide::wide_function Raw bytes (10): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 8b, 01] @@ -29,4 +32,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 14, 1) to (start + 0, 139) +Highest counter ID seen: c0 diff --git a/tests/coverage/loop-break.cov-map b/tests/coverage/loop-break.cov-map index 890d5d84539..63280a0bf7c 100644 --- a/tests/coverage/loop-break.cov-map +++ b/tests/coverage/loop-break.cov-map @@ -11,4 +11,5 @@ Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18) - Code(Counter(1)) at (prev + 1, 10) to (start + 0, 11) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/loop_break_value.cov-map b/tests/coverage/loop_break_value.cov-map index d8dca8a85c3..e48d078f672 100644 --- a/tests/coverage/loop_break_value.cov-map +++ b/tests/coverage/loop_break_value.cov-map @@ -5,4 +5,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 4, 1) to (start + 10, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index 9187dcbd865..1d263611a3a 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -75,6 +75,7 @@ Number of file 0 mappings: 20 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) - Code(Expression(34, Add)) at (prev + 1, 5) to (start + 0, 6) = ((c9 + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - c4)) + c6) +Highest counter ID seen: c9 Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt Raw bytes (230): 0x[01, 01, 2b, 01, 00, 02, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, a7, 01, ab, 01, 00, 0d, 00, 15, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 00, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 93, 01, 25, 96, 01, 19, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0e, 00, 0f, 02, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 9e, 01, 02, 0d, 00, 0e, a3, 01, 00, 12, 00, 17, 9e, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 9a, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4a, 01, 12, 00, 13, 9a, 01, 01, 11, 00, 22, 96, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, 8f, 01, 01, 05, 00, 06] @@ -156,6 +157,7 @@ Number of file 0 mappings: 20 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) - Code(Expression(35, Add)) at (prev + 1, 5) to (start + 0, 6) = (((((((Zero + c3) + (Zero + c5)) - c6) - Zero) - c5) + c6) + c9) +Highest counter ID seen: c9 Function name: loops_branches::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02] @@ -164,4 +166,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 55, 1) to (start + 5, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/macro_in_closure.cov-map b/tests/coverage/macro_in_closure.cov-map index 2feaab717b5..9614154a366 100644 --- a/tests/coverage/macro_in_closure.cov-map +++ b/tests/coverage/macro_in_closure.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 7, 28) to (start + 0, 45) +Highest counter ID seen: c0 Function name: macro_in_closure::WITH_BLOCK::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 1e, 02, 02] @@ -13,4 +14,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 9, 30) to (start + 2, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/macro_name_span.cov-map b/tests/coverage/macro_name_span.cov-map index f3ee44d2a5a..58620452b2b 100644 --- a/tests/coverage/macro_name_span.cov-map +++ b/tests/coverage/macro_name_span.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 22, 28) to (start + 1, 64) +Highest counter ID seen: c0 Function name: macro_name_span::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] @@ -13,4 +14,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map index 60b7024533d..f6491ea262d 100644 --- a/tests/coverage/match_or_pattern.cov-map +++ b/tests/coverage/match_or_pattern.cov-map @@ -72,4 +72,5 @@ Number of file 0 mappings: 25 = (c14 + c15) - Code(Expression(26, Add)) at (prev + 2, 1) to (start + 0, 2) = ((c14 + c15) + c16) +Highest counter ID seen: c16 diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map index b4447a33691..a3e3b1d09c4 100644 --- a/tests/coverage/mcdc/condition-limit.cov-map +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -1,5 +1,5 @@ -Function name: condition_limit::bad -Raw bytes (204): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 11, 01, 14, 01, 03, 09, 20, 05, 02, 03, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 7a, 1d, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 20, 76, 19, 00, 12, 00, 13, 76, 00, 17, 00, 18, 20, 72, 15, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 20, 6e, 11, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 20, 6a, 0d, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 20, 21, 09, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02] +Function name: condition_limit::accept_7_conditions +Raw bytes (232): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 7a, 1d, 07, 06, 00, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 30, 76, 19, 06, 05, 00, 00, 12, 00, 13, 76, 00, 17, 00, 18, 30, 72, 15, 05, 04, 00, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 30, 6e, 11, 04, 03, 00, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 30, 6a, 0d, 03, 02, 00, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 30, 21, 09, 02, 00, 00, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 44 @@ -47,38 +47,39 @@ Number of expressions: 44 - expression 41 operands: lhs = Expression(42, Add), rhs = Counter(5) - expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4) - expression 43 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 17 -- Code(Counter(0)) at (prev + 20, 1) to (start + 3, 9) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 3, 8) to (start + 0, 9) +Number of file 0 mappings: 18 +- Code(Counter(0)) at (prev + 7, 1) to (start + 2, 9) +- MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 2, 8) to (start + 0, 39) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 7, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- Branch { true: Expression(30, Sub), false: Counter(7) } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Expression(30, Sub), false: Counter(7), condition_id: 7, true_next_id: 6, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = (c1 - c7) false = c7 - Code(Expression(30, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c1 - c7) -- Branch { true: Expression(29, Sub), false: Counter(6) } at (prev + 0, 18) to (start + 0, 19) +- MCDCBranch { true: Expression(29, Sub), false: Counter(6), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = ((c1 - c7) - c6) false = c6 - Code(Expression(29, Sub)) at (prev + 0, 23) to (start + 0, 24) = ((c1 - c7) - c6) -- Branch { true: Expression(28, Sub), false: Counter(5) } at (prev + 0, 23) to (start + 0, 24) +- MCDCBranch { true: Expression(28, Sub), false: Counter(5), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) true = (((c1 - c7) - c6) - c5) false = c5 - Code(Expression(28, Sub)) at (prev + 0, 28) to (start + 0, 29) = (((c1 - c7) - c6) - c5) -- Branch { true: Expression(27, Sub), false: Counter(4) } at (prev + 0, 28) to (start + 0, 29) +- MCDCBranch { true: Expression(27, Sub), false: Counter(4), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) true = ((((c1 - c7) - c6) - c5) - c4) false = c4 - Code(Expression(27, Sub)) at (prev + 0, 33) to (start + 0, 34) = ((((c1 - c7) - c6) - c5) - c4) -- Branch { true: Expression(26, Sub), false: Counter(3) } at (prev + 0, 33) to (start + 0, 34) +- MCDCBranch { true: Expression(26, Sub), false: Counter(3), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) true = (((((c1 - c7) - c6) - c5) - c4) - c3) false = c3 - Code(Expression(26, Sub)) at (prev + 0, 38) to (start + 0, 39) = (((((c1 - c7) - c6) - c5) - c4) - c3) -- Branch { true: Counter(8), false: Counter(2) } at (prev + 0, 38) to (start + 0, 39) +- MCDCBranch { true: Counter(8), false: Counter(2), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 38) to (start + 0, 39) true = c8 false = c2 - Code(Counter(8)) at (prev + 0, 40) to (start + 2, 6) @@ -86,77 +87,5 @@ Number of file 0 mappings: 17 = ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1)) - Code(Expression(37, Add)) at (prev + 1, 1) to (start + 0, 2) = (c8 + ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1))) - -Function name: condition_limit::good -Raw bytes (180): 0x[01, 01, 20, 01, 05, 05, 19, 05, 19, 52, 15, 05, 19, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 1d, 6f, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 10, 01, 0c, 01, 03, 09, 28, 00, 06, 03, 08, 00, 22, 30, 05, 02, 01, 06, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 52, 19, 06, 05, 00, 00, 0d, 00, 0e, 52, 00, 12, 00, 13, 30, 4e, 15, 05, 04, 00, 00, 12, 00, 13, 4e, 00, 17, 00, 18, 30, 4a, 11, 04, 03, 00, 00, 17, 00, 18, 4a, 00, 1c, 00, 1d, 30, 46, 0d, 03, 02, 00, 00, 1c, 00, 1d, 46, 00, 21, 00, 22, 30, 1d, 09, 02, 00, 00, 00, 21, 00, 22, 1d, 00, 23, 02, 06, 6f, 02, 06, 00, 07, 6b, 01, 01, 00, 02] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 32 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(1), rhs = Counter(6) -- expression 2 operands: lhs = Counter(1), rhs = Counter(6) -- expression 3 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 4 operands: lhs = Counter(1), rhs = Counter(6) -- expression 5 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 6 operands: lhs = Counter(1), rhs = Counter(6) -- expression 7 operands: lhs = Expression(19, Sub), rhs = Counter(4) -- expression 8 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 9 operands: lhs = Counter(1), rhs = Counter(6) -- expression 10 operands: lhs = Expression(19, Sub), rhs = Counter(4) -- expression 11 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 12 operands: lhs = Counter(1), rhs = Counter(6) -- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(3) -- expression 14 operands: lhs = Expression(19, Sub), rhs = Counter(4) -- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 16 operands: lhs = Counter(1), rhs = Counter(6) -- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(3) -- expression 18 operands: lhs = Expression(19, Sub), rhs = Counter(4) -- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 20 operands: lhs = Counter(1), rhs = Counter(6) -- expression 21 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub) -- expression 22 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 23 operands: lhs = Expression(30, Add), rhs = Counter(5) -- expression 24 operands: lhs = Expression(31, Add), rhs = Counter(4) -- expression 25 operands: lhs = Counter(2), rhs = Counter(3) -- expression 26 operands: lhs = Counter(7), rhs = Expression(27, Add) -- expression 27 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub) -- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(5) -- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(4) -- expression 31 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 16 -- Code(Counter(0)) at (prev + 12, 1) to (start + 3, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 6 } at (prev + 3, 8) to (start + 0, 34) -- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 6, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) - true = c1 - false = (c0 - c1) -- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- MCDCBranch { true: Expression(20, Sub), false: Counter(6), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) - true = (c1 - c6) - false = c6 -- Code(Expression(20, Sub)) at (prev + 0, 18) to (start + 0, 19) - = (c1 - c6) -- MCDCBranch { true: Expression(19, Sub), false: Counter(5), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) - true = ((c1 - c6) - c5) - false = c5 -- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 24) - = ((c1 - c6) - c5) -- MCDCBranch { true: Expression(18, Sub), false: Counter(4), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) - true = (((c1 - c6) - c5) - c4) - false = c4 -- Code(Expression(18, Sub)) at (prev + 0, 28) to (start + 0, 29) - = (((c1 - c6) - c5) - c4) -- MCDCBranch { true: Expression(17, Sub), false: Counter(3), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) - true = ((((c1 - c6) - c5) - c4) - c3) - false = c3 -- Code(Expression(17, Sub)) at (prev + 0, 33) to (start + 0, 34) - = ((((c1 - c6) - c5) - c4) - c3) -- MCDCBranch { true: Counter(7), false: Counter(2), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) - true = c7 - false = c2 -- Code(Counter(7)) at (prev + 0, 35) to (start + 2, 6) -- Code(Expression(27, Add)) at (prev + 2, 6) to (start + 0, 7) - = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) -- Code(Expression(26, Add)) at (prev + 1, 1) to (start + 0, 2) - = (c7 + (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1))) +Highest counter ID seen: c8 diff --git a/tests/coverage/mcdc/condition-limit.coverage b/tests/coverage/mcdc/condition-limit.coverage index ae8596bb961..d11b8a17710 100644 --- a/tests/coverage/mcdc/condition-limit.coverage +++ b/tests/coverage/mcdc/condition-limit.coverage @@ -1,76 +1,56 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | - LL| |// Check that MC/DC instrumentation can gracefully handle conditions that - LL| |// exceed LLVM's limit of 6 conditions per decision. - LL| |// - LL| |// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) - LL| | - LL| 1|fn good() { - LL| 1| // With only 6 conditions, perform full MC/DC instrumentation. - LL| 1| let [a, b, c, d, e, f] = <[bool; 6]>::default(); - LL| 1| if a && b && c && d && e && f { - ^0 ^0 ^0 ^0 ^0 + LL| 2|fn accept_7_conditions(bool_arr: [bool; 7]) { + LL| 2| let [a, b, c, d, e, f, g] = bool_arr; + LL| 2| if a && b && c && d && e && f && g { + ^1 ^1 ^1 ^1 ^1 ^1 ------------------ - | Branch (LL:8): [True: 0, False: 1] - | Branch (LL:13): [True: 0, False: 0] - | Branch (LL:18): [True: 0, False: 0] - | Branch (LL:23): [True: 0, False: 0] - | Branch (LL:28): [True: 0, False: 0] - | Branch (LL:33): [True: 0, False: 0] + | Branch (LL:8): [True: 1, False: 1] + | Branch (LL:13): [True: 1, False: 0] + | Branch (LL:18): [True: 1, False: 0] + | Branch (LL:23): [True: 1, False: 0] + | Branch (LL:28): [True: 1, False: 0] + | Branch (LL:33): [True: 1, False: 0] + | Branch (LL:38): [True: 1, False: 0] ------------------ - |---> MC/DC Decision Region (LL:8) to (LL:34) + |---> MC/DC Decision Region (LL:8) to (LL:39) | - | Number of Conditions: 6 + | Number of Conditions: 7 | Condition C1 --> (LL:8) | Condition C2 --> (LL:13) | Condition C3 --> (LL:18) | Condition C4 --> (LL:23) | Condition C5 --> (LL:28) | Condition C6 --> (LL:33) + | Condition C7 --> (LL:38) | | Executed MC/DC Test Vectors: | - | C1, C2, C3, C4, C5, C6 Result - | 1 { F, -, -, -, -, - = F } + | C1, C2, C3, C4, C5, C6, C7 Result + | 1 { F, -, -, -, -, -, - = F } + | 2 { T, T, T, T, T, T, T = T } | - | C1-Pair: not covered + | C1-Pair: covered: (1,2) | C2-Pair: not covered | C3-Pair: not covered | C4-Pair: not covered | C5-Pair: not covered | C6-Pair: not covered - | MC/DC Coverage for Decision: 0.00% + | C7-Pair: not covered + | MC/DC Coverage for Decision: 14.29% | ------------------ - LL| 0| core::hint::black_box("hello"); - LL| 1| } - LL| 1|} - LL| | - LL| 1|fn bad() { - LL| 1| // With 7 conditions, fall back to branch instrumentation only. - LL| 1| let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); - LL| 1| if a && b && c && d && e && f && g { - ^0 ^0 ^0 ^0 ^0 ^0 - ------------------ - | Branch (LL:8): [True: 0, False: 1] - | Branch (LL:13): [True: 0, False: 0] - | Branch (LL:18): [True: 0, False: 0] - | Branch (LL:23): [True: 0, False: 0] - | Branch (LL:28): [True: 0, False: 0] - | Branch (LL:33): [True: 0, False: 0] - | Branch (LL:38): [True: 0, False: 0] - ------------------ - LL| 0| core::hint::black_box("hello"); + LL| 1| core::hint::black_box("hello"); LL| 1| } - LL| 1|} + LL| 2|} LL| | LL| |#[coverage(off)] LL| |fn main() { - LL| | good(); - LL| | bad(); + LL| | accept_7_conditions([false; 7]); + LL| | accept_7_conditions([true; 7]); LL| |} diff --git a/tests/coverage/mcdc/condition-limit.rs b/tests/coverage/mcdc/condition-limit.rs index 0d8546b01cd..2e8f1619379 100644 --- a/tests/coverage/mcdc/condition-limit.rs +++ b/tests/coverage/mcdc/condition-limit.rs @@ -1,25 +1,11 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc -// Check that MC/DC instrumentation can gracefully handle conditions that -// exceed LLVM's limit of 6 conditions per decision. -// -// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) - -fn good() { - // With only 6 conditions, perform full MC/DC instrumentation. - let [a, b, c, d, e, f] = <[bool; 6]>::default(); - if a && b && c && d && e && f { - core::hint::black_box("hello"); - } -} - -fn bad() { - // With 7 conditions, fall back to branch instrumentation only. - let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); +fn accept_7_conditions(bool_arr: [bool; 7]) { + let [a, b, c, d, e, f, g] = bool_arr; if a && b && c && d && e && f && g { core::hint::black_box("hello"); } @@ -27,6 +13,6 @@ fn bad() { #[coverage(off)] fn main() { - good(); - bad(); + accept_7_conditions([false; 7]); + accept_7_conditions([true; 7]); } diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map index 9a7d15f700d..46960d31c01 100644 --- a/tests/coverage/mcdc/if.cov-map +++ b/tests/coverage/mcdc/if.cov-map @@ -1,5 +1,5 @@ Function name: if::mcdc_check_a -Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 0f, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 0f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -9,7 +9,7 @@ Number of expressions: 4 - expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -22,9 +22,10 @@ Number of file 0 mappings: 8 = (c2 + (c0 - c1)) - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) = (c3 + (c2 + (c0 - c1))) +Highest counter ID seen: c3 Function name: if::mcdc_check_b -Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 17, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 17, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -34,7 +35,7 @@ Number of expressions: 4 - expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 23, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -47,9 +48,10 @@ Number of file 0 mappings: 8 = (c2 + (c0 - c1)) - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) = (c3 + (c2 + (c0 - c1))) +Highest counter ID seen: c3 Function name: if::mcdc_check_both -Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 1f, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 1f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -59,7 +61,7 @@ Number of expressions: 4 - expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 31, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -72,9 +74,10 @@ Number of file 0 mappings: 8 = (c2 + (c0 - c1)) - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) = (c3 + (c2 + (c0 - c1))) +Highest counter ID seen: c3 Function name: if::mcdc_check_neither -Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 07, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 07, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -84,7 +87,7 @@ Number of expressions: 4 - expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -97,9 +100,10 @@ Number of file 0 mappings: 8 = (c2 + (c0 - c1)) - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) = (c3 + (c2 + (c0 - c1))) +Highest counter ID seen: c3 Function name: if::mcdc_check_not_tree_decision -Raw bytes (87): 0x[01, 01, 08, 01, 05, 02, 09, 05, 09, 0d, 1e, 02, 09, 11, 1b, 0d, 1e, 02, 09, 0a, 01, 31, 01, 03, 0a, 28, 00, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 1e, 03, 02, 00, 00, 0e, 00, 0f, 0b, 00, 14, 00, 15, 30, 11, 0d, 02, 00, 00, 00, 14, 00, 15, 11, 00, 16, 02, 06, 1b, 02, 0c, 02, 06, 17, 03, 01, 00, 02] +Raw bytes (87): 0x[01, 01, 08, 01, 05, 02, 09, 05, 09, 0d, 1e, 02, 09, 11, 1b, 0d, 1e, 02, 09, 0a, 01, 31, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 1e, 03, 02, 00, 00, 0e, 00, 0f, 0b, 00, 14, 00, 15, 30, 11, 0d, 02, 00, 00, 00, 14, 00, 15, 11, 00, 16, 02, 06, 1b, 02, 0c, 02, 06, 17, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -113,7 +117,7 @@ Number of expressions: 8 - expression 7 operands: lhs = Expression(0, Sub), rhs = Counter(2) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 49, 1) to (start + 3, 10) -- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) +- MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 3 } at (prev + 0, 9) to (start + 0, 10) true = c1 false = (c0 - c1) @@ -132,9 +136,10 @@ Number of file 0 mappings: 10 = (c3 + ((c0 - c1) - c2)) - Code(Expression(5, Add)) at (prev + 3, 1) to (start + 0, 2) = (c4 + (c3 + ((c0 - c1) - c2))) +Highest counter ID seen: c4 Function name: if::mcdc_check_tree_decision -Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 0d, 05, 0d, 0d, 11, 09, 02, 1b, 1f, 0d, 11, 09, 02, 0a, 01, 27, 01, 03, 09, 28, 00, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 0d, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 11, 09, 03, 00, 00, 00, 13, 00, 14, 1b, 00, 16, 02, 06, 1f, 02, 0c, 02, 06, 17, 03, 01, 00, 02] +Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 0d, 05, 0d, 0d, 11, 09, 02, 1b, 1f, 0d, 11, 09, 02, 0a, 01, 27, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 0d, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 11, 09, 03, 00, 00, 00, 13, 00, 14, 1b, 00, 16, 02, 06, 1f, 02, 0c, 02, 06, 17, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -148,7 +153,7 @@ Number of expressions: 8 - expression 7 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 39, 1) to (start + 3, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) +- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -167,9 +172,10 @@ Number of file 0 mappings: 10 = (c2 + (c0 - c1)) - Code(Expression(5, Add)) at (prev + 3, 1) to (start + 0, 2) = ((c3 + c4) + (c2 + (c0 - c1))) +Highest counter ID seen: c4 Function name: if::mcdc_nested_if -Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 01, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 0a, 00, 0b, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02] +Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 0a, 00, 0b, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 13 @@ -188,7 +194,7 @@ Number of expressions: 13 - expression 12 operands: lhs = Expression(0, Sub), rhs = Counter(2) Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 59, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -199,7 +205,7 @@ Number of file 0 mappings: 14 false = ((c0 - c1) - c2) - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 1, 13) = (c1 + c2) -- MCDCDecision { bitmap_idx: 1, conditions_num: 2 } at (prev + 1, 12) to (start + 0, 18) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 12) to (start + 0, 18) - MCDCBranch { true: Expression(5, Sub), false: Counter(5), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13) true = ((c1 + c2) - c5) false = c5 @@ -215,4 +221,5 @@ Number of file 0 mappings: 14 = ((c0 - c1) - c2) - Code(Expression(9, Add)) at (prev + 3, 1) to (start + 0, 2) = ((c3 + (c4 + c5)) + ((c0 - c1) - c2)) +Highest counter ID seen: c5 diff --git a/tests/coverage/mcdc/if.coverage b/tests/coverage/mcdc/if.coverage index d71de28c6f6..b000c7d5d2f 100644 --- a/tests/coverage/mcdc/if.coverage +++ b/tests/coverage/mcdc/if.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | @@ -145,12 +145,12 @@ | C1, C2, C3 Result | 1 { F, -, - = F } | 2 { T, F, F = F } - | 3 { T, T, - = T } - | 4 { T, F, T = T } + | 3 { T, F, T = T } + | 4 { T, T, - = T } | | C1-Pair: covered: (1,3) - | C2-Pair: covered: (2,3) - | C3-Pair: covered: (2,4) + | C2-Pair: covered: (2,4) + | C3-Pair: covered: (2,3) | MC/DC Coverage for Decision: 100.00% | ------------------ @@ -162,7 +162,7 @@ LL| | LL| 4|fn mcdc_check_not_tree_decision(a: bool, b: bool, c: bool) { LL| 4| // Contradict to `mcdc_check_tree_decision`, - LL| 4| // 100% branch coverage of this expression does not mean indicates 100% mcdc coverage. + LL| 4| // 100% branch coverage of this expression does not indicate 100% mcdc coverage. LL| 4| if (a || b) && c { ^1 ------------------ @@ -181,12 +181,12 @@ | | C1, C2, C3 Result | 1 { T, -, F = F } - | 2 { T, -, T = T } - | 3 { F, T, T = T } + | 2 { F, T, T = T } + | 3 { T, -, T = T } | | C1-Pair: not covered | C2-Pair: not covered - | C3-Pair: covered: (1,2) + | C3-Pair: covered: (1,3) | MC/DC Coverage for Decision: 33.33% | ------------------ diff --git a/tests/coverage/mcdc/if.rs b/tests/coverage/mcdc/if.rs index 17247f5e0c1..a2abb2edf11 100644 --- a/tests/coverage/mcdc/if.rs +++ b/tests/coverage/mcdc/if.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc @@ -48,7 +48,7 @@ fn mcdc_check_tree_decision(a: bool, b: bool, c: bool) { fn mcdc_check_not_tree_decision(a: bool, b: bool, c: bool) { // Contradict to `mcdc_check_tree_decision`, - // 100% branch coverage of this expression does not mean indicates 100% mcdc coverage. + // 100% branch coverage of this expression does not indicate 100% mcdc coverage. if (a || b) && c { say("pass"); } else { diff --git a/tests/coverage/mcdc/inlined_expressions.cov-map b/tests/coverage/mcdc/inlined_expressions.cov-map index 09b7291c964..4f44e0f2b85 100644 --- a/tests/coverage/mcdc/inlined_expressions.cov-map +++ b/tests/coverage/mcdc/inlined_expressions.cov-map @@ -1,5 +1,5 @@ Function name: inlined_expressions::inlined_instance -Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 08, 01, 01, 06, 28, 00, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 0d, 02, 00, 00, 00, 0a, 00, 0b, 07, 01, 01, 00, 02] +Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 08, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 0d, 02, 00, 00, 00, 0a, 00, 0b, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -8,7 +8,7 @@ Number of expressions: 3 - expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 8, 1) to (start + 1, 6) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 5) to (start + 0, 6) true = c1 false = (c0 - c1) @@ -18,4 +18,5 @@ Number of file 0 mappings: 6 false = c3 - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) = ((c2 + c3) + (c0 - c1)) +Highest counter ID seen: c3 diff --git a/tests/coverage/mcdc/inlined_expressions.coverage b/tests/coverage/mcdc/inlined_expressions.coverage index af0b78477d4..57c655a2054 100644 --- a/tests/coverage/mcdc/inlined_expressions.coverage +++ b/tests/coverage/mcdc/inlined_expressions.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc -Copt-level=z -Cllvm-args=--inline-threshold=0 LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | diff --git a/tests/coverage/mcdc/inlined_expressions.rs b/tests/coverage/mcdc/inlined_expressions.rs index 5c1fde6681a..651e2fe8438 100644 --- a/tests/coverage/mcdc/inlined_expressions.rs +++ b/tests/coverage/mcdc/inlined_expressions.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc -Copt-level=z -Cllvm-args=--inline-threshold=0 //@ llvm-cov-flags: --show-branches=count --show-mcdc diff --git a/tests/coverage/mcdc/nested_if.cov-map b/tests/coverage/mcdc/nested_if.cov-map index adeb6cbc1fb..3bed49e7a12 100644 --- a/tests/coverage/mcdc/nested_if.cov-map +++ b/tests/coverage/mcdc/nested_if.cov-map @@ -1,5 +1,5 @@ Function name: nested_if::doubly_nested_if_in_condition -Raw bytes (168): 0x[01, 01, 0e, 01, 05, 05, 11, 05, 11, 26, 19, 05, 11, 19, 1d, 19, 1d, 1d, 22, 26, 19, 05, 11, 11, 15, 09, 02, 0d, 37, 09, 02, 14, 01, 0f, 01, 01, 09, 28, 02, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 01, 02, 00, 10, 00, 36, 30, 11, 26, 01, 00, 02, 00, 10, 00, 11, 30, 15, 21, 02, 00, 00, 00, 15, 00, 36, 26, 00, 18, 00, 19, 28, 00, 02, 00, 18, 00, 1e, 30, 19, 22, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1a, 1d, 02, 00, 00, 00, 1d, 00, 1e, 1a, 00, 21, 00, 25, 1f, 00, 2f, 00, 34, 2b, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 0d, 00, 4f, 02, 06, 37, 02, 0c, 02, 06, 33, 03, 01, 00, 02] +Raw bytes (168): 0x[01, 01, 0e, 01, 05, 05, 11, 05, 11, 26, 19, 05, 11, 19, 1d, 19, 1d, 1d, 22, 26, 19, 05, 11, 11, 15, 09, 02, 0d, 37, 09, 02, 14, 01, 0f, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 11, 26, 01, 00, 02, 00, 10, 00, 11, 30, 15, 21, 02, 00, 00, 00, 15, 00, 36, 26, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 19, 22, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1a, 1d, 02, 00, 00, 00, 1d, 00, 1e, 1a, 00, 21, 00, 25, 1f, 00, 2f, 00, 34, 2b, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 0d, 00, 4f, 02, 06, 37, 02, 0c, 02, 06, 33, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 14 @@ -19,7 +19,7 @@ Number of expressions: 14 - expression 13 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 2, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 78) +- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 78) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -27,7 +27,7 @@ Number of file 0 mappings: 20 true = c3 false = c2 - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17) -- MCDCDecision { bitmap_idx: 1, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 54) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 54) - MCDCBranch { true: Counter(4), false: Expression(9, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17) true = c4 false = (c1 - c4) @@ -36,7 +36,7 @@ Number of file 0 mappings: 20 false = c8 - Code(Expression(9, Sub)) at (prev + 0, 24) to (start + 0, 25) = (c1 - c4) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 24) to (start + 0, 30) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 24) to (start + 0, 30) - MCDCBranch { true: Counter(6), false: Expression(8, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 24) to (start + 0, 25) true = c6 false = ((c1 - c4) - c6) @@ -56,9 +56,10 @@ Number of file 0 mappings: 20 = (c2 + (c0 - c1)) - Code(Expression(12, Add)) at (prev + 3, 1) to (start + 0, 2) = (c3 + (c2 + (c0 - c1))) +Highest counter ID seen: c8 Function name: nested_if::nested_if_in_condition -Raw bytes (120): 0x[01, 01, 0b, 01, 05, 05, 11, 05, 11, 1e, 15, 05, 11, 11, 15, 1e, 15, 05, 11, 09, 02, 0d, 2b, 09, 02, 0e, 01, 07, 01, 01, 09, 28, 01, 02, 01, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 00, 02, 00, 10, 00, 16, 30, 11, 1e, 01, 00, 02, 00, 10, 00, 11, 1e, 00, 15, 00, 16, 30, 15, 1a, 02, 00, 00, 00, 15, 00, 16, 17, 00, 19, 00, 1d, 1a, 00, 27, 00, 2c, 0d, 00, 2f, 02, 06, 2b, 02, 0c, 02, 06, 27, 03, 01, 00, 02] +Raw bytes (120): 0x[01, 01, 0b, 01, 05, 05, 11, 05, 11, 1e, 15, 05, 11, 11, 15, 1e, 15, 05, 11, 09, 02, 0d, 2b, 09, 02, 0e, 01, 07, 01, 01, 09, 28, 06, 02, 01, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 11, 1e, 01, 00, 02, 00, 10, 00, 11, 1e, 00, 15, 00, 16, 30, 15, 1a, 02, 00, 00, 00, 15, 00, 16, 17, 00, 19, 00, 1d, 1a, 00, 27, 00, 2c, 0d, 00, 2f, 02, 06, 2b, 02, 0c, 02, 06, 27, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 11 @@ -75,7 +76,7 @@ Number of expressions: 11 - expression 10 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 1, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 46) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 46) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -83,7 +84,7 @@ Number of file 0 mappings: 14 true = c3 false = c2 - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22) - MCDCBranch { true: Counter(4), false: Expression(7, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17) true = c4 false = (c1 - c4) @@ -101,9 +102,10 @@ Number of file 0 mappings: 14 = (c2 + (c0 - c1)) - Code(Expression(9, Add)) at (prev + 3, 1) to (start + 0, 2) = (c3 + (c2 + (c0 - c1))) +Highest counter ID seen: c5 Function name: nested_if::nested_in_then_block_in_condition -Raw bytes (176): 0x[01, 01, 12, 01, 05, 05, 11, 05, 11, 3a, 15, 05, 11, 11, 15, 33, 19, 11, 15, 19, 1d, 19, 1d, 1d, 2e, 33, 19, 11, 15, 3a, 15, 05, 11, 09, 02, 0d, 47, 09, 02, 14, 01, 22, 01, 01, 09, 28, 02, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 00, 02, 00, 10, 00, 16, 30, 11, 3a, 01, 00, 02, 00, 10, 00, 11, 3a, 00, 15, 00, 16, 30, 15, 36, 02, 00, 00, 00, 15, 00, 16, 33, 00, 1c, 00, 1d, 28, 01, 02, 00, 1c, 00, 22, 30, 19, 2e, 01, 02, 00, 00, 1c, 00, 1d, 19, 00, 21, 00, 22, 30, 26, 1d, 02, 00, 00, 00, 21, 00, 22, 26, 00, 25, 00, 29, 2b, 00, 33, 00, 38, 36, 00, 44, 00, 49, 0d, 00, 4c, 02, 06, 47, 02, 0c, 02, 06, 43, 03, 01, 00, 02] +Raw bytes (176): 0x[01, 01, 12, 01, 05, 05, 11, 05, 11, 3a, 15, 05, 11, 11, 15, 33, 19, 11, 15, 19, 1d, 19, 1d, 1d, 2e, 33, 19, 11, 15, 3a, 15, 05, 11, 09, 02, 0d, 47, 09, 02, 14, 01, 22, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 11, 3a, 01, 00, 02, 00, 10, 00, 11, 3a, 00, 15, 00, 16, 30, 15, 36, 02, 00, 00, 00, 15, 00, 16, 33, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 19, 2e, 01, 02, 00, 00, 1c, 00, 1d, 19, 00, 21, 00, 22, 30, 26, 1d, 02, 00, 00, 00, 21, 00, 22, 26, 00, 25, 00, 29, 2b, 00, 33, 00, 38, 36, 00, 44, 00, 49, 0d, 00, 4c, 02, 06, 47, 02, 0c, 02, 06, 43, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 18 @@ -127,7 +129,7 @@ Number of expressions: 18 - expression 17 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 34, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 2, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 75) +- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 75) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -135,7 +137,7 @@ Number of file 0 mappings: 20 true = c3 false = c2 - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22) - MCDCBranch { true: Counter(4), false: Expression(14, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17) true = c4 false = (c1 - c4) @@ -146,7 +148,7 @@ Number of file 0 mappings: 20 false = ((c1 - c4) - c5) - Code(Expression(12, Add)) at (prev + 0, 28) to (start + 0, 29) = (c4 + c5) -- MCDCDecision { bitmap_idx: 1, conditions_num: 2 } at (prev + 0, 28) to (start + 0, 34) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 28) to (start + 0, 34) - MCDCBranch { true: Counter(6), false: Expression(11, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) true = c6 false = ((c4 + c5) - c6) @@ -165,9 +167,10 @@ Number of file 0 mappings: 20 = (c2 + (c0 - c1)) - Code(Expression(16, Add)) at (prev + 3, 1) to (start + 0, 2) = (c3 + (c2 + (c0 - c1))) +Highest counter ID seen: c7 Function name: nested_if::nested_single_condition_decision -Raw bytes (85): 0x[01, 01, 06, 01, 05, 05, 11, 05, 11, 09, 02, 0d, 17, 09, 02, 0b, 01, 17, 01, 04, 09, 28, 00, 02, 04, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 11, 0a, 00, 10, 00, 11, 11, 00, 14, 00, 19, 0a, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 17, 02, 0c, 02, 06, 13, 03, 01, 00, 02] +Raw bytes (85): 0x[01, 01, 06, 01, 05, 05, 11, 05, 11, 09, 02, 0d, 17, 09, 02, 0b, 01, 17, 01, 04, 09, 28, 03, 02, 04, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 11, 0a, 00, 10, 00, 11, 11, 00, 14, 00, 19, 0a, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 17, 02, 0c, 02, 06, 13, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 6 @@ -179,7 +182,7 @@ Number of expressions: 6 - expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 11 - Code(Counter(0)) at (prev + 23, 1) to (start + 4, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 4, 8) to (start + 0, 41) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 4, 8) to (start + 0, 41) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -198,4 +201,5 @@ Number of file 0 mappings: 11 = (c2 + (c0 - c1)) - Code(Expression(4, Add)) at (prev + 3, 1) to (start + 0, 2) = (c3 + (c2 + (c0 - c1))) +Highest counter ID seen: c4 diff --git a/tests/coverage/mcdc/nested_if.coverage b/tests/coverage/mcdc/nested_if.coverage index 37aa33d5c57..ca0cb54d581 100644 --- a/tests/coverage/mcdc/nested_if.coverage +++ b/tests/coverage/mcdc/nested_if.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | @@ -40,11 +40,11 @@ | | C1, C2 Result | 1 { F, F = F } - | 2 { T, - = T } - | 3 { F, T = T } + | 2 { F, T = T } + | 3 { T, - = T } | - | C1-Pair: covered: (1,2) - | C2-Pair: covered: (1,3) + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (1,2) | MC/DC Coverage for Decision: 100.00% | ------------------ @@ -92,11 +92,11 @@ | | C1, C2 Result | 1 { F, F = F } - | 2 { T, - = T } - | 3 { F, T = T } + | 2 { F, T = T } + | 3 { T, - = T } | - | C1-Pair: covered: (1,2) - | C2-Pair: covered: (1,3) + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (1,2) | MC/DC Coverage for Decision: 100.00% | |---> MC/DC Decision Region (LL:24) to (LL:30) @@ -195,11 +195,11 @@ | | C1, C2 Result | 1 { F, F = F } - | 2 { T, - = T } - | 3 { F, T = T } + | 2 { F, T = T } + | 3 { T, - = T } | - | C1-Pair: covered: (1,2) - | C2-Pair: covered: (1,3) + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (1,2) | MC/DC Coverage for Decision: 100.00% | |---> MC/DC Decision Region (LL:28) to (LL:34) diff --git a/tests/coverage/mcdc/nested_if.rs b/tests/coverage/mcdc/nested_if.rs index 1443ccc23ab..83f188ea47e 100644 --- a/tests/coverage/mcdc/nested_if.rs +++ b/tests/coverage/mcdc/nested_if.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc diff --git a/tests/coverage/mcdc/non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map index f8576831e75..677e31e404e 100644 --- a/tests/coverage/mcdc/non_control_flow.cov-map +++ b/tests/coverage/mcdc/non_control_flow.cov-map @@ -1,5 +1,5 @@ Function name: non_control_flow::assign_3 -Raw bytes (89): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 22, 01, 00, 02, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Raw bytes (89): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 22, 01, 00, 02, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 9 @@ -17,7 +17,7 @@ Number of file 0 mappings: 10 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = (c1 + ((c2 + c3) + c4)) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) +- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) - MCDCBranch { true: Counter(1), false: Expression(8, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -33,9 +33,10 @@ Number of file 0 mappings: 10 false = c3 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = (c1 + ((c2 + c3) + c4)) +Highest counter ID seen: c4 Function name: non_control_flow::assign_3_bis -Raw bytes (85): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 1a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 16, 03, 00, 02, 00, 12, 00, 13, 13, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Raw bytes (85): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 1a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 16, 03, 00, 02, 00, 12, 00, 13, 13, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -51,7 +52,7 @@ Number of file 0 mappings: 10 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = ((c2 + c3) + c4) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) +- MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) - MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -66,9 +67,10 @@ Number of file 0 mappings: 10 false = c4 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = ((c2 + c3) + c4) +Highest counter ID seen: c4 Function name: non_control_flow::assign_and -Raw bytes (64): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 08, 01, 0c, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Raw bytes (64): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 08, 01, 0c, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -81,7 +83,7 @@ Number of file 0 mappings: 8 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = ((c2 + c3) + (c0 - c1)) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) - MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -91,9 +93,10 @@ Number of file 0 mappings: 8 false = c3 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = ((c2 + c3) + (c0 - c1)) +Highest counter ID seen: c3 Function name: non_control_flow::assign_or -Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -106,7 +109,7 @@ Number of file 0 mappings: 8 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = ((c1 + c2) + c3) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) - MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -117,6 +120,7 @@ Number of file 0 mappings: 8 false = c3 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = ((c1 + c2) + c3) +Highest counter ID seen: c3 Function name: non_control_flow::foo Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 02, 02] @@ -125,9 +129,10 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 37, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: non_control_flow::func_call -Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 29, 01, 01, 0a, 28, 00, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 07, 01, 01, 00, 02] +Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 29, 01, 01, 0a, 28, 03, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -136,7 +141,7 @@ Number of expressions: 3 - expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 41, 1) to (start + 1, 10) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 9) to (start + 0, 10) true = c1 false = (c0 - c1) @@ -146,9 +151,10 @@ Number of file 0 mappings: 6 false = c3 - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) = ((c2 + c3) + (c0 - c1)) +Highest counter ID seen: c3 Function name: non_control_flow::right_comb_tree -Raw bytes (139): 0x[01, 01, 13, 07, 1a, 0b, 19, 0f, 15, 13, 11, 09, 0d, 01, 05, 01, 05, 05, 19, 05, 19, 4a, 15, 05, 19, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 0e, 01, 20, 01, 00, 41, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 4a, 19, 02, 03, 00, 00, 13, 00, 14, 4a, 00, 19, 00, 1a, 30, 46, 15, 03, 04, 00, 00, 19, 00, 1a, 46, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 09, 0d, 05, 00, 00, 00, 24, 00, 27, 03, 01, 05, 01, 02] +Raw bytes (139): 0x[01, 01, 13, 07, 1a, 0b, 19, 0f, 15, 13, 11, 09, 0d, 01, 05, 01, 05, 05, 19, 05, 19, 4a, 15, 05, 19, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 0e, 01, 20, 01, 00, 41, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 4a, 19, 02, 03, 00, 00, 13, 00, 14, 4a, 00, 19, 00, 1a, 30, 46, 15, 03, 04, 00, 00, 19, 00, 1a, 46, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 09, 0d, 05, 00, 00, 00, 24, 00, 27, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 19 @@ -176,7 +182,7 @@ Number of file 0 mappings: 14 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42) +- MCDCDecision { bitmap_idx: 6, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42) - MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -201,4 +207,5 @@ Number of file 0 mappings: 14 false = c3 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) +Highest counter ID seen: c6 diff --git a/tests/coverage/mcdc/non_control_flow.coverage b/tests/coverage/mcdc/non_control_flow.coverage index 74c19cf12df..cead419fbdf 100644 --- a/tests/coverage/mcdc/non_control_flow.coverage +++ b/tests/coverage/mcdc/non_control_flow.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | @@ -83,11 +83,11 @@ | | C1, C2, C3 Result | 1 { F, F, - = F } - | 2 { T, -, - = T } - | 3 { F, T, T = T } + | 2 { F, T, T = T } + | 3 { T, -, - = T } | - | C1-Pair: covered: (1,2) - | C2-Pair: covered: (1,3) + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (1,2) | C3-Pair: not covered | MC/DC Coverage for Decision: 66.67% | diff --git a/tests/coverage/mcdc/non_control_flow.rs b/tests/coverage/mcdc/non_control_flow.rs index e0145ed8268..6cfce6fae93 100644 --- a/tests/coverage/mcdc/non_control_flow.rs +++ b/tests/coverage/mcdc/non_control_flow.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc diff --git a/tests/coverage/nested_loops.cov-map b/tests/coverage/nested_loops.cov-map index 35d92594e75..c145d4c5843 100644 --- a/tests/coverage/nested_loops.cov-map +++ b/tests/coverage/nested_loops.cov-map @@ -48,4 +48,5 @@ Number of file 0 mappings: 13 = (c1 + c2) - Code(Expression(22, Add)) at (prev + 2, 1) to (start + 0, 2) = (c4 + c3) +Highest counter ID seen: c6 diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map index 75234f6c3b7..28d0d9ff8ab 100644 --- a/tests/coverage/no_cov_crate.cov-map +++ b/tests/coverage/no_cov_crate.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 20, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: no_cov_crate::add_coverage_2 Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 02, 02] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 24, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: no_cov_crate::add_coverage_not_called (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1d, 01, 02, 02] @@ -21,6 +23,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 29, 1) to (start + 2, 2) +Highest counter ID seen: (none) Function name: no_cov_crate::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 4d, 01, 0b, 02] @@ -29,6 +32,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 77, 1) to (start + 11, 2) +Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer Raw bytes (14): 0x[01, 01, 00, 02, 01, 31, 05, 02, 23, 01, 0c, 05, 00, 06] @@ -38,6 +42,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 49, 5) to (start + 2, 35) - Code(Counter(0)) at (prev + 12, 5) to (start + 0, 6) +Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered Raw bytes (14): 0x[01, 01, 00, 02, 01, 3f, 05, 02, 17, 01, 0b, 05, 00, 06] @@ -47,6 +52,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 63, 5) to (start + 2, 23) - Code(Counter(0)) at (prev + 11, 5) to (start + 0, 6) +Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered::inner Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] @@ -60,4 +66,5 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) +Highest counter ID seen: c1 diff --git a/tests/coverage/no_spans.cov-map b/tests/coverage/no_spans.cov-map index 30171c3f319..7f43b68fa90 100644 --- a/tests/coverage/no_spans.cov-map +++ b/tests/coverage/no_spans.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 26, 28) to (start + 0, 29) +Highest counter ID seen: c0 Function name: no_spans::affected_function::{closure#0} Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 0c, 00, 0e] @@ -13,4 +14,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 27, 12) to (start + 0, 14) +Highest counter ID seen: c0 diff --git a/tests/coverage/no_spans_if_not.cov-map b/tests/coverage/no_spans_if_not.cov-map index bc3e14eddd5..9cb7e6a6cff 100644 --- a/tests/coverage/no_spans_if_not.cov-map +++ b/tests/coverage/no_spans_if_not.cov-map @@ -9,6 +9,7 @@ Number of file 0 mappings: 3 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 15) = (c0 - Zero) - Code(Zero) at (prev + 2, 13) to (start + 0, 15) +Highest counter ID seen: c0 Function name: no_spans_if_not::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] @@ -17,4 +18,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map index cb31f3d1f3e..f842ce3e896 100644 --- a/tests/coverage/overflow.cov-map +++ b/tests/coverage/overflow.cov-map @@ -25,6 +25,7 @@ Number of file 0 mappings: 9 - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) +Highest counter ID seen: c4 Function name: overflow::might_overflow Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 01, 01, 09, 05, 02] @@ -38,4 +39,5 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 5, 2) +Highest counter ID seen: c1 diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/panic_unwind.cov-map index f6089ce55ae..f4a7894cc1c 100644 --- a/tests/coverage/panic_unwind.cov-map +++ b/tests/coverage/panic_unwind.cov-map @@ -25,6 +25,7 @@ Number of file 0 mappings: 9 - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) +Highest counter ID seen: c4 Function name: panic_unwind::might_panic Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 19, 02, 02, 0c, 03, 02] @@ -37,4 +38,5 @@ Number of file 0 mappings: 3 - Code(Counter(1)) at (prev + 2, 9) to (start + 1, 25) - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) = (c0 - c1) +Highest counter ID seen: c1 diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map index 6c39ac0e378..21c8714ac99 100644 --- a/tests/coverage/partial_eq.cov-map +++ b/tests/coverage/partial_eq.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 5) to (start + 2, 6) +Highest counter ID seen: c0 Function name: partial_eq::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 0a, 02] @@ -13,4 +14,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 1) to (start + 10, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map index 541f7bf8fbd..b6f1e8f6afe 100644 --- a/tests/coverage/simple_loop.cov-map +++ b/tests/coverage/simple_loop.cov-map @@ -15,4 +15,5 @@ Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 4, 13) to (start + 0, 18) - Code(Counter(2)) at (prev + 2, 10) to (start + 3, 10) - Code(Counter(0)) at (prev + 6, 1) to (start + 0, 2) +Highest counter ID seen: c2 diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map index 49819b23482..b62edf12650 100644 --- a/tests/coverage/simple_match.cov-map +++ b/tests/coverage/simple_match.cov-map @@ -27,4 +27,5 @@ Number of file 0 mappings: 10 - Code(Counter(2)) at (prev + 4, 13) to (start + 7, 14) - Code(Counter(3)) at (prev + 10, 13) to (start + 0, 15) - Code(Counter(4)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c4 diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map index 361b70fb74f..4e7ed059c87 100644 --- a/tests/coverage/sort_groups.cov-map +++ b/tests/coverage/sort_groups.cov-map @@ -10,6 +10,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: sort_groups::generic_fn::<()> Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] @@ -23,6 +24,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: sort_groups::generic_fn::<char> Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] @@ -36,6 +38,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: sort_groups::generic_fn::<i32> Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] @@ -49,6 +52,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: sort_groups::main Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 02, 02] @@ -62,6 +66,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 2, 2) +Highest counter ID seen: c1 Function name: sort_groups::other_fn Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11] @@ -70,4 +75,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 17) +Highest counter ID seen: c0 diff --git a/tests/coverage/test_harness.cov-map b/tests/coverage/test_harness.cov-map index f75328b11c9..b513b3d0549 100644 --- a/tests/coverage/test_harness.cov-map +++ b/tests/coverage/test_harness.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 0, 16) +Highest counter ID seen: c0 Function name: test_harness::unused (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 07, 01, 00, 0f] @@ -13,4 +14,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 7, 1) to (start + 0, 15) +Highest counter ID seen: (none) diff --git a/tests/coverage/thin-lto.cov-map b/tests/coverage/thin-lto.cov-map deleted file mode 100644 index 1f61b805f62..00000000000 --- a/tests/coverage/thin-lto.cov-map +++ /dev/null @@ -1,8 +0,0 @@ -Function name: thin_lto::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 11] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 17) - diff --git a/tests/coverage/thin-lto.coverage b/tests/coverage/thin-lto.coverage deleted file mode 100644 index 5255aa7f5a4..00000000000 --- a/tests/coverage/thin-lto.coverage +++ /dev/null @@ -1,4 +0,0 @@ - LL| |//@ compile-flags: -O -C lto=thin -C prefer-dynamic=no - LL| | - LL| 1|pub fn main() {} - diff --git a/tests/coverage/thin-lto.rs b/tests/coverage/thin-lto.rs deleted file mode 100644 index 08843ea32ee..00000000000 --- a/tests/coverage/thin-lto.rs +++ /dev/null @@ -1,3 +0,0 @@ -//@ compile-flags: -O -C lto=thin -C prefer-dynamic=no - -pub fn main() {} diff --git a/tests/coverage/tight_inf_loop.cov-map b/tests/coverage/tight_inf_loop.cov-map index 7fe3146b080..2d2d59bf013 100644 --- a/tests/coverage/tight_inf_loop.cov-map +++ b/tests/coverage/tight_inf_loop.cov-map @@ -9,4 +9,5 @@ Number of file 0 mappings: 3 - Code(Zero) at (prev + 2, 9) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 1, 2) = (c0 - Zero) +Highest counter ID seen: c0 diff --git a/tests/coverage/trivial.cov-map b/tests/coverage/trivial.cov-map index 874e294a1c4..05f64896d9e 100644 --- a/tests/coverage/trivial.cov-map +++ b/tests/coverage/trivial.cov-map @@ -5,4 +5,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) +Highest counter ID seen: c0 diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index 11a99f5395e..246a1ba738b 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -10,6 +10,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 26) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) +Highest counter ID seen: c1 Function name: <try_error_result::Thing2>::call Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 01, 02, 05, 00, 06] @@ -23,6 +24,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) +Highest counter ID seen: c1 Function name: try_error_result::call Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] @@ -36,6 +38,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: try_error_result::main Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] @@ -49,6 +52,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c1 Function name: try_error_result::test1 Raw bytes (75): 0x[01, 01, 08, 01, 07, 00, 09, 03, 0d, 12, 1d, 03, 0d, 1b, 0d, 1f, 00, 11, 00, 0b, 01, 0d, 01, 02, 17, 03, 07, 09, 00, 0e, 12, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 00, 01, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0e, 04, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 17, 01, 01, 00, 02] @@ -79,6 +83,7 @@ Number of file 0 mappings: 11 - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) - Code(Expression(5, Add)) at (prev + 1, 1) to (start + 0, 2) = (((c4 + Zero) + Zero) + c3) +Highest counter ID seen: c7 Function name: try_error_result::test2 Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, c7, 01, db, 01, cb, 01, cf, 01, 11, 15, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02] @@ -207,4 +212,5 @@ Number of file 0 mappings: 40 - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) - Code(Expression(47, Add)) at (prev + 1, 1) to (start + 0, 2) = ((((c4 + c5) + ((c6 + c7) + (c8 + c9))) + ((c10 + c11) + ((c12 + c13) + (c14 + c15)))) + c3) +Highest counter ID seen: c19 diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index 06a2c930498..ac4e691ea7a 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -22,6 +22,7 @@ Number of file 0 mappings: 9 = ((c0 - c2) + c3) - Code(Expression(3, Add)) at (prev + 2, 5) to (start + 1, 2) = (c4 + ((c0 - c2) + c3)) +Highest counter ID seen: c4 Function name: unicode::他 (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 19, 00, 25] @@ -30,6 +31,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 30, 25) to (start + 0, 37) +Highest counter ID seen: (none) Function name: unicode::申し訳ございません Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 02, 02] @@ -38,4 +40,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 24, 1) to (start + 2, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/unreachable.cov-map b/tests/coverage/unreachable.cov-map index 09d3b234543..d4a5936a784 100644 --- a/tests/coverage/unreachable.cov-map +++ b/tests/coverage/unreachable.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 15, 39) to (start + 0, 71) +Highest counter ID seen: (none) Function name: unreachable::unreachable_function (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 01, 01, 25] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 17, 1) to (start + 1, 37) +Highest counter ID seen: (none) Function name: unreachable::unreachable_intrinsic (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 01, 2c] @@ -21,4 +23,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 22, 1) to (start + 1, 44) +Highest counter ID seen: (none) diff --git a/tests/coverage/unused.cov-map b/tests/coverage/unused.cov-map index 9383d1e90ac..9f1ad59ce83 100644 --- a/tests/coverage/unused.cov-map +++ b/tests/coverage/unused.cov-map @@ -17,6 +17,7 @@ Number of file 0 mappings: 6 - Code(Expression(3, Add)) at (prev + 1, 9) to (start + 0, 15) = (c1 + c2) - Code(Counter(3)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c3 Function name: unused::foo::<u32> Raw bytes (42): 0x[01, 01, 04, 01, 0f, 05, 09, 03, 0d, 05, 09, 06, 01, 03, 01, 01, 12, 03, 02, 0b, 00, 11, 0a, 01, 09, 00, 0f, 09, 00, 13, 00, 19, 0f, 01, 09, 00, 0f, 0d, 02, 01, 00, 02] @@ -37,6 +38,7 @@ Number of file 0 mappings: 6 - Code(Expression(3, Add)) at (prev + 1, 9) to (start + 0, 15) = (c1 + c2) - Code(Counter(3)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c3 Function name: unused::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 04, 02] @@ -45,6 +47,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 37, 1) to (start + 4, 2) +Highest counter ID seen: c0 Function name: unused::unused_func (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] @@ -56,6 +59,7 @@ Number of file 0 mappings: 4 - Code(Zero) at (prev + 1, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 6) to (start + 0, 7) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: (none) Function name: unused::unused_func2 (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] @@ -67,6 +71,7 @@ Number of file 0 mappings: 4 - Code(Zero) at (prev + 1, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 6) to (start + 0, 7) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: (none) Function name: unused::unused_func3 (unused) Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] @@ -78,6 +83,7 @@ Number of file 0 mappings: 4 - Code(Zero) at (prev + 1, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 6) to (start + 0, 7) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: (none) Function name: unused::unused_template_func::<_> (unused) Raw bytes (34): 0x[01, 01, 00, 06, 00, 0b, 01, 01, 12, 00, 02, 0b, 00, 11, 00, 01, 09, 00, 0f, 00, 00, 13, 00, 19, 00, 01, 09, 00, 0f, 00, 02, 01, 00, 02] @@ -91,4 +97,5 @@ Number of file 0 mappings: 6 - Code(Zero) at (prev + 0, 19) to (start + 0, 25) - Code(Zero) at (prev + 1, 9) to (start + 0, 15) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: (none) diff --git a/tests/coverage/unused_mod.cov-map b/tests/coverage/unused_mod.cov-map index 241cb2610ff..af10906fa3c 100644 --- a/tests/coverage/unused_mod.cov-map +++ b/tests/coverage/unused_mod.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 4, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: unused_mod::unused_module::never_called_function (unused) Raw bytes (9): 0x[01, 01, 00, 01, 00, 02, 01, 02, 02] @@ -13,4 +14,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Zero) at (prev + 2, 1) to (start + 2, 2) +Highest counter ID seen: (none) diff --git a/tests/coverage/uses_crate.cov-map b/tests/coverage/uses_crate.cov-map index 9c06eab7005..5c23f882697 100644 --- a/tests/coverage/uses_crate.cov-map +++ b/tests/coverage/uses_crate.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 27, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>> Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02] @@ -13,6 +14,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: used_crate::used_only_from_bin_crate_generic_function::<&str> Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02] @@ -21,6 +23,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str> Raw bytes (9): 0x[01, 01, 00, 01, 01, 1f, 01, 02, 02] @@ -29,6 +32,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 31, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: uses_crate::main Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 07, 02] @@ -37,4 +41,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 1) to (start + 7, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map index 55ceb46b060..a6909768162 100644 --- a/tests/coverage/uses_inline_crate.cov-map +++ b/tests/coverage/uses_inline_crate.cov-map @@ -5,6 +5,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 44, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: used_inline_crate::used_inline_function Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 01, 02] @@ -18,6 +19,7 @@ Number of file 0 mappings: 4 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c1 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>> Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] @@ -26,6 +28,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&str> Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] @@ -34,6 +37,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str> Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 02, 02] @@ -42,6 +46,7 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 49, 1) to (start + 2, 2) +Highest counter ID seen: c0 Function name: uses_inline_crate::main Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 0a, 02] @@ -50,4 +55,5 @@ Number of files: 1 Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 12, 1) to (start + 10, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map index 4d813a935a0..29493a651dc 100644 --- a/tests/coverage/while.cov-map +++ b/tests/coverage/while.cov-map @@ -10,4 +10,5 @@ Number of file 0 mappings: 4 = (c0 + Zero) - Code(Zero) at (prev + 0, 21) to (start + 2, 6) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/while_early_ret.cov-map index c883eb4baf2..6254dfbcf01 100644 --- a/tests/coverage/while_early_ret.cov-map +++ b/tests/coverage/while_early_ret.cov-map @@ -23,4 +23,5 @@ Number of file 0 mappings: 9 - Code(Counter(2)) at (prev + 6, 5) to (start + 0, 11) - Code(Expression(4, Add)) at (prev + 1, 1) to (start + 0, 2) = ((c3 + c4) + c2) +Highest counter ID seen: c4 diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index a273c688e24..578994a4530 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -39,6 +39,7 @@ Number of file 0 mappings: 16 - Code(Expression(10, Add)) at (prev + 1, 14) to (start + 0, 52) = (c9 + c10) - Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c11 Function name: yield::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 09, 08, 01, 10, 05, 02, 10, 01, 06] @@ -48,6 +49,7 @@ Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 9, 8) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) +Highest counter ID seen: c1 Function name: yield::main::{closure#1} Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 08, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] @@ -59,4 +61,5 @@ Number of file 0 mappings: 4 - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) - Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) +Highest counter ID seen: c3 diff --git a/tests/crashes/117942.rs b/tests/crashes/117942.rs deleted file mode 100644 index 6fdfc689250..00000000000 --- a/tests/crashes/117942.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #117942 -struct Foo { - _: union { - #[rustfmt::skip] - f: String - }, -} diff --git a/tests/crashes/119716-2.rs b/tests/crashes/119716-2.rs deleted file mode 100644 index 47bffb5c1de..00000000000 --- a/tests/crashes/119716-2.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #119716 -#![feature(non_lifetime_binders)] -trait Trait<T> {} -fn f() -> impl for<T> Trait<impl Trait<T>> {} diff --git a/tests/crashes/119716.rs b/tests/crashes/119716.rs deleted file mode 100644 index d7cba0f51c4..00000000000 --- a/tests/crashes/119716.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #119716 -#![feature(non_lifetime_binders)] -trait v0<v1> {} -fn kind :(v3main impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {} diff --git a/tests/crashes/120241-2.rs b/tests/crashes/120241-2.rs deleted file mode 100644 index 9c4a3a50293..00000000000 --- a/tests/crashes/120241-2.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #120241 -//@ edition:2021 -#![feature(object_safe_for_dispatch)] -#![feature(unsized_fn_params)] - -fn guard(_s: Copy) -> bool { - panic!() -} - -fn main() {} diff --git a/tests/crashes/120241.rs b/tests/crashes/120241.rs deleted file mode 100644 index f18347a006c..00000000000 --- a/tests/crashes/120241.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #120241 -//@ edition:2021 -#![feature(object_safe_for_dispatch)] - -trait B { - fn f(a: A) -> A; -} - -trait A { - fn g(b: B) -> B; -} - -fn main() {} diff --git a/tests/crashes/120482.rs b/tests/crashes/120482.rs deleted file mode 100644 index 6cbc2009c5f..00000000000 --- a/tests/crashes/120482.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #120482 -//@ edition:2021 -#![feature(object_safe_for_dispatch)] - -trait B { - fn bar(&self, x: &Self); -} - -trait A { - fn g(new: B) -> B; -} - -fn main() {} diff --git a/tests/crashes/121161.rs b/tests/crashes/121161.rs deleted file mode 100644 index 6da6426a86d..00000000000 --- a/tests/crashes/121161.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #121161 -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - - -#[derive(Eq)] -#[repr(C)] -struct Bar { - _: union { - a: u8, - }, -} diff --git a/tests/crashes/121263-2.rs b/tests/crashes/121263-2.rs deleted file mode 100644 index 2c6327a8808..00000000000 --- a/tests/crashes/121263-2.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #121263 -#[repr(C)] -#[derive(Debug)] -struct L { - _: MyI32, -} diff --git a/tests/crashes/121263.rs b/tests/crashes/121263.rs deleted file mode 100644 index cd7583a7faf..00000000000 --- a/tests/crashes/121263.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #121263 -#[repr(C)] -#[repr(C)] -#[derive(Debug)] -struct L { - _: i32, - _: MyI32, - _: BadEnum, -} diff --git a/tests/crashes/121299.rs b/tests/crashes/121299.rs deleted file mode 100644 index be5e0c0df57..00000000000 --- a/tests/crashes/121299.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #121299 -#[derive(Eq)] -struct D { - _: union { - }, -} diff --git a/tests/crashes/121422.rs b/tests/crashes/121422.rs deleted file mode 100644 index 5d7ef6e8ce9..00000000000 --- a/tests/crashes/121422.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #121422 -#![feature(non_lifetime_binders)] - -trait Trait<T: ?Sized> {} - -fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> { - 16 -} diff --git a/tests/crashes/121722.rs b/tests/crashes/121722.rs deleted file mode 100644 index d1b8c447bf7..00000000000 --- a/tests/crashes/121722.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #121722 -#[repr(C)] -struct Foo { - _: u8, -} - -#[repr(C)] -struct D { - _: Foo, -} diff --git a/tests/crashes/121799.rs b/tests/crashes/121799.rs deleted file mode 100644 index 6035c9d9b15..00000000000 --- a/tests/crashes/121799.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #121799 -struct S { - _: str -} - -fn func(a: S) -{ - let _x = a.f; -} - -fn main() {} diff --git a/tests/crashes/124375.rs b/tests/crashes/124375.rs index 7165655178d..1d877caeb8b 100644 --- a/tests/crashes/124375.rs +++ b/tests/crashes/124375.rs @@ -3,9 +3,9 @@ //@ only-x86_64 #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; #[naked] pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { - asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); + naked_asm!("lea rax, [rdi + rsi]", "ret"); } diff --git a/tests/crashes/124894.rs b/tests/crashes/124894.rs deleted file mode 100644 index 230cf4a89c1..00000000000 --- a/tests/crashes/124894.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: rust-lang/rust#124894 -//@ compile-flags: -Znext-solver=coherence - -#![feature(generic_const_exprs)] - -pub trait IsTrue<const mem: bool> {} -impl<T> IsZST for T where (): IsTrue<{ std::mem::size_of::<T>() == 0 }> {} - -pub trait IsZST {} - -impl IsZST for IsZST {} diff --git a/tests/crashes/125512.rs b/tests/crashes/125512.rs deleted file mode 100644 index 1672b24a114..00000000000 --- a/tests/crashes/125512.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: rust-lang/rust#125512 -//@ edition:2021 -#![feature(object_safe_for_dispatch)] -trait B { - fn f(a: A) -> A; -} -trait A { - fn concrete(b: B) -> B; -} -fn main() {} diff --git a/tests/crashes/125843.rs b/tests/crashes/125843.rs deleted file mode 100644 index 8b9a3913c7e..00000000000 --- a/tests/crashes/125843.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: rust-lang/rust#125843 -#![feature(non_lifetime_binders)] -trait v0<> {} -fn kind :(v3main impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {} diff --git a/tests/crashes/126969.rs b/tests/crashes/126969.rs deleted file mode 100644 index 676563d059c..00000000000 --- a/tests/crashes/126969.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: rust-lang/rust#126969 - -struct S<T> { - _: union { t: T }, -} - -fn f(S::<&i8> { .. }: S<&i8>) {} - -fn main() {} diff --git a/tests/crashes/128176.rs b/tests/crashes/128176.rs index 70fada4f0fe..970ad9ff2cd 100644 --- a/tests/crashes/128176.rs +++ b/tests/crashes/128176.rs @@ -1,7 +1,7 @@ //@ known-bug: rust-lang/rust#128176 #![feature(generic_const_exprs)] -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait X { type Y<const N: i16>; } diff --git a/tests/crashes/129099.rs b/tests/crashes/129099.rs deleted file mode 100644 index 9aaab756b5b..00000000000 --- a/tests/crashes/129099.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: rust-lang/rust#129099 - -#![feature(type_alias_impl_trait)] - -fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> { - loop {} -} - -pub fn main() { - type Opaque = impl Sized; - fn define() -> Opaque { - let x: Opaque = dyn_hoops::<()>(0); - x - } -} diff --git a/tests/crashes/130521.rs b/tests/crashes/130521.rs index 2d30b658024..7c078ab5790 100644 --- a/tests/crashes/130521.rs +++ b/tests/crashes/130521.rs @@ -1,6 +1,6 @@ //@ known-bug: #130521 -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] struct Vtable(dyn Cap); trait Cap<'a> {} diff --git a/tests/crashes/130956.rs b/tests/crashes/130956.rs new file mode 100644 index 00000000000..ebb986d123f --- /dev/null +++ b/tests/crashes/130956.rs @@ -0,0 +1,37 @@ +//@ known-bug: #130956 + +mod impl_trait_mod { + use super::*; + pub type OpaqueBlock = impl Trait; + pub type OpaqueIf = impl Trait; + + pub struct BlockWrapper(OpaqueBlock); + pub struct IfWrapper(pub OpaqueIf); + + pub fn if_impl() -> Parser<OpaqueIf> { + bind(option(block()), |_| block()) + } +} +use impl_trait_mod::*; + +pub trait Trait { + type Assoc; +} +pub struct Parser<P>(P); +pub struct Bind<P, F>(P, F); +impl<P, F> Trait for Bind<P, F> { type Assoc = (); } +impl Trait for BlockWrapper { type Assoc = (); } +impl Trait for IfWrapper { type Assoc = (); } + +pub fn block() -> Parser<BlockWrapper> { + loop {} +} +pub fn option<P: Trait>(arg: Parser<P>) -> Parser<impl Trait> { + bind(arg, |_| block()) +} +fn bind<P: Trait, P2, F: Fn(P::Assoc) -> Parser<P2>>(_: Parser<P>, _: F) -> Parser<Bind<P, F>> + { loop {} } + +fn main() { + if_impl().0; +} diff --git a/tests/crashes/130967.rs b/tests/crashes/130967.rs new file mode 100644 index 00000000000..8a3aae72c20 --- /dev/null +++ b/tests/crashes/130967.rs @@ -0,0 +1,13 @@ +//@ known-bug: #130967 + +trait Producer { + type Produced; + fn make_one() -> Self::Produced; +} + +impl<E: ?Sized> Producer for () { + type Produced = Option<E>; + fn make_one() -> Self::Produced { + loop {} + } +} diff --git a/tests/crashes/131046.rs b/tests/crashes/131046.rs new file mode 100644 index 00000000000..2638705ae18 --- /dev/null +++ b/tests/crashes/131046.rs @@ -0,0 +1,15 @@ +//@ known-bug: #131046 + +trait Owner { + const C<const N: u32>: u32; +} + +impl Owner for () { + const C<const N: u32>: u32 = N; +} + +fn take0<const N: u64>(_: impl Owner<C<N> = { N }>) {} + +fn main() { + take0::<128>(()); +} diff --git a/tests/crashes/131048.rs b/tests/crashes/131048.rs new file mode 100644 index 00000000000..d57e9921a8a --- /dev/null +++ b/tests/crashes/131048.rs @@ -0,0 +1,7 @@ +//@ known-bug: #131048 + +impl<A> std::ops::CoerceUnsized<A> for A {} + +fn main() { + format_args!("Hello, world!"); +} diff --git a/tests/crashes/131050.rs b/tests/crashes/131050.rs new file mode 100644 index 00000000000..07f8662d016 --- /dev/null +++ b/tests/crashes/131050.rs @@ -0,0 +1,27 @@ +//@ known-bug: #131050 +//@ compile-flags: --edition=2021 + +fn query_as<D>() {} + +async fn create_user() { + query_as(); +} + +async fn post_user_filter() -> impl Filter { + AndThen(&(), || async { create_user().await }) +} + +async fn get_app() -> impl Send { + post_user_filter().await +} + +trait Filter {} + +struct AndThen<T, F>(T, F); + +impl<T, F, R> Filter for AndThen<T, F> +where + F: Fn() -> R, + R: Send, +{ +} diff --git a/tests/crashes/131052.rs b/tests/crashes/131052.rs new file mode 100644 index 00000000000..7ae3ec08f3e --- /dev/null +++ b/tests/crashes/131052.rs @@ -0,0 +1,8 @@ +//@ known-bug: #131052 +#![feature(adt_const_params)] + +struct ConstBytes<const T: &'static [*mut u8; 3]>; + +pub fn main() { + let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; +} diff --git a/tests/crashes/131101.rs b/tests/crashes/131101.rs new file mode 100644 index 00000000000..3ec441101b7 --- /dev/null +++ b/tests/crashes/131101.rs @@ -0,0 +1,12 @@ +//@ known-bug: #131101 +trait Foo<const N: u8> { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +impl Foo<const 3> for Bar { + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} diff --git a/tests/crashes/131102.rs b/tests/crashes/131102.rs new file mode 100644 index 00000000000..12b35f8d1b2 --- /dev/null +++ b/tests/crashes/131102.rs @@ -0,0 +1,4 @@ +//@ known-bug: #131102 +pub struct Blorb<const N: u16>([String; N]); +pub struct Wrap(Blorb<0>); +pub const fn i(_: Wrap) {} diff --git a/tests/crashes/131103.rs b/tests/crashes/131103.rs new file mode 100644 index 00000000000..70193e8b3bd --- /dev/null +++ b/tests/crashes/131103.rs @@ -0,0 +1,6 @@ +//@ known-bug: #131103 +struct Struct<const N: i128>(pub [u8; N]); + +pub fn function(value: Struct<3>) -> u8 { + value.0[0] +} diff --git a/tests/crashes/131190.rs b/tests/crashes/131190.rs new file mode 100644 index 00000000000..3a0e64c69d5 --- /dev/null +++ b/tests/crashes/131190.rs @@ -0,0 +1,19 @@ +//@ known-bug: #131190 +//@ compile-flags: -Cinstrument-coverage --edition=2018 + +use std::future::Future; + +pub fn block_on<T>(fut: impl Future<Output = T>) -> T {} + +async fn call_once(f: impl async FnOnce(DropMe)) { + f(DropMe("world")).await; +} + +struct DropMe(&'static str); + +pub fn main() { + block_on(async { + let async_closure = async move |a: DropMe| {}; + call_once(async_closure).await; + }); +} diff --git a/tests/crashes/131227.rs b/tests/crashes/131227.rs new file mode 100644 index 00000000000..f46185b5b4a --- /dev/null +++ b/tests/crashes/131227.rs @@ -0,0 +1,16 @@ +//@ known-bug: #131227 +//@ compile-flags: -Zmir-opt-level=3 + +static mut G: () = (); + +fn myfunc() -> i32 { + let var = &raw mut G; + if var.is_null() { + return 0; + } + 0 +} + +fn main() { + myfunc(); +} diff --git a/tests/crashes/131292.rs b/tests/crashes/131292.rs new file mode 100644 index 00000000000..01e0eca0bd6 --- /dev/null +++ b/tests/crashes/131292.rs @@ -0,0 +1,7 @@ +//@ known-bug: #131292 +//@ only-x86_64 +use std::arch::asm; + +unsafe fn f6() { + asm!(concat!(r#"lJÆ�.�"#, "{}/day{:02}.txt")); +} diff --git a/tests/crashes/131294-2.rs b/tests/crashes/131294-2.rs new file mode 100644 index 00000000000..130a8b10fb7 --- /dev/null +++ b/tests/crashes/131294-2.rs @@ -0,0 +1,25 @@ +//@ known-bug: #131294 +//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir -Zcross-crate-inline-threshold=always + +// https://github.com/rust-lang/rust/issues/131294#issuecomment-2395088049 second comment +struct Rows; + +impl Iterator for Rows { + type Item = String; + + fn next() -> Option<String> { + let args = format_args!("Hello world"); + + { + match args.as_str() { + Some(t) => t.to_owned(), + None => String::new(), + } + } + .into() + } +} + +fn main() { + Rows.next(); +} diff --git a/tests/crashes/131294.rs b/tests/crashes/131294.rs new file mode 100644 index 00000000000..ec6c9567467 --- /dev/null +++ b/tests/crashes/131294.rs @@ -0,0 +1,16 @@ +//@ known-bug: #131294 +//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir -Zcross-crate-inline-threshold=always + +struct Rows; + +impl Iterator for Rows { + type Item = String; + + fn next() -> Option<Self::Item> { + std::fmt::format(format_args!("Hello world")).into() + } +} + +fn main() { + Rows.next(); +} diff --git a/tests/crashes/131295.rs b/tests/crashes/131295.rs new file mode 100644 index 00000000000..f31d6bc324a --- /dev/null +++ b/tests/crashes/131295.rs @@ -0,0 +1,9 @@ +//@ known-bug: #131295 + +#![feature(generic_const_exprs)] + +async fn foo<'a>() -> [(); { + let _y: &'a (); + 4 + }] { +} diff --git a/tests/crashes/131298.rs b/tests/crashes/131298.rs new file mode 100644 index 00000000000..833f1b04ffa --- /dev/null +++ b/tests/crashes/131298.rs @@ -0,0 +1,12 @@ +//@ known-bug: #131298 + +fn dyn_hoops<T>() -> *const dyn Iterator<Item = impl Captures> { + loop {} +} + +mod typeck { + type Opaque = impl Sized; + fn define() -> Opaque { + let _: Opaque = super::dyn_hoops::<u8>(); + } +} diff --git a/tests/crashes/131342-2.rs b/tests/crashes/131342-2.rs new file mode 100644 index 00000000000..79b6a837a49 --- /dev/null +++ b/tests/crashes/131342-2.rs @@ -0,0 +1,40 @@ +//@ known-bug: #131342 +// see also: 131342.rs + +fn main() { + problem_thingy(Once); +} + +struct Once; + +impl Iterator for Once { + type Item = (); +} + +fn problem_thingy(items: impl Iterator) { + let peeker = items.peekable(); + problem_thingy(&peeker); +} + +trait Iterator { + type Item; + + fn peekable(self) -> Peekable<Self> + where + Self: Sized, + { + loop {} + } +} + +struct Peekable<I: Iterator> { + _peeked: I::Item, +} + +impl<I: Iterator> Iterator for Peekable<I> { + type Item = I::Item; +} + +impl<I: Iterator + ?Sized> Iterator for &I { + type Item = I::Item; +} diff --git a/tests/crashes/131342.rs b/tests/crashes/131342.rs new file mode 100644 index 00000000000..7f7ee9c9ac1 --- /dev/null +++ b/tests/crashes/131342.rs @@ -0,0 +1,16 @@ +//@ known-bug: #131342 +// see also: 131342-2.rs + +fn main() { + let mut items = vec![1, 2, 3, 4, 5].into_iter(); + problem_thingy(&mut items); +} + +fn problem_thingy(items: &mut impl Iterator<Item = u8>) { + let mut peeker = items.peekable(); + match peeker.peek() { + Some(_) => (), + None => return (), + } + problem_thingy(&mut peeker); +} diff --git a/tests/crashes/131347.rs b/tests/crashes/131347.rs new file mode 100644 index 00000000000..15f367d79e2 --- /dev/null +++ b/tests/crashes/131347.rs @@ -0,0 +1,9 @@ +//@ known-bug: #131347 +//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir + +struct S; +static STUFF: [i8] = [0; S::N]; + +fn main() { + assert_eq!(STUFF, [0; 63]); +} diff --git a/tests/crashes/131373.rs b/tests/crashes/131373.rs new file mode 100644 index 00000000000..661fecd7620 --- /dev/null +++ b/tests/crashes/131373.rs @@ -0,0 +1,33 @@ +//@ known-bug: #131373 + +trait LockReference: 'static { + type Ref<'a>; +} + +struct SliceRef<'a, T: ?Sized> { + _x: &'a T, +} + +impl<'a, T: ?Sized, SR: LockReference> IntoIterator for SliceRef<'a, T> +where + &'a T: IntoIterator<Item = &'a SR>, +{ + type Item = SR::Ref<'a>; + type IntoIter = std::iter::Map<<&'a T as IntoIterator>::IntoIter, + for<'c> fn(&'c SR) -> SR::Ref<'c>>; + fn into_iter(self) -> Self::IntoIter { + loop {} + } +} + +impl LockReference for () { + type Ref<'a> = (); +} + +fn locked() -> SliceRef<'static, [()]> { + loop {} +} + +fn main() { + let _ = locked().into_iter(); +} diff --git a/tests/crashes/131406.rs b/tests/crashes/131406.rs new file mode 100644 index 00000000000..ea642f94928 --- /dev/null +++ b/tests/crashes/131406.rs @@ -0,0 +1,12 @@ +//@ known-bug: #131406 + +trait Owner { + const C<const N: u32>: u32 = N; +} + +impl Owner for () {} +fn take0<const N: u64>(_: impl Owner<C<N> = { N }>) {} + +fn main() { + take0::<128>(()); +} diff --git a/tests/crashes/131507.rs b/tests/crashes/131507.rs new file mode 100644 index 00000000000..d402fb8afc3 --- /dev/null +++ b/tests/crashes/131507.rs @@ -0,0 +1,10 @@ +//@ known-bug: #131507 +//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir +#![feature(non_lifetime_binders)] + +fn brick() +where + for<T> T: Copy, +{ + || format_args!(""); +} diff --git a/tests/crashes/131534.rs b/tests/crashes/131534.rs new file mode 100644 index 00000000000..545b3e68fe8 --- /dev/null +++ b/tests/crashes/131534.rs @@ -0,0 +1,5 @@ +//@ known-bug: #131534 +#![feature(generic_const_exprs)] +type Value<'v> = &[[u8; SIZE]]; + +trait Trait: Fn(Value) -> Value {} diff --git a/tests/crashes/131535.rs b/tests/crashes/131535.rs new file mode 100644 index 00000000000..47ccdf87f2d --- /dev/null +++ b/tests/crashes/131535.rs @@ -0,0 +1,4 @@ +//@ known-bug: #131535 +#![feature(non_lifetime_binders)] +trait v0<> {} +fn kind :(v0<'_, > impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {} diff --git a/tests/crashes/131538.rs b/tests/crashes/131538.rs new file mode 100644 index 00000000000..f971d8b7791 --- /dev/null +++ b/tests/crashes/131538.rs @@ -0,0 +1,13 @@ +//@ known-bug: #131538 +#![feature(generic_associated_types_extended)] +#![feature(trivial_bounds)] + +trait HealthCheck { + async fn check<const N: usize>(); +} + +fn do_health_check_par() +where + HealthCheck: HealthCheck, +{ +} diff --git a/tests/debuginfo/type-names.rs b/tests/debuginfo/type-names.rs index 6831786c228..4caaf3fc97f 100644 --- a/tests/debuginfo/type-names.rs +++ b/tests/debuginfo/type-names.rs @@ -17,7 +17,7 @@ // gdb-check:type = type_names::GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3> // gdb-command:whatis generic_struct2 -// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize> +// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "system" fn(isize) -> usize> // gdb-command:whatis mod_struct // gdb-check:type = type_names::mod1::Struct2 @@ -372,7 +372,7 @@ fn main() { let simple_struct = Struct1; let generic_struct1: GenericStruct<mod1::Struct2, mod1::mod2::Struct3> = GenericStruct(PhantomData); - let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(isize) -> usize> = + let generic_struct2: GenericStruct<Struct1, extern "system" fn(isize) -> usize> = GenericStruct(PhantomData); let mod_struct = mod1::Struct2; diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs index ab4d578458d..016a1813bab 100644 --- a/tests/incremental/hashes/function_interfaces.rs +++ b/tests/incremental/hashes/function_interfaces.rs @@ -318,9 +318,9 @@ pub fn change_return_impl_trait() -> impl Clone { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "typeck")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg = "cfail6")] pub fn change_return_impl_trait() -> impl Copy { 0u32 diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff new file mode 100644 index 00000000000..047441e6099 --- /dev/null +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff @@ -0,0 +1,46 @@ +- // MIR for `bitwise_not` before JumpThreading ++ // MIR for `bitwise_not` after JumpThreading + + fn bitwise_not() -> i32 { + let mut _0: i32; + let mut _1: i32; + let mut _2: bool; + let mut _3: i32; + let mut _4: i32; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const 0_i32; + _1 = const 1_i32; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = copy _1; + _3 = Not(move _4); + StorageDead(_4); + _2 = Eq(move _3, const 0_i32); + switchInt(move _2) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_3); + _0 = const 1_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff new file mode 100644 index 00000000000..047441e6099 --- /dev/null +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff @@ -0,0 +1,46 @@ +- // MIR for `bitwise_not` before JumpThreading ++ // MIR for `bitwise_not` after JumpThreading + + fn bitwise_not() -> i32 { + let mut _0: i32; + let mut _1: i32; + let mut _2: bool; + let mut _3: i32; + let mut _4: i32; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const 0_i32; + _1 = const 1_i32; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = copy _1; + _3 = Not(move _4); + StorageDead(_4); + _2 = Eq(move _3, const 0_i32); + switchInt(move _2) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_3); + _0 = const 1_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 9487a4e7e5f..743ee8e728b 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -2,7 +2,6 @@ //@ compile-flags: -Zmir-enable-passes=+Inline // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -#![feature(control_flow_enum)] #![feature(try_trait_v2)] #![feature(custom_mir, core_intrinsics, rustc_attrs)] @@ -531,6 +530,16 @@ fn floats() -> u32 { if x == 0.0 { 0 } else { 1 } } +pub fn bitwise_not() -> i32 { + // CHECK-LABEL: fn bitwise_not( + // CHECK: switchInt( + + // Test for #131195, which was optimizing `!a == b` into `a != b`. + let mut a: i32 = 0; + a = 1; + if !a == 0 { 1 } else { 0 } +} + fn main() { // CHECK-LABEL: fn main( too_complex(Ok(0)); @@ -562,3 +571,4 @@ fn main() { // EMIT_MIR jump_threading.assume.JumpThreading.diff // EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff // EMIT_MIR jump_threading.floats.JumpThreading.diff +// EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff diff --git a/tests/mir-opt/pre-codegen/slice_iter.rs b/tests/mir-opt/pre-codegen/slice_iter.rs index 3f89ab0e6f3..fee4214982d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.rs +++ b/tests/mir-opt/pre-codegen/slice_iter.rs @@ -1,6 +1,7 @@ // skip-filecheck //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 //@ only-64bit (constants for `None::<&T>` show in the output) +//@ ignore-debug: precondition checks on ptr::add are under cfg(debug_assertions) // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![crate_type = "lib"] diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 0ad7f5910a0..4d964b0afb7 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -5,66 +5,61 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] { let mut _0: &[u8]; scope 1 (inlined <Vec<u8> as Deref>::deref) { debug self => _1; - let mut _6: usize; - scope 2 (inlined Vec::<u8>::as_ptr) { + scope 2 (inlined Vec::<u8>::as_slice) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec<u8>; - scope 3 (inlined alloc::raw_vec::RawVec::<u8>::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; - scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) { - debug self => _3; - scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) { + let mut _6: usize; + scope 3 (inlined Vec::<u8>::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec<u8>; + scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) { + debug self => _2; + let mut _3: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) { debug self => _3; - let mut _4: std::ptr::NonNull<u8>; - scope 6 (inlined Unique::<u8>::cast::<u8>) { - debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; - debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; - scope 7 (inlined NonNull::<u8>::cast::<u8>) { - debug self => _4; - scope 8 (inlined NonNull::<u8>::as_ptr) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) { + debug self => _3; + let mut _4: std::ptr::NonNull<u8>; + scope 7 (inlined Unique::<u8>::cast::<u8>) { + debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; + debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; + scope 8 (inlined NonNull::<u8>::cast::<u8>) { debug self => _4; - let mut _5: *const u8; + scope 9 (inlined NonNull::<u8>::as_ptr) { + debug self => _4; + let mut _5: *const u8; + } } } - } - scope 9 (inlined #[track_caller] <Unique<u8> as Into<NonNull<u8>>>::into) { - debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; - debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; - scope 10 (inlined <NonNull<u8> as From<Unique<u8>>>::from) { - debug ((unique: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; - debug ((unique: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; - scope 11 (inlined Unique::<u8>::as_non_null_ptr) { - debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; - debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; - } + scope 10 (inlined Unique::<u8>::as_non_null_ptr) { + debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; + debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; } } + scope 11 (inlined NonNull::<u8>::as_ptr) { + debug self => _4; + } } - scope 12 (inlined NonNull::<u8>::as_ptr) { - debug self => _4; - } - } - } - } - scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _5; - debug len => _6; - let _7: *const [u8]; - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { } } - scope 16 (inlined std::mem::size_of::<u8>) { - } - scope 17 (inlined align_of::<u8>) { - } - scope 18 (inlined slice_from_raw_parts::<u8>) { + scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { debug data => _5; debug len => _6; - scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _5; - debug metadata => _6; + let _7: *const [u8]; + scope 13 (inlined core::ub_checks::check_language_ub) { + scope 14 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 15 (inlined std::mem::size_of::<u8>) { + } + scope 16 (inlined align_of::<u8>) { + } + scope 17 (inlined slice_from_raw_parts::<u8>) { + debug data => _5; + debug len => _6; + scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + debug data_pointer => _5; + debug metadata => _6; + } } } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 0ad7f5910a0..4d964b0afb7 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -5,66 +5,61 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] { let mut _0: &[u8]; scope 1 (inlined <Vec<u8> as Deref>::deref) { debug self => _1; - let mut _6: usize; - scope 2 (inlined Vec::<u8>::as_ptr) { + scope 2 (inlined Vec::<u8>::as_slice) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec<u8>; - scope 3 (inlined alloc::raw_vec::RawVec::<u8>::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; - scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) { - debug self => _3; - scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) { + let mut _6: usize; + scope 3 (inlined Vec::<u8>::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec<u8>; + scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) { + debug self => _2; + let mut _3: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) { debug self => _3; - let mut _4: std::ptr::NonNull<u8>; - scope 6 (inlined Unique::<u8>::cast::<u8>) { - debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; - debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; - scope 7 (inlined NonNull::<u8>::cast::<u8>) { - debug self => _4; - scope 8 (inlined NonNull::<u8>::as_ptr) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) { + debug self => _3; + let mut _4: std::ptr::NonNull<u8>; + scope 7 (inlined Unique::<u8>::cast::<u8>) { + debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; + debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; + scope 8 (inlined NonNull::<u8>::cast::<u8>) { debug self => _4; - let mut _5: *const u8; + scope 9 (inlined NonNull::<u8>::as_ptr) { + debug self => _4; + let mut _5: *const u8; + } } } - } - scope 9 (inlined #[track_caller] <Unique<u8> as Into<NonNull<u8>>>::into) { - debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; - debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; - scope 10 (inlined <NonNull<u8> as From<Unique<u8>>>::from) { - debug ((unique: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; - debug ((unique: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; - scope 11 (inlined Unique::<u8>::as_non_null_ptr) { - debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; - debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; - } + scope 10 (inlined Unique::<u8>::as_non_null_ptr) { + debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4; + debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>; } } + scope 11 (inlined NonNull::<u8>::as_ptr) { + debug self => _4; + } } - scope 12 (inlined NonNull::<u8>::as_ptr) { - debug self => _4; - } - } - } - } - scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _5; - debug len => _6; - let _7: *const [u8]; - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { } } - scope 16 (inlined std::mem::size_of::<u8>) { - } - scope 17 (inlined align_of::<u8>) { - } - scope 18 (inlined slice_from_raw_parts::<u8>) { + scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { debug data => _5; debug len => _6; - scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _5; - debug metadata => _6; + let _7: *const [u8]; + scope 13 (inlined core::ub_checks::check_language_ub) { + scope 14 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 15 (inlined std::mem::size_of::<u8>) { + } + scope 16 (inlined align_of::<u8>) { + } + scope 17 (inlined slice_from_raw_parts::<u8>) { + debug data => _5; + debug len => _6; + scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + debug data_pointer => _5; + debug metadata => _6; + } } } } diff --git a/tests/mir-opt/separate_const_switch.rs b/tests/mir-opt/separate_const_switch.rs index 5e8371b3e49..05835942980 100644 --- a/tests/mir-opt/separate_const_switch.rs +++ b/tests/mir-opt/separate_const_switch.rs @@ -1,5 +1,4 @@ // skip-filecheck -#![feature(control_flow_enum)] #![feature(try_trait_v2)] //@ compile-flags: -Zunsound-mir-opts diff --git a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir index 240f409817d..02e1f4be15e 100644 --- a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir +++ b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir @@ -3,9 +3,8 @@ fn process_never(_1: *const !) -> () { debug input => _1; let mut _0: (); - let _2: &!; scope 1 { - debug _input => _2; + debug _input => const (); } bb0: { diff --git a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir index 51514ba5e5d..64711755f73 100644 --- a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir +++ b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir @@ -4,7 +4,7 @@ fn process_void(_1: *const Void) -> () { debug input => _1; let mut _0: (); scope 1 { - debug _input => _1; + debug _input => const ZeroSized: Void; } bb0: { diff --git a/tests/mir-opt/uninhabited_enum.rs b/tests/mir-opt/uninhabited_enum.rs index 859535852cf..90b5353f291 100644 --- a/tests/mir-opt/uninhabited_enum.rs +++ b/tests/mir-opt/uninhabited_enum.rs @@ -1,18 +1,19 @@ // skip-filecheck #![feature(never_type)] +#[derive(Copy, Clone)] pub enum Void {} // EMIT_MIR uninhabited_enum.process_never.SimplifyLocals-final.after.mir #[no_mangle] pub fn process_never(input: *const !) { - let _input = unsafe { &*input }; + let _input = unsafe { *input }; } // EMIT_MIR uninhabited_enum.process_void.SimplifyLocals-final.after.mir #[no_mangle] pub fn process_void(input: *const Void) { - let _input = unsafe { &*input }; + let _input = unsafe { *input }; // In the future, this should end with `unreachable`, but we currently only do // unreachability analysis for `!`. } diff --git a/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir new file mode 100644 index 00000000000..6bf4be652be --- /dev/null +++ b/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir @@ -0,0 +1,49 @@ +// MIR for `main` after SimplifyLocals-final + +fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: *const !; + let mut _3: *const u8; + let _4: u8; + let mut _5: *const !; + let mut _6: *const u8; + scope 1 { + debug x => _1; + scope 2 { + debug x => _2; + scope 3 { + } + } + } + scope 4 { + debug x => _4; + scope 5 { + debug x => _5; + scope 6 { + } + } + } + + bb0: { + StorageLive(_1); + _1 = const 3_u8; + StorageLive(_2); + StorageLive(_3); + _3 = &raw const _1; + _2 = move _3 as *const ! (PtrToPtr); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + StorageLive(_4); + _4 = const 3_u8; + StorageLive(_5); + StorageLive(_6); + _6 = &raw const _4; + _5 = move _6 as *const ! (PtrToPtr); + StorageDead(_6); + StorageDead(_5); + StorageDead(_4); + return; + } +} diff --git a/tests/mir-opt/uninhabited_not_read.rs b/tests/mir-opt/uninhabited_not_read.rs new file mode 100644 index 00000000000..15769cdd75b --- /dev/null +++ b/tests/mir-opt/uninhabited_not_read.rs @@ -0,0 +1,26 @@ +// skip-filecheck + +//@ edition: 2021 +// In ed 2021 and below, we don't fallback `!` to `()`. +// This would introduce a `! -> ()` coercion which would +// be UB if we didn't disallow this explicitly. + +#![feature(never_type)] + +// EMIT_MIR uninhabited_not_read.main.SimplifyLocals-final.after.mir +fn main() { + // With a type annotation + unsafe { + let x = 3u8; + let x: *const ! = &x as *const u8 as *const _; + let _: ! = *x; + } + + // Without a type annotation, make sure we don't implicitly coerce `!` to `()` + // when we do the noop `*x`. + unsafe { + let x = 3u8; + let x: *const ! = &x as *const u8 as *const _; + let _ = *x; + } +} diff --git a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir deleted file mode 100644 index f1904e5d0f4..00000000000 --- a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir +++ /dev/null @@ -1,59 +0,0 @@ -// MIR for `bar` after SimplifyCfg-initial - -fn bar(_1: Bar) -> () { - debug bar => _1; - let mut _0: (); - let _2: (); - let mut _3: u8; - let _4: (); - let mut _5: i8; - let _6: (); - let mut _7: bool; - let _8: (); - let mut _9: [u8; 1]; - - bb0: { - StorageLive(_2); - StorageLive(_3); - _3 = copy (_1.0: u8); - _2 = access::<u8>(move _3) -> [return: bb1, unwind: bb5]; - } - - bb1: { - StorageDead(_3); - StorageDead(_2); - StorageLive(_4); - StorageLive(_5); - _5 = copy ((_1.1: Bar::{anon_adt#0}).0: i8); - _4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5]; - } - - bb2: { - StorageDead(_5); - StorageDead(_4); - StorageLive(_6); - StorageLive(_7); - _7 = copy ((_1.1: Bar::{anon_adt#0}).1: bool); - _6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5]; - } - - bb3: { - StorageDead(_7); - StorageDead(_6); - StorageLive(_8); - StorageLive(_9); - _9 = copy (((_1.2: Bar::{anon_adt#1}).0: Bar::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]); - _8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5]; - } - - bb4: { - StorageDead(_9); - StorageDead(_8); - _0 = const (); - return; - } - - bb5 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir deleted file mode 100644 index c279f590012..00000000000 --- a/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir +++ /dev/null @@ -1,59 +0,0 @@ -// MIR for `foo` after SimplifyCfg-initial - -fn foo(_1: Foo) -> () { - debug foo => _1; - let mut _0: (); - let _2: (); - let mut _3: u8; - let _4: (); - let mut _5: i8; - let _6: (); - let mut _7: bool; - let _8: (); - let mut _9: [u8; 1]; - - bb0: { - StorageLive(_2); - StorageLive(_3); - _3 = copy (_1.0: u8); - _2 = access::<u8>(move _3) -> [return: bb1, unwind: bb5]; - } - - bb1: { - StorageDead(_3); - StorageDead(_2); - StorageLive(_4); - StorageLive(_5); - _5 = copy ((_1.1: Foo::{anon_adt#0}).0: i8); - _4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5]; - } - - bb2: { - StorageDead(_5); - StorageDead(_4); - StorageLive(_6); - StorageLive(_7); - _7 = copy ((_1.1: Foo::{anon_adt#0}).1: bool); - _6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5]; - } - - bb3: { - StorageDead(_7); - StorageDead(_6); - StorageLive(_8); - StorageLive(_9); - _9 = copy (((_1.2: Foo::{anon_adt#1}).0: Foo::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]); - _8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5]; - } - - bb4: { - StorageDead(_9); - StorageDead(_8); - _0 = const (); - return; - } - - bb5 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/unnamed-fields/field_access.rs b/tests/mir-opt/unnamed-fields/field_access.rs deleted file mode 100644 index cc0ac9a3427..00000000000 --- a/tests/mir-opt/unnamed-fields/field_access.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Tests the correct handling of unnamed fields within structs and unions marked with #[repr(C)]. - -// EMIT_MIR field_access.foo.SimplifyCfg-initial.after.mir -// EMIT_MIR field_access.bar.SimplifyCfg-initial.after.mir - -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -#[repr(C)] -struct Foo { - a: u8, - _: struct { - b: i8, - c: bool, - }, - _: struct { - _: struct { - d: [u8; 1], - } - }, -} - -#[repr(C)] -union Bar { - a: u8, - _: union { - b: i8, - c: bool, - }, - _: union { - _: union { - d: [u8; 1], - } - }, -} - -fn access<T>(_: T) {} - -// CHECK-LABEL: fn foo( -fn foo(foo: Foo) { - // CHECK [[a:_.*]] = (_1.0: u8); - // CHECK _.* = access::<u8>(move [[a]]) -> [return: bb1, unwind: bb5]; - access(foo.a); - // CHECK [[b:_.*]] = ((_1.1: Foo::{anon_adt#0}).0: i8); - // CHECK _.* = access::<i8>(move [[b]]) -> [return: bb2, unwind: bb5]; - access(foo.b); - // CHECK [[c:_.*]] = ((_1.1: Foo::{anon_adt#0}).1: bool); - // CHECK _.* = access::<bool>(move [[c]]) -> [return: bb3, unwind: bb5]; - access(foo.c); - // CHECK [[d:_.*]] = (((_1.2: Foo::{anon_adt#1}).0: Foo::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]); - // CHECK _.* = access::<[u8; 1]>(move [[d]]) -> [return: bb4, unwind: bb5]; - access(foo.d); -} - -// CHECK-LABEL: fn bar( -fn bar(bar: Bar) { - unsafe { - // CHECK [[a:_.*]] = (_1.0: u8); - // CHECK _.* = access::<u8>(move [[a]]) -> [return: bb1, unwind: bb5]; - access(bar.a); - // CHECK [[b:_.*]] = ((_1.1: Bar::{anon_adt#0}).0: i8); - // CHECK _.* = access::<i8>(move [[b]]) -> [return: bb2, unwind: bb5]; - access(bar.b); - // CHECK [[c:_.*]] = ((_1.1: Bar::{anon_adt#0}).1: bool); - // CHECK _.* = access::<bool>(move [[c]]) -> [return: bb3, unwind: bb5]; - access(bar.c); - // CHECK [[d:_.*]] = (((_1.2: Bar::{anon_adt#1}).0: Bar::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]); - // CHECK _.* = access::<[u8; 1]>(move [[d]]) -> [return: bb4, unwind: bb5]; - access(bar.d); - } -} - -fn main() {} diff --git a/tests/run-make/broken-pipe-no-ice/rmake.rs b/tests/run-make/broken-pipe-no-ice/rmake.rs new file mode 100644 index 00000000000..378c3289cb7 --- /dev/null +++ b/tests/run-make/broken-pipe-no-ice/rmake.rs @@ -0,0 +1,79 @@ +//! Check that `rustc` and `rustdoc` does not ICE upon encountering a broken pipe due to unhandled +//! panics from raw std `println!` usages. +//! +//! Regression test for <https://github.com/rust-lang/rust/issues/34376>. + +//@ ignore-cross-compile (needs to run test binary) + +//@ ignore-apple +// FIXME(#131436): on macOS rustc is still reporting the std broken pipe io error panick but it +// doesn't fail with 101 exit status (it terminates with a wait status of SIGPIPE). It doesn't say +// Internal Compiler Error strangely, but it doesn't even go through normal diagnostic infra. Very +// strange. + +#![feature(anonymous_pipe)] + +use std::io::Read; +use std::process::{Command, Stdio}; + +use run_make_support::env_var; + +#[derive(Debug, PartialEq)] +enum Binary { + Rustc, + Rustdoc, +} + +fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) { + let (reader, writer) = std::pipe::pipe().unwrap(); + drop(reader); // close read-end + cmd.stdout(writer).stderr(Stdio::piped()); + + let mut child = cmd.spawn().unwrap(); + + let mut stderr = String::new(); + child.stderr.as_mut().unwrap().read_to_string(&mut stderr).unwrap(); + let status = child.wait().unwrap(); + + assert!(!status.success(), "{bin:?} unexpectedly succeeded"); + + const PANIC_ICE_EXIT_CODE: i32 = 101; + + #[cfg(not(windows))] + { + // On non-Windows, rustc/rustdoc built with `-Zon-broken-pipe=kill` shouldn't have an exit + // code of 101 because it should have an wait status that corresponds to SIGPIPE signal + // number. + assert_ne!(status.code(), Some(PANIC_ICE_EXIT_CODE), "{bin:?}"); + // And the stderr should be empty because rustc/rustdoc should've gotten killed. + assert!(stderr.is_empty(), "{bin:?} stderr:\n{}", stderr); + } + + #[cfg(windows)] + { + match bin { + // On Windows, rustc has a paper that propagates the panic exit code of 101 but converts + // broken pipe errors into fatal errors instead of ICEs. + Binary::Rustc => { + assert_eq!(status.code(), Some(PANIC_ICE_EXIT_CODE), "{bin:?}"); + // But make sure it doesn't manifest as an ICE. + assert!(!stderr.contains("internal compiler error"), "{bin:?} ICE'd"); + } + // On Windows, rustdoc seems to cleanly exit with exit code of 1. + Binary::Rustdoc => { + assert_eq!(status.code(), Some(1), "{bin:?}"); + assert!(!stderr.contains("panic"), "{bin:?} stderr contains panic"); + } + } + } +} + +fn main() { + let mut rustc = Command::new(env_var("RUSTC")); + rustc.arg("--print=sysroot"); + check_broken_pipe_handled_gracefully(Binary::Rustc, rustc); + + let mut rustdoc = Command::new(env_var("RUSTDOC")); + rustdoc.arg("--version"); + check_broken_pipe_handled_gracefully(Binary::Rustdoc, rustdoc); +} diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rmake.rs b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rmake.rs index 03c9af4bb89..50790e18cec 100644 --- a/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rmake.rs +++ b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rmake.rs @@ -9,7 +9,7 @@ // RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their // name. -//@ needs-profiler-support +//@ needs-profiler-runtime // FIXME(Oneirical): Except that due to the reliance on llvm-profdata, this test // never runs, because `x86_64-gnu-debug` does not have the `profiler_builtins` crate. diff --git a/tests/run-make/emit-to-stdout/Makefile b/tests/run-make/emit-to-stdout/Makefile deleted file mode 100644 index 80e9b6a4ded..00000000000 --- a/tests/run-make/emit-to-stdout/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -include ../tools.mk - -SRC=test.rs -OUT=$(TMPDIR)/out - -all: asm llvm-ir dep-info mir llvm-bc obj metadata link multiple-types multiple-types-option-o - -asm: $(OUT) - $(RUSTC) --emit asm=$(OUT)/$@ $(SRC) - $(RUSTC) --emit asm=- $(SRC) | diff - $(OUT)/$@ -llvm-ir: $(OUT) - $(RUSTC) --emit llvm-ir=$(OUT)/$@ $(SRC) - $(RUSTC) --emit llvm-ir=- $(SRC) | diff - $(OUT)/$@ -dep-info: $(OUT) - $(RUSTC) -Z dep-info-omit-d-target=yes --emit dep-info=$(OUT)/$@ $(SRC) - $(RUSTC) --emit dep-info=- $(SRC) | diff - $(OUT)/$@ -mir: $(OUT) - $(RUSTC) --emit mir=$(OUT)/$@ $(SRC) - $(RUSTC) --emit mir=- $(SRC) | diff - $(OUT)/$@ - -llvm-bc: $(OUT) - $(RUSTC) --emit llvm-bc=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-llvm-bc.stderr -obj: $(OUT) - $(RUSTC) --emit obj=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-obj.stderr - -# For metadata output, a temporary directory will be created to hold the temporary -# metadata file. But when output is stdout, the temporary directory will be located -# in the same place as $(SRC), which is mounted as read-only in the tests. Thus as -# a workaround, $(SRC) is copied to the test output directory $(OUT) and we compile -# it there. -metadata: $(OUT) - cp $(SRC) $(OUT) - (cd $(OUT); $(RUSTC) --emit metadata=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true) - diff $(OUT)/$@ emit-metadata.stderr - -link: $(OUT) - $(RUSTC) --emit link=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-link.stderr - -multiple-types: $(OUT) - $(RUSTC) --emit asm=- --emit llvm-ir=- --emit dep-info=- --emit mir=- $(SRC) 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-multiple-types.stderr - -multiple-types-option-o: $(OUT) - $(RUSTC) -o - --emit asm,llvm-ir,dep-info,mir $(SRC) 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-multiple-types.stderr - -$(OUT): - mkdir -p $(OUT) diff --git a/tests/run-make/emit-to-stdout/rmake.rs b/tests/run-make/emit-to-stdout/rmake.rs new file mode 100644 index 00000000000..a9a3796731b --- /dev/null +++ b/tests/run-make/emit-to-stdout/rmake.rs @@ -0,0 +1,73 @@ +//! If `-o -` or `--emit KIND=-` is provided, output should be written to stdout +//! instead. Binary output (`obj`, `llvm-bc`, `link` and `metadata`) +//! being written this way will result in an error if stdout is a tty. +//! Multiple output types going to stdout will trigger an error too, +//! as they would all be mixed together. +//! +//! See <https://github.com/rust-lang/rust/pull/111626>. + +use std::fs::File; + +use run_make_support::{diff, run_in_tmpdir, rustc}; + +// Test emitting text outputs to stdout works correctly +fn run_diff(name: &str, file_args: &[&str]) { + rustc().emit(format!("{name}={name}")).input("test.rs").args(file_args).run(); + let out = rustc().emit(format!("{name}=-")).input("test.rs").run().stdout_utf8(); + diff().expected_file(name).actual_text("stdout", &out).run(); +} + +// Test that emitting binary formats to a terminal gives the correct error +fn run_terminal_err_diff(name: &str) { + #[cfg(not(windows))] + let terminal = File::create("/dev/ptmx").unwrap(); + // FIXME: If this test fails and the compiler does print to the console, + // then this will produce a lot of output. + // We should spawn a new console instead to print stdout. + #[cfg(windows)] + let terminal = File::options().read(true).write(true).open(r"\\.\CONOUT$").unwrap(); + + let err = File::create(name).unwrap(); + rustc().emit(format!("{name}=-")).input("test.rs").stdout(terminal).stderr(err).run_fail(); + diff().expected_file(format!("emit-{name}.stderr")).actual_file(name).run(); +} + +fn main() { + run_in_tmpdir(|| { + run_diff("asm", &[]); + run_diff("llvm-ir", &[]); + run_diff("dep-info", &["-Zdep-info-omit-d-target=yes"]); + run_diff("mir", &[]); + + run_terminal_err_diff("llvm-bc"); + run_terminal_err_diff("obj"); + run_terminal_err_diff("metadata"); + run_terminal_err_diff("link"); + + // Test error for emitting multiple types to stdout + rustc() + .input("test.rs") + .emit("asm=-") + .emit("llvm-ir=-") + .emit("dep-info=-") + .emit("mir=-") + .stderr(File::create("multiple-types").unwrap()) + .run_fail(); + diff().expected_file("emit-multiple-types.stderr").actual_file("multiple-types").run(); + + // Same as above, but using `-o` + rustc() + .input("test.rs") + .output("-") + .emit("asm,llvm-ir,dep-info,mir") + .stderr(File::create("multiple-types-option-o").unwrap()) + .run_fail(); + diff() + .expected_file("emit-multiple-types.stderr") + .actual_file("multiple-types-option-o") + .run(); + + // Test that `-o -` redirected to a file works correctly (#26719) + rustc().input("test.rs").output("-").stdout(File::create("out-stdout").unwrap()).run(); + }); +} diff --git a/tests/run-make/msvc-lld-thinlto-imp-symbols/issue_81408.rs b/tests/run-make/msvc-lld-thinlto-imp-symbols/issue_81408.rs new file mode 100644 index 00000000000..afb0dc42f44 --- /dev/null +++ b/tests/run-make/msvc-lld-thinlto-imp-symbols/issue_81408.rs @@ -0,0 +1,13 @@ +use std::sync::atomic::{AtomicPtr, Ordering}; + +#[inline(always)] +pub fn memrchr() { + fn detect() {} + + static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ()); + + unsafe { + let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst); + std::mem::transmute::<*mut (), fn()>(fun)() + } +} diff --git a/tests/run-make/msvc-lld-thinlto-imp-symbols/main.rs b/tests/run-make/msvc-lld-thinlto-imp-symbols/main.rs new file mode 100644 index 00000000000..2d2d2e68125 --- /dev/null +++ b/tests/run-make/msvc-lld-thinlto-imp-symbols/main.rs @@ -0,0 +1,5 @@ +extern crate issue_81408; + +fn main() { + issue_81408::memrchr(); +} diff --git a/tests/run-make/msvc-lld-thinlto-imp-symbols/rmake.rs b/tests/run-make/msvc-lld-thinlto-imp-symbols/rmake.rs new file mode 100644 index 00000000000..3db1ae3452d --- /dev/null +++ b/tests/run-make/msvc-lld-thinlto-imp-symbols/rmake.rs @@ -0,0 +1,33 @@ +// This is a non-regression test for issue #81408 involving an lld bug and ThinLTO, on windows. +// MSVC's link.exe doesn't need any workarounds in rustc, but lld does, so we'll check that the +// binary runs successfully instead of using a codegen test. + +//@ only-x86_64-pc-windows-msvc +//@ needs-rust-lld +//@ ignore-cross-compile: the built binary is executed + +use run_make_support::{run, rustc}; + +fn test_with_linker(linker: &str) { + rustc().input("issue_81408.rs").crate_name("issue_81408").crate_type("lib").opt().run(); + rustc() + .input("main.rs") + .crate_type("bin") + .arg("-Clto=thin") + .opt() + .arg(&format!("-Clinker={linker}")) + .extern_("issue_81408", "libissue_81408.rlib") + .run(); + + // To make possible failures clearer, print an intro that will only be shown if the test does + // fail when running the binary. + eprint!("Running binary linked with {linker}... "); + run("main"); + eprintln!("ok"); +} + +fn main() { + // We want the reproducer to work when linked with both linkers. + test_with_linker("link"); + test_with_linker("rust-lld"); +} diff --git a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs index f00123f006b..8dd19e613bf 100644 --- a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs +++ b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs @@ -1,7 +1,7 @@ #![feature(naked_functions, asm_const, linkage)] #![crate_type = "dylib"] -use std::arch::asm; +use std::arch::naked_asm; pub trait TraitWithConst { const COUNT: u32; @@ -28,7 +28,7 @@ extern "C" fn private_vanilla() -> u32 { #[naked] extern "C" fn private_naked() -> u32 { - unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret") } } #[no_mangle] @@ -39,7 +39,7 @@ pub extern "C" fn public_vanilla() -> u32 { #[naked] #[no_mangle] pub extern "C" fn public_naked() -> u32 { - unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret") } } pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 { @@ -48,7 +48,7 @@ pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 { #[naked] pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 { - unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) } + unsafe { naked_asm!("mov rax, {}", "ret", const T::COUNT) } } #[linkage = "external"] @@ -59,7 +59,7 @@ extern "C" fn vanilla_external_linkage() -> u32 { #[naked] #[linkage = "external"] extern "C" fn naked_external_linkage() -> u32 { - unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret") } } #[cfg(not(windows))] @@ -72,7 +72,7 @@ extern "C" fn vanilla_weak_linkage() -> u32 { #[cfg(not(windows))] #[linkage = "weak"] extern "C" fn naked_weak_linkage() -> u32 { - unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret") } } // functions that are declared in an `extern "C"` block are currently not exported diff --git a/tests/run-make/optimization-remarks-dir-pgo/rmake.rs b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs index 228c43cc5f1..471ce89f188 100644 --- a/tests/run-make/optimization-remarks-dir-pgo/rmake.rs +++ b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs @@ -4,7 +4,7 @@ // the output remark files. // See https://github.com/rust-lang/rust/pull/114439 -//@ needs-profiler-support +//@ needs-profiler-runtime //@ ignore-cross-compile use run_make_support::{ diff --git a/tests/run-make/pgo-branch-weights/rmake.rs b/tests/run-make/pgo-branch-weights/rmake.rs index 105c2fafc5a..1893248e307 100644 --- a/tests/run-make/pgo-branch-weights/rmake.rs +++ b/tests/run-make/pgo-branch-weights/rmake.rs @@ -7,7 +7,7 @@ // If the test passes, the expected function call count was added to the use-phase LLVM-IR. // See https://github.com/rust-lang/rust/pull/66631 -//@ needs-profiler-support +//@ needs-profiler-runtime //@ ignore-cross-compile use std::path::Path; diff --git a/tests/run-make/pgo-gen-lto/rmake.rs b/tests/run-make/pgo-gen-lto/rmake.rs index 53d1623bf58..4f7ae9fb24c 100644 --- a/tests/run-make/pgo-gen-lto/rmake.rs +++ b/tests/run-make/pgo-gen-lto/rmake.rs @@ -2,7 +2,7 @@ // should be generated. // See https://github.com/rust-lang/rust/pull/48346 -//@ needs-profiler-support +//@ needs-profiler-runtime // Reason: this exercises LTO profiling //@ ignore-cross-compile // Reason: the compiled binary is executed diff --git a/tests/run-make/pgo-gen/rmake.rs b/tests/run-make/pgo-gen/rmake.rs index ad2f6388e8f..5cd5a4583ed 100644 --- a/tests/run-make/pgo-gen/rmake.rs +++ b/tests/run-make/pgo-gen/rmake.rs @@ -3,7 +3,7 @@ // optimizes code. This test checks that these files are generated. // See https://github.com/rust-lang/rust/pull/48346 -//@ needs-profiler-support +//@ needs-profiler-runtime //@ ignore-cross-compile use run_make_support::{cwd, has_extension, has_prefix, run, rustc, shallow_find_files}; diff --git a/tests/run-make/pgo-indirect-call-promotion/rmake.rs b/tests/run-make/pgo-indirect-call-promotion/rmake.rs index 28232eb2566..ce9754f13b9 100644 --- a/tests/run-make/pgo-indirect-call-promotion/rmake.rs +++ b/tests/run-make/pgo-indirect-call-promotion/rmake.rs @@ -5,7 +5,7 @@ // whether it can make a direct call instead of the indirect call. // See https://github.com/rust-lang/rust/pull/66631 -//@ needs-profiler-support +//@ needs-profiler-runtime // Reason: llvm_profdata is used //@ ignore-cross-compile // Reason: the compiled binary is executed diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs index 276af9ea263..c09a82353b9 100644 --- a/tests/run-make/pgo-use/rmake.rs +++ b/tests/run-make/pgo-use/rmake.rs @@ -5,7 +5,7 @@ // be marked as cold. // See https://github.com/rust-lang/rust/pull/60262 -//@ needs-profiler-support +//@ needs-profiler-runtime //@ ignore-cross-compile use run_make_support::{ diff --git a/tests/run-make/profile/rmake.rs b/tests/run-make/profile/rmake.rs index 4287ab0a931..58a1b53c040 100644 --- a/tests/run-make/profile/rmake.rs +++ b/tests/run-make/profile/rmake.rs @@ -6,7 +6,7 @@ // See https://github.com/rust-lang/rust/pull/42433 //@ ignore-cross-compile -//@ needs-profiler-support +//@ needs-profiler-runtime use run_make_support::{path, run, rustc}; diff --git a/tests/run-make/track-pgo-dep-info/rmake.rs b/tests/run-make/track-pgo-dep-info/rmake.rs index 84f4e0bd383..5869dbf9c24 100644 --- a/tests/run-make/track-pgo-dep-info/rmake.rs +++ b/tests/run-make/track-pgo-dep-info/rmake.rs @@ -6,7 +6,7 @@ //@ ignore-cross-compile // Reason: the binary is executed -//@ needs-profiler-support +//@ needs-profiler-runtime use run_make_support::{llvm_profdata, rfs, run, rustc}; diff --git a/tests/run-pass-valgrind/cast-enum-with-dtor.rs b/tests/run-pass-valgrind/cast-enum-with-dtor.rs deleted file mode 100644 index a57dc373478..00000000000 --- a/tests/run-pass-valgrind/cast-enum-with-dtor.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![allow(dead_code, cenum_impl_drop_cast)] - -// check dtor calling order when casting enums. - -use std::mem; -use std::sync::atomic; -use std::sync::atomic::Ordering; - -enum E { - A = 0, - B = 1, - C = 2, -} - -static FLAG: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - -impl Drop for E { - fn drop(&mut self) { - // avoid dtor loop - unsafe { mem::forget(mem::replace(self, E::B)) }; - - FLAG.store(FLAG.load(Ordering::SeqCst) + 1, Ordering::SeqCst); - } -} - -fn main() { - assert_eq!(FLAG.load(Ordering::SeqCst), 0); - { - let e = E::C; - assert_eq!(e as u32, 2); - assert_eq!(FLAG.load(Ordering::SeqCst), 1); - } - assert_eq!(FLAG.load(Ordering::SeqCst), 1); -} diff --git a/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs b/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs deleted file mode 100644 index e4ce80b3305..00000000000 --- a/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs +++ /dev/null @@ -1,28 +0,0 @@ -// This would previously leak the Box<Trait> because we wouldn't -// schedule cleanups when auto borrowing trait objects. -// This program should be valgrind clean. - -static mut DROP_RAN: bool = false; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN = true; - } - } -} - -trait Trait { - fn dummy(&self) {} -} -impl Trait for Foo {} - -pub fn main() { - { - let _x: &Trait = &*(Box::new(Foo) as Box<Trait>); - } - unsafe { - assert!(DROP_RAN); - } -} diff --git a/tests/run-pass-valgrind/cleanup-stdin.rs b/tests/run-pass-valgrind/cleanup-stdin.rs deleted file mode 100644 index cf8f81cf5aa..00000000000 --- a/tests/run-pass-valgrind/cleanup-stdin.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let _ = std::io::stdin(); - let _ = std::io::stdout(); - let _ = std::io::stderr(); -} diff --git a/tests/run-pass-valgrind/coerce-match-calls.rs b/tests/run-pass-valgrind/coerce-match-calls.rs deleted file mode 100644 index 8c7375610dd..00000000000 --- a/tests/run-pass-valgrind/coerce-match-calls.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Check that coercions are propagated through match and if expressions. - -//@ pretty-expanded FIXME #23616 - -use std::boxed::Box; - -pub fn main() { - let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) }; - - let _: Box<[isize]> = match true { - true => Box::new([1, 2, 3]), - false => Box::new([1]), - }; - - // Check we don't get over-keen at propagating coercions in the case of casts. - let x = if true { 42 } else { 42u8 } as u16; - let x = match true { - true => 42, - false => 42u8, - } as u16; -} diff --git a/tests/run-pass-valgrind/coerce-match.rs b/tests/run-pass-valgrind/coerce-match.rs deleted file mode 100644 index 95f16a8cc89..00000000000 --- a/tests/run-pass-valgrind/coerce-match.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Check that coercions are propagated through match and if expressions. - -//@ pretty-expanded FIXME #23616 - -pub fn main() { - let _: Box<[isize]> = if true { - let b: Box<_> = Box::new([1, 2, 3]); - b - } else { - let b: Box<_> = Box::new([1]); - b - }; - - let _: Box<[isize]> = match true { - true => { - let b: Box<_> = Box::new([1, 2, 3]); - b - } - false => { - let b: Box<_> = Box::new([1]); - b - } - }; - - // Check we don't get over-keen at propagating coercions in the case of casts. - let x = if true { 42 } else { 42u8 } as u16; - let x = match true { - true => 42, - false => 42u8, - } as u16; -} diff --git a/tests/run-pass-valgrind/down-with-thread-dtors.rs b/tests/run-pass-valgrind/down-with-thread-dtors.rs deleted file mode 100644 index 0d3745bba5b..00000000000 --- a/tests/run-pass-valgrind/down-with-thread-dtors.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@ ignore-emscripten - -thread_local!(static FOO: Foo = Foo); -thread_local!(static BAR: Bar = Bar(1)); -thread_local!(static BAZ: Baz = Baz); - -static mut HIT: bool = false; - -struct Foo; -struct Bar(i32); -struct Baz; - -impl Drop for Foo { - fn drop(&mut self) { - BAR.with(|_| {}); - } -} - -impl Drop for Bar { - fn drop(&mut self) { - assert_eq!(self.0, 1); - self.0 = 2; - BAZ.with(|_| {}); - assert_eq!(self.0, 2); - } -} - -impl Drop for Baz { - fn drop(&mut self) { - unsafe { - HIT = true; - } - } -} - -fn main() { - std::thread::spawn(|| { - FOO.with(|_| {}); - }) - .join() - .unwrap(); - assert!(unsafe { HIT }); -} diff --git a/tests/run-pass-valgrind/dst-dtor-1.rs b/tests/run-pass-valgrind/dst-dtor-1.rs deleted file mode 100644 index 47065151a03..00000000000 --- a/tests/run-pass-valgrind/dst-dtor-1.rs +++ /dev/null @@ -1,28 +0,0 @@ -static mut DROP_RAN: bool = false; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN = true; - } - } -} - -trait Trait { - fn dummy(&self) {} -} -impl Trait for Foo {} - -struct Fat<T: ?Sized> { - f: T, -} - -pub fn main() { - { - let _x: Box<Fat<Trait>> = Box::<Fat<Foo>>::new(Fat { f: Foo }); - } - unsafe { - assert!(DROP_RAN); - } -} diff --git a/tests/run-pass-valgrind/dst-dtor-2.rs b/tests/run-pass-valgrind/dst-dtor-2.rs deleted file mode 100644 index d8abebfb447..00000000000 --- a/tests/run-pass-valgrind/dst-dtor-2.rs +++ /dev/null @@ -1,23 +0,0 @@ -static mut DROP_RAN: isize = 0; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN += 1; - } - } -} - -struct Fat<T: ?Sized> { - f: T, -} - -pub fn main() { - { - let _x: Box<Fat<[Foo]>> = Box::<Fat<[Foo; 3]>>::new(Fat { f: [Foo, Foo, Foo] }); - } - unsafe { - assert_eq!(DROP_RAN, 3); - } -} diff --git a/tests/run-pass-valgrind/dst-dtor-3.rs b/tests/run-pass-valgrind/dst-dtor-3.rs deleted file mode 100644 index 09adaca21c7..00000000000 --- a/tests/run-pass-valgrind/dst-dtor-3.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(unsized_tuple_coercion)] - -static mut DROP_RAN: bool = false; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN = true; - } - } -} - -trait Trait { - fn dummy(&self) {} -} -impl Trait for Foo {} - -pub fn main() { - { - let _x: Box<(i32, Trait)> = Box::<(i32, Foo)>::new((42, Foo)); - } - unsafe { - assert!(DROP_RAN); - } -} diff --git a/tests/run-pass-valgrind/dst-dtor-4.rs b/tests/run-pass-valgrind/dst-dtor-4.rs deleted file mode 100644 index a66ac8e3cfc..00000000000 --- a/tests/run-pass-valgrind/dst-dtor-4.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![feature(unsized_tuple_coercion)] - -static mut DROP_RAN: isize = 0; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN += 1; - } - } -} - -pub fn main() { - { - let _x: Box<(i32, [Foo])> = Box::<(i32, [Foo; 3])>::new((42, [Foo, Foo, Foo])); - } - unsafe { - assert_eq!(DROP_RAN, 3); - } -} diff --git a/tests/run-pass-valgrind/exit-flushes.rs b/tests/run-pass-valgrind/exit-flushes.rs deleted file mode 100644 index 4e25ef76d39..00000000000 --- a/tests/run-pass-valgrind/exit-flushes.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ ignore-wasm32 no subprocess support -//@ ignore-sgx no processes -//@ ignore-apple this needs valgrind 3.11 or higher; see -// https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679 - -use std::env; -use std::process::{Command, exit}; - -fn main() { - if env::args().len() > 1 { - print!("hello!"); - exit(0); - } else { - let out = Command::new(env::args().next().unwrap()).arg("foo").output().unwrap(); - assert!(out.status.success()); - assert_eq!(String::from_utf8(out.stdout).unwrap(), "hello!"); - assert_eq!(String::from_utf8(out.stderr).unwrap(), ""); - } -} diff --git a/tests/run-pass-valgrind/issue-44800.rs b/tests/run-pass-valgrind/issue-44800.rs deleted file mode 100644 index f76657ca752..00000000000 --- a/tests/run-pass-valgrind/issue-44800.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::alloc::System; -use std::collections::VecDeque; - -#[global_allocator] -static ALLOCATOR: System = System; - -fn main() { - let mut deque = VecDeque::with_capacity(32); - deque.push_front(0); - deque.reserve(31); - deque.push_back(0); -} diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs deleted file mode 100644 index 5d3f558a63a..00000000000 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![feature(unsized_locals)] -#![feature(unboxed_closures)] -#![feature(tuple_trait)] - -pub trait FnOnce<Args: std::marker::Tuple> { - type Output; - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -struct A; - -impl FnOnce<()> for A { - type Output = String; - extern "rust-call" fn call_once(self, (): ()) -> Self::Output { - format!("hello") - } -} - -struct B(i32); - -impl FnOnce<()> for B { - type Output = String; - extern "rust-call" fn call_once(self, (): ()) -> Self::Output { - format!("{}", self.0) - } -} - -struct C(String); - -impl FnOnce<()> for C { - type Output = String; - extern "rust-call" fn call_once(self, (): ()) -> Self::Output { - self.0 - } -} - -struct D(Box<String>); - -impl FnOnce<()> for D { - type Output = String; - extern "rust-call" fn call_once(self, (): ()) -> Self::Output { - *self.0 - } -} - -fn main() { - let x = *(Box::new(A) as Box<dyn FnOnce<(), Output = String>>); - assert_eq!(x.call_once(()), format!("hello")); - let x = *(Box::new(B(42)) as Box<dyn FnOnce<(), Output = String>>); - assert_eq!(x.call_once(()), format!("42")); - let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn FnOnce<(), Output = String>>); - assert_eq!(x.call_once(()), format!("jumping fox")); - let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn FnOnce<(), Output = String>>); - assert_eq!(x.call_once(()), format!("lazy dog")); -} diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs deleted file mode 100644 index 9b6648f2e27..00000000000 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![feature(unsized_locals)] -#![feature(unboxed_closures)] -#![feature(tuple_trait)] - -pub trait FnOnce<Args: std::marker::Tuple> { - type Output; - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -struct A; - -impl FnOnce<(String, Box<str>)> for A { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - format!("hello") - } -} - -struct B(i32); - -impl FnOnce<(String, Box<str>)> for B { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - format!("{}", self.0) - } -} - -struct C(String); - -impl FnOnce<(String, Box<str>)> for C { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - self.0 - } -} - -struct D(Box<String>); - -impl FnOnce<(String, Box<str>)> for D { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - *self.0 - } -} - -fn main() { - let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); - let x = *(Box::new(A) as Box<dyn FnOnce<(String, Box<str>), Output = String>>); - assert_eq!(x.call_once((s1, s2)), format!("hello")); - let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); - let x = *(Box::new(B(42)) as Box<dyn FnOnce<(String, Box<str>), Output = String>>); - assert_eq!(x.call_once((s1, s2)), format!("42")); - let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); - let x = *(Box::new(C(format!("jumping fox"))) - as Box<dyn FnOnce<(String, Box<str>), Output = String>>); - assert_eq!(x.call_once((s1, s2)), format!("jumping fox")); - let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); - let x = *(Box::new(D(Box::new(format!("lazy dog")))) - as Box<dyn FnOnce<(String, Box<str>), Output = String>>); - assert_eq!(x.call_once((s1, s2)), format!("lazy dog")); -} diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs deleted file mode 100644 index 3f6b6d262b5..00000000000 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![feature(unsized_locals)] - -pub trait Foo { - fn foo(self) -> String; -} - -struct A; - -impl Foo for A { - fn foo(self) -> String { - format!("hello") - } -} - -struct B(i32); - -impl Foo for B { - fn foo(self) -> String { - format!("{}", self.0) - } -} - -struct C(String); - -impl Foo for C { - fn foo(self) -> String { - self.0 - } -} - -struct D(Box<String>); - -impl Foo for D { - fn foo(self) -> String { - *self.0 - } -} - -fn main() { - let x = *(Box::new(A) as Box<dyn Foo>); - assert_eq!(x.foo(), format!("hello")); - let x = *(Box::new(B(42)) as Box<dyn Foo>); - assert_eq!(x.foo(), format!("42")); - let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn Foo>); - assert_eq!(x.foo(), format!("jumping fox")); - let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn Foo>); - assert_eq!(x.foo(), format!("lazy dog")); -} diff --git a/tests/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs b/tests/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs deleted file mode 100644 index a7b9052617f..00000000000 --- a/tests/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] - -use std::fmt; - -fn gen_foo() -> Box<fmt::Display> { - Box::new(Box::new("foo")) -} - -fn foo(x: fmt::Display) { - assert_eq!(x.to_string(), "foo"); -} - -fn foo_indirect(x: fmt::Display) { - foo(x); -} - -fn main() { - foo(*gen_foo()); - foo_indirect(*gen_foo()); - - { - let x: fmt::Display = *gen_foo(); - foo(x); - } - - { - let x: fmt::Display = *gen_foo(); - let y: fmt::Display = *gen_foo(); - foo(x); - foo(y); - } - - { - let mut cnt: usize = 3; - let x = loop { - let x: fmt::Display = *gen_foo(); - if cnt == 0 { - break x; - } else { - cnt -= 1; - } - }; - foo(x); - } - - { - let x: fmt::Display = *gen_foo(); - let x = if true { x } else { *gen_foo() }; - foo(x); - } -} diff --git a/tests/rustdoc-gui/README.md b/tests/rustdoc-gui/README.md index 1126a72ab67..efd513715d4 100644 --- a/tests/rustdoc-gui/README.md +++ b/tests/rustdoc-gui/README.md @@ -23,12 +23,5 @@ $ ./x.py test tests/rustdoc-gui --stage 1 --test-args --no-headless To see the supported options, use `--help`. -Important to be noted: if the chromium instance crashes when you run it, you might need to -use `--no-sandbox` to make it work: - -```bash -$ ./x.py test tests/rustdoc-gui --stage 1 --test-args --no-sandbox -``` - [browser-ui-test]: https://github.com/GuillaumeGomez/browser-UI-test/ [puppeteer]: https://pptr.dev/ diff --git a/tests/rustdoc-gui/list-margins.goml b/tests/rustdoc-gui/list-margins.goml new file mode 100644 index 00000000000..c83f5898e8e --- /dev/null +++ b/tests/rustdoc-gui/list-margins.goml @@ -0,0 +1,11 @@ +// This test ensures that the documentation list markers are correctly placed. +// It also serves as a regression test for <https://github.com/rust-lang/rust/issues/130622>. + +go-to: "file://" + |DOC_PATH| + "/test_docs/long_list/index.html" +show-text: true + +// 0.3em +assert-css: (".docblock li p:not(last-child)", {"margin-bottom": "4.8px"}) +assert-css: (".docblock li p + p:last-child", {"margin-bottom": "0px"}) +// 0.4em +assert-css: (".docblock li", {"margin-bottom": "6.4px"}) diff --git a/tests/rustdoc-gui/methods-left-margin.goml b/tests/rustdoc-gui/methods-left-margin.goml new file mode 100644 index 00000000000..1003cec33f9 --- /dev/null +++ b/tests/rustdoc-gui/methods-left-margin.goml @@ -0,0 +1,19 @@ +// This test is to ensure that methods are correctly aligned on the left side. + +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" + +// First we ensure that we have methods with and without documentation. +assert: ".impl-items > details.method-toggle > summary > section.method" +assert: ".impl-items > section.method" + +// Checking on desktop. +set-window-size: (900, 600) +wait-for-size: ("body", {"width": 900}) +store-position: (".impl-items section.method", {"x": x}) +assert-position: (".impl-items section.method", {"x": |x|}, ALL) + +// Checking on mobile. +set-window-size: (600, 600) +wait-for-size: ("body", {"width": 600}) +store-position: (".impl-items section.method", {"x": x}) +assert-position: (".impl-items section.method", {"x": |x|}, ALL) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index b8fa26b17f6..e02974e6082 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -84,9 +84,10 @@ call-function: ("check-notable-tooltip-position", { // Checking on mobile now. set-window-size: (650, 600) +wait-for-size: ("body", {"width": 650}) call-function: ("check-notable-tooltip-position-complete", { - "x": 15, - "i_x": 293, + "x": 25, + "i_x": 303, "popover_x": 0, }) diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 7397992c0ab..352995c4903 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -628,3 +628,27 @@ pub mod short_docs { /// subt_vec_num(x: &[f64], y: f64) pub fn subt_vec_num() {} } + +pub mod long_list { + //! bla + //! + //! * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque et libero ut leo + //! interdum laoreet vitae a mi. Aliquam erat volutpat. Suspendisse volutpat non quam non + //! commodo. + //! + //! Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique + //! augue. Phasellus vel pretium lectus. + //! * Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique + //! augue. Phasellus vel pretium lectus. + //! * Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique + //! augue. Phasellus vel pretium lectus. + //! + //! Another list: + //! + //! * [`TryFromBytes`](#a) indicates that a type may safely be converted from certain byte + //! sequence (conditional on runtime checks) + //! * [`FromZeros`](#a) indicates that a sequence of zero bytes represents a valid instance of + //! a type + //! * [`FromBytes`](#a) indicates that a type may safely be converted from an arbitrary byte + //! sequence +} diff --git a/tests/rustdoc-json/fns/extern_safe.rs b/tests/rustdoc-json/fns/extern_safe.rs new file mode 100644 index 00000000000..a4a2d2c7f8c --- /dev/null +++ b/tests/rustdoc-json/fns/extern_safe.rs @@ -0,0 +1,17 @@ +extern "C" { + //@ is "$.index[*][?(@.name=='f1')].inner.function.header.is_unsafe" true + pub fn f1(); + + // items in unadorned `extern` blocks cannot have safety qualifiers +} + +unsafe extern "C" { + //@ is "$.index[*][?(@.name=='f4')].inner.function.header.is_unsafe" true + pub fn f4(); + + //@ is "$.index[*][?(@.name=='f5')].inner.function.header.is_unsafe" true + pub unsafe fn f5(); + + //@ is "$.index[*][?(@.name=='f6')].inner.function.header.is_unsafe" false + pub safe fn f6(); +} diff --git a/tests/rustdoc-ui/cfg-boolean-literal.rs b/tests/rustdoc-ui/cfg-boolean-literal.rs new file mode 100644 index 00000000000..4d4e599bfee --- /dev/null +++ b/tests/rustdoc-ui/cfg-boolean-literal.rs @@ -0,0 +1,19 @@ +//@ check-pass + +#![feature(cfg_boolean_literals)] +#![feature(doc_cfg)] + +#[doc(cfg(false))] +pub fn foo() {} + +#[doc(cfg(true))] +pub fn bar() {} + +#[doc(cfg(any(true)))] +pub fn zoo() {} + +#[doc(cfg(all(true)))] +pub fn toy() {} + +#[doc(cfg(not(true)))] +pub fn nay() {} diff --git a/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout b/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout index f39d2c2608b..c1f750017e7 100644 --- a/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout +++ b/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout @@ -18,7 +18,6 @@ LL | impl Trait for &Local {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> note: the lint level is defined here --> $DIR/non-local-defs-impl.rs:11:9 | diff --git a/tests/rustdoc-ui/doctest/non_local_defs.stderr b/tests/rustdoc-ui/doctest/non_local_defs.stderr index 2b47e6b5bc4..e39dc4d5ee0 100644 --- a/tests/rustdoc-ui/doctest/non_local_defs.stderr +++ b/tests/rustdoc-ui/doctest/non_local_defs.stderr @@ -6,7 +6,6 @@ LL | macro_rules! a_macro { () => {} } | = help: remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() { ... }` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default warning: 1 warning emitted diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs index 8142bd83877..f63a9e87497 100644 --- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs +++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs @@ -91,7 +91,7 @@ struct X { //~| HELP prefix with `field@` /// Link to [field@S::A] -//~^ ERROR incompatible link kind for `S::A` -//~| NOTE this link resolved +//~^ ERROR unresolved link to `S::A` +//~| NOTE this link resolves //~| HELP prefix with `variant@` pub fn f() {} diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr index 488120304fd..ef7fec77b1e 100644 --- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr +++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -74,7 +74,7 @@ error: unresolved link to `m` --> $DIR/disambiguator-mismatch.rs:52:14 | LL | /// Link to [m()] - | ^^^ this link resolves to the macro `m`, which is not in the value namespace + | ^^^ this link resolves to the macro `m`, which is not a function | help: to link to the macro, add an exclamation mark | @@ -142,7 +142,7 @@ error: unresolved link to `std` --> $DIR/disambiguator-mismatch.rs:83:14 | LL | /// Link to [fn@std] - | ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace + | ^^^^^^ this link resolves to the crate `std`, which is not a function | help: to link to the crate, prefix with `mod@` | @@ -160,13 +160,13 @@ help: to link to the field, prefix with `field@` LL | /// Link to [field@X::y] | ~~~~~~ -error: incompatible link kind for `S::A` +error: unresolved link to `S::A` --> $DIR/disambiguator-mismatch.rs:93:14 | LL | /// Link to [field@S::A] - | ^^^^^^^^^^ this link resolved to a unit variant, which is not a field + | ^^^^^^^^^^ this link resolves to the variant `A`, which is not a field | -help: to link to the unit variant, prefix with `variant@` +help: to link to the variant, prefix with `variant@` | LL | /// Link to [variant@S::A] | ~~~~~~~~ diff --git a/tests/rustdoc-ui/intra-doc/errors.rs b/tests/rustdoc-ui/intra-doc/errors.rs index f37f49c24cc..e885a3b35f6 100644 --- a/tests/rustdoc-ui/intra-doc/errors.rs +++ b/tests/rustdoc-ui/intra-doc/errors.rs @@ -98,7 +98,7 @@ pub trait T { /// [m()] //~^ ERROR unresolved link //~| HELP to link to the macro -//~| NOTE not in the value namespace +//~| NOTE not a function #[macro_export] macro_rules! m { () => {}; diff --git a/tests/rustdoc-ui/intra-doc/errors.stderr b/tests/rustdoc-ui/intra-doc/errors.stderr index a982bba0095..07d328f99a3 100644 --- a/tests/rustdoc-ui/intra-doc/errors.stderr +++ b/tests/rustdoc-ui/intra-doc/errors.stderr @@ -104,7 +104,7 @@ error: unresolved link to `S` --> $DIR/errors.rs:68:6 | LL | /// [S!] - | ^^ this link resolves to the struct `S`, which is not in the macro namespace + | ^^ this link resolves to the struct `S`, which is not a macro | help: to link to the struct, prefix with `struct@` | @@ -158,7 +158,7 @@ error: unresolved link to `m` --> $DIR/errors.rs:98:6 | LL | /// [m()] - | ^^^ this link resolves to the macro `m`, which is not in the value namespace + | ^^^ this link resolves to the macro `m`, which is not a function | help: to link to the macro, add an exclamation mark | diff --git a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr index 6c834fd0a1b..a347044bfe9 100644 --- a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr +++ b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr @@ -2,7 +2,7 @@ error: unresolved link to `Clone` --> $DIR/issue-110495-suffix-with-space.rs:3:6 | LL | //! [Clone ()]. - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | note: the lint level is defined here --> $DIR/issue-110495-suffix-with-space.rs:2:9 @@ -31,7 +31,7 @@ error: unresolved link to `Clone` --> $DIR/issue-110495-suffix-with-space.rs:5:7 | LL | //! [`Clone ()`]. - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | diff --git a/tests/rustdoc-ui/intra-doc/value-ctor.rs b/tests/rustdoc-ui/intra-doc/value-ctor.rs new file mode 100644 index 00000000000..6f57b7c6f10 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/value-ctor.rs @@ -0,0 +1,35 @@ +// https://github.com/rust-lang/rust/issues/130591 +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "foo"] + +/// [value@Foo::X] //~ERROR broken +pub enum Foo { + X, +} + +/// [tst][value@MyStruct] //~ERROR broken +pub struct MyStruct; + +pub enum MyEnum { + Internals, +} + +pub use MyEnum::*; + +/// In this context, [a][type@Internals] is a struct, +/// while [b][value@Internals] fails. //~ERROR broken +/// Also, [c][struct@Internals] is a struct, +/// while [d][variant@Internals] fails. //~ERROR broken +pub struct Internals { + foo: (), +} + +pub mod inside { + pub struct Internals2; +} + +use inside::*; + +/// In this context, [a][type@Internals2] is an enum, +/// while [b][value@Internals2] fails. //~ERROR broken +pub enum Internals2 {} diff --git a/tests/rustdoc-ui/intra-doc/value-ctor.stderr b/tests/rustdoc-ui/intra-doc/value-ctor.stderr new file mode 100644 index 00000000000..8d2a6649f4c --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/value-ctor.stderr @@ -0,0 +1,62 @@ +error: unresolved link to `Foo::X` + --> $DIR/value-ctor.rs:5:6 + | +LL | /// [value@Foo::X] + | ^^^^^^^^^^^^ this link resolves to the variant `X`, which is not in the value namespace + | +note: the lint level is defined here + --> $DIR/value-ctor.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the variant, prefix with `variant@` + | +LL | /// [variant@Foo::X] + | ~~~~~~~~ + +error: unresolved link to `MyStruct` + --> $DIR/value-ctor.rs:10:11 + | +LL | /// [tst][value@MyStruct] + | ^^^^^^^^^^^^^^ this link resolves to the struct `MyStruct`, which is not in the value namespace + | +help: to link to the struct, prefix with `struct@` + | +LL | /// [tst][struct@MyStruct] + | ~~~~~~~ + +error: unresolved link to `Internals` + --> $DIR/value-ctor.rs:20:15 + | +LL | /// while [b][value@Internals] fails. + | ^^^^^^^^^^^^^^^ this link resolves to the struct `Internals`, which is not in the value namespace + | +help: to link to the struct, prefix with `struct@` + | +LL | /// while [b][struct@Internals] fails. + | ~~~~~~~ + +error: incompatible link kind for `Internals` + --> $DIR/value-ctor.rs:22:15 + | +LL | /// while [d][variant@Internals] fails. + | ^^^^^^^^^^^^^^^^^ this link resolved to a struct, which is not a variant + | +help: to link to the struct, prefix with `struct@` + | +LL | /// while [d][struct@Internals] fails. + | ~~~~~~~ + +error: unresolved link to `Internals2` + --> $DIR/value-ctor.rs:34:15 + | +LL | /// while [b][value@Internals2] fails. + | ^^^^^^^^^^^^^^^^ this link resolves to the enum `Internals2`, which is not in the value namespace + | +help: to link to the enum, prefix with `enum@` + | +LL | /// while [b][enum@Internals2] fails. + | ~~~~~ + +error: aborting due to 5 previous errors + diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index f50feb57fcc..17bcbc783fd 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -40,7 +40,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:27:9 | LL | /// [ `Clone ()` ] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -52,7 +52,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:30:7 | LL | /// [`Clone ()` ] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -64,7 +64,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:33:9 | LL | /// [ `Clone ()`] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -76,7 +76,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:36:9 | LL | /// [```Clone ()```] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -88,7 +88,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:42:13 | LL | /// [ ``` Clone () ``` ] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -122,7 +122,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:74:9 | LL | /// [x][Clone()] - | ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -134,7 +134,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:77:9 | LL | /// [x][Clone ()] - | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -176,7 +176,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:97:9 | LL | /// [w](Clone\(\)) - | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -188,7 +188,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:103:9 | LL | /// [w](Clone()) - | ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -256,7 +256,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:132:9 | LL | /// The [cln][] link here will produce a plain text suggestion - | ^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^ this link resolves to the trait `Clone`, which is not a function | = help: to link to the trait, prefix with `trait@`: trait@Clone diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 7518ea902ec..5b7da7bb129 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -8,7 +8,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 7752ff51ac8..1e2f640f39f 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -10,7 +10,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index be52853a479..131fd99ebaa 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -7,7 +7,6 @@ //@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 #![feature(rustc_private)] -#![feature(control_flow_enum)] extern crate rustc_hir; #[macro_use] diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs index 9f45b62d343..ec3cf1753e2 100644 --- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -10,7 +10,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index 5bb1053f187..3402b345818 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs index 06d2af4ac8a..4acbabbb6be 100644 --- a/tests/ui-fulldeps/stable-mir/check_foreign.rs +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] extern crate rustc_middle; #[macro_use] diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 68eb3c54593..7d63e202fa6 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index 1d5b19304c1..91baa074c10 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index 5098547c2c8..8721f243587 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index 1d3e4c6845b..40217b9aa95 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -8,7 +8,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index 0b8cfcf27fd..0715e0cfc52 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -10,7 +10,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 4c9a8a665b8..6b458c5d923 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] extern crate rustc_hir; #[macro_use] diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index d68e7d37950..a8bf4c1d399 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] extern crate rustc_hir; #[macro_use] diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index 07f404fd471..6f5478c08bf 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -10,7 +10,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs index 957d840f7a2..7dbf892f9e4 100644 --- a/tests/ui-fulldeps/stable-mir/smir_serde.rs +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index ac428c80e0f..f1bc03781b9 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui/abi/riscv32e-registers.riscv32e.stderr b/tests/ui/abi/riscv32e-registers.riscv32e.stderr new file mode 100644 index 00000000000..e3894431eb4 --- /dev/null +++ b/tests/ui/abi/riscv32e-registers.riscv32e.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:43:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:46:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:49:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:52:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:55:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/abi/riscv32e-registers.riscv32em.stderr b/tests/ui/abi/riscv32e-registers.riscv32em.stderr new file mode 100644 index 00000000000..e3894431eb4 --- /dev/null +++ b/tests/ui/abi/riscv32e-registers.riscv32em.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:43:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:46:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:49:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:52:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:55:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/abi/riscv32e-registers.riscv32emc.stderr b/tests/ui/abi/riscv32e-registers.riscv32emc.stderr new file mode 100644 index 00000000000..e3894431eb4 --- /dev/null +++ b/tests/ui/abi/riscv32e-registers.riscv32emc.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:43:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:46:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:49:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:52:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:55:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/abi/riscv32e-registers.rs b/tests/ui/abi/riscv32e-registers.rs new file mode 100644 index 00000000000..714b0ee4633 --- /dev/null +++ b/tests/ui/abi/riscv32e-registers.rs @@ -0,0 +1,91 @@ +// Test that loads into registers x16..=x31 are never generated for riscv32{e,em,emc} targets +// +//@ build-fail +//@ revisions: riscv32e riscv32em riscv32emc +// +//@ compile-flags: --crate-type=rlib +//@ [riscv32e] needs-llvm-components: riscv +//@ [riscv32e] compile-flags: --target=riscv32e-unknown-none-elf +//@ [riscv32em] needs-llvm-components: riscv +//@ [riscv32em] compile-flags: --target=riscv32em-unknown-none-elf +//@ [riscv32emc] needs-llvm-components: riscv +//@ [riscv32emc] compile-flags: --target=riscv32emc-unknown-none-elf + +#![no_core] +#![feature(no_core, lang_items, rustc_attrs)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} + +// Verify registers x1..=x15 are addressable on riscv32e, but registers x16..=x31 are not +#[no_mangle] +pub unsafe fn registers() { + asm!("li x1, 0"); + asm!("li x2, 0"); + asm!("li x3, 0"); + asm!("li x4, 0"); + asm!("li x5, 0"); + asm!("li x6, 0"); + asm!("li x7, 0"); + asm!("li x8, 0"); + asm!("li x9, 0"); + asm!("li x10, 0"); + asm!("li x11, 0"); + asm!("li x12, 0"); + asm!("li x13, 0"); + asm!("li x14, 0"); + asm!("li x15, 0"); + asm!("li x16, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x17, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x18, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x19, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x20, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x21, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x22, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x23, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x24, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x25, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x26, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x27, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x28, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x29, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x30, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x31, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here +} diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 123e7663257..00a5b4b2ee1 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -1,55 +1,209 @@ +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:35:15 + | +LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:40:1 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:49:17 + | +LL | fn aapcs_ptr(f: extern "aapcs" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"aapcs"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:1 + | +LL | extern "aapcs" {} + | ^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:71:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:1 + | +LL | extern "msp430-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:81:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:1 + | +LL | extern "avr-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:94:17 + | +LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:105:1 + | +LL | extern "riscv-interrupt-m" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:116:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:127:1 + | +LL | extern "x86-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:139:20 + | +LL | fn thiscall_ptr(f: extern "thiscall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"thiscall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:152:1 + | +LL | extern "thiscall" {} + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:170:19 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:183:1 + | +LL | extern "stdcall" {} + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> + = note: `#[warn(unsupported_calling_conventions)]` on by default + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:195:21 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:203:22 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:208:1 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:33:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:69:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:79:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:40:1 + --> $DIR/unsupported.rs:89:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 + --> $DIR/unsupported.rs:111:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:1 + --> $DIR/unsupported.rs:133:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> - = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:201:1 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors; 12 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 7376bb17d6b..dfb5ceb0c33 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -1,49 +1,188 @@ +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:35:15 + | +LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:40:1 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:71:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:1 + | +LL | extern "msp430-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:81:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:1 + | +LL | extern "avr-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:94:17 + | +LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:105:1 + | +LL | extern "riscv-interrupt-m" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:116:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:127:1 + | +LL | extern "x86-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:139:20 + | +LL | fn thiscall_ptr(f: extern "thiscall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"thiscall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:152:1 + | +LL | extern "thiscall" {} + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:170:19 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:183:1 + | +LL | extern "stdcall" {} + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> + = note: `#[warn(unsupported_calling_conventions)]` on by default + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:195:21 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:203:22 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:208:1 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:33:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:69:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:79:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:40:1 + --> $DIR/unsupported.rs:89:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 + --> $DIR/unsupported.rs:111:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:1 + --> $DIR/unsupported.rs:133:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> - = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 6 previous errors; 1 warning emitted +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:201:1 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 14 previous errors; 11 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 23b0e581887..6537ce66057 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -1,33 +1,139 @@ +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:35:15 + | +LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:40:1 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:49:17 + | +LL | fn aapcs_ptr(f: extern "aapcs" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"aapcs"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:1 + | +LL | extern "aapcs" {} + | ^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:71:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:1 + | +LL | extern "msp430-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:81:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:1 + | +LL | extern "avr-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:94:17 + | +LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:105:1 + | +LL | extern "riscv-interrupt-m" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:195:21 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:203:22 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:208:1 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:33:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:69:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:79:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:40:1 + --> $DIR/unsupported.rs:89:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:201:1 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors; 7 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index 708fd2c92a9..a53f85f28bc 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -1,49 +1,188 @@ +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:35:15 + | +LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:40:1 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:49:17 + | +LL | fn aapcs_ptr(f: extern "aapcs" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"aapcs"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:1 + | +LL | extern "aapcs" {} + | ^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:71:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:1 + | +LL | extern "msp430-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:81:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:1 + | +LL | extern "avr-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:116:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:127:1 + | +LL | extern "x86-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:139:20 + | +LL | fn thiscall_ptr(f: extern "thiscall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"thiscall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:152:1 + | +LL | extern "thiscall" {} + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:170:19 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:183:1 + | +LL | extern "stdcall" {} + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> + = note: `#[warn(unsupported_calling_conventions)]` on by default + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:195:21 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:203:22 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:208:1 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:33:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:69:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:79:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 + --> $DIR/unsupported.rs:111:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:1 + --> $DIR/unsupported.rs:133:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> - = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 6 previous errors; 1 warning emitted +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:201:1 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 14 previous errors; 11 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index 708fd2c92a9..a53f85f28bc 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -1,49 +1,188 @@ +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:35:15 + | +LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:40:1 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:49:17 + | +LL | fn aapcs_ptr(f: extern "aapcs" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"aapcs"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:1 + | +LL | extern "aapcs" {} + | ^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:71:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:1 + | +LL | extern "msp430-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:81:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:1 + | +LL | extern "avr-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:116:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:127:1 + | +LL | extern "x86-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:139:20 + | +LL | fn thiscall_ptr(f: extern "thiscall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"thiscall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:152:1 + | +LL | extern "thiscall" {} + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:170:19 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:183:1 + | +LL | extern "stdcall" {} + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> + = note: `#[warn(unsupported_calling_conventions)]` on by default + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:195:21 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:203:22 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:208:1 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:33:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:69:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:79:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 + --> $DIR/unsupported.rs:111:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:1 + --> $DIR/unsupported.rs:133:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> - = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 6 previous errors; 1 warning emitted +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:201:1 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 14 previous errors; 11 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index c12883e3fce..0eb039269a3 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -20,39 +20,142 @@ abi_msp430_interrupt, abi_avr_interrupt, abi_x86_interrupt, - abi_riscv_interrupt + abi_riscv_interrupt, + abi_c_cmse_nonsecure_call, + cmse_nonsecure_entry )] #[lang = "sized"] trait Sized {} +#[lang = "copy"] +trait Copy {} + extern "ptx-kernel" fn ptx() {} //~^ ERROR is not a supported ABI +fn ptx_ptr(f: extern "ptx-kernel" fn()) { + //~^ WARN unsupported_fn_ptr_calling_conventions + //~^^ WARN this was previously accepted + f() +} +extern "ptx-kernel" {} +//~^ ERROR is not a supported ABI + extern "aapcs" fn aapcs() {} //[x64]~^ ERROR is not a supported ABI //[i686]~^^ ERROR is not a supported ABI //[aarch64]~^^^ ERROR is not a supported ABI //[riscv32]~^^^^ ERROR is not a supported ABI //[riscv64]~^^^^^ ERROR is not a supported ABI +fn aapcs_ptr(f: extern "aapcs" fn()) { + //[x64]~^ WARN unsupported_fn_ptr_calling_conventions + //[x64]~^^ WARN this was previously accepted + //[i686]~^^^ WARN unsupported_fn_ptr_calling_conventions + //[i686]~^^^^ WARN this was previously accepted + //[aarch64]~^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[aarch64]~^^^^^^ WARN this was previously accepted + //[riscv32]~^^^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[riscv32]~^^^^^^^^ WARN this was previously accepted + //[riscv64]~^^^^^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[riscv64]~^^^^^^^^^^ WARN this was previously accepted + f() +} +extern "aapcs" {} +//[x64]~^ ERROR is not a supported ABI +//[i686]~^^ ERROR is not a supported ABI +//[aarch64]~^^^ ERROR is not a supported ABI +//[riscv32]~^^^^ ERROR is not a supported ABI +//[riscv64]~^^^^^ ERROR is not a supported ABI + extern "msp430-interrupt" fn msp430() {} //~^ ERROR is not a supported ABI +fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + //~^ WARN unsupported_fn_ptr_calling_conventions + //~^^ WARN this was previously accepted + f() +} +extern "msp430-interrupt" {} +//~^ ERROR is not a supported ABI + extern "avr-interrupt" fn avr() {} //~^ ERROR is not a supported ABI +fn avr_ptr(f: extern "avr-interrupt" fn()) { + //~^ WARN unsupported_fn_ptr_calling_conventions + //~^^ WARN this was previously accepted + f() +} +extern "avr-interrupt" {} +//~^ ERROR is not a supported ABI + extern "riscv-interrupt-m" fn riscv() {} //[arm]~^ ERROR is not a supported ABI //[x64]~^^ ERROR is not a supported ABI //[i686]~^^^ ERROR is not a supported ABI //[aarch64]~^^^^ ERROR is not a supported ABI +fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { + //[arm]~^ WARN unsupported_fn_ptr_calling_conventions + //[arm]~^^ WARN this was previously accepted + //[x64]~^^^ WARN unsupported_fn_ptr_calling_conventions + //[x64]~^^^^ WARN this was previously accepted + //[i686]~^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[i686]~^^^^^^ WARN this was previously accepted + //[aarch64]~^^^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[aarch64]~^^^^^^^^ WARN this was previously accepted + f() +} +extern "riscv-interrupt-m" {} +//[arm]~^ ERROR is not a supported ABI +//[x64]~^^ ERROR is not a supported ABI +//[i686]~^^^ ERROR is not a supported ABI +//[aarch64]~^^^^ ERROR is not a supported ABI + extern "x86-interrupt" fn x86() {} //[aarch64]~^ ERROR is not a supported ABI //[arm]~^^ ERROR is not a supported ABI //[riscv32]~^^^ ERROR is not a supported ABI //[riscv64]~^^^^ ERROR is not a supported ABI +fn x86_ptr(f: extern "x86-interrupt" fn()) { + //[aarch64]~^ WARN unsupported_fn_ptr_calling_conventions + //[aarch64]~^^ WARN this was previously accepted + //[arm]~^^^ WARN unsupported_fn_ptr_calling_conventions + //[arm]~^^^^ WARN this was previously accepted + //[riscv32]~^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[riscv32]~^^^^^^ WARN this was previously accepted + //[riscv64]~^^^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[riscv64]~^^^^^^^^ WARN this was previously accepted + f() +} +extern "x86-interrupt" {} +//[aarch64]~^ ERROR is not a supported ABI +//[arm]~^^ ERROR is not a supported ABI +//[riscv32]~^^^ ERROR is not a supported ABI +//[riscv64]~^^^^ ERROR is not a supported ABI + extern "thiscall" fn thiscall() {} //[x64]~^ ERROR is not a supported ABI //[arm]~^^ ERROR is not a supported ABI //[aarch64]~^^^ ERROR is not a supported ABI //[riscv32]~^^^^ ERROR is not a supported ABI //[riscv64]~^^^^^ ERROR is not a supported ABI +fn thiscall_ptr(f: extern "thiscall" fn()) { + //[x64]~^ WARN unsupported_fn_ptr_calling_conventions + //[x64]~^^ WARN this was previously accepted + //[arm]~^^^ WARN unsupported_fn_ptr_calling_conventions + //[arm]~^^^^ WARN this was previously accepted + //[aarch64]~^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[aarch64]~^^^^^^ WARN this was previously accepted + //[riscv32]~^^^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[riscv32]~^^^^^^^^ WARN this was previously accepted + //[riscv64]~^^^^^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[riscv64]~^^^^^^^^^^ WARN this was previously accepted + f() +} +extern "thiscall" {} +//[x64]~^ ERROR is not a supported ABI +//[arm]~^^ ERROR is not a supported ABI +//[aarch64]~^^^ ERROR is not a supported ABI +//[riscv32]~^^^^ ERROR is not a supported ABI +//[riscv64]~^^^^^ ERROR is not a supported ABI + extern "stdcall" fn stdcall() {} //[x64]~^ WARN use of calling convention not supported //[x64]~^^ WARN this was previously accepted @@ -64,3 +167,43 @@ extern "stdcall" fn stdcall() {} //[riscv32]~^^^^^^^^ WARN this was previously accepted //[riscv64]~^^^^^^^^^ WARN use of calling convention not supported //[riscv64]~^^^^^^^^^^ WARN this was previously accepted +fn stdcall_ptr(f: extern "stdcall" fn()) { + //[x64]~^ WARN unsupported_fn_ptr_calling_conventions + //[x64]~^^ WARN this was previously accepted + //[arm]~^^^ WARN unsupported_fn_ptr_calling_conventions + //[arm]~^^^^ WARN this was previously accepted + //[aarch64]~^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[aarch64]~^^^^^^ WARN this was previously accepted + //[riscv32]~^^^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[riscv32]~^^^^^^^^ WARN this was previously accepted + //[riscv64]~^^^^^^^^^ WARN unsupported_fn_ptr_calling_conventions + //[riscv64]~^^^^^^^^^^ WARN this was previously accepted + f() +} +extern "stdcall" {} +//[x64]~^ WARN use of calling convention not supported +//[x64]~^^ WARN this was previously accepted +//[arm]~^^^ WARN use of calling convention not supported +//[arm]~^^^^ WARN this was previously accepted +//[aarch64]~^^^^^ WARN use of calling convention not supported +//[aarch64]~^^^^^^ WARN this was previously accepted +//[riscv32]~^^^^^^^ WARN use of calling convention not supported +//[riscv32]~^^^^^^^^ WARN this was previously accepted +//[riscv64]~^^^^^^^^^ WARN use of calling convention not supported +//[riscv64]~^^^^^^^^^^ WARN this was previously accepted + +fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + //~^ WARN unsupported_fn_ptr_calling_conventions + //~^^ WARN this was previously accepted + f() +} + +extern "C-cmse-nonsecure-entry" fn cmse_entry() {} +//~^ ERROR is not a supported ABI +fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + //~^ WARN unsupported_fn_ptr_calling_conventions + //~^^ WARN this was previously accepted + f() +} +extern "C-cmse-nonsecure-entry" {} +//~^ ERROR is not a supported ABI diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 7b918a948d3..45ba9a6649c 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -1,49 +1,188 @@ +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:35:15 + | +LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:40:1 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:49:17 + | +LL | fn aapcs_ptr(f: extern "aapcs" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"aapcs"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:1 + | +LL | extern "aapcs" {} + | ^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:71:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:1 + | +LL | extern "msp430-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:81:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:1 + | +LL | extern "avr-interrupt" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:94:17 + | +LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:105:1 + | +LL | extern "riscv-interrupt-m" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:139:20 + | +LL | fn thiscall_ptr(f: extern "thiscall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"thiscall"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:152:1 + | +LL | extern "thiscall" {} + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:170:19 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:183:1 + | +LL | extern "stdcall" {} + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> + = note: `#[warn(unsupported_calling_conventions)]` on by default + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:195:21 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +warning: use of calling convention not supported on this target on function pointer + --> $DIR/unsupported.rs:203:22 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> + +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:208:1 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:33:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:69:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:79:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:40:1 + --> $DIR/unsupported.rs:89:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:1 + --> $DIR/unsupported.rs:133:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:56:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> - = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 6 previous errors; 1 warning emitted +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:201:1 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 14 previous errors; 11 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/allocator/dyn-compatible.rs b/tests/ui/allocator/dyn-compatible.rs new file mode 100644 index 00000000000..9d8235e58d9 --- /dev/null +++ b/tests/ui/allocator/dyn-compatible.rs @@ -0,0 +1,13 @@ +//@ run-pass + +// Check that `Allocator` is dyn-compatible, this allows for polymorphic allocators + +#![feature(allocator_api)] + +use std::alloc::{Allocator, System}; + +fn ensure_dyn_compatible(_: &dyn Allocator) {} + +fn main() { + ensure_dyn_compatible(&System); +} diff --git a/tests/ui/allocator/object-safe.rs b/tests/ui/allocator/object-safe.rs deleted file mode 100644 index 1c1f4fe0bf6..00000000000 --- a/tests/ui/allocator/object-safe.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -// Check that `Allocator` is object safe, this allows for polymorphic allocators - -#![feature(allocator_api)] - -use std::alloc::{Allocator, System}; - -fn ensure_object_safe(_: &dyn Allocator) {} - -fn main() { - ensure_object_safe(&System); -} diff --git a/tests/ui/asm/naked-functions-ffi.rs b/tests/ui/asm/naked-functions-ffi.rs index 93d23885b13..b78d1e6a0d1 100644 --- a/tests/ui/asm/naked-functions-ffi.rs +++ b/tests/ui/asm/naked-functions-ffi.rs @@ -3,13 +3,13 @@ #![feature(naked_functions)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::naked_asm; #[naked] pub extern "C" fn naked(p: char) -> u128 { //~^ WARN uses type `char` //~| WARN uses type `u128` unsafe { - asm!("", options(noreturn)); + naked_asm!(""); } } diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs index b81b65cff74..37c7b52c191 100644 --- a/tests/ui/asm/naked-functions-instruction-set.rs +++ b/tests/ui/asm/naked-functions-instruction-set.rs @@ -8,7 +8,7 @@ #![no_core] #[rustc_builtin_macro] -macro_rules! asm { +macro_rules! naked_asm { () => {}; } @@ -19,12 +19,12 @@ trait Sized {} #[naked] #[instruction_set(arm::t32)] unsafe extern "C" fn test_thumb() { - asm!("bx lr", options(noreturn)); + naked_asm!("bx lr"); } #[no_mangle] #[naked] #[instruction_set(arm::t32)] unsafe extern "C" fn test_arm() { - asm!("bx lr", options(noreturn)); + naked_asm!("bx lr"); } diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs index 12943ac0378..7e373270e9f 100644 --- a/tests/ui/asm/naked-functions-testattrs.rs +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -6,13 +6,13 @@ #![feature(test)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::naked_asm; #[test] #[naked] //~^ ERROR [E0736] fn test_naked() { - unsafe { asm!("", options(noreturn)) }; + unsafe { naked_asm!("") }; } #[should_panic] @@ -20,7 +20,7 @@ fn test_naked() { #[naked] //~^ ERROR [E0736] fn test_naked_should_panic() { - unsafe { asm!("", options(noreturn)) }; + unsafe { naked_asm!("") }; } #[ignore] @@ -28,12 +28,12 @@ fn test_naked_should_panic() { #[naked] //~^ ERROR [E0736] fn test_naked_ignore() { - unsafe { asm!("", options(noreturn)) }; + unsafe { naked_asm!("") }; } #[bench] #[naked] //~^ ERROR [E0736] fn bench_naked() { - unsafe { asm!("", options(noreturn)) }; + unsafe { naked_asm!("") }; } diff --git a/tests/ui/asm/naked-functions-unused.aarch64.stderr b/tests/ui/asm/naked-functions-unused.aarch64.stderr index 8d3c300e058..ea63ced1aab 100644 --- a/tests/ui/asm/naked-functions-unused.aarch64.stderr +++ b/tests/ui/asm/naked-functions-unused.aarch64.stderr @@ -18,49 +18,49 @@ LL | pub extern "C" fn function(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:26:38 + --> $DIR/naked-functions-unused.rs:28:38 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:26:48 + --> $DIR/naked-functions-unused.rs:28:48 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:32:41 + --> $DIR/naked-functions-unused.rs:36:41 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:32:51 + --> $DIR/naked-functions-unused.rs:36:51 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:40:40 + --> $DIR/naked-functions-unused.rs:46:40 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:40:50 + --> $DIR/naked-functions-unused.rs:46:50 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:46:43 + --> $DIR/naked-functions-unused.rs:54:43 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:46:53 + --> $DIR/naked-functions-unused.rs:54:53 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` diff --git a/tests/ui/asm/naked-functions-unused.rs b/tests/ui/asm/naked-functions-unused.rs index 745d30e6a84..c27037819a4 100644 --- a/tests/ui/asm/naked-functions-unused.rs +++ b/tests/ui/asm/naked-functions-unused.rs @@ -17,7 +17,9 @@ pub mod normal { pub extern "C" fn function(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } pub struct Normal; @@ -26,13 +28,17 @@ pub mod normal { pub extern "C" fn associated(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } pub extern "C" fn method(&self, a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } } @@ -40,23 +46,29 @@ pub mod normal { extern "C" fn trait_associated(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } } } pub mod naked { - use std::arch::asm; + use std::arch::naked_asm; #[naked] pub extern "C" fn function(a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!(""); + } } pub struct Naked; @@ -64,24 +76,32 @@ pub mod naked { impl Naked { #[naked] pub extern "C" fn associated(a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!(""); + } } #[naked] pub extern "C" fn method(&self, a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!(""); + } } } impl super::Trait for Naked { #[naked] extern "C" fn trait_associated(a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!(""); + } } #[naked] extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!(""); + } } } } diff --git a/tests/ui/asm/naked-functions-unused.x86_64.stderr b/tests/ui/asm/naked-functions-unused.x86_64.stderr index 8d3c300e058..ea63ced1aab 100644 --- a/tests/ui/asm/naked-functions-unused.x86_64.stderr +++ b/tests/ui/asm/naked-functions-unused.x86_64.stderr @@ -18,49 +18,49 @@ LL | pub extern "C" fn function(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:26:38 + --> $DIR/naked-functions-unused.rs:28:38 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:26:48 + --> $DIR/naked-functions-unused.rs:28:48 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:32:41 + --> $DIR/naked-functions-unused.rs:36:41 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:32:51 + --> $DIR/naked-functions-unused.rs:36:51 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:40:40 + --> $DIR/naked-functions-unused.rs:46:40 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:40:50 + --> $DIR/naked-functions-unused.rs:46:50 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:46:43 + --> $DIR/naked-functions-unused.rs:54:43 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:46:53 + --> $DIR/naked-functions-unused.rs:54:53 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 116a84506c5..5c58f1498cc 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -6,7 +6,13 @@ #![feature(asm_unwind, linkage)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::{asm, naked_asm}; + +#[naked] +pub unsafe extern "C" fn inline_asm_macro() { + asm!("", options(raw)); + //~^ERROR the `asm!` macro is not allowed in naked functions +} #[repr(C)] pub struct P { @@ -25,12 +31,12 @@ pub unsafe extern "C" fn patterns( P { x, y }: P, //~^ ERROR patterns not allowed in naked function parameters ) { - asm!("", options(noreturn)) + naked_asm!("") } #[naked] pub unsafe extern "C" fn inc(a: u32) -> u32 { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation a + 1 //~^ ERROR referencing function parameters is not allowed in naked functions } @@ -38,20 +44,19 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 { #[naked] #[allow(asm_sub_register)] pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { - asm!("/* {0} */", in(reg) a, options(noreturn)); - //~^ ERROR referencing function parameters is not allowed in naked functions - //~| ERROR only `const` and `sym` operands are supported in naked functions + naked_asm!("/* {0} */", in(reg) a) + //~^ ERROR the `in` operand cannot be used with `naked_asm!` } #[naked] pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation (|| a + 1)() } #[naked] pub unsafe extern "C" fn unsupported_operands() { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation let mut a = 0usize; let mut b = 0usize; let mut c = 0usize; @@ -59,10 +64,9 @@ pub unsafe extern "C" fn unsupported_operands() { let mut e = 0usize; const F: usize = 0usize; static G: usize = 0usize; - asm!("/* {0} {1} {2} {3} {4} {5} {6} */", - //~^ ERROR asm in naked functions must use `noreturn` option + naked_asm!("/* {0} {1} {2} {3} {4} {5} {6} */", in(reg) a, - //~^ ERROR only `const` and `sym` operands are supported in naked functions + //~^ ERROR the `in` operand cannot be used with `naked_asm!` inlateout(reg) b, inout(reg) c, lateout(reg) d, @@ -74,27 +78,23 @@ pub unsafe extern "C" fn unsupported_operands() { #[naked] pub extern "C" fn missing_assembly() { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation } #[naked] pub extern "C" fn too_many_asm_blocks() { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation unsafe { - asm!(""); - //~^ ERROR asm in naked functions must use `noreturn` option - asm!(""); - //~^ ERROR asm in naked functions must use `noreturn` option - asm!(""); - //~^ ERROR asm in naked functions must use `noreturn` option - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); + //~^ ERROR the `noreturn` option cannot be used with `naked_asm!` + naked_asm!(""); } } pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { #[naked] pub extern "C" fn inner(y: usize) -> usize { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation *&y //~^ ERROR referencing function parameters is not allowed in naked functions } @@ -103,40 +103,41 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { #[naked] unsafe extern "C" fn invalid_options() { - asm!("", options(nomem, preserves_flags, noreturn)); - //~^ ERROR asm options unsupported in naked functions: `nomem`, `preserves_flags` + naked_asm!("", options(nomem, preserves_flags)); + //~^ ERROR the `nomem` option cannot be used with `naked_asm!` + //~| ERROR the `preserves_flags` option cannot be used with `naked_asm!` } #[naked] unsafe extern "C" fn invalid_options_continued() { - asm!("", options(readonly, nostack), options(pure)); - //~^ ERROR asm with the `pure` option must have at least one output - //~| ERROR asm options unsupported in naked functions: `pure`, `readonly`, `nostack` - //~| ERROR asm in naked functions must use `noreturn` option + naked_asm!("", options(readonly, nostack), options(pure)); + //~^ ERROR the `readonly` option cannot be used with `naked_asm!` + //~| ERROR the `nostack` option cannot be used with `naked_asm!` + //~| ERROR the `pure` option cannot be used with `naked_asm!` } #[naked] unsafe extern "C" fn invalid_may_unwind() { - asm!("", options(noreturn, may_unwind)); - //~^ ERROR asm options unsupported in naked functions: `may_unwind` + naked_asm!("", options(may_unwind)); + //~^ ERROR the `may_unwind` option cannot be used with `naked_asm!` } #[naked] pub unsafe fn default_abi() { //~^ WARN Rust ABI is unsupported in naked functions - asm!("", options(noreturn)); + naked_asm!(""); } #[naked] pub unsafe fn rust_abi() { //~^ WARN Rust ABI is unsupported in naked functions - asm!("", options(noreturn)); + naked_asm!(""); } #[naked] pub extern "C" fn valid_a<T>() -> T { unsafe { - asm!("", options(noreturn)); + naked_asm!(""); } } @@ -145,7 +146,7 @@ pub extern "C" fn valid_b() { unsafe { { { - asm!("", options(noreturn)); + naked_asm!(""); }; }; } @@ -153,13 +154,13 @@ pub extern "C" fn valid_b() { #[naked] pub unsafe extern "C" fn valid_c() { - asm!("", options(noreturn)); + naked_asm!(""); } #[cfg(target_arch = "x86_64")] #[naked] pub unsafe extern "C" fn valid_att_syntax() { - asm!("", options(noreturn, att_syntax)); + naked_asm!("", options(att_syntax)); } #[naked] @@ -173,12 +174,12 @@ pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { compile_error!("this is a user specified error"); //~^ ERROR this is a user specified error - asm!("", options(noreturn)) + naked_asm!("") } #[naked] pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { - asm!(invalid_syntax) + naked_asm!(invalid_syntax) //~^ ERROR asm template must be a string literal } @@ -186,7 +187,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { #[cfg_attr(target_pointer_width = "64", no_mangle)] #[naked] pub unsafe extern "C" fn compatible_cfg_attributes() { - asm!("", options(noreturn, att_syntax)); + naked_asm!("", options(att_syntax)); } #[allow(dead_code)] @@ -195,25 +196,24 @@ pub unsafe extern "C" fn compatible_cfg_attributes() { #[forbid(dead_code)] #[naked] pub unsafe extern "C" fn compatible_diagnostic_attributes() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[deprecated = "test"] #[naked] pub unsafe extern "C" fn compatible_deprecated_attributes() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[cfg(target_arch = "x86_64")] #[must_use] #[naked] pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { - asm!( + naked_asm!( " mov rax, 42 ret ", - options(noreturn) ) } @@ -222,20 +222,20 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[no_mangle] #[naked] pub unsafe extern "C" fn compatible_ffi_attributes_1() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[cold] #[naked] pub unsafe extern "C" fn compatible_codegen_attributes() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse2")] #[naked] pub unsafe extern "C" fn compatible_target_feature() { - asm!("", options(noreturn)); + naked_asm!(""); } #[doc = "foo bar baz"] @@ -244,11 +244,11 @@ pub unsafe extern "C" fn compatible_target_feature() { #[doc(alias = "ADocAlias")] #[naked] pub unsafe extern "C" fn compatible_doc_attributes() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[linkage = "external"] #[naked] pub unsafe extern "C" fn compatible_linkage() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 93c02e2fbef..0898f3620f2 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -1,193 +1,162 @@ -error: asm with the `pure` option must have at least one output - --> $DIR/naked-functions.rs:112:14 +error: the `in` operand cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:47:29 | -LL | asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ +LL | naked_asm!("/* {0} */", in(reg) a) + | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `in` operand cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:68:10 + | +LL | in(reg) a, + | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `noreturn` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:88:32 + | +LL | naked_asm!("", options(noreturn)); + | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly + +error: the `nomem` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:106:28 + | +LL | naked_asm!("", options(nomem, preserves_flags)); + | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly + +error: the `preserves_flags` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:106:35 + | +LL | naked_asm!("", options(nomem, preserves_flags)); + | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly + +error: the `readonly` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:113:28 + | +LL | naked_asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly + +error: the `nostack` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:113:38 + | +LL | naked_asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly + +error: the `pure` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:113:56 + | +LL | naked_asm!("", options(readonly, nostack), options(pure)); + | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly + +error: the `may_unwind` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:121:28 + | +LL | naked_asm!("", options(may_unwind)); + | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly error: this is a user specified error - --> $DIR/naked-functions.rs:168:5 + --> $DIR/naked-functions.rs:169:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:174:5 + --> $DIR/naked-functions.rs:175:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:181:10 + --> $DIR/naked-functions.rs:182:16 | -LL | asm!(invalid_syntax) - | ^^^^^^^^^^^^^^ +LL | naked_asm!(invalid_syntax) + | ^^^^^^^^^^^^^^ + +error[E0787]: the `asm!` macro is not allowed in naked functions + --> $DIR/naked-functions.rs:13:5 + | +LL | asm!("", options(raw)); + | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:19:5 + --> $DIR/naked-functions.rs:25:5 | LL | mut a: u32, | ^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:21:5 + --> $DIR/naked-functions.rs:27:5 | LL | &b: &i32, | ^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:23:6 + --> $DIR/naked-functions.rs:29:6 | LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>, | ^^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:25:5 + --> $DIR/naked-functions.rs:31:5 | LL | P { x, y }: P, | ^^^^^^^^^^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:34:5 + --> $DIR/naked-functions.rs:40:5 | LL | a + 1 | ^ | = help: follow the calling convention in asm block to use parameters -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:32:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:38:1 | LL | pub unsafe extern "C" fn inc(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | a + 1 - | ----- non-asm is unsupported in naked functions - -error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:41:31 - | -LL | asm!("/* {0} */", in(reg) a, options(noreturn)); - | ^ - | - = help: follow the calling convention in asm block to use parameters - -error[E0787]: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:41:23 - | -LL | asm!("/* {0} */", in(reg) a, options(noreturn)); - | ^^^^^^^^^ + | ----- not allowed in naked functions -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:47:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:52:1 | LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | (|| a + 1)() - | ------------ non-asm is unsupported in naked functions + | ------------ not allowed in naked functions -error[E0787]: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:64:10 - | -LL | in(reg) a, - | ^^^^^^^^^ -LL | -LL | inlateout(reg) b, - | ^^^^^^^^^^^^^^^^ -LL | inout(reg) c, - | ^^^^^^^^^^^^ -LL | lateout(reg) d, - | ^^^^^^^^^^^^^^ -LL | out(reg) e, - | ^^^^^^^^^^ - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:62:5 - | -LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */", -LL | | -LL | | in(reg) a, -LL | | -... | -LL | | sym G, -LL | | ); - | |_____^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | sym G, options(noreturn), - | +++++++++++++++++++ - -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:53:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:58:1 | LL | pub unsafe extern "C" fn unsupported_operands() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | let mut a = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions LL | let mut b = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions LL | let mut c = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions LL | let mut d = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions LL | let mut e = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:76:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:80:1 | LL | pub extern "C" fn missing_assembly() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:84:9 - | -LL | asm!(""); - | ^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | asm!("", options(noreturn)); - | +++++++++++++++++++ - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:86:9 - | -LL | asm!(""); - | ^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | asm!("", options(noreturn)); - | +++++++++++++++++++ - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:88:9 - | -LL | asm!(""); - | ^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | asm!("", options(noreturn)); - | +++++++++++++++++++ - -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:81:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:85:1 | LL | pub extern "C" fn too_many_asm_blocks() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | asm!(""); - | -------- multiple asm blocks are unsupported in naked functions -LL | -LL | asm!(""); - | -------- multiple asm blocks are unsupported in naked functions -LL | -LL | asm!("", options(noreturn)); - | --------------------------- multiple asm blocks are unsupported in naked functions +LL | naked_asm!(""); + | -------------- multiple `naked_asm!` invocations are not allowed in naked functions error: referencing function parameters is not allowed in naked functions --> $DIR/naked-functions.rs:98:11 @@ -197,46 +166,17 @@ LL | *&y | = help: follow the calling convention in asm block to use parameters -error[E0787]: naked functions must contain a single asm block +error[E0787]: naked functions must contain a single `naked_asm!` invocation --> $DIR/naked-functions.rs:96:5 | LL | pub extern "C" fn inner(y: usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | *&y - | --- non-asm is unsupported in naked functions - -error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags` - --> $DIR/naked-functions.rs:106:5 - | -LL | asm!("", options(nomem, preserves_flags, noreturn)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0787]: asm options unsupported in naked functions: `pure`, `readonly`, `nostack` - --> $DIR/naked-functions.rs:112:5 - | -LL | asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:112:5 - | -LL | asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | asm!("", options(noreturn), options(readonly, nostack), options(pure)); - | +++++++++++++++++++ - -error[E0787]: asm options unsupported in naked functions: `may_unwind` - --> $DIR/naked-functions.rs:120:5 - | -LL | asm!("", options(noreturn, may_unwind)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --- not allowed in naked functions warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:125:1 + --> $DIR/naked-functions.rs:126:1 | LL | pub unsafe fn default_abi() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,11 +184,11 @@ LL | pub unsafe fn default_abi() { = note: `#[warn(undefined_naked_function_abi)]` on by default warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:131:1 + --> $DIR/naked-functions.rs:132:1 | LL | pub unsafe fn rust_abi() { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 27 previous errors; 2 warnings emitted +error: aborting due to 25 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0787`. diff --git a/tests/ui/asm/naked-invalid-attr.rs b/tests/ui/asm/naked-invalid-attr.rs index 57edd57de99..4053c58fb51 100644 --- a/tests/ui/asm/naked-invalid-attr.rs +++ b/tests/ui/asm/naked-invalid-attr.rs @@ -4,7 +4,7 @@ #![feature(naked_functions)] #![naked] //~ ERROR should be applied to a function definition -use std::arch::asm; +use std::arch::naked_asm; extern "C" { #[naked] //~ ERROR should be applied to a function definition @@ -26,27 +26,28 @@ trait Invoke { impl Invoke for S { #[naked] extern "C" fn invoke(&self) { - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } } #[naked] extern "C" fn ok() { - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } impl S { #[naked] extern "C" fn g() { - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } #[naked] extern "C" fn h(&self) { - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } } fn main() { - #[naked] || {}; //~ ERROR should be applied to a function definition + #[naked] //~ ERROR should be applied to a function definition + || {}; } diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index e8ddccc854a..640f9d9510d 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -13,8 +13,10 @@ LL | | } error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:51:5 | -LL | #[naked] || {}; - | ^^^^^^^^ ----- not a function definition +LL | #[naked] + | ^^^^^^^^ +LL | || {}; + | ----- not a function definition error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:22:5 diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs index 687fe1ad73d..18b9c1014c3 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.rs +++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs @@ -2,14 +2,14 @@ #![feature(naked_functions)] #![feature(fn_align)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::naked_asm; #[repr(C)] //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] #[naked] extern "C" fn example1() { //~^ NOTE not a struct, enum, or union - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } #[repr(transparent)] @@ -17,7 +17,7 @@ extern "C" fn example1() { #[naked] extern "C" fn example2() { //~^ NOTE not a struct, enum, or union - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } #[repr(align(16), C)] @@ -25,7 +25,7 @@ extern "C" fn example2() { #[naked] extern "C" fn example3() { //~^ NOTE not a struct, enum, or union - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } // note: two errors because of packed and C @@ -36,7 +36,7 @@ extern "C" fn example3() { extern "C" fn example4() { //~^ NOTE not a struct, enum, or union //~| NOTE not a struct or union - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } #[repr(u8)] @@ -44,5 +44,5 @@ extern "C" fn example4() { #[naked] extern "C" fn example5() { //~^ NOTE not an enum - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.stderr b/tests/ui/asm/naked-with-invalid-repr-attr.stderr index 3740f17a9dc..8248a8c1657 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.stderr +++ b/tests/ui/asm/naked-with-invalid-repr-attr.stderr @@ -6,7 +6,7 @@ LL | #[repr(C)] ... LL | / extern "C" fn example1() { LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct, enum, or union @@ -18,7 +18,7 @@ LL | #[repr(transparent)] ... LL | / extern "C" fn example2() { LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct, enum, or union @@ -30,7 +30,7 @@ LL | #[repr(align(16), C)] ... LL | / extern "C" fn example3() { LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct, enum, or union @@ -43,7 +43,7 @@ LL | #[repr(C, packed)] LL | / extern "C" fn example4() { LL | | LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct, enum, or union @@ -56,7 +56,7 @@ LL | #[repr(C, packed)] LL | / extern "C" fn example4() { LL | | LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct or union @@ -68,7 +68,7 @@ LL | #[repr(u8)] ... LL | / extern "C" fn example5() { LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not an enum diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs index 043aab9029d..77831e679ed 100644 --- a/tests/ui/asm/named-asm-labels.rs +++ b/tests/ui/asm/named-asm-labels.rs @@ -12,7 +12,7 @@ #![feature(naked_functions)] -use std::arch::{asm, global_asm}; +use std::arch::{asm, global_asm, naked_asm}; #[no_mangle] pub static FOO: usize = 42; @@ -177,7 +177,7 @@ fn main() { // label or LTO can cause labels to break #[naked] pub extern "C" fn foo() -> i32 { - unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } + unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) } //~^ ERROR avoid using named labels } @@ -192,7 +192,7 @@ pub extern "C" fn bar() { pub extern "C" fn aaa() { fn _local() {} - unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels + unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels } pub fn normal() { @@ -202,7 +202,7 @@ pub fn normal() { pub extern "C" fn bbb() { fn _very_local() {} - unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels + unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels } fn _local2() {} @@ -221,7 +221,7 @@ fn closures() { || { #[naked] unsafe extern "C" fn _nested() { - asm!("ret;", options(noreturn)); + naked_asm!("ret;"); } unsafe { diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr index e5e177fb8b8..44ce358c62b 100644 --- a/tests/ui/asm/named-asm-labels.stderr +++ b/tests/ui/asm/named-asm-labels.stderr @@ -475,10 +475,10 @@ LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:180:20 + --> $DIR/named-asm-labels.rs:180:26 | -LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } - | ^^^^^ +LL | unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) } + | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information @@ -493,19 +493,19 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:195:20 + --> $DIR/named-asm-labels.rs:195:26 | -LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } - | ^^^^^ +LL | unsafe { naked_asm!(".Laaa: nop; ret;") } + | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:205:24 + --> $DIR/named-asm-labels.rs:205:30 | -LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } - | ^^^^^ +LL | unsafe { naked_asm!(".Lbbb: nop; ret;") } + | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr index cf4809991c3..0dabcbdce1b 100644 --- a/tests/ui/associated-type-bounds/duplicate.stderr +++ b/tests/ui/associated-type-bounds/duplicate.stderr @@ -208,17 +208,6 @@ LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:136:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::<T>() - | +++++ - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:139:42 | @@ -237,17 +226,6 @@ LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:142:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::<T>() - | +++++ - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:145:45 | @@ -266,17 +244,6 @@ LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:148:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::<T>() - | +++++ - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:151:40 | @@ -697,6 +664,39 @@ LL | type A: Iterator<Item: 'static, Item: 'static>; | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:136:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::<T>() + | +++++ + +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:142:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::<T>() + | +++++ + +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:148:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::<T>() + | +++++ + error: aborting due to 81 previous errors Some errors have detailed explanations: E0282, E0719. diff --git a/tests/ui/associated-type-bounds/entails-sized-object-safety.rs b/tests/ui/associated-type-bounds/entails-sized-dyn-compatibility.rs index ad2cbe48209..943df68493f 100644 --- a/tests/ui/associated-type-bounds/entails-sized-object-safety.rs +++ b/tests/ui/associated-type-bounds/entails-sized-dyn-compatibility.rs @@ -4,21 +4,21 @@ trait Tr1: Sized { type As1; } trait Tr2<'a>: Sized { type As2; } trait ObjTr1 { fn foo() -> Self where Self: Tr1<As1: Copy>; } -fn _assert_obj_safe_1(_: Box<dyn ObjTr1>) {} +fn _assert_dyn_compat_1(_: Box<dyn ObjTr1>) {} trait ObjTr2 { fn foo() -> Self where Self: Tr1<As1: 'static>; } -fn _assert_obj_safe_2(_: Box<dyn ObjTr2>) {} +fn _assert_dyn_compat_2(_: Box<dyn ObjTr2>) {} trait ObjTr3 { fn foo() -> Self where Self: Tr1<As1: Into<u8> + 'static + Copy>; } -fn _assert_obj_safe_3(_: Box<dyn ObjTr3>) {} +fn _assert_dyn_compat_3(_: Box<dyn ObjTr3>) {} trait ObjTr4 { fn foo() -> Self where Self: Tr1<As1: for<'a> Tr2<'a>>; } -fn _assert_obj_safe_4(_: Box<dyn ObjTr4>) {} +fn _assert_dyn_compat_4(_: Box<dyn ObjTr4>) {} trait ObjTr5 { fn foo() -> Self where for<'a> Self: Tr1<As1: Tr2<'a>>; } -fn _assert_obj_safe_5(_: Box<dyn ObjTr5>) {} +fn _assert_dyn_compat_5(_: Box<dyn ObjTr5>) {} trait ObjTr6 { fn foo() -> Self where Self: for<'a> Tr1<As1: Tr2<'a, As2: for<'b> Tr2<'b>>>; } -fn _assert_obj_safe_6(_: Box<dyn ObjTr6>) {} +fn _assert_dyn_compat_6(_: Box<dyn ObjTr6>) {} fn main() {} diff --git a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs index 7df042d5f88..c8bb0ebd574 100644 --- a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs +++ b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs @@ -2,28 +2,24 @@ //@ edition: 2021 fn f(_: impl Trait<T = Copy>) {} -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object //~| HELP you might have meant to write a bound here -//~| ERROR the trait `Copy` cannot be made into an object fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {} -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object //~| HELP you might have meant to write a bound here -//~| ERROR only auto traits can be used as additional traits in a trait object -//~| HELP consider creating a new trait -//~| ERROR the trait `Eq` cannot be made into an object fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {} -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object //~| HELP you might have meant to write a bound here // Don't suggest assoc ty bound in trait object types, that's not valid: type Obj = dyn Trait<T = Clone>; -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object trait Trait { type T; } diff --git a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr index bec60187e42..dbe285c5310 100644 --- a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr +++ b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr @@ -1,41 +1,10 @@ -error[E0038]: the trait `Copy` cannot be made into an object - --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:20 - | -LL | fn f(_: impl Trait<T = Copy>) {} - | ^^^^^^^^ `Copy` cannot be made into an object - | - = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - -error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:42 - | -LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {} - | --------------- ^^ additional non-auto trait - | | - | first non-auto trait - | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Debug + Eq {}` - = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> - -error[E0038]: the trait `Eq` cannot be made into an object - --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24 - | -LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {} - | ^^^^^^^^^^^^^^^^^^^^ `Eq` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $SRC_DIR/core/src/cmp.rs:LL:COL - | - = note: the trait cannot be made into an object because it uses `Self` as a type parameter - -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:24 | LL | fn f(_: impl Trait<T = Copy>) {} | ^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | fn f(_: impl Trait<T = dyn Copy>) {} | +++ @@ -44,13 +13,13 @@ help: you might have meant to write a bound here LL | fn f(_: impl Trait<T: Copy>) {} | ~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24 +error[E0782]: expected a type, found a trait + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:9:24 | LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {} | ^^^^^^^^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | fn g(_: impl Trait<T = dyn std::fmt::Debug + Eq>) {} | +++ @@ -59,13 +28,13 @@ help: you might have meant to write a bound here LL | fn g(_: impl Trait<T: std::fmt::Debug + Eq>) {} | ~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:18:26 +error[E0782]: expected a type, found a trait + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:14:26 | LL | fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | fn h(_: impl Trait<T<> = dyn 'static + for<'a> Fn(&'a ())>) {} | +++ @@ -74,18 +43,17 @@ help: you might have meant to write a bound here LL | fn h(_: impl Trait<T<>: 'static + for<'a> Fn(&'a ())>) {} | ~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:24:26 +error[E0782]: expected a type, found a trait + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:20:26 | LL | type Obj = dyn Trait<T = Clone>; | ^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | type Obj = dyn Trait<T = dyn Clone>; | +++ -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0038, E0225, E0782. -For more information about an error, try `rustc --explain E0038`. +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs index 6083cc7d96d..b4df58b3c25 100644 --- a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs @@ -14,7 +14,6 @@ impl Foo for Baz { //~^ ERROR `F` cannot be sent between threads safely where F: FnMut() + Send, - //~^ ERROR impl has stricter requirements than trait { () } diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr index 7f3cd2a5900..e6379954776 100644 --- a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr @@ -16,18 +16,6 @@ LL | async fn bar<F>(&mut self, _func: F) -> () LL | F: FnMut() + Send, | ^^^^ required by this bound in `<Baz as Foo>::bar` -error[E0276]: impl has stricter requirements than trait - --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22 - | -LL | / fn bar<F>(&mut self, func: F) -> impl std::future::Future<Output = ()> + Send -LL | | where -LL | | F: FnMut(); - | |___________________- definition of `bar` from trait -... -LL | F: FnMut() + Send, - | ^^^^ impl has extra requirement `F: Send` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0276, E0277. -For more information about an error, try `rustc --explain E0276`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr index 23ffee0d0a6..358bb3e112e 100644 --- a/tests/ui/async-await/async-fn/edition-2015.stderr +++ b/tests/ui/async-await/async-fn/edition-2015.stderr @@ -39,20 +39,20 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } = help: to use an async block, remove the `||`: `async {` error[E0658]: use of unstable library feature 'async_closure' - --> $DIR/edition-2015.rs:1:22 + --> $DIR/edition-2015.rs:1:42 | LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } - | ^^^^ + | ^^^^ | = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information = help: add `#![feature(async_closure)]` 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 'async_closure' - --> $DIR/edition-2015.rs:1:42 + --> $DIR/edition-2015.rs:1:22 | LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } - | ^^^^ + | ^^^^ | = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information = help: add `#![feature(async_closure)]` to the crate attributes to enable diff --git a/tests/ui/async-await/in-trait/object-safety.rs b/tests/ui/async-await/in-trait/dyn-compatibility.rs index 8174a803e79..8174a803e79 100644 --- a/tests/ui/async-await/in-trait/object-safety.rs +++ b/tests/ui/async-await/in-trait/dyn-compatibility.rs diff --git a/tests/ui/async-await/in-trait/object-safety.stderr b/tests/ui/async-await/in-trait/dyn-compatibility.stderr index 8e73abab933..5cc3b6800dd 100644 --- a/tests/ui/async-await/in-trait/object-safety.stderr +++ b/tests/ui/async-await/in-trait/dyn-compatibility.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:9:12 + --> $DIR/dyn-compatibility.rs:9:12 | LL | let x: &dyn Foo = todo!(); | ^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:5:14 + --> $DIR/dyn-compatibility.rs:5:14 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr index 7bfa9be66dd..7b7b3dbc757 100644 --- a/tests/ui/async-await/inference_var_self_argument.stderr +++ b/tests/ui/async-await/inference_var_self_argument.stderr @@ -1,3 +1,12 @@ +error[E0307]: invalid `self` parameter type: `&dyn Foo` + --> $DIR/inference_var_self_argument.rs:5:24 + | +LL | async fn foo(self: &dyn Foo) { + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/inference_var_self_argument.rs:5:5 | @@ -13,15 +22,6 @@ LL | async fn foo(self: &dyn Foo) { | ^^^ ...because method `foo` is `async` = help: consider moving `foo` to another trait -error[E0307]: invalid `self` parameter type: `&dyn Foo` - --> $DIR/inference_var_self_argument.rs:5:24 - | -LL | async fn foo(self: &dyn Foo) { - | ^^^^^^^^ - | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) - error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0307. diff --git a/tests/ui/async-await/issue-66312.stderr b/tests/ui/async-await/issue-66312.stderr index 702e0b375e5..c95ae1147df 100644 --- a/tests/ui/async-await/issue-66312.stderr +++ b/tests/ui/async-await/issue-66312.stderr @@ -1,9 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/issue-66312.rs:9:8 - | -LL | if x.is_some() { - | ^^^^^^^^^^^ expected `bool`, found `()` - error[E0307]: invalid `self` parameter type: `T` --> $DIR/issue-66312.rs:4:22 | @@ -13,6 +7,12 @@ LL | fn is_some(self: T); = note: type of `self` must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) +error[E0308]: mismatched types + --> $DIR/issue-66312.rs:9:8 + | +LL | if x.is_some() { + | ^^^^^^^^^^^ expected `bool`, found `()` + error: aborting due to 2 previous errors Some errors have detailed explanations: E0307, E0308. diff --git a/tests/ui/async-await/pin-reborrow-self.rs b/tests/ui/async-await/pin-reborrow-self.rs index b60b6982bb8..ee617617da0 100644 --- a/tests/ui/async-await/pin-reborrow-self.rs +++ b/tests/ui/async-await/pin-reborrow-self.rs @@ -1,24 +1,33 @@ //@ check-pass -//@ignore-test - -// Currently ignored due to self reborrowing not being implemented for Pin #![feature(pin_ergonomics)] #![allow(incomplete_features)] use std::pin::Pin; -struct Foo; +pub struct Foo; impl Foo { fn foo(self: Pin<&mut Self>) { } + + fn baz(self: Pin<&Self>) { + } } -fn bar(x: Pin<&mut Foo>) { +pub fn bar(x: Pin<&mut Foo>) { x.foo(); x.foo(); // for this to work we need to automatically reborrow, // as if the user had written `x.as_mut().foo()`. + + Foo::baz(x); + + x.baz(); +} + +pub fn baaz(x: Pin<&Foo>) { + x.baz(); + x.baz(); } fn main() {} diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs index fce6210b2f4..d47a8e085fd 100644 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs +++ b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs @@ -1,3 +1,5 @@ +//@ only-x86_64 + fn efiapi(f: extern "efiapi" fn(usize, ...)) { //~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl` //~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr index 94e9628f0f0..41be3784245 100644 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr +++ b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr @@ -1,5 +1,5 @@ error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:1:14 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14 | LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,13 +9,13 @@ LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl` - --> $DIR/feature-gate-extended_varargs_abi_support.rs:1:14 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14 | LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:6:12 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12 | LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,13 +25,13 @@ LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl` - --> $DIR/feature-gate-extended_varargs_abi_support.rs:6:12 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12 | LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11 | LL | fn win(f: extern "win64" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | fn win(f: extern "win64" fn(usize, ...)) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl` - --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11 | LL | fn win(f: extern "win64" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention diff --git a/tests/ui/c-variadic/variadic-ffi-2-arm.rs b/tests/ui/c-variadic/variadic-ffi-2-arm.rs new file mode 100644 index 00000000000..3b0a71007a0 --- /dev/null +++ b/tests/ui/c-variadic/variadic-ffi-2-arm.rs @@ -0,0 +1,9 @@ +//@ only-arm +//@ build-pass +#![feature(extended_varargs_abi_support)] + +fn aapcs(f: extern "aapcs" fn(usize, ...)) { + f(22, 44); +} + +fn main() {} diff --git a/tests/ui/c-variadic/variadic-ffi-2.rs b/tests/ui/c-variadic/variadic-ffi-2.rs index a7261ebe936..bafb7e2b20c 100644 --- a/tests/ui/c-variadic/variadic-ffi-2.rs +++ b/tests/ui/c-variadic/variadic-ffi-2.rs @@ -1,6 +1,7 @@ //@ ignore-arm stdcall isn't supported #![feature(extended_varargs_abi_support)] +#[allow(unsupported_fn_ptr_calling_conventions)] fn baz(f: extern "stdcall" fn(usize, ...)) { //~^ ERROR: C-variadic function must have a compatible calling convention, // like C, cdecl, system, aapcs, win64, sysv64 or efiapi @@ -10,15 +11,22 @@ fn baz(f: extern "stdcall" fn(usize, ...)) { fn system(f: extern "system" fn(usize, ...)) { f(22, 44); } -fn aapcs(f: extern "aapcs" fn(usize, ...)) { - f(22, 44); -} +#[cfg(target_arch = "x86_64")] fn sysv(f: extern "sysv64" fn(usize, ...)) { f(22, 44); } +#[cfg(target_arch = "x86_64")] fn win(f: extern "win64" fn(usize, ...)) { f(22, 44); } +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "x86", + target_arch = "x86_64" +))] fn efiapi(f: extern "efiapi" fn(usize, ...)) { f(22, 44); } diff --git a/tests/ui/c-variadic/variadic-ffi-2.stderr b/tests/ui/c-variadic/variadic-ffi-2.stderr index fbf273b1f1d..e52de93a926 100644 --- a/tests/ui/c-variadic/variadic-ffi-2.stderr +++ b/tests/ui/c-variadic/variadic-ffi-2.stderr @@ -1,5 +1,5 @@ error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi` - --> $DIR/variadic-ffi-2.rs:4:11 + --> $DIR/variadic-ffi-2.rs:5:11 | LL | fn baz(f: extern "stdcall" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention diff --git a/tests/ui/cast/fat-ptr-cast.stderr b/tests/ui/cast/fat-ptr-cast.stderr index 18e7b68ff3c..2b0bceebf15 100644 --- a/tests/ui/cast/fat-ptr-cast.stderr +++ b/tests/ui/cast/fat-ptr-cast.stderr @@ -44,7 +44,7 @@ LL | p as usize; | = help: cast through a thin pointer first -error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]` +error[E0607]: cannot cast thin pointer `*const i32` to wide pointer `*const [i32]` --> $DIR/fat-ptr-cast.rs:19:5 | LL | q as *const [i32]; diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs b/tests/ui/cfg/crate-attributes-using-cfg_attr.rs index 3ced3a630e3..f99fad881f2 100644 --- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs +++ b/tests/ui/cfg/crate-attributes-using-cfg_attr.rs @@ -3,13 +3,9 @@ #![cfg_attr(foo, crate_type="bin")] //~^ERROR `crate_type` within -//~| WARN this was previously accepted //~|ERROR `crate_type` within -//~| WARN this was previously accepted #![cfg_attr(foo, crate_name="bar")] //~^ERROR `crate_name` within -//~| WARN this was previously accepted //~|ERROR `crate_name` within -//~| WARN this was previously accepted fn main() {} diff --git a/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr new file mode 100644 index 00000000000..1dfca2b88d0 --- /dev/null +++ b/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr @@ -0,0 +1,30 @@ +error: `crate_type` within an `#![cfg_attr]` attribute is forbidden + --> $DIR/crate-attributes-using-cfg_attr.rs:4: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 + | +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 + | +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 + | +LL | #![cfg_attr(foo, crate_name="bar")] + | ^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr deleted file mode 100644 index 82b2d7d1b1d..00000000000 --- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error: `crate_type` within an `#![cfg_attr]` attribute is deprecated - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18 - | -LL | #![cfg_attr(foo, crate_type="bin")] - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> - = note: `#[deny(deprecated_cfg_attr_crate_type_name)]` on by default - -error: `crate_name` within an `#![cfg_attr]` attribute is deprecated - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18 - | -LL | #![cfg_attr(foo, crate_name="bar")] - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> - -error: `crate_type` within an `#![cfg_attr]` attribute is deprecated - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18 - | -LL | #![cfg_attr(foo, crate_type="bin")] - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `crate_name` within an `#![cfg_attr]` attribute is deprecated - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18 - | -LL | #![cfg_attr(foo, crate_name="bar")] - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/cfg/raw-true-false.rs b/tests/ui/cfg/raw-true-false.rs new file mode 100644 index 00000000000..4cb8bb71c92 --- /dev/null +++ b/tests/ui/cfg/raw-true-false.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ compile-flags: --cfg false --check-cfg=cfg(r#false) + +#![deny(warnings)] + +#[expect(unexpected_cfgs)] +mod a { + #[cfg(r#true)] + pub fn foo() {} +} + +mod b { + #[cfg(r#false)] + pub fn bar() {} +} + +fn main() { + b::bar() +} diff --git a/tests/ui/cfg/true-false.rs b/tests/ui/cfg/true-false.rs new file mode 100644 index 00000000000..03d96fbafec --- /dev/null +++ b/tests/ui/cfg/true-false.rs @@ -0,0 +1,30 @@ +//@ run-pass + +#![feature(link_cfg)] +#![feature(cfg_boolean_literals)] + +#[cfg(true)] +fn foo() -> bool { + cfg!(true) +} + +#[cfg(false)] +fn foo() -> bool { + cfg!(false) +} + +#[cfg_attr(true, cfg(false))] +fn foo() {} + +#[link(name = "foo", cfg(false))] +extern "C" {} + +fn main() { + assert!(foo()); + assert!(cfg!(true)); + assert!(!cfg!(false)); + assert!(cfg!(not(false))); + assert!(cfg!(all(true))); + assert!(cfg!(any(true))); + assert!(!cfg!(not(true))); +} diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 7726c2d52f5..c21016e9290 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 244 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 245 more = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 3c99fdd3821..da790bbd528 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` + = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr index f8ed792e3c6..e0d900a1eb5 100644 --- a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr @@ -7,14 +7,12 @@ LL | let c1 = || match x { }; | ^ `x` used here but it isn't initialized error[E0381]: used binding `x` isn't initialized - --> $DIR/pattern-matching-should-fail.rs:15:14 + --> $DIR/pattern-matching-should-fail.rs:15:23 | LL | let x: !; | - binding declared here but left uninitialized LL | let c2 = || match x { _ => () }; - | ^^ - borrow occurs due to use in closure - | | - | `x` used here but it isn't initialized + | ^ `x` used here but it isn't initialized error[E0381]: used binding `variant` isn't initialized --> $DIR/pattern-matching-should-fail.rs:27:13 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs index e05dbf3bbc4..2d0ed5d2a30 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs @@ -1,8 +1,9 @@ // gate-test-abi_c_cmse_nonsecure_call +#[allow(unsupported_fn_ptr_calling_conventions)] fn main() { let non_secure_function = unsafe { core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32, i32, i32, i32) -> i32>( - //~^ ERROR [E0658] + //~^ ERROR [E0658] 0x10000004, ) }; diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr index 64e9b7cc639..120d5cc5293 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr @@ -1,5 +1,5 @@ error[E0658]: C-cmse-nonsecure-call ABI is experimental and subject to change - --> $DIR/gate_test.rs:4:46 + --> $DIR/gate_test.rs:5:46 | LL | core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32, i32, i32, i32) -> i32>( | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.rs index bce3b0fd729..f41d3a783ab 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs +++ b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.rs @@ -1,10 +1,10 @@ // Test that we give suitable error messages when the user attempts to // impl a trait `Trait` for its own object type. -// If the trait is not object-safe, we give a more tailored message +// If the trait is dyn-incompatible, we give a more tailored message // because we're such schnuckels: -trait NotObjectSafe { fn eq(&self, other: Self); } -impl NotObjectSafe for dyn NotObjectSafe { } +trait DynIncompatible { fn eq(&self, other: Self); } +impl DynIncompatible for dyn DynIncompatible { } //~^ ERROR E0038 //~| ERROR E0046 diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr new file mode 100644 index 00000000000..542be2dbc30 --- /dev/null +++ b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr @@ -0,0 +1,27 @@ +error[E0038]: the trait `DynIncompatible` cannot be made into an object + --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:7:26 + | +LL | impl DynIncompatible for dyn DynIncompatible { } + | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:6:45 + | +LL | trait DynIncompatible { fn eq(&self, other: Self); } + | --------------- ^^^^ ...because method `eq` references the `Self` type in this parameter + | | + | this trait cannot be made into an object... + = help: consider moving `eq` to another trait + +error[E0046]: not all trait items implemented, missing: `eq` + --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:7:1 + | +LL | trait DynIncompatible { fn eq(&self, other: Self); } + | -------------------------- `eq` from trait +LL | impl DynIncompatible for dyn DynIncompatible { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `eq` in implementation + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0038, E0046. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr deleted file mode 100644 index ce65e079ab4..00000000000 --- a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0038]: the trait `NotObjectSafe` cannot be made into an object - --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:24 - | -LL | impl NotObjectSafe for dyn NotObjectSafe { } - | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:6:43 - | -LL | trait NotObjectSafe { fn eq(&self, other: Self); } - | ------------- ^^^^ ...because method `eq` references the `Self` type in this parameter - | | - | this trait cannot be made into an object... - = help: consider moving `eq` to another trait - -error[E0046]: not all trait items implemented, missing: `eq` - --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:1 - | -LL | trait NotObjectSafe { fn eq(&self, other: Self); } - | -------------------------- `eq` from trait -LL | impl NotObjectSafe for dyn NotObjectSafe { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `eq` in implementation - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0038, E0046. -For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/coherence/coherence-unsafe-trait-object-impl.rs b/tests/ui/coherence/coherence-unsafe-trait-object-impl.rs index 9859a226efd..16baf0958a6 100644 --- a/tests/ui/coherence/coherence-unsafe-trait-object-impl.rs +++ b/tests/ui/coherence/coherence-unsafe-trait-object-impl.rs @@ -1,7 +1,7 @@ // Check that unsafe trait object do not implement themselves // automatically -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait Trait: Sized { fn call(&self); diff --git a/tests/ui/command/command-current-dir.rs b/tests/ui/command/command-current-dir.rs index 95c16bce6e8..23269e41231 100644 --- a/tests/ui/command/command-current-dir.rs +++ b/tests/ui/command/command-current-dir.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ no-prefer-dynamic We move the binary around, so do not depend dynamically on libstd //@ ignore-wasm32 no processes //@ ignore-sgx no processes //@ ignore-fuchsia Needs directory creation privilege diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs index 6a553c2e085..6a553c2e085 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr index 831b40887ac..84281eb53c9 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `ConstParamTy_` cannot be made into an object - --> $DIR/const_param_ty_object_safety.rs:6:12 + --> $DIR/const_param_ty_dyn_compatibility.rs:6:12 | LL | fn foo(a: &dyn ConstParamTy_) {} | ^^^^^^^^^^^^^^^^^ `ConstParamTy_` cannot be made into an object @@ -14,7 +14,7 @@ LL | fn foo(a: &impl ConstParamTy_) {} | ~~~~ error[E0038]: the trait `UnsizedConstParamTy` cannot be made into an object - --> $DIR/const_param_ty_object_safety.rs:9:12 + --> $DIR/const_param_ty_dyn_compatibility.rs:9:12 | LL | fn bar(a: &dyn UnsizedConstParamTy) {} | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` cannot be made into an object diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs index 1620e257667..1620e257667 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.rs +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr index fb57da42bb2..d2017615e67 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-err-ret.rs:17:16 + --> $DIR/dyn-compatibility-err-ret.rs:17:16 | LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-err-ret.rs:8:8 + --> $DIR/dyn-compatibility-err-ret.rs:8:8 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -17,13 +17,13 @@ LL | fn test(&self) -> [u8; bar::<Self>()]; = help: only type `()` implements the trait, consider using it directly instead error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-err-ret.rs:18:5 + --> $DIR/dyn-compatibility-err-ret.rs:18:5 | LL | v.test(); | ^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-err-ret.rs:8:8 + --> $DIR/dyn-compatibility-err-ret.rs:8:8 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs index b3bbb842638..b3bbb842638 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr index 831bda71295..26ca2d4df5f 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-err-where-bounds.rs:15:16 + --> $DIR/dyn-compatibility-err-where-bounds.rs:15:16 | LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-err-where-bounds.rs:8:8 + --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -15,13 +15,13 @@ LL | fn test(&self) where [u8; bar::<Self>()]: Sized; = help: only type `()` implements the trait, consider using it directly instead error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-err-where-bounds.rs:17:5 + --> $DIR/dyn-compatibility-err-where-bounds.rs:17:5 | LL | v.test(); | ^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-err-where-bounds.rs:8:8 + --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-ok-infer-err.rs index 298cfb512e4..298cfb512e4 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-ok-infer-err.rs diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-ok-infer-err.stderr index d1e1c976da6..a124fbc6092 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-ok-infer-err.stderr @@ -1,11 +1,11 @@ error[E0284]: type annotations needed - --> $DIR/object-safety-ok-infer-err.rs:19:5 + --> $DIR/dyn-compatibility-ok-infer-err.rs:19:5 | LL | use_dyn(&()); | ^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `use_dyn` | note: required by a const generic parameter in `use_dyn` - --> $DIR/object-safety-ok-infer-err.rs:14:12 + --> $DIR/dyn-compatibility-ok-infer-err.rs:14:12 | LL | fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized { | ^^^^^^^^^^^^^^ required by this const generic parameter in `use_dyn` @@ -15,7 +15,7 @@ LL | use_dyn::<N>(&()); | +++++ error[E0284]: type annotations needed - --> $DIR/object-safety-ok-infer-err.rs:19:5 + --> $DIR/dyn-compatibility-ok-infer-err.rs:19:5 | LL | use_dyn(&()); | ^^^^^^^ --- type must be known at this point @@ -23,7 +23,7 @@ LL | use_dyn(&()); | cannot infer the value of the const parameter `N` declared on the function `use_dyn` | note: required for `()` to implement `Foo<_>` - --> $DIR/object-safety-ok-infer-err.rs:8:22 + --> $DIR/dyn-compatibility-ok-infer-err.rs:8:22 | LL | impl<const N: usize> Foo<N> for () { | -------------- ^^^^^^ ^^ diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-ok.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-ok.rs index 6220d681fe1..6220d681fe1 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-ok.rs +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-ok.rs diff --git a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs index 4bea3ad87f5..c1d3321f840 100644 --- a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs +++ b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs @@ -14,10 +14,8 @@ fn f<T>( 1 }], ) -> impl Iterator<Item = SubAssign> { -//~^ ERROR the type parameter `Rhs` must be explicitly specified +//~^ ERROR expected a type, found a trait //~| ERROR `()` is not an iterator -//~| ERROR trait objects must include the `dyn` keyword -//~| ERROR the type parameter `Rhs` must be explicitly specified [E0393] } pub fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr index 416a9381124..5c4d643a28e 100644 --- a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr +++ b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr @@ -16,37 +16,6 @@ help: you might be missing a type parameter LL | fn f<T, F>( | +++ -error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27 - | -LL | ) -> impl Iterator<Item = SubAssign> { - | ^^^^^^^^^ - --> $SRC_DIR/core/src/ops/arith.rs:LL:COL - | - = note: type parameter `Rhs` must be specified for this - | - = note: because of the default `Self` reference, type parameters must be specified on object types -help: set the type parameter to the desired type - | -LL | ) -> impl Iterator<Item = SubAssign<Rhs>> { - | +++++ - -error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27 - | -LL | ) -> impl Iterator<Item = SubAssign> { - | ^^^^^^^^^ - --> $SRC_DIR/core/src/ops/arith.rs:LL:COL - | - = note: type parameter `Rhs` must be specified for this - | - = note: because of the default `Self` reference, type parameters must be specified on object types - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: set the type parameter to the desired type - | -LL | ) -> impl Iterator<Item = SubAssign<Rhs>> { - | +++++ - error[E0277]: `()` is not an iterator --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:6 | @@ -55,13 +24,13 @@ LL | ) -> impl Iterator<Item = SubAssign> { | = help: the trait `Iterator` is not implemented for `()` -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27 | LL | ) -> impl Iterator<Item = SubAssign> { | ^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | ) -> impl Iterator<Item = dyn SubAssign> { | +++ @@ -70,7 +39,7 @@ help: you might have meant to write a bound here LL | ) -> impl Iterator<Item: SubAssign> { | ~ -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0393, E0412, E0782. +Some errors have detailed explanations: E0277, E0412, E0782. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.rs b/tests/ui/const-generics/not_wf_param_in_rpitit.rs index eb672194340..b454562ad49 100644 --- a/tests/ui/const-generics/not_wf_param_in_rpitit.rs +++ b/tests/ui/const-generics/not_wf_param_in_rpitit.rs @@ -1,12 +1,11 @@ //@ edition:2021 -trait Trait<const N: Trait = bar> { +trait Trait<const N: dyn Trait = bar> { //~^ ERROR: cannot find value `bar` in this scope //~| ERROR: cycle detected when computing type of `Trait::N` //~| ERROR: the trait `Trait` cannot be made into an object //~| ERROR: the trait `Trait` cannot be made into an object //~| ERROR: the trait `Trait` cannot be made into an object - //~| ERROR: trait objects must include the `dyn` keyword async fn a() {} } diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr index ade40550c73..2500409e828 100644 --- a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr +++ b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr @@ -1,33 +1,33 @@ error[E0425]: cannot find value `bar` in this scope - --> $DIR/not_wf_param_in_rpitit.rs:3:30 + --> $DIR/not_wf_param_in_rpitit.rs:3:34 | -LL | trait Trait<const N: Trait = bar> { - | ^^^ not found in this scope +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^ not found in this scope error[E0391]: cycle detected when computing type of `Trait::N` - --> $DIR/not_wf_param_in_rpitit.rs:3:22 + --> $DIR/not_wf_param_in_rpitit.rs:3:26 | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^ +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^^^ | = note: ...which immediately requires computing type of `Trait::N` again note: cycle used when computing explicit predicates of trait `Trait` --> $DIR/not_wf_param_in_rpitit.rs:3:1 | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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[E0038]: the trait `Trait` cannot be made into an object --> $DIR/not_wf_param_in_rpitit.rs:3:22 | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^ `Trait` cannot be made into an object +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/not_wf_param_in_rpitit.rs:10:14 + --> $DIR/not_wf_param_in_rpitit.rs:9:14 | -LL | trait Trait<const N: Trait = bar> { +LL | trait Trait<const N: dyn Trait = bar> { | ----- this trait cannot be made into an object... ... LL | async fn a() {} @@ -44,13 +44,13 @@ LL | async fn a() where Self: Sized {} error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/not_wf_param_in_rpitit.rs:3:13 | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/not_wf_param_in_rpitit.rs:10:14 + --> $DIR/not_wf_param_in_rpitit.rs:9:14 | -LL | trait Trait<const N: Trait = bar> { +LL | trait Trait<const N: dyn Trait = bar> { | ----- this trait cannot be made into an object... ... LL | async fn a() {} @@ -67,13 +67,13 @@ LL | async fn a() where Self: Sized {} error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/not_wf_param_in_rpitit.rs:3:13 | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/not_wf_param_in_rpitit.rs:10:14 + --> $DIR/not_wf_param_in_rpitit.rs:9:14 | -LL | trait Trait<const N: Trait = bar> { +LL | trait Trait<const N: dyn Trait = bar> { | ----- this trait cannot be made into an object... ... LL | async fn a() {} @@ -88,18 +88,7 @@ help: alternatively, consider constraining `a` so it does not apply to trait obj LL | async fn a() where Self: Sized {} | +++++++++++++++++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/not_wf_param_in_rpitit.rs:3:22 - | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^ - | -help: add `dyn` keyword before this trait - | -LL | trait Trait<const N: dyn Trait = bar> { - | +++ - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0038, E0391, E0425, E0782. +Some errors have detailed explanations: E0038, E0391, E0425. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr index 847f1da16f6..a060488b328 100644 --- a/tests/ui/const-generics/opaque_types.stderr +++ b/tests/ui/const-generics/opaque_types.stderr @@ -1,3 +1,11 @@ +error: `Foo` is forbidden as the type of a const generic parameter + --> $DIR/opaque_types.rs:7:17 + | +LL | fn foo<const C: Foo>() {} + | ^^^ + | + = note: the only supported types are integers, `bool`, and `char` + error: item does not constrain `Foo::{opaque#0}`, but has it in its signature --> $DIR/opaque_types.rs:7:4 | @@ -68,14 +76,6 @@ LL | type Foo = 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: `Foo` is forbidden as the type of a const generic parameter - --> $DIR/opaque_types.rs:7:17 - | -LL | fn foo<const C: Foo>() {} - | ^^^ - | - = note: the only supported types are integers, `bool`, and `char` - error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}` --> $DIR/opaque_types.rs:3:12 | diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs new file mode 100644 index 00000000000..19c78f019aa --- /dev/null +++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs @@ -0,0 +1,70 @@ +const fn foo(ptr: *const u8) -> usize { + unsafe { + std::mem::transmute(ptr) + //~^ WARN pointers cannot be transmuted to integers + } +} + +trait Human { + const ID: usize = { + let value = 10; + let ptr: *const usize = &value; + unsafe { + std::mem::transmute(ptr) + //~^ WARN pointers cannot be transmuted to integers + } + }; + + fn id_plus_one() -> usize { + Self::ID + 1 + } +} + +struct Type<T>(T); + +impl<T> Type<T> { + const ID: usize = { + let value = 10; + let ptr: *const usize = &value; + unsafe { + std::mem::transmute(ptr) + //~^ WARN pointers cannot be transmuted to integers + } + }; + + fn id_plus_one() -> usize { + Self::ID + 1 + } +} + +fn control(ptr: *const u8) -> usize { + unsafe { + std::mem::transmute(ptr) + } +} + +struct ControlStruct; + +impl ControlStruct { + fn new() -> usize { + let value = 10; + let ptr: *const i32 = &value; + unsafe { + std::mem::transmute(ptr) + } + } +} + + +const fn zoom(ptr: *const u8) -> usize { + unsafe { + std::mem::transmute(ptr) + //~^ WARN pointers cannot be transmuted to integers + } +} + +fn main() { + const a: u8 = 10; + const value: usize = zoom(&a); + //~^ ERROR evaluation of constant value failed +} diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr new file mode 100644 index 00000000000..ca6ad9408ab --- /dev/null +++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr @@ -0,0 +1,53 @@ +warning: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:61:9 + | +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + = note: `#[warn(ptr_to_integer_transmute_in_consts)]` on by default + +error[E0080]: evaluation of constant value failed + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:68:26 + | +LL | const value: usize = zoom(&a); + | ^^^^^^^^ unable to turn pointer into integer + | + = 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 + +warning: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:3:9 + | +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + +warning: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:13:13 + | +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + +warning: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:30:13 + | +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + +error: aborting due to 1 previous error; 4 warnings emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-unwrap.rs b/tests/ui/consts/const-unwrap.rs index bc79c7db2fc..ea0a15af1be 100644 --- a/tests/ui/consts/const-unwrap.rs +++ b/tests/ui/consts/const-unwrap.rs @@ -1,11 +1,15 @@ //@ check-fail - -#![feature(const_option)] +// Verify that panicking `const_option` methods do the correct thing const FOO: i32 = Some(42i32).unwrap(); const BAR: i32 = Option::<i32>::None.unwrap(); -//~^ERROR: evaluation of constant value failed +//~^ ERROR: evaluation of constant value failed +//~| NOTE: the evaluated program panicked + +const BAZ: i32 = Option::<i32>::None.expect("absolutely not!"); +//~^ ERROR: evaluation of constant value failed +//~| NOTE: absolutely not! fn main() { println!("{}", FOO); diff --git a/tests/ui/consts/const-unwrap.stderr b/tests/ui/consts/const-unwrap.stderr index fee22a1d070..aa5dd9a5c36 100644 --- a/tests/ui/consts/const-unwrap.stderr +++ b/tests/ui/consts/const-unwrap.stderr @@ -1,9 +1,15 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-unwrap.rs:7:18 + --> $DIR/const-unwrap.rs:6:18 | LL | const BAR: i32 = Option::<i32>::None.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'called `Option::unwrap()` on a `None` value', $DIR/const-unwrap.rs:7:38 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'called `Option::unwrap()` on a `None` value', $DIR/const-unwrap.rs:6:38 -error: aborting due to 1 previous error +error[E0080]: evaluation of constant value failed + --> $DIR/const-unwrap.rs:10:18 + | +LL | const BAZ: i32 = Option::<i32>::None.expect("absolutely not!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'absolutely not!', $DIR/const-unwrap.rs:10:38 + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 56c4b6ea36f..2e30eebb07b 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -1,6 +1,6 @@ //@ known-bug: #103507 -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_vec_string_slice)] struct Foo<'a> { bar: &'a mut Vec<usize>, diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index ebfa09b2e5d..a85c5e10374 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -1,11 +1,3 @@ -error[E0015]: cannot call non-const fn `Vec::<u32>::len` in constant functions - --> $DIR/issue-94675.rs:11:27 - | -LL | self.bar[0] = baz.len(); - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - error[E0015]: cannot call non-const operator in constant functions --> $DIR/issue-94675.rs:11:17 | @@ -20,6 +12,6 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-77062-large-zst-array.rs b/tests/ui/consts/large-zst-array-77062.rs index ef5178fba95..089353d0885 100644 --- a/tests/ui/consts/issue-77062-large-zst-array.rs +++ b/tests/ui/consts/large-zst-array-77062.rs @@ -1,4 +1,5 @@ //@ build-pass +pub static FOO: [(); usize::MAX] = [(); usize::MAX]; fn main() { let _ = &[(); usize::MAX]; diff --git a/tests/ui/consts/load-preserves-partial-init.rs b/tests/ui/consts/load-preserves-partial-init.rs index d97e9cb3d9d..2a8adbd5e16 100644 --- a/tests/ui/consts/load-preserves-partial-init.rs +++ b/tests/ui/consts/load-preserves-partial-init.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(const_ptr_write)] // issue: https://github.com/rust-lang/rust/issues/69488 // Loads of partially-initialized data could produce completely-uninitialized results. // Test to make sure that we no longer do such a "deinitializing" load. diff --git a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr index 3b861d784d8..19e7a723a22 100644 --- a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr +++ b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr @@ -1,4 +1,4 @@ -error[E0607]: cannot cast thin pointer `*const [i64; 0]` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const [i64; 0]` to wide pointer `*const [u8]` --> $DIR/slice_elem_ty_mismatch_in_unsizing_cast.rs:1:31 | LL | const FOO: &str = unsafe { &*(1_usize as *const [i64; 0] as *const [u8] as *const str) }; diff --git a/tests/ui/coverage-attr/bad-attr-ice.rs b/tests/ui/coverage-attr/bad-attr-ice.rs index ae4d27d65eb..55c86d260d4 100644 --- a/tests/ui/coverage-attr/bad-attr-ice.rs +++ b/tests/ui/coverage-attr/bad-attr-ice.rs @@ -1,7 +1,7 @@ #![cfg_attr(feat, feature(coverage_attribute))] //@ revisions: feat nofeat //@ compile-flags: -Cinstrument-coverage -//@ needs-profiler-support +//@ needs-profiler-runtime // Malformed `#[coverage(..)]` attributes should not cause an ICE when built // with `-Cinstrument-coverage`. diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index 03ded300bb4..6a627be3b64 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -3,22 +3,6 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -warning: this function depends on never type fallback being `()` - --> $DIR/unsupported.rs:20:9 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/unsupported.rs:20:28 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default - error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}` --> $DIR/unsupported.rs:27:25 | @@ -52,6 +36,22 @@ note: in edition 2024, the requirement `!: opaque::Trait` will fail | LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } | ^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: this function depends on never type fallback being `()` + --> $DIR/unsupported.rs:20:9 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/unsupported.rs:20:28 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:25>::{synthetic#0}` --> $DIR/unsupported.rs:30:24 diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-smart-pointer-neg.rs index f02fb56130f..41d3039236f 100644 --- a/tests/ui/deriving/deriving-smart-pointer-neg.rs +++ b/tests/ui/deriving/deriving-smart-pointer-neg.rs @@ -53,6 +53,39 @@ struct NoMaybeSized<'a, #[pointee] T> { ptr: &'a T, } +#[derive(SmartPointer)] +#[repr(transparent)] +struct PointeeOnField<'a, #[pointee] T: ?Sized> { + #[pointee] + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + ptr: &'a T +} + +#[derive(SmartPointer)] +#[repr(transparent)] +struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> { + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + ptr: &'a T, +} + +#[derive(SmartPointer)] +#[repr(transparent)] +struct PointeeInConstConstBlock< + 'a, + T: ?Sized, + const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }> + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters +{ + ptr: &'a T, +} + +#[derive(SmartPointer)] +#[repr(transparent)] +struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> { + ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }> + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters +} + // However, reordering attributes should work nevertheless. #[repr(transparent)] #[derive(SmartPointer)] diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr index e7c2afc8b00..9ab117698c7 100644 --- a/tests/ui/deriving/deriving-smart-pointer-neg.stderr +++ b/tests/ui/deriving/deriving-smart-pointer-neg.stderr @@ -58,6 +58,30 @@ error: `derive(SmartPointer)` requires T to be marked `?Sized` LL | struct NoMaybeSized<'a, #[pointee] T> { | ^ +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-smart-pointer-neg.rs:59:5 + | +LL | #[pointee] + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-smart-pointer-neg.rs:66:74 + | +LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> { + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-smart-pointer-neg.rs:76:34 + | +LL | const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }> + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-smart-pointer-neg.rs:85:56 + | +LL | ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }> + | ^^^^^^^^^^ + error[E0392]: lifetime parameter `'a` is never used --> $DIR/deriving-smart-pointer-neg.rs:15:16 | @@ -90,6 +114,6 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -error: aborting due to 12 previous errors +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/object-safety/almost-supertrait-associated-type.rs b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs index 963cdff526e..83076f7d5fc 100644 --- a/tests/ui/object-safety/almost-supertrait-associated-type.rs +++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs @@ -1,5 +1,5 @@ // Test for fixed unsoundness in #126079. -// Enforces that the associated types that are object safe +// Enforces that the associated types that are dyn-compatible. use std::marker::PhantomData; diff --git a/tests/ui/object-safety/almost-supertrait-associated-type.stderr b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr index 99bcccc20c0..99bcccc20c0 100644 --- a/tests/ui/object-safety/almost-supertrait-associated-type.stderr +++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr diff --git a/tests/ui/object-safety/assoc_const_bounds.rs b/tests/ui/dyn-compatibility/assoc_const_bounds.rs index 32c4de1981b..32c4de1981b 100644 --- a/tests/ui/object-safety/assoc_const_bounds.rs +++ b/tests/ui/dyn-compatibility/assoc_const_bounds.rs diff --git a/tests/ui/object-safety/assoc_const_bounds_sized.rs b/tests/ui/dyn-compatibility/assoc_const_bounds_sized.rs index 1272a735e83..1272a735e83 100644 --- a/tests/ui/object-safety/assoc_const_bounds_sized.rs +++ b/tests/ui/dyn-compatibility/assoc_const_bounds_sized.rs diff --git a/tests/ui/object-safety/assoc_type_bounds.rs b/tests/ui/dyn-compatibility/assoc_type_bounds.rs index 8634ba626a1..8634ba626a1 100644 --- a/tests/ui/object-safety/assoc_type_bounds.rs +++ b/tests/ui/dyn-compatibility/assoc_type_bounds.rs diff --git a/tests/ui/object-safety/assoc_type_bounds.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds.stderr index 3d5482625af..3d5482625af 100644 --- a/tests/ui/object-safety/assoc_type_bounds.stderr +++ b/tests/ui/dyn-compatibility/assoc_type_bounds.stderr diff --git a/tests/ui/object-safety/assoc_type_bounds2.rs b/tests/ui/dyn-compatibility/assoc_type_bounds2.rs index f7dc2fb8839..f7dc2fb8839 100644 --- a/tests/ui/object-safety/assoc_type_bounds2.rs +++ b/tests/ui/dyn-compatibility/assoc_type_bounds2.rs diff --git a/tests/ui/object-safety/assoc_type_bounds2.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr index 815747436bf..815747436bf 100644 --- a/tests/ui/object-safety/assoc_type_bounds2.stderr +++ b/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed b/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.fixed index 88697bad4d7..88697bad4d7 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.fixed diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs b/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.rs index 944b296aa4d..944b296aa4d 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.rs diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.stderr index 9bb770ce431..9bb770ce431 100644 --- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.stderr diff --git a/tests/ui/object-safety/assoc_type_bounds_sized.rs b/tests/ui/dyn-compatibility/assoc_type_bounds_sized.rs index 7535871afe5..7535871afe5 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized.rs +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_sized.rs diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_others.rs b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_others.rs index 5b07bc92f32..5b07bc92f32 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_others.rs +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_others.rs diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_others.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_others.stderr index 5438faaaf05..5438faaaf05 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_others.stderr +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_others.stderr diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_unnecessary.rs index e9216da5927..e9216da5927 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_unnecessary.rs diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_unnecessary.stderr index aaadc4ed7b1..aaadc4ed7b1 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_unnecessary.stderr diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.rs b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.rs index d59fc1712ea..d59fc1712ea 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.rs +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.rs diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.stderr index b67a1244ece..b67a1244ece 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.stderr diff --git a/tests/ui/object-safety/object-safety-associated-consts.curr.stderr b/tests/ui/dyn-compatibility/associated-consts.curr.stderr index 3c070f17c82..17d184942c7 100644 --- a/tests/ui/object-safety/object-safety-associated-consts.curr.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.curr.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-associated-consts.rs:12:31 + --> $DIR/associated-consts.rs:12:31 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-associated-consts.rs:9:11 + --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -14,13 +14,13 @@ LL | const X: usize; = help: consider moving `X` to another trait error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-associated-consts.rs:14:5 + --> $DIR/associated-consts.rs:14:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-associated-consts.rs:9:11 + --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr index 5b98cc35505..cc5120232c2 100644 --- a/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-associated-consts.rs:14:5 + --> $DIR/associated-consts.rs:14:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-associated-consts.rs:9:11 + --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-associated-consts.rs b/tests/ui/dyn-compatibility/associated-consts.rs index a090214bbb4..fc7b372b782 100644 --- a/tests/ui/object-safety/object-safety-associated-consts.rs +++ b/tests/ui/dyn-compatibility/associated-consts.rs @@ -1,9 +1,9 @@ // Check that we correctly prevent users from making trait objects // from traits with associated consts. // -//@ revisions: curr object_safe_for_dispatch +//@ revisions: curr dyn_compatible_for_dispatch -#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] +#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))] trait Bar { const X: usize; diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.new.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.new.stderr new file mode 100644 index 00000000000..83795f3128e --- /dev/null +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.new.stderr @@ -0,0 +1,19 @@ +error[E0782]: expected a type, found a trait + --> $DIR/avoid-ice-on-warning-2.rs:4:13 + | +LL | fn id<F>(f: Copy) -> usize { + | ^^^^ + | + = note: `Copy` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `Copy` + | +LL | fn id<F, T: Copy>(f: T) -> usize { + | +++++++++ ~ +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 id<F>(f: impl Copy) -> usize { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr index 180cd679dea..54daefea31c 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr @@ -36,7 +36,7 @@ LL | fn id<F>(f: Copy) -> usize { = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> error[E0618]: expected function, found `(dyn Copy + 'static)` - --> $DIR/avoid-ice-on-warning-2.rs:11:5 + --> $DIR/avoid-ice-on-warning-2.rs:12:5 | LL | fn id<F>(f: Copy) -> usize { | - `f` has type `(dyn Copy + 'static)` diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.rs b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs index db2f4aea05b..3c2da667b39 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-2.rs +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs @@ -2,13 +2,14 @@ //@[old] edition:2015 //@[new] edition:2021 fn id<F>(f: Copy) -> usize { -//~^ ERROR the trait `Copy` cannot be made into an object -//~| ERROR: the size for values of type `(dyn Copy + 'static)` +//[new]~^ ERROR expected a type, found a trait +//[old]~^^ ERROR the trait `Copy` cannot be made into an object +//[old]~| ERROR the size for values of type `(dyn Copy + 'static)` //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! f() - //~^ ERROR: expected function, found `(dyn Copy + 'static)` + //[old]~^ ERROR: expected function, found `(dyn Copy + 'static)` } fn main() {} diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.new.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.new.stderr new file mode 100644 index 00000000000..813b5863738 --- /dev/null +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.new.stderr @@ -0,0 +1,57 @@ +error[E0782]: expected a type, found a trait + --> $DIR/avoid-ice-on-warning-3.rs:14:19 + | +LL | trait A { fn g(b: B) -> B; } + | ^ + | + = note: `B` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `B` + | +LL | trait A { fn g<T: B>(b: T) -> B; } + | ++++++ ~ +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 | trait A { fn g(b: impl B) -> B; } + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/avoid-ice-on-warning-3.rs:14:25 + | +LL | trait A { fn g(b: B) -> B; } + | ^ + | +help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as you return a single underlying type + | +LL | trait A { fn g(b: B) -> impl B; } + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/avoid-ice-on-warning-3.rs:4:19 + | +LL | trait B { fn f(a: A) -> A; } + | ^ + | + = note: `A` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `A` + | +LL | trait B { fn f<T: A>(a: T) -> A; } + | ++++++ ~ +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 | trait B { fn f(a: impl A) -> A; } + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/avoid-ice-on-warning-3.rs:4:25 + | +LL | trait B { fn f(a: A) -> A; } + | ^ + | +help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as you return a single underlying type + | +LL | trait B { fn f(a: A) -> impl A; } + | ++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr index bd362abb355..6bc2d73a0d0 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr @@ -26,7 +26,7 @@ LL | trait B { fn f(a: A) -> dyn A; } | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/avoid-ice-on-warning-3.rs:12:19 + --> $DIR/avoid-ice-on-warning-3.rs:14:19 | LL | trait A { fn g(b: B) -> B; } | ^ @@ -39,7 +39,7 @@ LL | trait A { fn g(b: dyn B) -> B; } | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/avoid-ice-on-warning-3.rs:12:25 + --> $DIR/avoid-ice-on-warning-3.rs:14:25 | LL | trait A { fn g(b: B) -> B; } | ^ @@ -72,7 +72,7 @@ LL | trait B { fn f(a: A) -> A; } | ^ `A` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/avoid-ice-on-warning-3.rs:12:14 + --> $DIR/avoid-ice-on-warning-3.rs:14:14 | LL | trait A { fn g(b: B) -> B; } | - ^ ...because associated function `g` has no `self` parameter @@ -88,7 +88,7 @@ LL | trait A { fn g(b: B) -> B where Self: Sized; } | +++++++++++++++++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/avoid-ice-on-warning-3.rs:12:19 + --> $DIR/avoid-ice-on-warning-3.rs:14:19 | LL | trait A { fn g(b: B) -> B; } | ^ @@ -102,7 +102,7 @@ LL | trait A { fn g(b: dyn B) -> B; } | +++ error[E0038]: the trait `B` cannot be made into an object - --> $DIR/avoid-ice-on-warning-3.rs:12:19 + --> $DIR/avoid-ice-on-warning-3.rs:14:19 | LL | trait A { fn g(b: B) -> B; } | ^ `B` cannot be made into an object diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.rs b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs index 38bee8142bb..00d47225e92 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-3.rs +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs @@ -2,7 +2,9 @@ //@[old] edition:2015 //@[new] edition:2021 trait B { fn f(a: A) -> A; } -//~^ ERROR the trait `A` cannot be made into an object +//[new]~^ ERROR expected a type, found a trait +//[new]~| ERROR expected a type, found a trait +//[old]~^^^ ERROR the trait `A` cannot be made into an object //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN trait objects without an explicit `dyn` are deprecated @@ -10,7 +12,9 @@ trait B { fn f(a: A) -> A; } //[old]~| WARN this is accepted in the current edition //[old]~| WARN this is accepted in the current edition trait A { fn g(b: B) -> B; } -//~^ ERROR the trait `B` cannot be made into an object +//[new]~^ ERROR expected a type, found a trait +//[new]~| ERROR expected a type, found a trait +//[old]~^^^ ERROR the trait `B` cannot be made into an object //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN trait objects without an explicit `dyn` are deprecated diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning.new.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning.new.stderr new file mode 100644 index 00000000000..e9eb1cdd0c2 --- /dev/null +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning.new.stderr @@ -0,0 +1,32 @@ +error: return types are denoted using `->` + --> $DIR/avoid-ice-on-warning.rs:4:23 + | +LL | fn call_this<F>(f: F) : Fn(&str) + call_that {} + | ^ + | +help: use `->` instead + | +LL | fn call_this<F>(f: F) -> Fn(&str) + call_that {} + | ~~ + +error[E0405]: cannot find trait `call_that` in this scope + --> $DIR/avoid-ice-on-warning.rs:4:36 + | +LL | fn call_this<F>(f: F) : Fn(&str) + call_that {} + | ^^^^^^^^^ not found in this scope + +error[E0782]: expected a type, found a trait + --> $DIR/avoid-ice-on-warning.rs:4:25 + | +LL | fn call_this<F>(f: F) : Fn(&str) + call_that {} + | ^^^^^^^^^^^^^^^^^^^^ + | +help: `Fn(&str) + call_that` is dyn-incompatible, use `impl Fn(&str) + call_that` to return an opaque type, as long as you return a single underlying type + | +LL | fn call_this<F>(f: F) : impl Fn(&str) + call_that {} + | ++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0405, E0782. +For more information about an error, try `rustc --explain E0405`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr index 646fb57af9e..646fb57af9e 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr diff --git a/tests/ui/object-safety/avoid-ice-on-warning.rs b/tests/ui/dyn-compatibility/avoid-ice-on-warning.rs index b90d8911d50..ef82321df0e 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning.rs +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning.rs @@ -4,6 +4,7 @@ fn call_this<F>(f: F) : Fn(&str) + call_that {} //~^ ERROR return types are denoted using `->` //~| ERROR cannot find trait `call_that` in this scope +//[new]~| ERROR expected a type, found a trait //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! fn main() {} diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed index 4f5310082e1..a54892afd3e 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed +++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed @@ -4,7 +4,8 @@ //@[new] run-rustfix #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> impl Ord { - //~^ ERROR the trait `Ord` cannot be made into an object + //[new]~^ ERROR expected a type, found a trait + //[old]~^^ ERROR the trait `Ord` cannot be made into an object //[old]~| ERROR trait objects without an explicit `dyn` are deprecated //[old]~| WARNING this is accepted in the current edition (Rust 2015) (s.starts_with("."), s) diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.stderr b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.stderr new file mode 100644 index 00000000000..52168261a64 --- /dev/null +++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.stderr @@ -0,0 +1,14 @@ +error[E0782]: expected a type, found a trait + --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33 + | +LL | fn ord_prefer_dot(s: String) -> Ord { + | ^^^ + | +help: `Ord` is dyn-incompatible, use `impl Ord` to return an opaque type, as long as you return a single underlying type + | +LL | fn ord_prefer_dot(s: String) -> impl Ord { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr index 45c9b0ce5d9..45c9b0ce5d9 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr +++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs index cb5a305eab0..cf9be612d2e 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs +++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs @@ -4,7 +4,8 @@ //@[new] run-rustfix #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> Ord { - //~^ ERROR the trait `Ord` cannot be made into an object + //[new]~^ ERROR expected a type, found a trait + //[old]~^^ ERROR the trait `Ord` cannot be made into an object //[old]~| ERROR trait objects without an explicit `dyn` are deprecated //[old]~| WARNING this is accepted in the current edition (Rust 2015) (s.starts_with("."), s) diff --git a/tests/ui/object-safety/object-safety-bounds.rs b/tests/ui/dyn-compatibility/bounds.rs index 44bd369324a..1e04d11c516 100644 --- a/tests/ui/object-safety/object-safety-bounds.rs +++ b/tests/ui/dyn-compatibility/bounds.rs @@ -1,4 +1,4 @@ -// Traits with bounds mentioning `Self` are not object safe +// Traits with bounds mentioning `Self` are dyn-incompatible. trait X { type U: PartialEq<Self>; diff --git a/tests/ui/object-safety/object-safety-bounds.stderr b/tests/ui/dyn-compatibility/bounds.stderr index 96a81a69639..9231d524fd1 100644 --- a/tests/ui/object-safety/object-safety-bounds.stderr +++ b/tests/ui/dyn-compatibility/bounds.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `X` cannot be made into an object - --> $DIR/object-safety-bounds.rs:7:15 + --> $DIR/bounds.rs:7:15 | LL | fn f() -> Box<dyn X<U = u32>> { | ^^^^^^^^^^^^^^ `X` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-bounds.rs:4:13 + --> $DIR/bounds.rs:4:13 | LL | trait X { | - this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-by-value-self-use.rs b/tests/ui/dyn-compatibility/by-value-self-use.rs index 8e93c538217..3c04ec0cd88 100644 --- a/tests/ui/object-safety/object-safety-by-value-self-use.rs +++ b/tests/ui/dyn-compatibility/by-value-self-use.rs @@ -1,4 +1,4 @@ -// Check that while a trait with by-value self is object-safe, we +// Check that while a trait with by-value self is dyn-compatible, we // can't actually invoke it from an object (yet...?). #![feature(rustc_attrs)] diff --git a/tests/ui/object-safety/object-safety-by-value-self-use.stderr b/tests/ui/dyn-compatibility/by-value-self-use.stderr index 1701f6059a8..14785b982a3 100644 --- a/tests/ui/object-safety/object-safety-by-value-self-use.stderr +++ b/tests/ui/dyn-compatibility/by-value-self-use.stderr @@ -1,5 +1,5 @@ error[E0161]: cannot move a value of type `dyn Bar` - --> $DIR/object-safety-by-value-self-use.rs:15:5 + --> $DIR/by-value-self-use.rs:15:5 | LL | t.bar() | ^ the size of `dyn Bar` cannot be statically determined diff --git a/tests/ui/object-safety/object-safety-by-value-self.rs b/tests/ui/dyn-compatibility/by-value-self.rs index 0d20032327c..a057a7ff0b5 100644 --- a/tests/ui/object-safety/object-safety-by-value-self.rs +++ b/tests/ui/dyn-compatibility/by-value-self.rs @@ -1,4 +1,4 @@ -// Check that a trait with by-value self is considered object-safe. +// Check that a trait with by-value self is considered dyn-compatible. //@ build-pass (FIXME(62277): could be check-pass?) #![allow(dead_code)] diff --git a/tests/ui/object-safety/call-when-assoc-ty-is-sized.rs b/tests/ui/dyn-compatibility/call-when-assoc-ty-is-sized.rs index 7a3a7f3ca2f..7a3a7f3ca2f 100644 --- a/tests/ui/object-safety/call-when-assoc-ty-is-sized.rs +++ b/tests/ui/dyn-compatibility/call-when-assoc-ty-is-sized.rs diff --git a/tests/ui/object-safety/issue-102933.rs b/tests/ui/dyn-compatibility/elaborated-predicates-ordering.rs index aa678fea176..d3c3963a673 100644 --- a/tests/ui/object-safety/issue-102933.rs +++ b/tests/ui/dyn-compatibility/elaborated-predicates-ordering.rs @@ -1,4 +1,5 @@ //@ check-pass +// issue: rust-lang/rust#102933 use std::future::Future; diff --git a/tests/ui/object-safety/erroneous_signature.rs b/tests/ui/dyn-compatibility/erroneous_signature.rs index cc1841cc4b2..cc1841cc4b2 100644 --- a/tests/ui/object-safety/erroneous_signature.rs +++ b/tests/ui/dyn-compatibility/erroneous_signature.rs diff --git a/tests/ui/object-safety/erroneous_signature.stderr b/tests/ui/dyn-compatibility/erroneous_signature.stderr index f3b14ffe34c..f3b14ffe34c 100644 --- a/tests/ui/object-safety/erroneous_signature.stderr +++ b/tests/ui/dyn-compatibility/erroneous_signature.stderr diff --git a/tests/ui/object-safety/object-safety-generics.curr.stderr b/tests/ui/dyn-compatibility/generics.curr.stderr index 7528785d90b..c63db38a080 100644 --- a/tests/ui/object-safety/object-safety-generics.curr.stderr +++ b/tests/ui/dyn-compatibility/generics.curr.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:18:31 + --> $DIR/generics.rs:18:31 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-generics.rs:10:8 + --> $DIR/generics.rs:10:8 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -14,13 +14,13 @@ LL | fn bar<T>(&self, t: T); = help: consider moving `bar` to another trait error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:25:40 + --> $DIR/generics.rs:25:40 | LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-generics.rs:10:8 + --> $DIR/generics.rs:10:8 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -29,13 +29,13 @@ LL | fn bar<T>(&self, t: T); = help: consider moving `bar` to another trait error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:20:5 + --> $DIR/generics.rs:20:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-generics.rs:10:8 + --> $DIR/generics.rs:10:8 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -45,13 +45,13 @@ LL | fn bar<T>(&self, t: T); = note: required for the cast from `&T` to `&dyn Bar` error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:27:10 + --> $DIR/generics.rs:27:10 | LL | t as &dyn Bar | ^^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-generics.rs:10:8 + --> $DIR/generics.rs:10:8 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -60,13 +60,13 @@ LL | fn bar<T>(&self, t: T); = help: consider moving `bar` to another trait error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:27:5 + --> $DIR/generics.rs:27:5 | LL | t as &dyn Bar | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-generics.rs:10:8 + --> $DIR/generics.rs:10:8 | LL | trait Bar { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr index 4686b994b33..ba2546ef2dc 100644 --- a/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:20:5 + --> $DIR/generics.rs:20:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-generics.rs:10:8 + --> $DIR/generics.rs:10:8 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -15,13 +15,13 @@ LL | fn bar<T>(&self, t: T); = note: required for the cast from `&T` to `&dyn Bar` error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:27:5 + --> $DIR/generics.rs:27:5 | LL | t as &dyn Bar | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-generics.rs:10:8 + --> $DIR/generics.rs:10:8 | LL | trait Bar { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-generics.rs b/tests/ui/dyn-compatibility/generics.rs index f005a689ac4..b51555aa500 100644 --- a/tests/ui/object-safety/object-safety-generics.rs +++ b/tests/ui/dyn-compatibility/generics.rs @@ -1,9 +1,9 @@ // Check that we correctly prevent users from making trait objects // from traits with generic methods, unless `where Self : Sized` is // present. -//@ revisions: curr object_safe_for_dispatch +//@ revisions: curr dyn_compatible_for_dispatch -#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] +#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))] trait Bar { @@ -18,14 +18,14 @@ trait Quux { fn make_bar<T:Bar>(t: &T) -> &dyn Bar { //[curr]~^ ERROR E0038 t - //[object_safe_for_dispatch]~^ ERROR E0038 + //[dyn_compatible_for_dispatch]~^ ERROR E0038 //[curr]~^^ ERROR E0038 } fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar { //[curr]~^ ERROR E0038 t as &dyn Bar - //[object_safe_for_dispatch]~^ ERROR E0038 + //[dyn_compatible_for_dispatch]~^ ERROR E0038 //[curr]~^^ ERROR E0038 //[curr]~| ERROR E0038 } diff --git a/tests/ui/object-safety/issue-106247.rs b/tests/ui/dyn-compatibility/impossible-predicates-multiple_supertrait_upcastable-check.rs index 20a451a59a1..c2b8ecc141d 100644 --- a/tests/ui/object-safety/issue-106247.rs +++ b/tests/ui/dyn-compatibility/impossible-predicates-multiple_supertrait_upcastable-check.rs @@ -1,4 +1,5 @@ //@ check-pass +// issue: rust-lang/rust#106247 pub trait Trait { fn method(&self) where Self: Sync; diff --git a/tests/ui/object-safety/item-bounds-can-reference-self.rs b/tests/ui/dyn-compatibility/item-bounds-can-reference-self.rs index 4ae982e8f95..4ae982e8f95 100644 --- a/tests/ui/object-safety/item-bounds-can-reference-self.rs +++ b/tests/ui/dyn-compatibility/item-bounds-can-reference-self.rs diff --git a/tests/ui/object-safety/issue-19538.rs b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.rs index 7054ef41b1c..1289d2d7874 100644 --- a/tests/ui/object-safety/issue-19538.rs +++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.rs @@ -1,3 +1,5 @@ +// issue: rust-lang/rust#19538 + trait Foo { fn foo<T>(&self, val: T); } diff --git a/tests/ui/object-safety/issue-19538.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr index 3dbe389686a..7378ec023c9 100644 --- a/tests/ui/object-safety/issue-19538.stderr +++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/issue-19538.rs:17:15 + --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:15 | LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/issue-19538.rs:2:8 + --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 | LL | fn foo<T>(&self, val: T); | ^^^ ...because method `foo` has generic type parameters @@ -16,13 +16,13 @@ LL | trait Bar: Foo { } = help: only type `Thing` implements the trait, consider using it directly instead error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/issue-19538.rs:17:30 + --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:30 | LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/issue-19538.rs:2:8 + --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 | LL | fn foo<T>(&self, val: T); | ^^^ ...because method `foo` has generic type parameters diff --git a/tests/ui/object-safety/object-safety-issue-22040.rs b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs index c9ec44cc0b8..c9ec44cc0b8 100644 --- a/tests/ui/object-safety/object-safety-issue-22040.rs +++ b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs diff --git a/tests/ui/object-safety/object-safety-issue-22040.stderr b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr index e5723f12258..7578edce7d1 100644 --- a/tests/ui/object-safety/object-safety-issue-22040.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Expr` cannot be made into an object - --> $DIR/object-safety-issue-22040.rs:12:23 + --> $DIR/mentions-Self-in-super-predicates.rs:12:23 | LL | elements: Vec<Box<dyn Expr + 'x>>, | ^^^^^^^^^^^^^ `Expr` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-issue-22040.rs:5:21 + --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { | ---- ^^^^^^^^^ ...because it uses `Self` as a type parameter @@ -14,13 +14,13 @@ LL | trait Expr: Debug + PartialEq { = help: only type `SExpr<'x>` implements the trait, consider using it directly instead error[E0038]: the trait `Expr` cannot be made into an object - --> $DIR/object-safety-issue-22040.rs:38:16 + --> $DIR/mentions-Self-in-super-predicates.rs:38:16 | LL | let a: Box<dyn Expr> = Box::new(SExpr::new()); | ^^^^^^^^ `Expr` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-issue-22040.rs:5:21 + --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { | ---- ^^^^^^^^^ ...because it uses `Self` as a type parameter @@ -29,13 +29,13 @@ LL | trait Expr: Debug + PartialEq { = help: only type `SExpr<'x>` implements the trait, consider using it directly instead error[E0038]: the trait `Expr` cannot be made into an object - --> $DIR/object-safety-issue-22040.rs:40:16 + --> $DIR/mentions-Self-in-super-predicates.rs:40:16 | LL | let b: Box<dyn Expr> = Box::new(SExpr::new()); | ^^^^^^^^ `Expr` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-issue-22040.rs:5:21 + --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { | ---- ^^^^^^^^^ ...because it uses `Self` as a type parameter diff --git a/tests/ui/object-safety/object-safety-mentions-Self.curr.stderr b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr index 7efb6ec3542..434e41cf218 100644 --- a/tests/ui/object-safety/object-safety-mentions-Self.curr.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:22:31 + --> $DIR/mentions-Self.rs:22:31 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-mentions-Self.rs:11:22 + --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -14,13 +14,13 @@ LL | fn bar(&self, x: &Self); = help: consider moving `bar` to another trait error[E0038]: the trait `Baz` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:28:31 + --> $DIR/mentions-Self.rs:28:31 | LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz { | ^^^^^^^ `Baz` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-mentions-Self.rs:15:22 + --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { | --- this trait cannot be made into an object... @@ -29,13 +29,13 @@ LL | fn baz(&self) -> Self; = help: consider moving `baz` to another trait error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:24:5 + --> $DIR/mentions-Self.rs:24:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-mentions-Self.rs:11:22 + --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -45,13 +45,13 @@ LL | fn bar(&self, x: &Self); = note: required for the cast from `&T` to `&dyn Bar` error[E0038]: the trait `Baz` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:30:5 + --> $DIR/mentions-Self.rs:30:5 | LL | t | ^ `Baz` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-mentions-Self.rs:15:22 + --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr index d0efb9c587e..dc2d1f87eb7 100644 --- a/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:24:5 + --> $DIR/mentions-Self.rs:24:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-mentions-Self.rs:11:22 + --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { | --- this trait cannot be made into an object... @@ -15,13 +15,13 @@ LL | fn bar(&self, x: &Self); = note: required for the cast from `&T` to `&dyn Bar` error[E0038]: the trait `Baz` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:30:5 + --> $DIR/mentions-Self.rs:30:5 | LL | t | ^ `Baz` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-mentions-Self.rs:15:22 + --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-mentions-Self.rs b/tests/ui/dyn-compatibility/mentions-Self.rs index 1311faf97bc..84c229e252d 100644 --- a/tests/ui/object-safety/object-safety-mentions-Self.rs +++ b/tests/ui/dyn-compatibility/mentions-Self.rs @@ -2,9 +2,9 @@ // form traits that make use of `Self` in an argument or return // position, unless `where Self : Sized` is present.. // -//@ revisions: curr object_safe_for_dispatch +//@ revisions: curr dyn_compatible_for_dispatch -#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] +#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))] trait Bar { diff --git a/tests/ui/traits/object/object-unsafe-missing-assoc-type.rs b/tests/ui/dyn-compatibility/missing-assoc-type.rs index c83be544c0a..c83be544c0a 100644 --- a/tests/ui/traits/object/object-unsafe-missing-assoc-type.rs +++ b/tests/ui/dyn-compatibility/missing-assoc-type.rs diff --git a/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr b/tests/ui/dyn-compatibility/missing-assoc-type.stderr index 9258b38f26c..f8450ba212d 100644 --- a/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr +++ b/tests/ui/dyn-compatibility/missing-assoc-type.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-unsafe-missing-assoc-type.rs:5:16 + --> $DIR/missing-assoc-type.rs:5:16 | LL | fn bar(x: &dyn Foo) {} | ^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 + --> $DIR/missing-assoc-type.rs:2:10 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -14,13 +14,13 @@ LL | type Bar<T>; = help: consider moving `Bar` to another trait error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-unsafe-missing-assoc-type.rs:5:16 + --> $DIR/missing-assoc-type.rs:5:16 | LL | fn bar(x: &dyn Foo) {} | ^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 + --> $DIR/missing-assoc-type.rs:2:10 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -30,13 +30,13 @@ LL | type Bar<T>; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-unsafe-missing-assoc-type.rs:5:16 + --> $DIR/missing-assoc-type.rs:5:16 | LL | fn bar(x: &dyn Foo) {} | ^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 + --> $DIR/missing-assoc-type.rs:2:10 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -46,13 +46,13 @@ LL | type Bar<T>; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-unsafe-missing-assoc-type.rs:5:12 + --> $DIR/missing-assoc-type.rs:5:12 | LL | fn bar(x: &dyn Foo) {} | ^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 + --> $DIR/missing-assoc-type.rs:2:10 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-no-static.curr.stderr b/tests/ui/dyn-compatibility/no-static.curr.stderr index 91c3d89602e..584db779855 100644 --- a/tests/ui/object-safety/object-safety-no-static.curr.stderr +++ b/tests/ui/dyn-compatibility/no-static.curr.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-no-static.rs:12:22 + --> $DIR/no-static.rs:12:22 | LL | fn diverges() -> Box<dyn Foo> { | ^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-no-static.rs:9:8 + --> $DIR/no-static.rs:9:8 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -22,13 +22,13 @@ LL | fn foo() where Self: Sized {} | +++++++++++++++++ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-no-static.rs:22:12 + --> $DIR/no-static.rs:22:12 | LL | let b: Box<dyn Foo> = Box::new(Bar); | ^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-no-static.rs:9:8 + --> $DIR/no-static.rs:9:8 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -45,13 +45,13 @@ LL | fn foo() where Self: Sized {} | +++++++++++++++++ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-no-static.rs:22:27 + --> $DIR/no-static.rs:22:27 | LL | let b: Box<dyn Foo> = Box::new(Bar); | ^^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-no-static.rs:9:8 + --> $DIR/no-static.rs:9:8 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr index 52f6865b6f3..f2deb3b8d84 100644 --- a/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-no-static.rs:22:27 + --> $DIR/no-static.rs:22:27 | LL | let b: Box<dyn Foo> = Box::new(Bar); | ^^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-no-static.rs:9:8 + --> $DIR/no-static.rs:9:8 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-no-static.rs b/tests/ui/dyn-compatibility/no-static.rs index 4f4e03d734e..54af16fe18e 100644 --- a/tests/ui/object-safety/object-safety-no-static.rs +++ b/tests/ui/dyn-compatibility/no-static.rs @@ -1,9 +1,9 @@ // Check that we correctly prevent users from making trait objects // from traits with static methods. // -//@ revisions: curr object_safe_for_dispatch +//@ revisions: curr dyn_compatible_for_dispatch -#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] +#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))] trait Foo { fn foo() {} diff --git a/tests/ui/object-safety/object-safety-phantom-fn.rs b/tests/ui/dyn-compatibility/phantom-fn.rs index 1019c24859f..9e410da82ee 100644 --- a/tests/ui/object-safety/object-safety-phantom-fn.rs +++ b/tests/ui/dyn-compatibility/phantom-fn.rs @@ -1,4 +1,4 @@ -// Check that `Self` appearing in a phantom fn does not make a trait not object safe. +// Check that `Self` appearing in a phantom fn does not make a trait dyn-incompatible. //@ build-pass (FIXME(62277): could be check-pass?) #![allow(dead_code)] diff --git a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs b/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs index dabaa309c16..7bc2af463cb 100644 --- a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs +++ b/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs @@ -6,104 +6,102 @@ struct IceCream; impl IceCream { fn foo(_: &Trait) {} - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait fn bar(self, _: &'a Trait) {} - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait //~| ERROR: use of undeclared lifetime name fn alice<'a>(&self, _: &Trait) {} - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait fn bob<'a>(_: &'a Trait) {} - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait fn cat() -> &Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait &Type } fn dog<'a>() -> &Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait &Type } fn kitten() -> &'a Trait { //~^ ERROR: use of undeclared lifetime name - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait &Type } fn puppy<'a>() -> &'a Trait { - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait &Type } fn parrot() -> &mut Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait &mut Type - //~^ ERROR: cannot return reference to temporary value } } trait Sing { fn foo(_: &Trait); - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait fn bar(_: &'a Trait); - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait //~| ERROR: use of undeclared lifetime name fn alice<'a>(_: &Trait); - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait fn bob<'a>(_: &'a Trait); - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait fn cat() -> &Trait; //~^ ERROR: missing lifetime specifier - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait fn dog<'a>() -> &Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait &Type } fn kitten() -> &'a Trait { //~^ ERROR: use of undeclared lifetime name - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait &Type } fn puppy<'a>() -> &'a Trait { - //~^ ERROR: trait objects must include the `dyn` keyword + //~^ ERROR: expected a type, found a trait &Type } fn parrot() -> &mut Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait &mut Type - //~^ ERROR: cannot return reference to temporary value } } fn foo(_: &Trait) {} -//~^ ERROR: trait objects must include the `dyn` keyword +//~^ ERROR: expected a type, found a trait fn bar(_: &'a Trait) {} -//~^ ERROR: trait objects must include the `dyn` keyword +//~^ ERROR: expected a type, found a trait //~| ERROR: use of undeclared lifetime name fn alice<'a>(_: &Trait) {} -//~^ ERROR: trait objects must include the `dyn` keyword +//~^ ERROR: expected a type, found a trait fn bob<'a>(_: &'a Trait) {} -//~^ ERROR: trait objects must include the `dyn` keyword +//~^ ERROR: expected a type, found a trait struct Type; @@ -111,32 +109,31 @@ impl Trait for Type {} fn cat() -> &Trait { //~^ ERROR: missing lifetime specifier -//~| ERROR: trait objects must include the `dyn` keyword +//~| ERROR: expected a type, found a trait &Type } fn dog<'a>() -> &Trait { //~^ ERROR: missing lifetime specifier -//~| ERROR: trait objects must include the `dyn` keyword +//~| ERROR: expected a type, found a trait &Type } fn kitten() -> &'a Trait { //~^ ERROR: use of undeclared lifetime name -//~| ERROR: trait objects must include the `dyn` keyword +//~| ERROR: expected a type, found a trait &Type } fn puppy<'a>() -> &'a Trait { -//~^ ERROR: trait objects must include the `dyn` keyword +//~^ ERROR: expected a type, found a trait &Type } fn parrot() -> &mut Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: trait objects must include the `dyn` keyword + //~| ERROR: expected a type, found a trait &mut Type - //~^ ERROR: cannot return reference to temporary value } fn main() {} diff --git a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr b/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr index 8bdfea7766e..4c6d84f0534 100644 --- a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr +++ b/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr @@ -65,7 +65,7 @@ LL | fn parrot() -> &'static mut Trait { | +++++++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:56:16 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:55:16 | LL | fn bar(_: &'a Trait); | ^^ undeclared lifetime @@ -80,7 +80,7 @@ LL | trait Sing<'a> { | ++++ error[E0106]: missing lifetime specifier - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:66:17 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:65:17 | LL | fn cat() -> &Trait; | ^ expected named lifetime parameter @@ -97,7 +97,7 @@ LL + fn cat() -> Trait; | error[E0106]: missing lifetime specifier - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:70:21 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:69:21 | LL | fn dog<'a>() -> &Trait { | ^ expected named lifetime parameter @@ -109,7 +109,7 @@ LL | fn dog<'a>() -> &'a Trait { | ++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:76:21 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:75:21 | LL | fn kitten() -> &'a Trait { | ^^ undeclared lifetime @@ -124,7 +124,7 @@ LL | trait Sing<'a> { | ++++ error[E0106]: missing lifetime specifier - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:20 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:86:20 | LL | fn parrot() -> &mut Trait { | ^ expected named lifetime parameter @@ -136,7 +136,7 @@ LL | fn parrot() -> &'static mut Trait { | +++++++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:98:12 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:96:12 | LL | fn bar(_: &'a Trait) {} | - ^^ undeclared lifetime @@ -144,7 +144,7 @@ LL | fn bar(_: &'a Trait) {} | help: consider introducing lifetime `'a` here: `<'a>` error[E0106]: missing lifetime specifier - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:112:13 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:110:13 | LL | fn cat() -> &Trait { | ^ expected named lifetime parameter @@ -156,7 +156,7 @@ LL | fn cat() -> &'static Trait { | +++++++ error[E0106]: missing lifetime specifier - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:118:17 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:116:17 | LL | fn dog<'a>() -> &Trait { | ^ expected named lifetime parameter @@ -168,7 +168,7 @@ LL | fn dog<'a>() -> &'a Trait { | ++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:124:17 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:122:17 | LL | fn kitten() -> &'a Trait { | - ^^ undeclared lifetime @@ -176,7 +176,7 @@ LL | fn kitten() -> &'a Trait { | help: consider introducing lifetime `'a` here: `<'a>` error[E0106]: missing lifetime specifier - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:16 + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:133:16 | LL | fn parrot() -> &mut Trait { | ^ expected named lifetime parameter @@ -187,35 +187,8 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're LL | fn parrot() -> &'static mut Trait { | +++++++ -error[E0515]: cannot return reference to temporary value - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:47:9 - | -LL | &mut Type - | ^^^^^---- - | | | - | | temporary value created here - | returns a reference to data owned by the current function - -error[E0515]: cannot return reference to temporary value - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:90:9 - | -LL | &mut Type - | ^^^^^---- - | | | - | | temporary value created here - | returns a reference to data owned by the current function - -error[E0515]: cannot return reference to temporary value - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:138:5 - | -LL | &mut Type - | ^^^^^---- - | | | - | | temporary value created here - | returns a reference to data owned by the current function - -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:53:16 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:52:16 | LL | fn foo(_: &Trait); | ^^^^^ @@ -233,8 +206,8 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn foo(_: &dyn Trait); | +++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:56:19 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:55:19 | LL | fn bar(_: &'a Trait); | ^^^^^ @@ -252,8 +225,8 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn bar(_: &'a dyn Trait); | +++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:60:22 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:59:22 | LL | fn alice<'a>(_: &Trait); | ^^^^^ @@ -271,8 +244,8 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn alice<'a>(_: &dyn Trait); | +++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:63:23 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:62:23 | LL | fn bob<'a>(_: &'a Trait); | ^^^^^ @@ -290,8 +263,8 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn bob<'a>(_: &'a dyn Trait); | +++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:66:18 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:65:18 | LL | fn cat() -> &Trait; | ^^^^^ @@ -305,8 +278,8 @@ help: alternatively, you can return an owned trait object LL | fn cat() -> Box<dyn Trait>; | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:70:22 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:69:22 | LL | fn dog<'a>() -> &Trait { | ^^^^^ @@ -320,8 +293,8 @@ help: alternatively, you can return an owned trait object LL | fn dog<'a>() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:76:24 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:75:24 | LL | fn kitten() -> &'a Trait { | ^^^^^ @@ -335,8 +308,8 @@ help: alternatively, you can return an owned trait object LL | fn kitten() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:82:27 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:81:27 | LL | fn puppy<'a>() -> &'a Trait { | ^^^^^ @@ -350,8 +323,8 @@ help: alternatively, you can return an owned trait object LL | fn puppy<'a>() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:25 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:86:25 | LL | fn parrot() -> &mut Trait { | ^^^^^ @@ -365,8 +338,8 @@ help: alternatively, you can return an owned trait object LL | fn parrot() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:95:12 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:93:12 | LL | fn foo(_: &Trait) {} | ^^^^^ @@ -384,8 +357,8 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn foo(_: &dyn Trait) {} | +++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:98:15 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:96:15 | LL | fn bar(_: &'a Trait) {} | ^^^^^ @@ -403,8 +376,8 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn bar(_: &'a dyn Trait) {} | +++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:102:18 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:100:18 | LL | fn alice<'a>(_: &Trait) {} | ^^^^^ @@ -422,8 +395,8 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn alice<'a>(_: &dyn Trait) {} | +++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:105:19 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:103:19 | LL | fn bob<'a>(_: &'a Trait) {} | ^^^^^ @@ -441,8 +414,8 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn bob<'a>(_: &'a dyn Trait) {} | +++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:112:14 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:110:14 | LL | fn cat() -> &Trait { | ^^^^^ @@ -456,8 +429,8 @@ help: alternatively, you can return an owned trait object LL | fn cat() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:118:18 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:116:18 | LL | fn dog<'a>() -> &Trait { | ^^^^^ @@ -471,8 +444,8 @@ help: alternatively, you can return an owned trait object LL | fn dog<'a>() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:124:20 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:122:20 | LL | fn kitten() -> &'a Trait { | ^^^^^ @@ -486,8 +459,8 @@ help: alternatively, you can return an owned trait object LL | fn kitten() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:130:23 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:128:23 | LL | fn puppy<'a>() -> &'a Trait { | ^^^^^ @@ -501,8 +474,8 @@ help: alternatively, you can return an owned trait object LL | fn puppy<'a>() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:21 +error[E0782]: expected a type, found a trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:133:21 | LL | fn parrot() -> &mut Trait { | ^^^^^ @@ -516,7 +489,7 @@ help: alternatively, you can return an owned trait object LL | fn parrot() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:8:16 | LL | fn foo(_: &Trait) {} @@ -535,7 +508,7 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn foo(_: &dyn Trait) {} | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:11:25 | LL | fn bar(self, _: &'a Trait) {} @@ -554,7 +527,7 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn bar(self, _: &'a dyn Trait) {} | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:15:29 | LL | fn alice<'a>(&self, _: &Trait) {} @@ -573,7 +546,7 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn alice<'a>(&self, _: &dyn Trait) {} | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:18:23 | LL | fn bob<'a>(_: &'a Trait) {} @@ -592,7 +565,7 @@ help: alternatively, use a trait object to accept any type that implements `Trai LL | fn bob<'a>(_: &'a dyn Trait) {} | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:21:18 | LL | fn cat() -> &Trait { @@ -607,7 +580,7 @@ help: alternatively, you can return an owned trait object LL | fn cat() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:27:22 | LL | fn dog<'a>() -> &Trait { @@ -622,7 +595,7 @@ help: alternatively, you can return an owned trait object LL | fn dog<'a>() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:33:24 | LL | fn kitten() -> &'a Trait { @@ -637,7 +610,7 @@ help: alternatively, you can return an owned trait object LL | fn kitten() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:39:27 | LL | fn puppy<'a>() -> &'a Trait { @@ -652,7 +625,7 @@ help: alternatively, you can return an owned trait object LL | fn puppy<'a>() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:44:25 | LL | fn parrot() -> &mut Trait { @@ -667,7 +640,7 @@ help: alternatively, you can return an owned trait object LL | fn parrot() -> Box<dyn Trait> { | ~~~~~~~~~~~~~~ -error: aborting due to 45 previous errors +error: aborting due to 42 previous errors -Some errors have detailed explanations: E0106, E0261, E0515, E0782. +Some errors have detailed explanations: E0106, E0261, E0782. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/object-safety/object-safety-sized-2.curr.stderr b/tests/ui/dyn-compatibility/sized-2.curr.stderr index 4ce7ac5704e..1017fde53d3 100644 --- a/tests/ui/object-safety/object-safety-sized-2.curr.stderr +++ b/tests/ui/dyn-compatibility/sized-2.curr.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized-2.rs:14:31 + --> $DIR/sized-2.rs:14:31 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-sized-2.rs:9:18 + --> $DIR/sized-2.rs:9:18 | LL | trait Bar | --- this trait cannot be made into an object... @@ -13,13 +13,13 @@ LL | where Self : Sized | ^^^^^ ...because it requires `Self: Sized` error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized-2.rs:16:5 + --> $DIR/sized-2.rs:16:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-sized-2.rs:9:18 + --> $DIR/sized-2.rs:9:18 | LL | trait Bar | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr index 99066c104b7..534cf0f1b03 100644 --- a/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized-2.rs:16:5 + --> $DIR/sized-2.rs:16:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-sized-2.rs:9:18 + --> $DIR/sized-2.rs:9:18 | LL | trait Bar | --- this trait cannot be made into an object... diff --git a/tests/ui/object-safety/object-safety-sized-2.rs b/tests/ui/dyn-compatibility/sized-2.rs index cfb5d588d70..f5edd287f24 100644 --- a/tests/ui/object-safety/object-safety-sized-2.rs +++ b/tests/ui/dyn-compatibility/sized-2.rs @@ -1,9 +1,9 @@ // Check that we correctly prevent users from making trait objects // from traits where `Self : Sized`. // -//@ revisions: curr object_safe_for_dispatch +//@ revisions: curr dyn_compatible_for_dispatch -#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] +#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))] trait Bar where Self : Sized diff --git a/tests/ui/object-safety/object-safety-sized.curr.stderr b/tests/ui/dyn-compatibility/sized.curr.stderr index b61f968d902..613833aad12 100644 --- a/tests/ui/object-safety/object-safety-sized.curr.stderr +++ b/tests/ui/dyn-compatibility/sized.curr.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized.rs:12:32 + --> $DIR/sized.rs:12:32 | LL | fn make_bar<T: Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-sized.rs:8:12 + --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { | --- ^^^^^ ...because it requires `Self: Sized` @@ -13,13 +13,13 @@ LL | trait Bar: Sized { | this trait cannot be made into an object... error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized.rs:14:5 + --> $DIR/sized.rs:14:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-sized.rs:8:12 + --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { | --- ^^^^^ ...because it requires `Self: Sized` diff --git a/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr index 5ce713375a4..cf847bc1577 100644 --- a/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized.rs:14:5 + --> $DIR/sized.rs:14:5 | LL | t | ^ `Bar` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-sized.rs:8:12 + --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { | --- ^^^^^ ...because it requires `Self: Sized` diff --git a/tests/ui/object-safety/object-safety-sized.rs b/tests/ui/dyn-compatibility/sized.rs index f4d6c945b33..4c4fe3f8f25 100644 --- a/tests/ui/object-safety/object-safety-sized.rs +++ b/tests/ui/dyn-compatibility/sized.rs @@ -1,9 +1,9 @@ // Check that we correctly prevent users from making trait objects // from traits where `Self : Sized`. // -//@ revisions: curr object_safe_for_dispatch +//@ revisions: curr dyn_compatible_for_dispatch -#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] +#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))] trait Bar: Sized { fn bar<T>(&self, t: T); diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.rs b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs index 14e00d2ef32..14e00d2ef32 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.rs +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr index 4d44627e779..ac5a5b28d94 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr @@ -1,14 +1,14 @@ error[E0311]: the parameter type `Self` may not live long enough | note: ...that is required by this bound - --> $DIR/object-safety-supertrait-mentions-GAT.rs:6:15 + --> $DIR/supertrait-mentions-GAT.rs:6:15 | LL | Self: 'a; | ^^ = help: consider adding an explicit lifetime bound `Self: 'a`... error: associated item referring to unboxed trait object for its own trait - --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20 + --> $DIR/supertrait-mentions-GAT.rs:10:20 | LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> { | ---------- in this trait @@ -21,13 +21,13 @@ LL | fn c(&self) -> Self; | ~~~~ error[E0038]: the trait `SuperTrait` cannot be made into an object - --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20 + --> $DIR/supertrait-mentions-GAT.rs:10:20 | LL | fn c(&self) -> dyn SuperTrait<T>; | ^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-supertrait-mentions-GAT.rs:4:10 + --> $DIR/supertrait-mentions-GAT.rs:4:10 | LL | type Gat<'a> | ^^^ ...because it contains the generic associated type `Gat` diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.rs b/tests/ui/dyn-compatibility/supertrait-mentions-Self.rs index d96c7ba72a3..d96c7ba72a3 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.rs +++ b/tests/ui/dyn-compatibility/supertrait-mentions-Self.rs diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr index b1a70fb859d..6474b115c46 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr @@ -1,11 +1,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/object-safety-supertrait-mentions-Self.rs:8:13 + --> $DIR/supertrait-mentions-Self.rs:8:13 | LL | trait Baz : Bar<Self> { | ^^^^^^^^^ doesn't have a size known at compile-time | note: required by an implicit `Sized` bound in `Bar` - --> $DIR/object-safety-supertrait-mentions-Self.rs:4:11 + --> $DIR/supertrait-mentions-Self.rs:4:11 | LL | trait Bar<T> { | ^ required by the implicit `Sized` requirement on this type parameter in `Bar` @@ -19,13 +19,13 @@ LL | trait Bar<T: ?Sized> { | ++++++++ error[E0038]: the trait `Baz` cannot be made into an object - --> $DIR/object-safety-supertrait-mentions-Self.rs:16:31 + --> $DIR/supertrait-mentions-Self.rs:16:31 | LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz { | ^^^^^^^ `Baz` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-supertrait-mentions-Self.rs:8:13 + --> $DIR/supertrait-mentions-Self.rs:8:13 | LL | trait Baz : Bar<Self> { | --- ^^^^^^^^^ ...because it uses `Self` as a type parameter diff --git a/tests/ui/object-safety/issue-102762.rs b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs index 576f73e08bc..5c71bd7769c 100644 --- a/tests/ui/object-safety/issue-102762.rs +++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs @@ -1,7 +1,8 @@ //@ compile-flags: --crate-type=lib // This test checks that the `where_clauses_object_safety` lint does not cause -// other object safety *hard errors* to be suppressed, because we currently -// only emit one object safety error per trait... +// other dyn-compatibility *hard errors* to be suppressed, because we currently +// only emit one dyn-compatibility error per trait... +// issue: rust-lang/rust#102762 use std::future::Future; use std::pin::Pin; diff --git a/tests/ui/object-safety/issue-102762.stderr b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr index 05451eb8399..8d62ac9d923 100644 --- a/tests/ui/object-safety/issue-102762.stderr +++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Fetcher` cannot be made into an object - --> $DIR/issue-102762.rs:18:21 + --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:19:21 | LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` @@ -8,7 +8,7 @@ LL | fn fetcher() -> Box<dyn Fetcher> { | ^^^^^^^^^^^ `Fetcher` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/issue-102762.rs:10:22 + --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { | ------- this trait cannot be made into an object... @@ -16,7 +16,7 @@ LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on error[E0038]: the trait `Fetcher` cannot be made into an object - --> $DIR/issue-102762.rs:24:19 + --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:25:19 | LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` @@ -25,7 +25,7 @@ LL | let fetcher = fetcher(); | ^^^^^^^^^ `Fetcher` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/issue-102762.rs:10:22 + --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { | ------- this trait cannot be made into an object... @@ -33,7 +33,7 @@ LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on error[E0038]: the trait `Fetcher` cannot be made into an object - --> $DIR/issue-102762.rs:26:13 + --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:27:13 | LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` @@ -42,7 +42,7 @@ LL | let _ = fetcher.get(); | ^^^^^^^^^^^^^ `Fetcher` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/issue-102762.rs:10:22 + --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { | ------- this trait cannot be made into an object... diff --git a/tests/ui/dyn-keyword/dyn-2021-edition-error.rs b/tests/ui/dyn-keyword/dyn-2021-edition-error.rs index f98bf4ef5d1..5d607d82ea1 100644 --- a/tests/ui/dyn-keyword/dyn-2021-edition-error.rs +++ b/tests/ui/dyn-keyword/dyn-2021-edition-error.rs @@ -1,10 +1,10 @@ //@ edition:2021 fn function(x: &SomeTrait, y: Box<SomeTrait>) { - //~^ ERROR trait objects must include the `dyn` keyword - //~| ERROR trait objects must include the `dyn` keyword + //~^ ERROR expected a type, found a trait + //~| ERROR expected a type, found a trait let _x: &SomeTrait = todo!(); - //~^ ERROR trait objects must include the `dyn` keyword + //~^ ERROR expected a type, found a trait } trait SomeTrait {} diff --git a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr index 52ee6c81ab7..6d1a1618ac0 100644 --- a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr +++ b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr @@ -1,4 +1,4 @@ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/dyn-2021-edition-error.rs:3:17 | LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) { @@ -17,24 +17,24 @@ help: alternatively, use a trait object to accept any type that implements `Some LL | fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) { | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/dyn-2021-edition-error.rs:3:35 | LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) { | ^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) { | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/dyn-2021-edition-error.rs:6:14 | LL | let _x: &SomeTrait = todo!(); | ^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | let _x: &dyn SomeTrait = todo!(); | +++ diff --git a/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs index 19b5edb620f..bee15788da9 100644 --- a/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs +++ b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs @@ -9,6 +9,7 @@ impl dyn Trait { fn main() { match () { Trait::CONST => {} - //~^ ERROR trait objects must include the `dyn` keyword + //~^ ERROR expected a type, found a trait + //~| HELP you can add the `dyn` keyword if you want a trait object } } diff --git a/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr index 4446a89b63b..6a2bb3ec09a 100644 --- a/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr +++ b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr @@ -1,10 +1,10 @@ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-dyn-on-bare-trait-in-pat.rs:11:9 | LL | Trait::CONST => {} | ^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | <dyn Trait>::CONST => {} | ++++ + diff --git a/tests/ui/editions/dyn-trait-sugg-2021.rs b/tests/ui/editions/dyn-trait-sugg-2021.rs index d702bfb2f88..a5364662600 100644 --- a/tests/ui/editions/dyn-trait-sugg-2021.rs +++ b/tests/ui/editions/dyn-trait-sugg-2021.rs @@ -8,5 +8,5 @@ impl<T> dyn Foo<T> { fn main() { Foo::hi(123); - //~^ ERROR trait objects must include the `dyn` keyword + //~^ ERROR expected a type, found a trait } diff --git a/tests/ui/editions/dyn-trait-sugg-2021.stderr b/tests/ui/editions/dyn-trait-sugg-2021.stderr index 8a65fea11c9..3aea8ac491d 100644 --- a/tests/ui/editions/dyn-trait-sugg-2021.stderr +++ b/tests/ui/editions/dyn-trait-sugg-2021.stderr @@ -1,10 +1,10 @@ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/dyn-trait-sugg-2021.rs:10:5 | LL | Foo::hi(123); | ^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | <dyn Foo>::hi(123); | ++++ + diff --git a/tests/ui/error-codes/E0010-teach.stderr b/tests/ui/error-codes/E0010-teach.stderr index 7634970f36e..37a9892ccbf 100644 --- a/tests/ui/error-codes/E0010-teach.stderr +++ b/tests/ui/error-codes/E0010-teach.stderr @@ -4,7 +4,7 @@ error[E0010]: allocations are not allowed in constants LL | const CON: Vec<i32> = vec![1, 2, 3]; | ^^^^^^^^^^^^^ allocation not allowed in constants | - = note: The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + = note: The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created. = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constants diff --git a/tests/ui/error-codes/E0607.stderr b/tests/ui/error-codes/E0607.stderr index 835ababf449..3fa134c2028 100644 --- a/tests/ui/error-codes/E0607.stderr +++ b/tests/ui/error-codes/E0607.stderr @@ -1,4 +1,4 @@ -error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]` --> $DIR/E0607.rs:3:5 | LL | v as *const [u8]; diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr index 9d75671c4e6..26393352b2b 100644 --- a/tests/ui/error-festival.stderr +++ b/tests/ui/error-festival.stderr @@ -81,7 +81,7 @@ help: dereference the expression LL | let y: u32 = *x as u32; | + -error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]` --> $DIR/error-festival.rs:41:5 | LL | v as *const [u8]; diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs new file mode 100644 index 00000000000..6784b445049 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs @@ -0,0 +1,10 @@ +#[cfg(true)] //~ ERROR `cfg(true)` is experimental +fn foo() {} + +#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental +//~^ ERROR `cfg(false)` is experimental +fn foo() {} + +fn main() { + cfg!(false); //~ ERROR `cfg(false)` is experimental +} diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr new file mode 100644 index 00000000000..64491464f1d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr @@ -0,0 +1,43 @@ +error[E0658]: `cfg(true)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:1:7 + | +LL | #[cfg(true)] + | ^^^^ + | + = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(true)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:4:12 + | +LL | #[cfg_attr(true, cfg(false))] + | ^^^^ + | + = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(false)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:4:22 + | +LL | #[cfg_attr(true, cfg(false))] + | ^^^^^ + | + = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(false)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:9:10 + | +LL | cfg!(false); + | ^^^^^ + | + = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs index 23857cbaca8..3c9e903d4ba 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs @@ -1,4 +1,4 @@ -// Check that a self parameter type requires a DispatchFromDyn impl to be object safe +// Check that a self parameter type requires a DispatchFromDyn impl to be dyn-compatible. #![feature(arbitrary_self_types, unsize, coerce_unsized)] diff --git a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.rs b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.rs new file mode 100644 index 00000000000..e38ab66dbe5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.rs @@ -0,0 +1,41 @@ +// Test that the use of the dyn-incompatible trait objects +// are gated by the `dyn_compatible_for_dispatch` feature gate. + +trait DynIncompatible1: Sized {} + +trait DynIncompatible2 { + fn static_fn() {} +} + +trait DynIncompatible3 { + fn foo<T>(&self); +} + +trait DynIncompatible4 { + fn foo(&self, s: &Self); +} + +fn takes_dyn_incompatible_ref<T>(obj: &dyn DynIncompatible1) { + //~^ ERROR E0038 +} + +fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 { + //~^ ERROR E0038 + loop {} +} + +fn takes_dyn_incompatible_box(obj: Box<dyn DynIncompatible3>) { + //~^ ERROR E0038 +} + +fn return_dyn_incompatible_rc() -> std::rc::Rc<dyn DynIncompatible4> { + //~^ ERROR E0038 + loop {} +} + +trait Trait {} + +impl Trait for dyn DynIncompatible1 {} +//~^ ERROR E0038 + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr new file mode 100644 index 00000000000..ed021c154a5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr @@ -0,0 +1,83 @@ +error[E0038]: the trait `DynIncompatible1` cannot be made into an object + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:18:40 + | +LL | fn takes_dyn_incompatible_ref<T>(obj: &dyn DynIncompatible1) { + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25 + | +LL | trait DynIncompatible1: Sized {} + | ---------------- ^^^^^ ...because it requires `Self: Sized` + | | + | this trait cannot be made into an object... + +error[E0038]: the trait `DynIncompatible2` cannot be made into an object + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:22:46 + | +LL | fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 { + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible2` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:7:8 + | +LL | trait DynIncompatible2 { + | ---------------- this trait cannot be made into an object... +LL | fn static_fn() {} + | ^^^^^^^^^ ...because associated function `static_fn` has no `self` parameter +help: consider turning `static_fn` into a method by giving it a `&self` argument + | +LL | fn static_fn(&self) {} + | +++++ +help: alternatively, consider constraining `static_fn` so it does not apply to trait objects + | +LL | fn static_fn() where Self: Sized {} + | +++++++++++++++++ + +error[E0038]: the trait `DynIncompatible3` cannot be made into an object + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:27:40 + | +LL | fn takes_dyn_incompatible_box(obj: Box<dyn DynIncompatible3>) { + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible3` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:11:8 + | +LL | trait DynIncompatible3 { + | ---------------- this trait cannot be made into an object... +LL | fn foo<T>(&self); + | ^^^ ...because method `foo` has generic type parameters + = help: consider moving `foo` to another trait + +error[E0038]: the trait `DynIncompatible4` cannot be made into an object + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:31:48 + | +LL | fn return_dyn_incompatible_rc() -> std::rc::Rc<dyn DynIncompatible4> { + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible4` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:15:22 + | +LL | trait DynIncompatible4 { + | ---------------- this trait cannot be made into an object... +LL | fn foo(&self, s: &Self); + | ^^^^^ ...because method `foo` references the `Self` type in this parameter + = help: consider moving `foo` to another trait + +error[E0038]: the trait `DynIncompatible1` cannot be made into an object + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:38:16 + | +LL | impl Trait for dyn DynIncompatible1 {} + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25 + | +LL | trait DynIncompatible1: Sized {} + | ---------------- ^^^^^ ...because it requires `Self: Sized` + | | + | this trait cannot be made into an object... + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr index d8a85c8838d..7dfd79c7286 100644 --- a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr @@ -18,14 +18,6 @@ LL | type Bop = impl std::fmt::Debug; = help: add `#![feature(impl_trait_in_assoc_type)]` 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: unconstrained opaque type - --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:6:16 - | -LL | type Bar = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: `Bar` must be used in combination with a concrete type within the same impl - error[E0658]: inherent associated types are unstable --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:5 | @@ -37,6 +29,14 @@ LL | type Bop = impl std::fmt::Debug; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: unconstrained opaque type + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:6:16 + | +LL | type Bar = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `Bar` must be used in combination with a concrete type within the same impl + +error: unconstrained opaque type --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:16 | LL | type Bop = impl std::fmt::Debug; diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs index 36980fd74c2..5fe0bbdc774 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions.rs @@ -1,19 +1,22 @@ //@ needs-asm-support -use std::arch::asm; +use std::arch::naked_asm; +//~^ ERROR use of unstable library feature 'naked_functions' #[naked] //~^ the `#[naked]` attribute is an experimental feature extern "C" fn naked() { - asm!("", options(noreturn)) - //~^ ERROR: requires unsafe + naked_asm!("") + //~^ ERROR use of unstable library feature 'naked_functions' + //~| ERROR: requires unsafe } #[naked] //~^ the `#[naked]` attribute is an experimental feature extern "C" fn naked_2() -> isize { - asm!("", options(noreturn)) - //~^ ERROR: requires unsafe + naked_asm!("") + //~^ ERROR use of unstable library feature 'naked_functions' + //~| ERROR: requires unsafe } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.stderr b/tests/ui/feature-gates/feature-gate-naked_functions.stderr index ffdf31e147a..709234eb023 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/tests/ui/feature-gates/feature-gate-naked_functions.stderr @@ -1,5 +1,25 @@ +error[E0658]: use of unstable library feature 'naked_functions' + --> $DIR/feature-gate-naked_functions.rs:9:5 + | +LL | naked_asm!("") + | ^^^^^^^^^ + | + = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information + = help: add `#![feature(naked_functions)]` 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 'naked_functions' + --> $DIR/feature-gate-naked_functions.rs:17:5 + | +LL | naked_asm!("") + | ^^^^^^^^^ + | + = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information + = help: add `#![feature(naked_functions)]` 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 `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:5:1 + --> $DIR/feature-gate-naked_functions.rs:6:1 | LL | #[naked] | ^^^^^^^^ @@ -9,7 +29,7 @@ LL | #[naked] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:12:1 + --> $DIR/feature-gate-naked_functions.rs:14:1 | LL | #[naked] | ^^^^^^^^ @@ -18,23 +38,33 @@ LL | #[naked] = help: add `#![feature(naked_functions)]` 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 'naked_functions' + --> $DIR/feature-gate-naked_functions.rs:3:5 + | +LL | use std::arch::naked_asm; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information + = help: add `#![feature(naked_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0133]: use of inline assembly is unsafe and requires unsafe function or block - --> $DIR/feature-gate-naked_functions.rs:8:5 + --> $DIR/feature-gate-naked_functions.rs:9:5 | -LL | asm!("", options(noreturn)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly +LL | naked_asm!("") + | ^^^^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior error[E0133]: use of inline assembly is unsafe and requires unsafe function or block - --> $DIR/feature-gate-naked_functions.rs:15:5 + --> $DIR/feature-gate-naked_functions.rs:17:5 | -LL | asm!("", options(noreturn)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly +LL | naked_asm!("") + | ^^^^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs b/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs deleted file mode 100644 index 37348e476d4..00000000000 --- a/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Test that the use of the non object-safe trait objects -// are gated by `object_safe_for_dispatch` feature gate. - -trait NonObjectSafe1: Sized {} - -trait NonObjectSafe2 { - fn static_fn() {} -} - -trait NonObjectSafe3 { - fn foo<T>(&self); -} - -trait NonObjectSafe4 { - fn foo(&self, s: &Self); -} - -fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) { - //~^ ERROR E0038 -} - -fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 { - //~^ ERROR E0038 - loop {} -} - -fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) { - //~^ ERROR E0038 -} - -fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> { - //~^ ERROR E0038 - loop {} -} - -trait Trait {} - -impl Trait for dyn NonObjectSafe1 {} -//~^ ERROR E0038 - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr deleted file mode 100644 index fd5ed9c40f7..00000000000 --- a/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr +++ /dev/null @@ -1,83 +0,0 @@ -error[E0038]: the trait `NonObjectSafe1` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:39 - | -LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) { - | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23 - | -LL | trait NonObjectSafe1: Sized {} - | -------------- ^^^^^ ...because it requires `Self: Sized` - | | - | this trait cannot be made into an object... - -error[E0038]: the trait `NonObjectSafe2` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:45 - | -LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 { - | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe2` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/feature-gate-object_safe_for_dispatch.rs:7:8 - | -LL | trait NonObjectSafe2 { - | -------------- this trait cannot be made into an object... -LL | fn static_fn() {} - | ^^^^^^^^^ ...because associated function `static_fn` has no `self` parameter -help: consider turning `static_fn` into a method by giving it a `&self` argument - | -LL | fn static_fn(&self) {} - | +++++ -help: alternatively, consider constraining `static_fn` so it does not apply to trait objects - | -LL | fn static_fn() where Self: Sized {} - | +++++++++++++++++ - -error[E0038]: the trait `NonObjectSafe3` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:39 - | -LL | fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) { - | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/feature-gate-object_safe_for_dispatch.rs:11:8 - | -LL | trait NonObjectSafe3 { - | -------------- this trait cannot be made into an object... -LL | fn foo<T>(&self); - | ^^^ ...because method `foo` has generic type parameters - = help: consider moving `foo` to another trait - -error[E0038]: the trait `NonObjectSafe4` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:47 - | -LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> { - | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe4` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/feature-gate-object_safe_for_dispatch.rs:15:22 - | -LL | trait NonObjectSafe4 { - | -------------- this trait cannot be made into an object... -LL | fn foo(&self, s: &Self); - | ^^^^^ ...because method `foo` references the `Self` type in this parameter - = help: consider moving `foo` to another trait - -error[E0038]: the trait `NonObjectSafe1` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:16 - | -LL | impl Trait for dyn NonObjectSafe1 {} - | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23 - | -LL | trait NonObjectSafe1: Sized {} - | -------------- ^^^^^ ...because it requires `Self: Sized` - | | - | this trait cannot be made into an object... - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index d694531d53a..3382504af9d 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -4,6 +4,11 @@ use std::pin::Pin; struct Foo; +impl Foo { + fn foo(self: Pin<&mut Self>) { + } +} + fn foo(_: Pin<&mut Foo>) { } @@ -12,4 +17,9 @@ fn bar(mut x: Pin<&mut Foo>) { foo(x); //~ ERROR use of moved value: `x` } +fn baz(mut x: Pin<&mut Foo>) { + x.foo(); + x.foo(); //~ ERROR use of moved value: `x` +} + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index 6c9029d8176..430b7866241 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:12:9 + --> $DIR/feature-gate-pin_ergonomics.rs:17:9 | LL | fn bar(mut x: Pin<&mut Foo>) { | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -9,13 +9,33 @@ LL | foo(x); | ^ value used here after move | note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary - --> $DIR/feature-gate-pin_ergonomics.rs:7:11 + --> $DIR/feature-gate-pin_ergonomics.rs:12:11 | LL | fn foo(_: Pin<&mut Foo>) { | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function -error: aborting due to 1 previous error +error[E0382]: use of moved value: `x` + --> $DIR/feature-gate-pin_ergonomics.rs:22:5 + | +LL | fn baz(mut x: Pin<&mut Foo>) { + | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait +LL | x.foo(); + | ----- `x` moved due to this method call +LL | x.foo(); + | ^ value used here after move + | +note: `Foo::foo` takes ownership of the receiver `self`, which moves `x` + --> $DIR/feature-gate-pin_ergonomics.rs:8:12 + | +LL | fn foo(self: Pin<&mut Self>) { + | ^^^^ +help: consider reborrowing the `Pin` instead of moving it + | +LL | x.as_mut().foo(); + | +++++++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs new file mode 100644 index 00000000000..308b41dfc68 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs @@ -0,0 +1,6 @@ +trait Foo { + fn test() -> impl Sized + use<Self>; + //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr new file mode 100644 index 00000000000..b2c6bf61124 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr @@ -0,0 +1,13 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/feature-gate-precise_capturing_in_traits.rs:2:31 + | +LL | fn test() -> impl Sized + use<Self>; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + = note: see issue #130044 <https://github.com/rust-lang/rust/issues/130044> for more information + = help: add `#![feature(precise_capturing_in_traits)]` 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 + diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs deleted file mode 100644 index 302a9bbeb45..00000000000 --- a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs +++ /dev/null @@ -1,29 +0,0 @@ -#[repr(C)] -struct Foo { - foo: u8, - _: union { //~ ERROR unnamed fields are not yet fully implemented [E0658] - //~^ ERROR unnamed fields are not yet fully implemented [E0658] - bar: u8, - baz: u16 - } -} - -#[repr(C)] -union Bar { - foobar: u8, - _: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658] - //~^ ERROR unnamed fields are not yet fully implemented [E0658] - foobaz: u8, - barbaz: u16 - } -} - -#[repr(C)] -struct S; - -#[repr(C)] -struct Baz { - _: S //~ ERROR unnamed fields are not yet fully implemented [E0658] -} - -fn main(){} diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr deleted file mode 100644 index bc9e95bab98..00000000000 --- a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr +++ /dev/null @@ -1,63 +0,0 @@ -error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:4:5 - | -LL | _: union { - | ^ - | - = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information - = help: add `#![feature(unnamed_fields)]` 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]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:4:8 - | -LL | _: union { - | ________^ -LL | | -LL | | bar: u8, -LL | | baz: u16 -LL | | } - | |_____^ - | - = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information - = help: add `#![feature(unnamed_fields)]` 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]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:14:5 - | -LL | _: struct { - | ^ - | - = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information - = help: add `#![feature(unnamed_fields)]` 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]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:14:8 - | -LL | _: struct { - | ________^ -LL | | -LL | | foobaz: u8, -LL | | barbaz: u16 -LL | | } - | |_____^ - | - = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information - = help: add `#![feature(unnamed_fields)]` 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]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:26:5 - | -LL | _: S - | ^ - | - = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information - = help: add `#![feature(unnamed_fields)]` 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/feature-gates/unstable-attribute-rejects-already-stable-features.rs b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.rs new file mode 100644 index 00000000000..9e697aaa0dc --- /dev/null +++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.rs @@ -0,0 +1,10 @@ +//! Ensure #[unstable] doesn't accept already stable features + +#![feature(staged_api)] +#![stable(feature = "rust_test", since = "1.0.0")] + +#[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] //~ ERROR can't mark as unstable using an already stable feature +#[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] //~ ERROR can't mark as unstable using an already stable feature +const fn my_fun() {} + +fn main() {} diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr new file mode 100644 index 00000000000..319056a9c88 --- /dev/null +++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr @@ -0,0 +1,31 @@ +error: can't mark as unstable using an already stable feature + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 + | +LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] +LL | const fn my_fun() {} + | -------------------- the stability attribute annotates this item + | +help: consider removing the attribute + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 + | +LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: can't mark as unstable using an already stable feature + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable +LL | const fn my_fun() {} + | -------------------- the stability attribute annotates this item + | +help: consider removing the attribute + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs index b19e67d5284..ca852ea2468 100644 --- a/tests/ui/float/classify-runtime-const.rs +++ b/tests/ui/float/classify-runtime-const.rs @@ -6,9 +6,8 @@ // This tests the float classification functions, for regular runtime code and for const evaluation. -#![feature(f16_const)] -#![feature(f128_const)] -#![feature(const_float_classify)] +#![feature(f16)] +#![feature(f128)] use std::num::FpCategory::*; diff --git a/tests/ui/float/conv-bits-runtime-const.rs b/tests/ui/float/conv-bits-runtime-const.rs index e85a889d2c2..3046728fe66 100644 --- a/tests/ui/float/conv-bits-runtime-const.rs +++ b/tests/ui/float/conv-bits-runtime-const.rs @@ -3,11 +3,8 @@ // This tests the float classification functions, for regular runtime code and for const evaluation. -#![feature(const_float_classify)] #![feature(f16)] #![feature(f128)] -#![feature(f16_const)] -#![feature(f128_const)] #![allow(unused_macro_rules)] use std::hint::black_box; diff --git a/tests/ui/generic-associated-types/trait-objects.rs b/tests/ui/generic-associated-types/trait-objects.rs index 277ffcc1f0d..743a3df0acc 100644 --- a/tests/ui/generic-associated-types/trait-objects.rs +++ b/tests/ui/generic-associated-types/trait-objects.rs @@ -6,7 +6,7 @@ trait StreamingIterator { type Item<'a> where Self: 'a; fn size_hint(&self) -> (usize, Option<usize>); - // Uncommenting makes `StreamingIterator` not object safe + // Uncommenting makes `StreamingIterator` dyn-incompatible. // fn next(&mut self) -> Self::Item<'_>; } diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr index 9831348de75..e2916725fbd 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -2,8 +2,9 @@ error: expected a pattern range bound, found an expression --> $DIR/range_pat_interactions1.rs:17:16 | LL | 0..5+1 => errors_only.push(x), - | ^^^ arbitrary expressions are not allowed in patterns + | ^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 5+1; diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr index 1b5e875cccb..f54e07c3a63 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr @@ -14,8 +14,9 @@ error: expected a pattern range bound, found an expression --> $DIR/range_pat_interactions2.rs:10:18 | LL | 0..=(5+1) => errors_only.push(x), - | ^^^ arbitrary expressions are not allowed in patterns + | ^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 5+1; diff --git a/tests/ui/hygiene/panic-location.rs b/tests/ui/hygiene/panic-location.rs index 7b20f1683a9..580a8bcff05 100644 --- a/tests/ui/hygiene/panic-location.rs +++ b/tests/ui/hygiene/panic-location.rs @@ -4,8 +4,7 @@ //@ normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC" // // Regression test for issue #70963 -// The captured stderr from this test reports a location -// inside `VecDeque::with_capacity`, instead of `<::core::macros::panic macros>` +// The reported panic location should not be `<::core::macros::panic macros>`. fn main() { std::collections::VecDeque::<String>::with_capacity(!0); } diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index bfed4cd6650..b9086ecef81 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at alloc/src/raw_vec.rs:LL:CC: +thread 'main' panicked at $DIR/panic-location.rs:LL:CC: capacity overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs index 068f7d3eea6..76dbb05f53d 100644 --- a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs @@ -1,24 +1,25 @@ #![allow(bare_trait_objects)] -trait NotObjectSafe { + +trait DynIncompatible { fn foo() -> Self; } struct A; struct B; -impl NotObjectSafe for A { +impl DynIncompatible for A { fn foo() -> Self { A } } -impl NotObjectSafe for B { +impl DynIncompatible for B { fn foo() -> Self { B } } -fn car() -> dyn NotObjectSafe { //~ ERROR the trait `NotObjectSafe` cannot be made into an object +fn car() -> dyn DynIncompatible { //~ ERROR the trait `DynIncompatible` cannot be made into an object //~^ ERROR return type cannot have an unboxed trait object if true { return A; @@ -26,7 +27,7 @@ fn car() -> dyn NotObjectSafe { //~ ERROR the trait `NotObjectSafe` cannot be ma B } -fn cat() -> Box<dyn NotObjectSafe> { //~ ERROR the trait `NotObjectSafe` cannot be made into an +fn cat() -> Box<dyn DynIncompatible> { //~ ERROR the trait `DynIncompatible` cannot be made into an if true { return Box::new(A); //~ ERROR cannot be made into an object } diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr index 2a36824e292..576bd909cbc 100644 --- a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr @@ -1,17 +1,17 @@ -error[E0038]: the trait `NotObjectSafe` cannot be made into an object - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:21:13 +error[E0038]: the trait `DynIncompatible` cannot be made into an object + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:22:13 | -LL | fn car() -> dyn NotObjectSafe { - | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object +LL | fn car() -> dyn DynIncompatible { + | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | -LL | trait NotObjectSafe { - | ------------- this trait cannot be made into an object... +LL | trait DynIncompatible { + | --------------- this trait cannot be made into an object... LL | fn foo() -> Self; | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `NotObjectSafe` for this new enum and using it instead: + = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead: A B help: consider turning `foo` into a method by giving it a `&self` argument @@ -23,20 +23,20 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() -> Self where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `NotObjectSafe` cannot be made into an object - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:29:17 +error[E0038]: the trait `DynIncompatible` cannot be made into an object + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:30:17 | -LL | fn cat() -> Box<dyn NotObjectSafe> { - | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object +LL | fn cat() -> Box<dyn DynIncompatible> { + | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | -LL | trait NotObjectSafe { - | ------------- this trait cannot be made into an object... +LL | trait DynIncompatible { + | --------------- this trait cannot be made into an object... LL | fn foo() -> Self; | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `NotObjectSafe` for this new enum and using it instead: + = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead: A B help: consider turning `foo` into a method by giving it a `&self` argument @@ -49,15 +49,15 @@ LL | fn foo() -> Self where Self: Sized; | +++++++++++++++++ error[E0746]: return type cannot have an unboxed trait object - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:21:13 + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:22:13 | -LL | fn car() -> dyn NotObjectSafe { - | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | fn car() -> dyn DynIncompatible { + | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: if there were a single returned type, you could use `impl Trait` instead help: box the return type, and wrap all of the returned values in `Box::new` | -LL ~ fn car() -> Box<dyn NotObjectSafe> { +LL ~ fn car() -> Box<dyn DynIncompatible> { LL | LL | if true { LL ~ return Box::new(A); @@ -65,23 +65,23 @@ LL | } LL ~ Box::new(B) | -error[E0038]: the trait `NotObjectSafe` cannot be made into an object - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:31:16 +error[E0038]: the trait `DynIncompatible` cannot be made into an object + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:32:16 | LL | return Box::new(A); - | ^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object + | ^^^^^^^^^^^ `DynIncompatible` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | -LL | trait NotObjectSafe { - | ------------- this trait cannot be made into an object... +LL | trait DynIncompatible { + | --------------- this trait cannot be made into an object... LL | fn foo() -> Self; | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `NotObjectSafe` for this new enum and using it instead: + = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead: A B - = note: required for the cast from `Box<A>` to `Box<(dyn NotObjectSafe + 'static)>` + = note: required for the cast from `Box<A>` to `Box<(dyn DynIncompatible + 'static)>` help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self) -> Self; @@ -91,23 +91,23 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() -> Self where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `NotObjectSafe` cannot be made into an object - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:33:5 +error[E0038]: the trait `DynIncompatible` cannot be made into an object + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:34:5 | LL | Box::new(B) - | ^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object + | ^^^^^^^^^^^ `DynIncompatible` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 + --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | -LL | trait NotObjectSafe { - | ------------- this trait cannot be made into an object... +LL | trait DynIncompatible { + | --------------- this trait cannot be made into an object... LL | fn foo() -> Self; | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `NotObjectSafe` for this new enum and using it instead: + = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead: A B - = note: required for the cast from `Box<B>` to `Box<(dyn NotObjectSafe + 'static)>` + = note: required for the cast from `Box<B>` to `Box<(dyn DynIncompatible + 'static)>` help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self) -> Self; diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.rs index 503515013b9..25a901e4ff3 100644 --- a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.rs @@ -1,42 +1,42 @@ -trait NotObjectSafe { +trait DynIncompatible { fn foo() -> Self; } -trait ObjectSafe { +trait DynCompatible { fn bar(&self); } struct A; struct B; -impl NotObjectSafe for A { +impl DynIncompatible for A { fn foo() -> Self { A } } -impl NotObjectSafe for B { +impl DynIncompatible for B { fn foo() -> Self { B } } -impl ObjectSafe for A { +impl DynCompatible for A { fn bar(&self) {} } -impl ObjectSafe for B { +impl DynCompatible for B { fn bar(&self) {} } -fn can() -> impl NotObjectSafe { +fn can() -> impl DynIncompatible { if true { return A; } B //~ ERROR mismatched types } -fn cat() -> impl ObjectSafe { +fn cat() -> impl DynCompatible { if true { return A; } diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.stderr index e5147bcea16..6a485881bfc 100644 --- a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.stderr @@ -1,17 +1,17 @@ error[E0308]: mismatched types - --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5 + --> $DIR/dyn-incompatible-trait-in-return-position-impl-trait.rs:36:5 | -LL | fn can() -> impl NotObjectSafe { - | ------------------ expected `A` because of return type +LL | fn can() -> impl DynIncompatible { + | -------------------- expected `A` because of return type ... LL | B | ^ expected `A`, found `B` error[E0308]: mismatched types - --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5 + --> $DIR/dyn-incompatible-trait-in-return-position-impl-trait.rs:43:5 | -LL | fn cat() -> impl ObjectSafe { - | --------------- expected `A` because of return type +LL | fn cat() -> impl DynCompatible { + | ------------------ expected `A` because of return type ... LL | B | ^ expected `A`, found `B` diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr index 7917fa991ee..1e268bc7f49 100644 --- a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr @@ -1,21 +1,14 @@ -error[E0277]: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied - --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13 - | -LL | fn ice() -> impl AsRef<Fn(&())> { - | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not implemented for `()` - -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:24 | LL | fn ice() -> impl AsRef<Fn(&())> { | ^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | fn ice() -> impl AsRef<dyn Fn(&())> { | +++ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0782. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs index 582386aa759..c71f794d5d1 100644 --- a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs @@ -5,8 +5,7 @@ fn ice() -> impl AsRef<Fn(&())> { //[edition2015]~^ ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277] - //[edition2021]~^^ ERROR: trait objects must include the `dyn` keyword [E0782] - //[edition2021]~| ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277] + //[edition2021]~^^ ERROR: expected a type, found a trait [E0782] todo!() } diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr index 50a9f3ebeab..91550f0e284 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -19,7 +19,10 @@ error[E0720]: cannot resolve opaque type --> $DIR/impl-fn-predefined-lifetimes.rs:4:35 | LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - | ^^^^^^^^^^^^^^^ cannot resolve opaque type + | ^^^^^^^^^^^^^^^ recursive opaque type +... +LL | |x| x + | ----- returning here with type `{closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8}` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs index daf29a0005d..daf29a0005d 100644 --- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr index af624e2a758..a975b6204aa 100644 --- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:20:22 + --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:20:22 | LL | MyTrait::foo(&self) | ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` @@ -9,13 +9,13 @@ LL | MyTrait::foo(&self) = help: the trait `MyTrait` is implemented for `Outer` error[E0038]: the trait `MyTrait` cannot be made into an object - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:20:9 + --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:20:9 | LL | MyTrait::foo(&self) | ^^^^^^^^^^^^ `MyTrait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 + --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { | ------- this trait cannot be made into an object... @@ -25,7 +25,7 @@ LL | fn foo(&self) -> impl Marker; = help: only type `Outer` implements the trait, consider using it directly instead error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:20:9 + --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:20:9 | LL | MyTrait::foo(&self) | ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` @@ -33,13 +33,13 @@ LL | MyTrait::foo(&self) = help: the trait `MyTrait` is implemented for `Outer` error[E0038]: the trait `MyTrait` cannot be made into an object - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:16:6 + --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:16:6 | LL | impl dyn MyTrait { | ^^^^^^^^^^^ `MyTrait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 + --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { | ------- this trait cannot be made into an object... @@ -49,13 +49,13 @@ LL | fn foo(&self) -> impl Marker; = help: only type `Outer` implements the trait, consider using it directly instead error[E0038]: the trait `MyTrait` cannot be made into an object - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:18:15 + --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:18:15 | LL | fn other(&self) -> impl Marker { | ^^^^ `MyTrait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 + --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { | ------- this trait cannot be made into an object... diff --git a/tests/ui/impl-trait/in-trait/object-safety-sized.rs b/tests/ui/impl-trait/in-trait/dyn-compatibility-sized.rs index b5b7a6ed9bf..b5b7a6ed9bf 100644 --- a/tests/ui/impl-trait/in-trait/object-safety-sized.rs +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility-sized.rs diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs index 5cca4ad839c..5cca4ad839c 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.rs +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr index e2f23bca621..115cb014b8c 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:14:33 + --> $DIR/dyn-compatibility.rs:14:33 | LL | let i = Box::new(42_u32) as Box<dyn Foo>; | ^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:4:22 + --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -15,13 +15,13 @@ LL | fn baz(&self) -> impl Debug; = help: only type `u32` implements the trait, consider using it directly instead error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:17:15 + --> $DIR/dyn-compatibility.rs:17:15 | LL | let s = i.baz(); | ^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:4:22 + --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -31,13 +31,13 @@ LL | fn baz(&self) -> impl Debug; = help: only type `u32` implements the trait, consider using it directly instead error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:17:13 + --> $DIR/dyn-compatibility.rs:17:13 | LL | let s = i.baz(); | ^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:4:22 + --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -47,13 +47,13 @@ LL | fn baz(&self) -> impl Debug; = help: only type `u32` implements the trait, consider using it directly instead error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:14:13 + --> $DIR/dyn-compatibility.rs:14:13 | LL | let i = Box::new(42_u32) as Box<dyn Foo>; | ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:4:22 + --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr index d71c1768a6a..058517f0014 100644 --- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr @@ -73,32 +73,6 @@ help: consider further restricting this bound LL | F: Callback<Self::CallbackArg> + MyFn<i32>, | +++++++++++ -error[E0277]: the trait bound `F: Callback<i32>` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:43:12 - | -LL | F: Callback<Self::CallbackArg>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` - | -note: required for `F` to implement `Callback<i32>` - --> $DIR/false-positive-predicate-entailment-error.rs:14:21 - | -LL | impl<A, F: MyFn<A>> Callback<A> for F { - | ------- ^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here -note: the requirement `F: Callback<i32>` appears on the `impl`'s method `autobatch` but not on the corresponding trait's method - --> $DIR/false-positive-predicate-entailment-error.rs:25:8 - | -LL | trait ChannelSender { - | ------------- in this trait -... -LL | fn autobatch<F>(self) -> impl Trait - | ^^^^^^^^^ this trait's method doesn't have the requirement `F: Callback<i32>` -help: consider further restricting this bound - | -LL | F: Callback<Self::CallbackArg> + MyFn<i32>, - | +++++++++++ - error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied --> $DIR/false-positive-predicate-entailment-error.rs:36:30 | @@ -168,6 +142,6 @@ help: consider further restricting this bound LL | F: Callback<Self::CallbackArg> + MyFn<i32>, | +++++++++++ -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs index 59fdeab9e0a..2987d183e04 100644 --- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs @@ -41,8 +41,7 @@ impl ChannelSender for Sender { //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied where F: Callback<Self::CallbackArg>, - //[current]~^ ERROR the trait bound `F: Callback<i32>` is not satisfied - //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied + //[current]~^ ERROR the trait bound `F: MyFn<i32>` is not satisfied { Thing } diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs index 84bc39d9263..ee47de2c732 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs @@ -8,7 +8,6 @@ impl Foo<char> for Bar { fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { //~^ ERROR: the trait bound `impl Foo<u8>: Foo<char>` is not satisfied [E0277] //~| ERROR: the trait bound `Bar: Foo<u8>` is not satisfied [E0277] - //~| ERROR: impl has stricter requirements than trait //~| ERROR: the trait bound `F2: Foo<u8>` is not satisfied self } diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index ae449099987..768224e4c51 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -23,15 +23,6 @@ note: required by a bound in `<Bar as Foo<char>>::foo` LL | fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { | ^^^^^^^ required by this bound in `<Bar as Foo<char>>::foo` -error[E0276]: impl has stricter requirements than trait - --> $DIR/return-dont-satisfy-bounds.rs:8:16 - | -LL | fn foo<F2>(self) -> impl Foo<T>; - | -------------------------------- definition of `foo` from trait -... -LL | fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { - | ^^^^^^^ impl has extra requirement `F2: Foo<u8>` - error[E0277]: the trait bound `Bar: Foo<u8>` is not satisfied --> $DIR/return-dont-satisfy-bounds.rs:8:34 | @@ -44,7 +35,6 @@ LL | self = help: the trait `Foo<char>` is implemented for `Bar` = help: for that trait implementation, expected `char`, found `u8` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0276, E0277. -For more information about an error, try `rustc --explain E0276`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index 0ac44bf7546..19905c608e3 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -1,22 +1,25 @@ -#![feature(rustc_attrs)] +#![feature(rustc_attrs, precise_capturing_in_traits)] #![allow(internal_features)] #![rustc_variance_of_opaques] -trait Captures<'a> {} -impl<T> Captures<'_> for T {} - trait Foo<'i> { fn implicit_capture_early<'a: 'a>() -> impl Sized {} - //~^ [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] + //~^ [Self: o, 'i: o, 'a: *, 'a: o, 'i: o] + + fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {} + //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] - fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} - //~^ [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] + fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {} + //~^ [Self: o, 'i: o, 'a: *, 'i: o] fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} - //~^ [Self: o, 'i: *, 'a: o, 'i: o] + //~^ [Self: o, 'i: o, 'a: o, 'i: o] + + fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Self> {} + //~^ [Self: o, 'i: o, 'i: o, 'a: o] - fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} - //~^ [Self: o, 'i: *, 'a: o, 'i: o] + fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} + //~^ [Self: o, 'i: o, 'i: o] } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr index 54e0afbaa95..f65174e1c35 100644 --- a/tests/ui/impl-trait/in-trait/variance.stderr +++ b/tests/ui/impl-trait/in-trait/variance.stderr @@ -1,26 +1,38 @@ -error: [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] - --> $DIR/variance.rs:9:44 +error: [Self: o, 'i: o, 'a: *, 'a: o, 'i: o] + --> $DIR/variance.rs:6:44 | LL | fn implicit_capture_early<'a: 'a>() -> impl Sized {} | ^^^^^^^^^^ -error: [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] - --> $DIR/variance.rs:12:44 +error: [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] + --> $DIR/variance.rs:9:44 + | +LL | fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [Self: o, 'i: o, 'a: *, 'i: o] + --> $DIR/variance.rs:12:40 | -LL | fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [Self: o, 'i: *, 'a: o, 'i: o] +error: [Self: o, 'i: o, 'a: o, 'i: o] --> $DIR/variance.rs:15:48 | LL | fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} | ^^^^^^^^^^ -error: [Self: o, 'i: *, 'a: o, 'i: o] +error: [Self: o, 'i: o, 'i: o, 'a: o] --> $DIR/variance.rs:18:48 | -LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Self> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [Self: o, 'i: o, 'i: o] + --> $DIR/variance.rs:21:44 + | +LL | fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/impl-trait/issues/issue-78722-2.stderr b/tests/ui/impl-trait/issues/issue-78722-2.stderr index dc5579c1c82..2cf6b94dd9d 100644 --- a/tests/ui/impl-trait/issues/issue-78722-2.stderr +++ b/tests/ui/impl-trait/issues/issue-78722-2.stderr @@ -1,9 +1,3 @@ -error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:18}` to be a future that resolves to `u8`, but it resolves to `()` - --> $DIR/issue-78722-2.rs:11:30 - | -LL | fn concrete_use() -> F { - | ^ expected `()`, found `u8` - error[E0308]: mismatched types --> $DIR/issue-78722-2.rs:16:20 | @@ -18,6 +12,12 @@ LL | let f: F = async { 1 }; = note: expected opaque type `F` found `async` block `{async block@$DIR/issue-78722-2.rs:16:20: 16:25}` +error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:18}` to be a future that resolves to `u8`, but it resolves to `()` + --> $DIR/issue-78722-2.rs:11:30 + | +LL | fn concrete_use() -> F { + | ^ expected `()`, found `u8` + error: aborting due to 2 previous errors Some errors have detailed explanations: E0271, E0308. diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index 9d68819f657..6c2477c9744 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -1,10 +1,11 @@ +#![feature(precise_capturing_in_traits)] + fn type_param<T>() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all type parameters in scope trait Foo { fn bar() -> impl Sized + use<>; //~^ ERROR `impl Trait` must mention the `Self` type of the trait - //~| ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index d9be9d543e4..93b44a0c18c 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,13 +1,5 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/forgot-to-capture-type.rs:5:30 - | -LL | fn bar() -> impl Sized + use<>; - | ^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-type.rs:1:23 + --> $DIR/forgot-to-capture-type.rs:3:23 | LL | fn type_param<T>() -> impl Sized + use<> {} | - ^^^^^^^^^^^^^^^^^^ @@ -17,7 +9,7 @@ LL | fn type_param<T>() -> impl Sized + use<> {} = note: currently, all type parameters are required to be mentioned in the precise captures list error: `impl Trait` must mention the `Self` type of the trait in `use<...>` - --> $DIR/forgot-to-capture-type.rs:5:17 + --> $DIR/forgot-to-capture-type.rs:7:17 | LL | trait Foo { | --------- `Self` type parameter is implicitly captured by this `impl Trait` @@ -26,5 +18,5 @@ LL | fn bar() -> impl Sized + use<>; | = note: currently, all type parameters are required to be mentioned in the precise captures list -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr b/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr deleted file mode 100644 index d1bcbaa33ae..00000000000 --- a/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr +++ /dev/null @@ -1,20 +0,0 @@ -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:5:19 - | -LL | fn hello<'a>() -> impl Sized + use<'a> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - | - = note: `#[warn(impl_trait_redundant_captures)]` on by default - -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:10:27 - | -LL | fn inherent(&self) -> impl Sized + use<'_> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - -warning: 2 warnings emitted - diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr b/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr deleted file mode 100644 index 213888356e5..00000000000 --- a/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/redundant.rs:16:35 - | -LL | fn in_trait() -> impl Sized + use<'a, Self>; - | ^^^^^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/redundant.rs:21:35 - | -LL | fn in_trait() -> impl Sized + use<'a> {} - | ^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - -error: aborting due to 2 previous errors - diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index 4a08ffb61be..e19d935f5b0 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -1,25 +1,24 @@ //@ compile-flags: -Zunstable-options --edition=2024 -//@ revisions: normal rpitit -//@[normal] check-pass +//@ check-pass + +#![feature(precise_capturing_in_traits)] fn hello<'a>() -> impl Sized + use<'a> {} -//[normal]~^ WARN all possible in-scope parameters are already captured +//~^ WARN all possible in-scope parameters are already captured struct Inherent; impl Inherent { fn inherent(&self) -> impl Sized + use<'_> {} - //[normal]~^ WARN all possible in-scope parameters are already captured + //~^ WARN all possible in-scope parameters are already captured } -#[cfg(rpitit)] trait Test<'a> { fn in_trait() -> impl Sized + use<'a, Self>; - //[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + //~^ WARN all possible in-scope parameters are already captured } -#[cfg(rpitit)] impl<'a> Test<'a> for () { fn in_trait() -> impl Sized + use<'a> {} - //[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + //~^ WARN all possible in-scope parameters are already captured } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr new file mode 100644 index 00000000000..274d9d2375f --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr @@ -0,0 +1,36 @@ +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:6:19 + | +LL | fn hello<'a>() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + | + = note: `#[warn(impl_trait_redundant_captures)]` on by default + +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:11:27 + | +LL | fn inherent(&self) -> impl Sized + use<'_> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:16:22 + | +LL | fn in_trait() -> impl Sized + use<'a, Self>; + | ^^^^^^^^^^^^^------------- + | | + | help: remove the `use<...>` syntax + +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:20:22 + | +LL | fn in_trait() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + +warning: 4 warnings emitted + diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs index 71a91fe319e..b39c1408c05 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs @@ -2,15 +2,15 @@ // trait definition, which is not allowed. Due to the default lifetime capture // rules of RPITITs, this is only doable if we use precise capturing. +#![feature(precise_capturing_in_traits)] + pub trait Foo { fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>; - //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } impl Foo for () { - fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} + fn bar<'im: 'im>(&'im mut self) -> impl Sized + use<'im> {} //~^ ERROR return type captures more lifetimes than trait definition - //~| WARN impl trait in impl method signature does not match trait method signature } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr index 339e2e6335e..45f755d3cc1 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr @@ -1,42 +1,17 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:53 - | -LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>; - | ^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - error: return type captures more lifetimes than trait definition - --> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40 + --> $DIR/rpitit-captures-more-method-lifetimes.rs:12:40 | -LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} - | --- ^^^^^^^^^^^^^^^^ +LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + use<'im> {} + | --- ^^^^^^^^^^^^^^^^^^^^^ | | | this lifetime was captured | note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:40 + --> $DIR/rpitit-captures-more-method-lifetimes.rs:8:40 | LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>; | ^^^^^^^^^^^^^^^^^^^^^^ - = note: hidden type inferred to be `impl Sized + 'im` - -warning: impl trait in impl method signature does not match trait method signature - --> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40 - | -LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>; - | ---------------------- return type from trait method defined here -... -LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} - | ^^^^^^^^^^^^^^^^ - | - = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate - = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information - = note: `#[warn(refining_impl_trait_reachable)]` on by default -help: replace the return type so that it matches the trait - | -LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized {} - | ~~~~~~~~~~ + = note: hidden type inferred to be `impl Sized` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs new file mode 100644 index 00000000000..b16b0522d6e --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs @@ -0,0 +1,14 @@ +#![feature(precise_capturing_in_traits)] + +struct Invariant<'a>(&'a mut &'a mut ()); + +trait Trait { + fn hello(self_: Invariant<'_>) -> impl Sized + use<Self>; +} + +impl Trait for () { + fn hello(self_: Invariant<'_>) -> impl Sized + use<'_> {} + //~^ ERROR return type captures more lifetimes than trait definition +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr new file mode 100644 index 00000000000..e1856b92910 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr @@ -0,0 +1,17 @@ +error: return type captures more lifetimes than trait definition + --> $DIR/rpitit-impl-captures-too-much.rs:10:39 + | +LL | fn hello(self_: Invariant<'_>) -> impl Sized + use<'_> {} + | -- ^^^^^^^^^^^^^^^^^^^^ + | | + | this lifetime was captured + | +note: hidden type must only reference lifetimes captured by this impl trait + --> $DIR/rpitit-impl-captures-too-much.rs:6:39 + | +LL | fn hello(self_: Invariant<'_>) -> impl Sized + use<Self>; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: hidden type inferred to be `impl Sized` + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.rs b/tests/ui/impl-trait/precise-capturing/rpitit.rs index feeeb1461e8..3f887e8e47f 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit.rs @@ -1,19 +1,34 @@ -//@ known-bug: unknown - // RPITITs don't have variances in their GATs, so they always relate invariantly // and act as if they capture all their args. // To fix this soundly, we need to make sure that all the trait header args // remain captured, since they affect trait selection. -trait Foo<'a> { - fn hello() -> impl PartialEq + use<Self>; +#![feature(precise_capturing_in_traits)] + +fn eq_types<T>(_: T, _: T) {} + +trait TraitLt<'a: 'a> { + fn hello() -> impl Sized + use<Self>; + //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list +} +fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { + eq_types( + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + <T as TraitLt<'a>>::hello(), + <T as TraitLt<'b>>::hello(), + ); } -fn test<'a, 'b, T: for<'r> Foo<'r>>() { - PartialEq::eq( - &<T as Foo<'a>>::hello(), - &<T as Foo<'b>>::hello(), +trait MethodLt { + fn hello<'a: 'a>() -> impl Sized + use<Self>; +} +fn method_lt<'a, 'b, T: MethodLt> () { + eq_types( + T::hello::<'a>(), + T::hello::<'b>(), ); + // Good! } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.stderr b/tests/ui/impl-trait/precise-capturing/rpitit.stderr index 5a120df9f04..498eae54a1c 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit.stderr @@ -1,44 +1,40 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/rpitit.rs:9:36 - | -LL | fn hello() -> impl PartialEq + use<Self>; - | ^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/rpitit.rs:9:19 + --> $DIR/rpitit.rs:11:19 | -LL | trait Foo<'a> { - | -- this lifetime parameter is captured -LL | fn hello() -> impl PartialEq + use<Self>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` +LL | trait TraitLt<'a: 'a> { + | -- all lifetime parameters originating from a trait are captured implicitly +LL | fn hello() -> impl Sized + use<Self>; + | ^^^^^^^^^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/rpitit.rs:13:5 + --> $DIR/rpitit.rs:15:5 | -LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | / PartialEq::eq( -LL | | &<T as Foo<'a>>::hello(), -LL | | &<T as Foo<'b>>::hello(), +LL | fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / eq_types( +LL | | +LL | | +LL | | <T as TraitLt<'a>>::hello(), +LL | | <T as TraitLt<'b>>::hello(), LL | | ); | |_____^ argument requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/rpitit.rs:13:5 + --> $DIR/rpitit.rs:15:5 | -LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | / PartialEq::eq( -LL | | &<T as Foo<'a>>::hello(), -LL | | &<T as Foo<'b>>::hello(), +LL | fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / eq_types( +LL | | +LL | | +LL | | <T as TraitLt<'a>>::hello(), +LL | | <T as TraitLt<'b>>::hello(), LL | | ); | |_____^ argument requires that `'b` must outlive `'a` | @@ -46,5 +42,5 @@ LL | | ); help: `'a` and `'b` must be the same: replace one with the other -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index a61a7f06edc..15985da50b5 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,6 +1,9 @@ +//@ check-pass + +#![feature(precise_capturing_in_traits)] + trait Foo { fn bar<'a>() -> impl Sized + use<Self>; - //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.stderr b/tests/ui/impl-trait/precise-capturing/self-capture.stderr deleted file mode 100644 index c1974600f30..00000000000 --- a/tests/ui/impl-trait/precise-capturing/self-capture.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/self-capture.rs:2:34 - | -LL | fn bar<'a>() -> impl Sized + use<Self>; - | ^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - -error: aborting due to 1 previous error - diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index 3692cc77b0f..6485aa20710 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -1,24 +1,3 @@ -error: item does not constrain `a::Foo::{opaque#0}`, but has it in its signature - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12 - | -LL | fn eq(&self, _other: &(Foo, i32)) -> bool { - | ^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 - | -LL | type Foo = impl PartialEq<(Foo, i32)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: unconstrained opaque type - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 - | -LL | type Foo = impl PartialEq<(Foo, i32)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module - error[E0053]: method `eq` has an incompatible type for trait --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:30 | @@ -35,8 +14,21 @@ help: change the parameter type to match the trait LL | fn eq(&self, _other: &(a::Bar, i32)) -> bool { | ~~~~~~~~~~~~~~ +error: item does not constrain `a::Foo::{opaque#0}`, but has it in its signature + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12 + | +LL | fn eq(&self, _other: &(Foo, i32)) -> bool { + | ^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: unconstrained opaque type - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:19:16 + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 | LL | type Foo = impl PartialEq<(Foo, i32)>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,6 +56,14 @@ help: change the parameter type to match the trait LL | fn eq(&self, _other: &(b::Foo, i32)) -> bool { | ~~~~~~~~~~~~~~ +error: unconstrained opaque type + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:19:16 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Foo` must be used in combination with a concrete type within the same module + error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 2770a6cc40e..13f50fcea7b 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -342,6 +342,47 @@ LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | = note: `impl Trait` is only allowed in arguments and return types of functions and methods +error[E0053]: method `in_trait_impl_return` has an incompatible type for trait + --> $DIR/where-allowed.rs:128:34 + | +LL | type Out = impl Debug; + | ---------- the expected opaque type +... +LL | fn in_trait_impl_return() -> impl Debug { () } + | ^^^^^^^^^^ expected opaque type, found a different opaque type + | +note: type in trait + --> $DIR/where-allowed.rs:118:34 + | +LL | fn in_trait_impl_return() -> Self::Out; + | ^^^^^^^^^ + = note: expected signature `fn() -> <() as DummyTrait>::Out` + found signature `fn() -> impl Debug` + = note: distinct uses of `impl Trait` result in different opaque types +help: change the output type to match the trait + | +LL | fn in_trait_impl_return() -> <() as DummyTrait>::Out { () } + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/where-allowed.rs:245:36 + | +LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> + = note: `#[deny(invalid_type_param_default)]` on by default + +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/where-allowed.rs:238:7 + | +LL | impl <T = impl Debug> T {} + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> + error[E0283]: type annotations needed --> $DIR/where-allowed.rs:46:57 | @@ -362,16 +403,6 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani - impl<Args, F, A> Fn<Args> for Box<F, A> where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized; -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:238:7 - | -LL | impl <T = impl Debug> T {} - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> - = note: `#[deny(invalid_type_param_default)]` on by default - error[E0118]: no nominal type found for inherent implementation --> $DIR/where-allowed.rs:238:1 | @@ -380,28 +411,6 @@ LL | impl <T = impl Debug> T {} | = note: either implement a trait on it or create a newtype to wrap it instead -error[E0053]: method `in_trait_impl_return` has an incompatible type for trait - --> $DIR/where-allowed.rs:128:34 - | -LL | type Out = impl Debug; - | ---------- the expected opaque type -... -LL | fn in_trait_impl_return() -> impl Debug { () } - | ^^^^^^^^^^ expected opaque type, found a different opaque type - | -note: type in trait - --> $DIR/where-allowed.rs:118:34 - | -LL | fn in_trait_impl_return() -> Self::Out; - | ^^^^^^^^^ - = note: expected signature `fn() -> <() as DummyTrait>::Out` - found signature `fn() -> impl Debug` - = note: distinct uses of `impl Trait` result in different opaque types -help: change the output type to match the trait - | -LL | fn in_trait_impl_return() -> <() as DummyTrait>::Out { () } - | ~~~~~~~~~~~~~~~~~~~~~~~ - error: unconstrained opaque type --> $DIR/where-allowed.rs:121:16 | @@ -410,25 +419,16 @@ LL | type Out = impl Debug; | = note: `Out` must be used in combination with a concrete type within the same impl -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:245:36 - | -LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> - error: aborting due to 49 previous errors Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0658, E0666. For more information about an error, try `rustc --explain E0053`. Future incompatibility report: Future breakage diagnostic: error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:238:7 + --> $DIR/where-allowed.rs:245:36 | -LL | impl <T = impl Debug> T {} - | ^^^^^^^^^^^^^^ +LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} + | ^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> @@ -436,10 +436,10 @@ LL | impl <T = impl Debug> T {} Future breakage diagnostic: error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:245:36 + --> $DIR/where-allowed.rs:238:7 | -LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} - | ^^^^^^^^^^^^^^ +LL | impl <T = impl Debug> T {} + | ^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr deleted file mode 100644 index b8b7d6e1a5e..00000000000 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: number of conditions in decision (7) exceeds limit (6), so MC/DC analysis will not count this expression - --> $DIR/mcdc-condition-limit.rs:28:8 - | -LL | if a && b && c && d && e && f && g { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: 1 warning emitted - diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.rs b/tests/ui/instrument-coverage/mcdc-condition-limit.rs index 91ff6381df7..118ae482fc6 100644 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.rs +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.rs @@ -1,5 +1,6 @@ //@ edition: 2021 -//@ revisions: good bad +//@ min-llvm-version: 19 +//@ revisions: good //@ check-pass //@ compile-flags: -Cinstrument-coverage -Zcoverage-options=mcdc -Zno-profiler-runtime @@ -14,18 +15,9 @@ #[cfg(good)] fn main() { - // 6 conditions is OK, so no diagnostic. - let [a, b, c, d, e, f] = <[bool; 6]>::default(); - if a && b && c && d && e && f { - core::hint::black_box("hello"); - } -} - -#[cfg(bad)] -fn main() { - // 7 conditions is too many, so issue a diagnostic. + // 7 conditions is allowed, so no diagnostic. let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); - if a && b && c && d && e && f && g { //[bad]~ WARNING number of conditions in decision + if a && b && c && d && e && f && g { core::hint::black_box("hello"); } } diff --git a/tests/ui/intrinsics/intrinsic-fmuladd.rs b/tests/ui/intrinsics/intrinsic-fmuladd.rs new file mode 100644 index 00000000000..d03297884f7 --- /dev/null +++ b/tests/ui/intrinsics/intrinsic-fmuladd.rs @@ -0,0 +1,42 @@ +//@ run-pass +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => {{ + let (a, b) = (&$a, &$b); + assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b); + }}; +} + +fn main() { + unsafe { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(fmuladdf32(1.23, 4.5, 0.67), 6.205); + assert_approx_eq!(fmuladdf32(-1.23, -4.5, -0.67), 4.865); + assert_approx_eq!(fmuladdf32(0.0, 8.9, 1.2), 1.2); + assert_approx_eq!(fmuladdf32(3.4, -0.0, 5.6), 5.6); + assert!(fmuladdf32(nan, 7.8, 9.0).is_nan()); + assert_eq!(fmuladdf32(inf, 7.8, 9.0), inf); + assert_eq!(fmuladdf32(neg_inf, 7.8, 9.0), neg_inf); + assert_eq!(fmuladdf32(8.9, inf, 3.2), inf); + assert_eq!(fmuladdf32(-3.2, 2.4, neg_inf), neg_inf); + } + unsafe { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(fmuladdf64(1.23, 4.5, 0.67), 6.205); + assert_approx_eq!(fmuladdf64(-1.23, -4.5, -0.67), 4.865); + assert_approx_eq!(fmuladdf64(0.0, 8.9, 1.2), 1.2); + assert_approx_eq!(fmuladdf64(3.4, -0.0, 5.6), 5.6); + assert!(fmuladdf64(nan, 7.8, 9.0).is_nan()); + assert_eq!(fmuladdf64(inf, 7.8, 9.0), inf); + assert_eq!(fmuladdf64(neg_inf, 7.8, 9.0), neg_inf); + assert_eq!(fmuladdf64(8.9, inf, 3.2), inf); + assert_eq!(fmuladdf64(-3.2, 2.4, neg_inf), neg_inf); + } +} diff --git a/tests/ui/issues/issue-31511.rs b/tests/ui/issues/issue-31511.rs index 53fecb01663..6c8df1157c6 100644 --- a/tests/ui/issues/issue-31511.rs +++ b/tests/ui/issues/issue-31511.rs @@ -1,6 +1,6 @@ fn cast_thin_to_fat(x: *const ()) { x as *const [u8]; - //~^ ERROR: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]` + //~^ ERROR: cannot cast thin pointer `*const ()` to wide pointer `*const [u8]` } fn main() {} diff --git a/tests/ui/issues/issue-31511.stderr b/tests/ui/issues/issue-31511.stderr index 177b78754cc..2048bd7ec16 100644 --- a/tests/ui/issues/issue-31511.stderr +++ b/tests/ui/issues/issue-31511.stderr @@ -1,4 +1,4 @@ -error[E0607]: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const ()` to wide pointer `*const [u8]` --> $DIR/issue-31511.rs:2:5 | LL | x as *const [u8]; diff --git a/tests/ui/issues/issue-58734.rs b/tests/ui/issues/issue-58734.rs index c838fde5d73..9b630666baf 100644 --- a/tests/ui/issues/issue-58734.rs +++ b/tests/ui/issues/issue-58734.rs @@ -1,22 +1,22 @@ trait Trait { fn exists(self) -> (); - fn not_object_safe() -> Self; + fn dyn_incompatible() -> Self; } impl Trait for () { fn exists(self) -> () { } - fn not_object_safe() -> Self { + fn dyn_incompatible() -> Self { () } } fn main() { - // object-safe or not, this call is OK + // dyn-compatible or not, this call is OK Trait::exists(()); - // no object safety error + // no dyn-compatibility error Trait::nonexistent(()); //~^ ERROR no function or associated item named `nonexistent` found //~| WARN trait objects without an explicit `dyn` are deprecated diff --git a/tests/ui/issues/issue-85461.rs b/tests/ui/issues/issue-85461.rs index 7fe7a4aa579..72538081ccb 100644 --- a/tests/ui/issues/issue-85461.rs +++ b/tests/ui/issues/issue-85461.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Cinstrument-coverage -Ccodegen-units=4 --crate-type dylib -Copt-level=0 //@ build-pass -//@ needs-profiler-support +//@ needs-profiler-runtime //@ needs-dynamic-linking // Regression test for #85461 where MSVC sometimes fails to link instrument-coverage binaries diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr index b4424f4750e..b4424f4750e 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/kindck/kindck-inherited-copy-bound.rs index c785736f42e..dda95229ddf 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.rs +++ b/tests/ui/kindck/kindck-inherited-copy-bound.rs @@ -1,8 +1,8 @@ // Test that Copy bounds inherited by trait are checked. // -//@ revisions: curr object_safe_for_dispatch +//@ revisions: curr dyn_compatible_for_dispatch -#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] +#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))] use std::any::Any; @@ -19,7 +19,7 @@ fn take_param<T:Foo>(foo: &T) { } fn a() { let x: Box<_> = Box::new(3); take_param(&x); //[curr]~ ERROR E0277 - //[object_safe_for_dispatch]~^ ERROR E0277 + //[dyn_compatible_for_dispatch]~^ ERROR E0277 } fn b() { @@ -28,7 +28,7 @@ fn b() { let z = &x as &dyn Foo; //[curr]~^ ERROR E0038 //[curr]~| ERROR E0038 - //[object_safe_for_dispatch]~^^^ ERROR E0038 + //[dyn_compatible_for_dispatch]~^^^ ERROR E0038 } fn main() { } diff --git a/tests/ui/layout/post-mono-layout-cycle-2.rs b/tests/ui/layout/post-mono-layout-cycle-2.rs new file mode 100644 index 00000000000..356f1e777c7 --- /dev/null +++ b/tests/ui/layout/post-mono-layout-cycle-2.rs @@ -0,0 +1,59 @@ +//@ build-fail +//@ edition: 2021 + +#![feature(async_closure, noop_waker)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on<T>(fut: impl Future<Output = T>) -> T { + let mut fut = pin!(fut); + // Poll loop, just to test the future... + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match fut.as_mut().poll(ctx) { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} + +trait Blah { + async fn iter<T>(&mut self, iterator: T) + where + T: IntoIterator<Item = ()>; +} + +impl Blah for () { + async fn iter<T>(&mut self, iterator: T) + //~^ ERROR recursion in an async fn requires boxing + where + T: IntoIterator<Item = ()>, + { + Blah::iter(self, iterator).await + } +} + +struct Wrap<T: Blah> { + t: T, +} + +impl<T: Blah> Wrap<T> +where + T: Blah, +{ + async fn ice(&mut self) { + //~^ ERROR a cycle occurred during layout computation + let arr: [(); 0] = []; + self.t.iter(arr.into_iter()).await; + } +} + +fn main() { + block_on(async { + let mut t = Wrap { t: () }; + t.ice(); + }) +} diff --git a/tests/ui/layout/post-mono-layout-cycle-2.stderr b/tests/ui/layout/post-mono-layout-cycle-2.stderr new file mode 100644 index 00000000000..ad01c2694fa --- /dev/null +++ b/tests/ui/layout/post-mono-layout-cycle-2.stderr @@ -0,0 +1,23 @@ +error[E0733]: recursion in an async fn requires boxing + --> $DIR/post-mono-layout-cycle-2.rs:30:5 + | +LL | / async fn iter<T>(&mut self, iterator: T) +LL | | +LL | | where +LL | | T: IntoIterator<Item = ()>, + | |___________________________________^ +LL | { +LL | Blah::iter(self, iterator).await + | -------------------------------- recursive call here + | + = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future + +error: a cycle occurred during layout computation + --> $DIR/post-mono-layout-cycle-2.rs:47:5 + | +LL | async fn ice(&mut self) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/layout/post-mono-layout-cycle.rs b/tests/ui/layout/post-mono-layout-cycle.rs new file mode 100644 index 00000000000..8d136190c00 --- /dev/null +++ b/tests/ui/layout/post-mono-layout-cycle.rs @@ -0,0 +1,25 @@ +//@ build-fail +//~^ cycle detected when computing layout of `Wrapper<()>` + +trait Trait { + type Assoc; +} + +impl Trait for () { + type Assoc = Wrapper<()>; +} + +struct Wrapper<T: Trait> { + _x: <T as Trait>::Assoc, +} + +fn abi<T: Trait>(_: Option<Wrapper<T>>) {} +//~^ ERROR a cycle occurred during layout computation + +fn indirect<T: Trait>() { + abi::<T>(None); +} + +fn main() { + indirect::<()>(); +} diff --git a/tests/ui/layout/post-mono-layout-cycle.stderr b/tests/ui/layout/post-mono-layout-cycle.stderr new file mode 100644 index 00000000000..47f7f30b1cb --- /dev/null +++ b/tests/ui/layout/post-mono-layout-cycle.stderr @@ -0,0 +1,16 @@ +error[E0391]: cycle detected when computing layout of `Wrapper<()>` + | + = note: ...which requires computing layout of `<() as Trait>::Assoc`... + = note: ...which again requires computing layout of `Wrapper<()>`, completing the cycle + = note: cycle used when computing layout of `core::option::Option<Wrapper<()>>` + = 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: a cycle occurred during layout computation + --> $DIR/post-mono-layout-cycle.rs:16:1 + | +LL | fn abi<T: Trait>(_: Option<Wrapper<T>>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparison.stderr index f2d55c107ba..054c06d38b3 100644 --- a/tests/ui/lint/invalid-nan-comparison.stderr +++ b/tests/ui/lint/invalid-nan-comparison.stderr @@ -5,6 +5,11 @@ LL | const TEST: bool = 5f32 == f32::NAN; | ^^^^^^^^^^^^^^^^ | = note: `#[warn(invalid_nan_comparisons)]` on by default +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - const TEST: bool = 5f32 == f32::NAN; +LL + const TEST: bool = 5f32.is_nan(); + | warning: incorrect NaN comparison, NaN cannot be directly compared to itself --> $DIR/invalid-nan-comparison.rs:14:5 diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr index 77ee28b48cc..d579fa391fc 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.stderr +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -12,7 +12,6 @@ LL | non_local_macro::non_local_impl!(LocalStruct); = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/non-local-defs/consts.rs b/tests/ui/lint/non-local-defs/consts.rs index d8a497e43e5..5b9dab3cfd3 100644 --- a/tests/ui/lint/non-local-defs/consts.rs +++ b/tests/ui/lint/non-local-defs/consts.rs @@ -63,6 +63,13 @@ fn main() { 1 }; + + const _: () = { + const _: () = { + impl Test {} + //~^ WARN non-local `impl` definition + }; + }; } trait Uto9 {} diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr index 7f76056c021..20fb4a6432e 100644 --- a/tests/ui/lint/non-local-defs/consts.stderr +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -15,7 +15,6 @@ LL | impl Uto for &Test {} | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item @@ -31,7 +30,6 @@ LL | impl Uto2 for Test {} | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:32:5 @@ -46,7 +44,6 @@ LL | impl Uto3 for Test {} | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:43:5 @@ -59,7 +56,6 @@ LL | impl Test { | `Test` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:50:9 @@ -78,7 +74,6 @@ LL | | }; | |_____- move the `impl` block outside of this inline constant `<unnameable>` and up 2 bodies | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:59:9 @@ -92,10 +87,22 @@ LL | impl Test { | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:72:9 + --> $DIR/consts.rs:69:13 + | +LL | const _: () = { + | ----------- move the `impl` block outside of this constant `_` and up 3 bodies +LL | impl Test {} + | ^^^^^---- + | | + | `Test` is not local + | + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint + +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item + --> $DIR/consts.rs:79:9 | LL | let _a = || { | -- move the `impl` block outside of this closure `<unnameable>` and up 2 bodies @@ -106,10 +113,9 @@ LL | impl Uto9 for Test {} | `Uto9` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item - --> $DIR/consts.rs:79:9 + --> $DIR/consts.rs:86:9 | LL | type A = [u32; { | ____________________- @@ -124,7 +130,6 @@ LL | | }]; | |_____- move the `impl` block outside of this constant expression `<unnameable>` and up 2 bodies | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> -warning: 8 warnings emitted +warning: 9 warnings emitted diff --git a/tests/ui/lint/non-local-defs/convoluted-locals-131474-with-mods.rs b/tests/ui/lint/non-local-defs/convoluted-locals-131474-with-mods.rs new file mode 100644 index 00000000000..72fd056d461 --- /dev/null +++ b/tests/ui/lint/non-local-defs/convoluted-locals-131474-with-mods.rs @@ -0,0 +1,45 @@ +// This test check that no matter the nesting of const-anons and modules +// we consider them as transparent. +// +// Similar to https://github.com/rust-lang/rust/issues/131474 + +//@ check-pass + +pub mod tmp { + pub mod tmp { + pub struct Test; + } +} + +const _: () = { + const _: () = { + const _: () = { + const _: () = { + impl tmp::tmp::Test {} + }; + }; + }; +}; + +const _: () = { + const _: () = { + mod tmp { + pub(super) struct InnerTest; + } + + impl tmp::InnerTest {} + }; +}; + +// https://github.com/rust-lang/rust/issues/131643 +const _: () = { + const _: () = { + impl tmp::InnerTest {} + }; + + mod tmp { + pub(super) struct InnerTest; + } +}; + +fn main() {} diff --git a/tests/ui/lint/non-local-defs/convoluted-locals-131474.rs b/tests/ui/lint/non-local-defs/convoluted-locals-131474.rs new file mode 100644 index 00000000000..8e738544a71 --- /dev/null +++ b/tests/ui/lint/non-local-defs/convoluted-locals-131474.rs @@ -0,0 +1,33 @@ +// This test check that no matter the nesting of const-anons we consider +// them as transparent. +// +// https://github.com/rust-lang/rust/issues/131474 + +//@ check-pass + +pub struct Test; + +const _: () = { + const _: () = { + impl Test {} + }; +}; + +const _: () = { + const _: () = { + struct InnerTest; + + impl InnerTest {} + }; +}; + +// https://github.com/rust-lang/rust/issues/131643 +const _: () = { + const _: () = { + impl InnerTest {} + }; + + struct InnerTest; +}; + +fn main() {} diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr index c58ec12aaac..83e46df185d 100644 --- a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr @@ -10,7 +10,6 @@ LL | impl PartialEq<()> for Dog { | `PartialEq` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item @@ -26,7 +25,6 @@ LL | impl PartialEq<()> for &Dog { | `PartialEq` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:21:5 @@ -41,7 +39,6 @@ LL | impl PartialEq<Dog> for () { | `PartialEq` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:28:5 @@ -56,7 +53,6 @@ LL | impl PartialEq<&Dog> for () { | `PartialEq` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:35:5 @@ -72,7 +68,6 @@ LL | impl PartialEq<Dog> for &Dog { | `PartialEq` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:42:5 @@ -88,7 +83,6 @@ LL | impl PartialEq<&Dog> for &Dog { | `PartialEq` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: 6 warnings emitted diff --git a/tests/ui/lint/non-local-defs/exhaustive.stderr b/tests/ui/lint/non-local-defs/exhaustive.stderr index dd41b2206d8..1e6fc910621 100644 --- a/tests/ui/lint/non-local-defs/exhaustive.stderr +++ b/tests/ui/lint/non-local-defs/exhaustive.stderr @@ -9,7 +9,6 @@ LL | impl Test { | `Test` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item @@ -25,7 +24,6 @@ LL | impl Display for Test { | `Display` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:22:5 @@ -39,7 +37,6 @@ LL | impl dyn Trait {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:25:5 @@ -54,7 +51,6 @@ LL | impl<T: Trait> Trait for Vec<T> { } | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:28:5 @@ -69,7 +65,6 @@ LL | impl Trait for &dyn Trait {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:31:5 @@ -84,7 +79,6 @@ LL | impl Trait for *mut Test {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:34:5 @@ -99,7 +93,6 @@ LL | impl Trait for *mut [Test] {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:37:5 @@ -114,7 +107,6 @@ LL | impl Trait for [Test; 8] {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:40:5 @@ -129,7 +121,6 @@ LL | impl Trait for (Test,) {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:43:5 @@ -144,7 +135,6 @@ LL | impl Trait for fn(Test) -> () {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:46:5 @@ -159,7 +149,6 @@ LL | impl Trait for fn() -> Test {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:50:9 @@ -173,7 +162,6 @@ LL | impl Trait for Test {} | `Trait` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:67:9 @@ -187,7 +175,6 @@ LL | impl Display for InsideMain { | `Display` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:74:9 @@ -201,7 +188,6 @@ LL | impl InsideMain { | `InsideMain` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: 14 warnings emitted diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.stderr b/tests/ui/lint/non-local-defs/from-local-for-global.stderr index 6839ebd2c8a..f173c054e78 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.stderr +++ b/tests/ui/lint/non-local-defs/from-local-for-global.stderr @@ -10,7 +10,6 @@ LL | impl From<Cat> for () { | `From` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default warning: 1 warning emitted diff --git a/tests/ui/lint/non-local-defs/generics.stderr b/tests/ui/lint/non-local-defs/generics.stderr index aefe8921fe2..66769cc1e0b 100644 --- a/tests/ui/lint/non-local-defs/generics.stderr +++ b/tests/ui/lint/non-local-defs/generics.stderr @@ -11,7 +11,6 @@ LL | impl<T: Local> Global for Vec<T> { } | `Global` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item @@ -27,7 +26,6 @@ LL | impl Uto7 for Test where Local: std::any::Any {} | `Uto7` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:23:5 @@ -41,7 +39,6 @@ LL | impl<T> Uto8 for T {} | `Uto8` is not local | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: 3 warnings emitted diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr index faab6aea2b3..b6fe1a921d7 100644 --- a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr @@ -14,7 +14,6 @@ LL | m!(); | = note: the macro `m` defines the non-local `impl`, and may need to be changed = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/non-local-defs/local.rs b/tests/ui/lint/non-local-defs/local.rs index 166ee88c021..f7ecd68f59e 100644 --- a/tests/ui/lint/non-local-defs/local.rs +++ b/tests/ui/lint/non-local-defs/local.rs @@ -51,3 +51,10 @@ fn bitflags() { impl Flags {} }; } + +fn bitflags_internal() { + const _: () = { + struct InternalFlags; + impl InternalFlags {} + }; +} diff --git a/tests/ui/lint/non-local-defs/macro_rules.stderr b/tests/ui/lint/non-local-defs/macro_rules.stderr index 4e86fc7b987..28779a78066 100644 --- a/tests/ui/lint/non-local-defs/macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/macro_rules.stderr @@ -6,7 +6,6 @@ LL | macro_rules! m0 { () => { } }; | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module @@ -17,7 +16,6 @@ LL | non_local_macro::non_local_macro_rules!(my_macro); | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `_MACRO_EXPORT` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -29,7 +27,6 @@ LL | macro_rules! m { () => { } }; | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module --> $DIR/macro_rules.rs:29:13 @@ -39,7 +36,6 @@ LL | macro_rules! m2 { () => { } }; | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current associated function `bar` and up 2 bodies = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: 4 warnings emitted diff --git a/tests/ui/lint/non-local-defs/weird-exprs.stderr b/tests/ui/lint/non-local-defs/weird-exprs.stderr index f6ce063929e..ec3517140ef 100644 --- a/tests/ui/lint/non-local-defs/weird-exprs.stderr +++ b/tests/ui/lint/non-local-defs/weird-exprs.stderr @@ -14,7 +14,6 @@ LL | | }]; | |_- move the `impl` block outside of this constant expression `<unnameable>` | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item @@ -33,7 +32,6 @@ LL | | } | |_____- move the `impl` block outside of this constant expression `<unnameable>` | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:25:9 @@ -52,7 +50,6 @@ LL | | }]; | |_____- move the `impl` block outside of this constant expression `<unnameable>` and up 2 bodies | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:34:9 @@ -70,7 +67,6 @@ LL | | }]; | |_____- move the `impl` block outside of this constant expression `<unnameable>` and up 2 bodies | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:41:9 @@ -88,7 +84,6 @@ LL | | }]) {} | |_____- move the `impl` block outside of this constant expression `<unnameable>` and up 2 bodies | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:48:9 @@ -107,7 +102,6 @@ LL | | }] { todo!() } | |_____- move the `impl` block outside of this constant expression `<unnameable>` and up 2 bodies | = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: 6 warnings emitted diff --git a/tests/ui/lint/unconditional_panic_promoted.rs b/tests/ui/lint/unconditional_panic_promoted.rs new file mode 100644 index 00000000000..37bcf046513 --- /dev/null +++ b/tests/ui/lint/unconditional_panic_promoted.rs @@ -0,0 +1,8 @@ +//@ build-fail + +fn main() { + // MIR encodes this as a reborrow from a promoted constant. + // But the array lenth can still be gotten from the type. + let slice = &[0, 1]; + let _ = slice[2]; //~ ERROR: this operation will panic at runtime [unconditional_panic] +} diff --git a/tests/ui/lint/unconditional_panic_promoted.stderr b/tests/ui/lint/unconditional_panic_promoted.stderr new file mode 100644 index 00000000000..647a84a55fd --- /dev/null +++ b/tests/ui/lint/unconditional_panic_promoted.stderr @@ -0,0 +1,10 @@ +error: this operation will panic at runtime + --> $DIR/unconditional_panic_promoted.rs:7:13 + | +LL | let _ = slice[2]; + | ^^^^^^^^ index out of bounds: the length is 2 but the index is 2 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.fixed b/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.fixed new file mode 100644 index 00000000000..8287b3d3ac7 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.fixed @@ -0,0 +1,15 @@ +//@ run-rustfix +// Check the `unused_parens` suggestion for paren_expr with attributes. +// The suggestion should retain attributes in the front. + +#![feature(stmt_expr_attributes)] +#![deny(unused_parens)] + +pub fn foo() -> impl Fn() { + let _ = #[inline] #[allow(dead_code)] || println!("Hello!"); //~ERROR unnecessary parentheses + #[inline] #[allow(dead_code)] || println!("Hello!") //~ERROR unnecessary parentheses +} + +fn main() { + let _ = foo(); +} diff --git a/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.rs b/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.rs new file mode 100644 index 00000000000..0b6edae30e7 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.rs @@ -0,0 +1,15 @@ +//@ run-rustfix +// Check the `unused_parens` suggestion for paren_expr with attributes. +// The suggestion should retain attributes in the front. + +#![feature(stmt_expr_attributes)] +#![deny(unused_parens)] + +pub fn foo() -> impl Fn() { + let _ = (#[inline] #[allow(dead_code)] || println!("Hello!")); //~ERROR unnecessary parentheses + (#[inline] #[allow(dead_code)] || println!("Hello!")) //~ERROR unnecessary parentheses +} + +fn main() { + let _ = foo(); +} diff --git a/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.stderr b/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.stderr new file mode 100644 index 00000000000..65513553f7e --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-for-stmt-expr-attributes-issue-129833.stderr @@ -0,0 +1,31 @@ +error: unnecessary parentheses around assigned value + --> $DIR/unused-parens-for-stmt-expr-attributes-issue-129833.rs:9:13 + | +LL | let _ = (#[inline] #[allow(dead_code)] || println!("Hello!")); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-for-stmt-expr-attributes-issue-129833.rs:6:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let _ = (#[inline] #[allow(dead_code)] || println!("Hello!")); +LL + let _ = #[inline] #[allow(dead_code)] || println!("Hello!"); + | + +error: unnecessary parentheses around block return value + --> $DIR/unused-parens-for-stmt-expr-attributes-issue-129833.rs:10:5 + | +LL | (#[inline] #[allow(dead_code)] || println!("Hello!")) + | ^ ^ + | +help: remove these parentheses + | +LL - (#[inline] #[allow(dead_code)] || println!("Hello!")) +LL + #[inline] #[allow(dead_code)] || println!("Hello!") + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs index 2aac50a9d01..50998572274 100644 --- a/tests/ui/macros/cfg.rs +++ b/tests/ui/macros/cfg.rs @@ -1,6 +1,6 @@ fn main() { cfg!(); //~ ERROR macro requires a cfg-pattern - cfg!(123); //~ ERROR expected identifier + cfg!(123); //~ ERROR literal in `cfg` predicate value must be a boolean cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern } diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr index 2633d5f720d..53326914865 100644 --- a/tests/ui/macros/cfg.stderr +++ b/tests/ui/macros/cfg.stderr @@ -6,11 +6,11 @@ LL | cfg!(); | = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected identifier, found `123` +error[E0565]: literal in `cfg` predicate value must be a boolean --> $DIR/cfg.rs:3:10 | LL | cfg!(123); - | ^^^ expected identifier + | ^^^ error[E0565]: literal in `cfg` predicate value must be a string --> $DIR/cfg.rs:4:16 diff --git a/tests/ui/meta/revision-bad.rs b/tests/ui/meta/revision-bad.rs index c5193b19d9e..0af5624ff9c 100644 --- a/tests/ui/meta/revision-bad.rs +++ b/tests/ui/meta/revision-bad.rs @@ -5,6 +5,7 @@ //@ revisions: foo bar //@ should-fail //@ needs-run-enabled +//@ compile-flags: --remap-path-prefix={{src-base}}=remapped //@[foo] error-pattern:bar //@[bar] error-pattern:foo diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index 3d12ba9899b..2e5cbb90036 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -158,7 +158,7 @@ LL | let _ = 42usize as *const [u8]; | | | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` -error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]` --> $DIR/cast-rfc0401.rs:52:13 | LL | let _ = v as *const [u8]; diff --git a/tests/ui/never_type/diverging-place-match.rs b/tests/ui/never_type/diverging-place-match.rs new file mode 100644 index 00000000000..b9bc29a218c --- /dev/null +++ b/tests/ui/never_type/diverging-place-match.rs @@ -0,0 +1,74 @@ +#![feature(never_type)] + +fn not_a_read() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let _: ! = *x; + // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this + // is unsound since we act as if it diverges but it doesn't. + } +} + +fn not_a_read_implicit() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let _ = *x; + } +} + +fn not_a_read_guide_coercion() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let _: () = *x; + //~^ ERROR mismatched types + } +} + +fn empty_match() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + match *x { _ => {} }; + } +} + +fn field_projection() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const (!, ()) = 0 as _; + let _ = (*x).0; + // ^ I think this is still UB, but because of the inbounds projection. + } +} + +fn covered_arm() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let (_ | 1i32) = *x; + //~^ ERROR mismatched types + } +} + +// FIXME: This *could* be considered a read of `!`, but we're not that sophisticated.. +fn uncovered_arm() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let (1i32 | _) = *x; + //~^ ERROR mismatched types + } +} + +fn coerce_ref_binding() -> ! { + unsafe { + let x: *const ! = 0 as _; + let ref _x: () = *x; + //~^ ERROR mismatched types + } +} + +fn main() {} diff --git a/tests/ui/never_type/diverging-place-match.stderr b/tests/ui/never_type/diverging-place-match.stderr new file mode 100644 index 00000000000..74e1bfa0a6b --- /dev/null +++ b/tests/ui/never_type/diverging-place-match.stderr @@ -0,0 +1,142 @@ +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:4:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let _: ! = *x; +LL | | // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this +LL | | // is unsound since we act as if it diverges but it doesn't. +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:14:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let _ = *x; +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:25:21 + | +LL | let _: () = *x; + | -- ^^ expected `()`, found `!` + | | + | expected due to this + | + = note: expected unit type `()` + found type `!` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:22:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let _: () = *x; +LL | | +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:31:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | match *x { _ => {} }; +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:39:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const (!, ()) = 0 as _; +LL | | let _ = (*x).0; +LL | | // ^ I think this is still UB, but because of the inbounds projection. +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:51:18 + | +LL | let (_ | 1i32) = *x; + | ^^^^ -- this expression has type `!` + | | + | expected `!`, found `i32` + | + = note: expected type `!` + found type `i32` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:48:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let (_ | 1i32) = *x; +LL | | +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:61:14 + | +LL | let (1i32 | _) = *x; + | ^^^^ -- this expression has type `!` + | | + | expected `!`, found `i32` + | + = note: expected type `!` + found type `i32` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:58:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let (1i32 | _) = *x; +LL | | +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:69:26 + | +LL | let ref _x: () = *x; + | ^^ expected `()`, found `!` + | + = note: expected unit type `()` + found type `!` + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr deleted file mode 100644 index 4e3d2ebebad..00000000000 --- a/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error[E0038]: the trait `Copy` cannot be made into an object - --> $DIR/avoid-ice-on-warning-2.rs:4:13 - | -LL | fn id<F>(f: Copy) -> usize { - | ^^^^ `Copy` cannot be made into an object - | - = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - -error[E0618]: expected function, found `(dyn Copy + 'static)` - --> $DIR/avoid-ice-on-warning-2.rs:11:5 - | -LL | fn id<F>(f: Copy) -> usize { - | - `f` has type `(dyn Copy + 'static)` -... -LL | f() - | ^-- - | | - | call expression requires function - -error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time - --> $DIR/avoid-ice-on-warning-2.rs:4:13 - | -LL | fn id<F>(f: Copy) -> usize { - | ^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(dyn Copy + 'static)` - = help: unsized fn params are gated as an unstable feature -help: you can use `impl Trait` as the argument type - | -LL | fn id<F>(f: impl Copy) -> usize { - | ++++ -help: function arguments must have a statically known size, borrowed types always have a known size - | -LL | fn id<F>(f: &dyn Copy) -> usize { - | ++++ - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0038, E0277, E0618. -For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr deleted file mode 100644 index fdd3e8ab507..00000000000 --- a/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0038]: the trait `A` cannot be made into an object - --> $DIR/avoid-ice-on-warning-3.rs:4:19 - | -LL | trait B { fn f(a: A) -> A; } - | ^ `A` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/avoid-ice-on-warning-3.rs:12:14 - | -LL | trait A { fn g(b: B) -> B; } - | - ^ ...because associated function `g` has no `self` parameter - | | - | this trait cannot be made into an object... -help: consider turning `g` into a method by giving it a `&self` argument - | -LL | trait A { fn g(&self, b: B) -> B; } - | ++++++ -help: alternatively, consider constraining `g` so it does not apply to trait objects - | -LL | trait A { fn g(b: B) -> B where Self: Sized; } - | +++++++++++++++++ - -error[E0038]: the trait `B` cannot be made into an object - --> $DIR/avoid-ice-on-warning-3.rs:12:19 - | -LL | trait A { fn g(b: B) -> B; } - | ^ `B` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/avoid-ice-on-warning-3.rs:4:14 - | -LL | trait B { fn f(a: A) -> A; } - | - ^ ...because associated function `f` has no `self` parameter - | | - | this trait cannot be made into an object... -help: consider turning `f` into a method by giving it a `&self` argument - | -LL | trait B { fn f(&self, a: A) -> A; } - | ++++++ -help: alternatively, consider constraining `f` so it does not apply to trait objects - | -LL | trait B { fn f(a: A) -> A where Self: Sized; } - | +++++++++++++++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr deleted file mode 100644 index 4ff45d7a848..00000000000 --- a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: return types are denoted using `->` - --> $DIR/avoid-ice-on-warning.rs:4:23 - | -LL | fn call_this<F>(f: F) : Fn(&str) + call_that {} - | ^ - | -help: use `->` instead - | -LL | fn call_this<F>(f: F) -> Fn(&str) + call_that {} - | ~~ - -error[E0405]: cannot find trait `call_that` in this scope - --> $DIR/avoid-ice-on-warning.rs:4:36 - | -LL | fn call_this<F>(f: F) : Fn(&str) + call_that {} - | ^^^^^^^^^ not found in this scope - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr deleted file mode 100644 index bb2bf6ddcda..00000000000 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0038]: the trait `Ord` cannot be made into an object - --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33 - | -LL | fn ord_prefer_dot(s: String) -> Ord { - | ^^^ `Ord` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $SRC_DIR/core/src/cmp.rs:LL:COL - | - = note: the trait cannot be made into an object because it uses `Self` as a type parameter - ::: $SRC_DIR/core/src/cmp.rs:LL:COL - | - = note: the trait cannot be made into an object because it uses `Self` as a type parameter -help: consider using an opaque type instead - | -LL | fn ord_prefer_dot(s: String) -> impl Ord { - | ++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr index 9ed387fc8d1..605567acdb5 100644 --- a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr +++ b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr @@ -5,7 +5,7 @@ LL | #[track_caller] | ^^^^^^^^^^^^^^^ LL | LL | fn panic(info: &PanicInfo) -> ! { - | ------------------------------- `#[panic_handler]` function is not allowed to have `#[target_feature]` + | ------------------------------- `#[panic_handler]` function is not allowed to have `#[track_caller]` error: aborting due to 1 previous error diff --git a/tests/ui/parser/bad-name.stderr b/tests/ui/parser/bad-name.stderr index 3fc416dd531..5ca248380ee 100644 --- a/tests/ui/parser/bad-name.stderr +++ b/tests/ui/parser/bad-name.stderr @@ -8,7 +8,9 @@ error: expected a pattern, found an expression --> $DIR/bad-name.rs:2:7 | LL | let x.y::<isize>.z foo; - | ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo` --> $DIR/bad-name.rs:2:22 diff --git a/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.fixed b/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.fixed new file mode 100644 index 00000000000..2c6fddccb73 --- /dev/null +++ b/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.fixed @@ -0,0 +1,7 @@ +//@ run-rustfix + +#[allow(dead_code)] +fn invalid_path_separator<T>() {} +//~^ ERROR invalid path separator in function definition + +fn main() {} diff --git a/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.rs b/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.rs new file mode 100644 index 00000000000..5f690615043 --- /dev/null +++ b/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.rs @@ -0,0 +1,7 @@ +//@ run-rustfix + +#[allow(dead_code)] +fn invalid_path_separator::<T>() {} +//~^ ERROR invalid path separator in function definition + +fn main() {} diff --git a/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.stderr b/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.stderr new file mode 100644 index 00000000000..3ad05050da0 --- /dev/null +++ b/tests/ui/parser/issues/invalid-path-sep-in-fn-definition-issue-130791.stderr @@ -0,0 +1,14 @@ +error: invalid path separator in function definition + --> $DIR/invalid-path-sep-in-fn-definition-issue-130791.rs:4:26 + | +LL | fn invalid_path_separator::<T>() {} + | ^^ + | +help: remove invalid path separator + | +LL - fn invalid_path_separator::<T>() {} +LL + fn invalid_path_separator<T>() {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr index 7ebbf4ac370..c92e165b23b 100644 --- a/tests/ui/parser/issues/issue-24197.stderr +++ b/tests/ui/parser/issues/issue-24197.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/issue-24197.rs:2:9 | LL | let buf[0] = 0; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index a25c277d78a..fef3fcde7b7 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -2,8 +2,9 @@ error: expected a pattern, found an expression --> $DIR/issue-24375.rs:6:9 | LL | tmp[0] => {} - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == tmp[0] => {} diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr index 18cf2df0282..a2a972652d1 100644 --- a/tests/ui/parser/pat-lt-bracket-5.stderr +++ b/tests/ui/parser/pat-lt-bracket-5.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/pat-lt-bracket-5.rs:2:9 | LL | let v[0] = v[1]; - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error[E0425]: cannot find value `v` in this scope --> $DIR/pat-lt-bracket-5.rs:2:16 diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 892883c4aed..14ae602fedf 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/pat-lt-bracket-6.rs:5:14 | LL | let Test(&desc[..]) = x; - | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error[E0308]: mismatched types --> $DIR/pat-lt-bracket-6.rs:10:30 diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr index 5e1f35d1b6f..ef080368e19 100644 --- a/tests/ui/parser/pat-ranges-3.stderr +++ b/tests/ui/parser/pat-ranges-3.stderr @@ -2,13 +2,17 @@ error: expected a pattern range bound, found an expression --> $DIR/pat-ranges-3.rs:4:16 | LL | let 10 ..= 10 + 3 = 12; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: expected a pattern range bound, found an expression --> $DIR/pat-ranges-3.rs:7:9 | LL | let 10 - 3 ..= 10 = 8; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: aborting due to 2 previous errors diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr index 63956f35c07..6cb3753de8d 100644 --- a/tests/ui/parser/recover/recover-pat-exprs.stderr +++ b/tests/ui/parser/recover/recover-pat-exprs.stderr @@ -2,8 +2,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:5:9 | LL | x.y => (), - | ^^^ arbitrary expressions are not allowed in patterns + | ^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x.y => (), @@ -24,8 +25,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:6:9 | LL | x.0 => (), - | ^^^ arbitrary expressions are not allowed in patterns + | ^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x.0 => (), @@ -47,8 +49,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:7:9 | LL | x._0 => (), - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x._0 => (), @@ -71,8 +74,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:8:9 | LL | x.0.1 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x.0.1 => (), @@ -95,8 +99,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:9:9 | LL | x.4.y.17.__z => (), - | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x.4.y.17.__z => (), @@ -149,8 +154,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:23:9 | LL | x[0] => (), - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x[0] => (), @@ -170,8 +176,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:24:9 | LL | x[..] => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x[..] => (), @@ -219,8 +226,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:37:9 | LL | x.f() => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x.f() => (), @@ -240,8 +248,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:38:9 | LL | x._f() => (), - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x._f() => (), @@ -262,8 +271,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:39:9 | LL | x? => (), - | ^^ arbitrary expressions are not allowed in patterns + | ^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x? => (), @@ -285,8 +295,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:40:9 | LL | ().f() => (), - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == ().f() => (), @@ -309,8 +320,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:41:9 | LL | (0, x)?.f() => (), - | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == (0, x)?.f() => (), @@ -333,8 +345,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:42:9 | LL | x.f().g() => (), - | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x.f().g() => (), @@ -357,8 +370,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:43:9 | LL | 0.f()?.g()?? => (), - | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == 0.f()?.g()?? => (), @@ -381,8 +395,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:50:9 | LL | x as usize => (), - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x as usize => (), @@ -402,8 +417,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:51:9 | LL | 0 as usize => (), - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == 0 as usize => (), @@ -424,8 +440,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:52:9 | LL | x.f().0.4 as f32 => (), - | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == x.f().0.4 as f32 => (), @@ -447,8 +464,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:59:9 | LL | 1 + 1 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == 1 + 1 => (), @@ -468,8 +486,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:60:9 | LL | (1 + 2) * 3 => (), - | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == (1 + 2) * 3 => (), @@ -490,8 +509,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:63:9 | LL | x.0 > 2 => (), - | ^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == (x.0 > 2) => (), @@ -514,8 +534,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:64:9 | LL | x.0 == 2 => (), - | ^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == (x.0 == 2) => (), @@ -538,8 +559,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:69:13 | LL | (x, y.0 > 2) if x != 0 => (), - | ^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to the match arm guard | LL | (x, val) if x != 0 && val == (y.0 > 2) => (), @@ -559,8 +581,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:70:13 | LL | (x, y.0 > 2) if x != 0 || x != 1 => (), - | ^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to the match arm guard | LL | (x, val) if (x != 0 || x != 1) && val == (y.0 > 2) => (), @@ -598,8 +621,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:81:9 | LL | u8::MAX.abs() => (), - | ^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == u8::MAX.abs() => (), @@ -619,8 +643,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:86:17 | LL | z @ w @ v.u() => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | z @ w @ val if val == v.u() => (), @@ -643,8 +668,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:88:9 | LL | y.ilog(3) => (), - | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == y.ilog(3) => (), @@ -667,8 +693,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:90:9 | LL | n + 1 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == n + 1 => (), @@ -691,8 +718,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:92:10 | LL | ("".f() + 14 * 8) => (), - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | (val) if val == "".f() + 14 * 8 => (), @@ -715,8 +743,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:95:9 | LL | f?() => (), - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | val if val == f?() => (), @@ -739,7 +768,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:101:9 | LL | let 1 + 1 = 2; - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: expected one of `)`, `,`, `@`, or `|`, found `*` --> $DIR/recover-pat-exprs.rs:104:28 @@ -754,19 +785,25 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:60:10 | LL | (1 + 2) * 3 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:75:5 | LL | 1 + 2 * PI.cos() => 2, - | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:83:9 | LL | x.sqrt() @ .. => (), - | ^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: aborting due to 45 previous errors diff --git a/tests/ui/parser/recover/recover-pat-issues.stderr b/tests/ui/parser/recover/recover-pat-issues.stderr index 596bff21395..17cb7b4aead 100644 --- a/tests/ui/parser/recover/recover-pat-issues.stderr +++ b/tests/ui/parser/recover/recover-pat-issues.stderr @@ -2,8 +2,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:6:13 | LL | Foo("hi".to_owned()) => true, - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | Foo(val) if val == "hi".to_owned() => true, @@ -23,8 +24,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:14:20 | LL | Bar { baz: "hi".to_owned() } => true, - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | Bar { baz } if baz == "hi".to_owned() => true, @@ -44,8 +46,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:25:11 | LL | &["foo".to_string()] => {} - | ^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider moving the expression to a match arm guard | LL | &[val] if val == "foo".to_string() => {} @@ -65,8 +68,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:36:17 | LL | if let Some(MAGIC.0 as usize) = None::<usize> {} - | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = MAGIC.0 as usize; @@ -81,8 +85,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:41:13 | LL | if let (-1.some(4)) = (0, Some(4)) {} - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = -1.some(4); @@ -97,8 +102,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:44:13 | LL | if let (-1.Some(4)) = (0, Some(4)) {} - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = -1.Some(4); diff --git a/tests/ui/parser/recover/recover-pat-lets.stderr b/tests/ui/parser/recover/recover-pat-lets.stderr index e54586b0924..b481813b246 100644 --- a/tests/ui/parser/recover/recover-pat-lets.stderr +++ b/tests/ui/parser/recover/recover-pat-lets.stderr @@ -2,26 +2,33 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:4:9 | LL | let x.expect("foo"); - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:7:9 | LL | let x.unwrap(): u32; - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:10:9 | LL | let x[0] = 1; - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:13:14 | LL | let Some(1 + 1) = x else { - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 + 1; @@ -36,8 +43,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:17:17 | LL | if let Some(1 + 1) = x { - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 + 1; diff --git a/tests/ui/parser/recover/recover-pat-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr index 088f83b0ccb..0a9b5447468 100644 --- a/tests/ui/parser/recover/recover-pat-ranges.stderr +++ b/tests/ui/parser/recover/recover-pat-ranges.stderr @@ -86,8 +86,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:11:12 | LL | ..=1 + 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 + 2; @@ -106,8 +107,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:15:10 | LL | (-4 + 0).. => (), - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = -4 + 0; @@ -126,8 +128,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:18:10 | LL | (1 + 4)...1 * 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 + 4; @@ -146,8 +149,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:18:19 | LL | (1 + 4)...1 * 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 * 2; @@ -166,8 +170,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:24:9 | LL | 0.x()..="y".z() => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 0.x(); @@ -186,8 +191,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:24:17 | LL | 0.x()..="y".z() => (), - | ^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = "y".z(); diff --git a/tests/ui/parser/recover/recover-pat-wildcards.stderr b/tests/ui/parser/recover/recover-pat-wildcards.stderr index 30307726a97..8d4212ed389 100644 --- a/tests/ui/parser/recover/recover-pat-wildcards.stderr +++ b/tests/ui/parser/recover/recover-pat-wildcards.stderr @@ -75,8 +75,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-wildcards.rs:55:14 | LL | 4..=(2 + _) => () - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 2 + _; diff --git a/tests/ui/privacy/private-type-in-interface.rs b/tests/ui/privacy/private-type-in-interface.rs index 2e8be28d76e..9eadd09867d 100644 --- a/tests/ui/privacy/private-type-in-interface.rs +++ b/tests/ui/privacy/private-type-in-interface.rs @@ -26,7 +26,5 @@ type A = <m::Alias as m::Trait>::X; //~ ERROR type `Priv` is private trait Tr2<T> {} impl<T> Tr2<T> for u8 {} fn g() -> impl Tr2<m::Alias> { 0 } //~ ERROR type `Priv` is private - //~| ERROR type `Priv` is private fn g_ext() -> impl Tr2<ext::Alias> { 0 } //~ ERROR type `ext::Priv` is private - //~| ERROR type `ext::Priv` is private fn main() {} diff --git a/tests/ui/privacy/private-type-in-interface.stderr b/tests/ui/privacy/private-type-in-interface.stderr index 091cae42dea..03225d84fdb 100644 --- a/tests/ui/privacy/private-type-in-interface.stderr +++ b/tests/ui/privacy/private-type-in-interface.stderr @@ -46,23 +46,11 @@ error: type `Priv` is private LL | fn g() -> impl Tr2<m::Alias> { 0 } | ^^^^^^^^^^^^^^^^^^ private type -error: type `Priv` is private - --> $DIR/private-type-in-interface.rs:28:11 - | -LL | fn g() -> impl Tr2<m::Alias> { 0 } - | ^^^^^^^^^^^^^^^^^^ private type - -error: type `ext::Priv` is private - --> $DIR/private-type-in-interface.rs:30:15 - | -LL | fn g_ext() -> impl Tr2<ext::Alias> { 0 } - | ^^^^^^^^^^^^^^^^^^^^ private type - error: type `ext::Priv` is private - --> $DIR/private-type-in-interface.rs:30:15 + --> $DIR/private-type-in-interface.rs:29:15 | LL | fn g_ext() -> impl Tr2<ext::Alias> { 0 } | ^^^^^^^^^^^^^^^^^^^^ private type -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/proc-macro/nested-macro-rules.stderr b/tests/ui/proc-macro/nested-macro-rules.stderr index 8fe041d61b8..439297d87ca 100644 --- a/tests/ui/proc-macro/nested-macro-rules.stderr +++ b/tests/ui/proc-macro/nested-macro-rules.stderr @@ -19,7 +19,6 @@ LL | nested_macro_rules::outer_macro!(SecondStruct, SecondAttrStruct); | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> note: the lint level is defined here --> $DIR/nested-macro-rules.rs:8:9 | diff --git a/tests/ui/raw-ref-op/never-place-isnt-diverging.rs b/tests/ui/raw-ref-op/never-place-isnt-diverging.rs new file mode 100644 index 00000000000..80d441729f7 --- /dev/null +++ b/tests/ui/raw-ref-op/never-place-isnt-diverging.rs @@ -0,0 +1,22 @@ +#![feature(never_type)] + +fn make_up_a_value<T>() -> T { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + &raw const *x; + // Since `*x` is `!`, HIR typeck used to think that it diverges + // and allowed the block to coerce to any value, leading to UB. + } +} + + +fn make_up_a_pointer<T>() -> *const T { + unsafe { + let x: *const ! = 0 as _; + &raw const *x + //~^ ERROR mismatched types + } +} + +fn main() {} diff --git a/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr b/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr new file mode 100644 index 00000000000..af9e7889821 --- /dev/null +++ b/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr @@ -0,0 +1,34 @@ +error[E0308]: mismatched types + --> $DIR/never-place-isnt-diverging.rs:4:5 + | +LL | fn make_up_a_value<T>() -> T { + | - expected this type parameter +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | &raw const *x; +LL | | // Since `*x` is `!`, HIR typeck used to think that it diverges +LL | | // and allowed the block to coerce to any value, leading to UB. +LL | | } + | |_____^ expected type parameter `T`, found `()` + | + = note: expected type parameter `T` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/never-place-isnt-diverging.rs:17:9 + | +LL | fn make_up_a_pointer<T>() -> *const T { + | - -------- expected `*const T` because of return type + | | + | expected this type parameter +... +LL | &raw const *x + | ^^^^^^^^^^^^^ expected `*const T`, found `*const !` + | + = note: expected raw pointer `*const T` + found raw pointer `*const !` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/reachable/expr_assign.stderr b/tests/ui/reachable/expr_assign.stderr index c51156b3f40..cfbbe04db76 100644 --- a/tests/ui/reachable/expr_assign.stderr +++ b/tests/ui/reachable/expr_assign.stderr @@ -14,12 +14,13 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_assign.rs:20:14 + --> $DIR/expr_assign.rs:20:9 | LL | *p = return; - | -- ^^^^^^ unreachable expression - | | - | any code following this expression is unreachable + | ^^^^^------ + | | | + | | any code following this expression is unreachable + | unreachable expression error: unreachable expression --> $DIR/expr_assign.rs:26:15 diff --git a/tests/ui/resolve/issue-10200.rs b/tests/ui/resolve/issue-10200.rs index fe36a7e00bf..d529536b952 100644 --- a/tests/ui/resolve/issue-10200.rs +++ b/tests/ui/resolve/issue-10200.rs @@ -3,7 +3,7 @@ fn foo(_: usize) -> Foo { Foo(false) } fn main() { match Foo(true) { - foo(x) //~ ERROR expected tuple struct or tuple variant, found function `foo` + foo(x) //~ ERROR expected a pattern, found a function call => () } } diff --git a/tests/ui/resolve/issue-10200.stderr b/tests/ui/resolve/issue-10200.stderr index 7b218694b26..172d016c6e6 100644 --- a/tests/ui/resolve/issue-10200.stderr +++ b/tests/ui/resolve/issue-10200.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected tuple struct or tuple variant, found function `foo` +error[E0532]: expected a pattern, found a function call --> $DIR/issue-10200.rs:6:9 | LL | struct Foo(bool); @@ -6,6 +6,8 @@ LL | struct Foo(bool); ... LL | foo(x) | ^^^ help: a tuple struct with a similar name exists (notice the capitalization): `Foo` + | + = note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-111312.rs b/tests/ui/resolve/issue-111312.rs index 79c6f67dadd..574e9870cd2 100644 --- a/tests/ui/resolve/issue-111312.rs +++ b/tests/ui/resolve/issue-111312.rs @@ -8,6 +8,5 @@ trait HasNot {} fn main() { HasNot::has(); - //~^ ERROR trait objects must include the `dyn` keyword - //~| ERROR no function or associated item named `has` found for trait `HasNot` + //~^ ERROR expected a type, found a trait } diff --git a/tests/ui/resolve/issue-111312.stderr b/tests/ui/resolve/issue-111312.stderr index 431802ead30..a1f8d6bc46c 100644 --- a/tests/ui/resolve/issue-111312.stderr +++ b/tests/ui/resolve/issue-111312.stderr @@ -1,27 +1,14 @@ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/issue-111312.rs:10:5 | LL | HasNot::has(); | ^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | <dyn HasNot>::has(); | ++++ + -error[E0599]: no function or associated item named `has` found for trait `HasNot` - --> $DIR/issue-111312.rs:10:13 - | -LL | HasNot::has(); - | ^^^ function or associated item not found in `HasNot` - | -note: `Has` defines an item `has` - --> $DIR/issue-111312.rs:3:1 - | -LL | trait Has { - | ^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0599, E0782. -For more information about an error, try `rustc --explain E0599`. +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/resolve/issue-111727.rs b/tests/ui/resolve/issue-111727.rs index fcab924b809..a5c2c0ca8c6 100644 --- a/tests/ui/resolve/issue-111727.rs +++ b/tests/ui/resolve/issue-111727.rs @@ -2,6 +2,5 @@ fn main() { std::any::Any::create(); - //~^ ERROR trait objects must include the `dyn` keyword - //~| ERROR no function or associated item named `create` found for trait `Any` + //~^ ERROR expected a type, found a trait } diff --git a/tests/ui/resolve/issue-111727.stderr b/tests/ui/resolve/issue-111727.stderr index 1ef5a1a1d5e..71ea989ac34 100644 --- a/tests/ui/resolve/issue-111727.stderr +++ b/tests/ui/resolve/issue-111727.stderr @@ -1,21 +1,14 @@ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/issue-111727.rs:4:5 | LL | std::any::Any::create(); | ^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | <dyn std::any::Any>::create(); | ++++ + -error[E0599]: no function or associated item named `create` found for trait `Any` - --> $DIR/issue-111727.rs:4:20 - | -LL | std::any::Any::create(); - | ^^^^^^ function or associated item not found in `Any` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0599, E0782. -For more information about an error, try `rustc --explain E0599`. +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/downcast-unsafe-trait-objects.rs index d4337dcb165..b1b2dcf3eb9 100644 --- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs +++ b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/downcast-unsafe-trait-objects.rs @@ -1,9 +1,9 @@ -// Check that we if we get ahold of an object unsafe trait +// Check that we if we get ahold of a dyn-incompatible trait // object with auto traits and lifetimes, we can downcast it // //@ check-pass -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait Trait: Sized {} diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr index 1489791b20d..1489791b20d 100644 --- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr +++ b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr index 1489791b20d..1489791b20d 100644 --- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr +++ b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.rs index a020d91fb14..425dc130d45 100644 --- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs +++ b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.rs @@ -1,11 +1,11 @@ -// Check that we can manually implement an object-unsafe trait for its trait object. +// Check that we can manually implement a dyn-incompatible trait for its trait object. //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver //@ run-pass -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait Bad { fn stat() -> char { diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/static-dispatch-unsafe-object.rs index cbf76a6830b..c38928a9f44 100644 --- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs +++ b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/static-dispatch-unsafe-object.rs @@ -3,7 +3,7 @@ // //@ check-pass -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait Statics { fn plain() {} 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 0c73b9abf35..0e85515fd10 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 @@ -1,14 +1,14 @@ //@ needs-asm-support #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; #[track_caller] //~ ERROR [E0736] //~^ ERROR `#[track_caller]` requires Rust ABI #[naked] extern "C" fn f() { unsafe { - asm!("", options(noreturn)); + naked_asm!(""); } } @@ -20,7 +20,7 @@ impl S { #[naked] extern "C" fn g() { unsafe { - asm!("", options(noreturn)); + naked_asm!(""); } } } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr index b59c6d1eed8..1040af7541c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr @@ -68,76 +68,76 @@ LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; | ^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:29 + --> $DIR/const-impl-trait.rs:29:29 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:48 + --> $DIR/const-impl-trait.rs:29:48 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { | ^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:29 + --> $DIR/const-impl-trait.rs:29:29 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { | ^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:48 + --> $DIR/const-impl-trait.rs:29:48 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { | ^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:29:29 + --> $DIR/const-impl-trait.rs:50:41 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^^^^ +LL | const fn apit(_: impl ~const T + ~const Destruct) {} + | ^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:29:48 + --> $DIR/const-impl-trait.rs:54:73 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^^^ +LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {} + | ^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:29:29 + --> $DIR/const-impl-trait.rs:25:29 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; | ^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:29:48 + --> $DIR/const-impl-trait.rs:25:48 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; | ^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:50:41 + --> $DIR/const-impl-trait.rs:25:29 | -LL | const fn apit(_: impl ~const T + ~const Destruct) {} - | ^^^^^^^^ +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:54:73 + --> $DIR/const-impl-trait.rs:25:48 | -LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {} - | ^^^^^^^^ +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-impl-trait.rs:25:29 diff --git a/tests/ui/runtime/stdout-before-main.rs b/tests/ui/runtime/stdout-before-main.rs new file mode 100644 index 00000000000..26c734d3e9e --- /dev/null +++ b/tests/ui/runtime/stdout-before-main.rs @@ -0,0 +1,24 @@ +//@ run-pass +//@ check-run-results +//@ only-gnu +//@ only-linux +// +// Regression test for #130210. +// .init_array doesn't work everywhere, so we limit the test to just GNU/Linux. + +use std::ffi::c_int; +use std::thread; + +#[used] +#[link_section = ".init_array"] +static INIT: extern "C" fn(c_int, *const *const u8, *const *const u8) = { + extern "C" fn init(_argc: c_int, _argv: *const *const u8, _envp: *const *const u8) { + print!("Hello from before "); + } + + init +}; + +fn main() { + println!("{}!", thread::current().name().unwrap()); +} diff --git a/tests/ui/runtime/stdout-before-main.run.stdout b/tests/ui/runtime/stdout-before-main.run.stdout new file mode 100644 index 00000000000..d7a3a4389ec --- /dev/null +++ b/tests/ui/runtime/stdout-before-main.run.stdout @@ -0,0 +1 @@ +Hello from before main! diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl-2.rs b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.rs new file mode 100644 index 00000000000..e57e9ce4844 --- /dev/null +++ b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.rs @@ -0,0 +1,15 @@ +// Doesn't trigger ICE when returning unsized trait that can be impl +// issue https://github.com/rust-lang/rust/issues/125512 +//@ edition:2021 +#![feature(dyn_compatible_for_dispatch)] +trait B { + fn f(a: A) -> A; + //~^ ERROR: expected a type, found a trait + //~| ERROR: expected a type, found a trait +} +trait A { + fn concrete(b: B) -> B; + //~^ ERROR: expected a type, found a trait + //~| ERROR: expected a type, found a trait +} +fn main() {} diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr new file mode 100644 index 00000000000..b8a9a5c8129 --- /dev/null +++ b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr @@ -0,0 +1,57 @@ +error[E0782]: expected a type, found a trait + --> $DIR/ice-return-unsized-can-impl-2.rs:11:20 + | +LL | fn concrete(b: B) -> B; + | ^ + | + = note: `B` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `B` + | +LL | fn concrete<T: B>(b: T) -> B; + | ++++++ ~ +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 concrete(b: impl B) -> B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/ice-return-unsized-can-impl-2.rs:11:26 + | +LL | fn concrete(b: B) -> 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 concrete(b: B) -> impl B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/ice-return-unsized-can-impl-2.rs:6:13 + | +LL | fn f(a: A) -> A; + | ^ + | + = note: `A` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `A` + | +LL | fn f<T: A>(a: T) -> A; + | ++++++ ~ +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 f(a: impl A) -> A; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/ice-return-unsized-can-impl-2.rs:6:19 + | +LL | fn f(a: A) -> A; + | ^ + | +help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(a: A) -> impl A; + | ++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl.rs b/tests/ui/rust-2021/ice-return-unsized-can-impl.rs new file mode 100644 index 00000000000..055b11b4424 --- /dev/null +++ b/tests/ui/rust-2021/ice-return-unsized-can-impl.rs @@ -0,0 +1,16 @@ +// Doesn't trigger ICE when returning unsized trait that can be impl +// issue https://github.com/rust-lang/rust/issues/120482 +//@ edition:2021 +#![feature(dyn_compatible_for_dispatch)] + +trait B { + fn bar(&self, x: &Self); +} + +trait A { + fn g(new: B) -> B; + //~^ ERROR: expected a type, found a trait + //~| ERROR: expected a type, found a trait +} + +fn main() {} diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr b/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr new file mode 100644 index 00000000000..c0969570e92 --- /dev/null +++ b/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr @@ -0,0 +1,30 @@ +error[E0782]: expected a type, found a trait + --> $DIR/ice-return-unsized-can-impl.rs:11:15 + | +LL | fn g(new: B) -> B; + | ^ + | + = note: `B` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `B` + | +LL | fn g<T: B>(new: T) -> B; + | ++++++ ~ +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 g(new: impl B) -> B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/ice-return-unsized-can-impl.rs:11:21 + | +LL | fn g(new: B) -> 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(new: B) -> impl B; + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/rust-2021/ice-unsized-fn-params-2.rs b/tests/ui/rust-2021/ice-unsized-fn-params-2.rs new file mode 100644 index 00000000000..2b4f7bd088f --- /dev/null +++ b/tests/ui/rust-2021/ice-unsized-fn-params-2.rs @@ -0,0 +1,12 @@ +//@ edition:2021 +// Test that it doesn't trigger an ICE when using an unsized fn params. +// https://github.com/rust-lang/rust/issues/120241 +#![feature(dyn_compatible_for_dispatch)] +#![feature(unsized_fn_params)] + +fn guard(_s: Copy) -> bool { + //~^ ERROR: expected a type, found a trait + panic!() +} + +fn main() {} diff --git a/tests/ui/rust-2021/ice-unsized-fn-params-2.stderr b/tests/ui/rust-2021/ice-unsized-fn-params-2.stderr new file mode 100644 index 00000000000..d35c8ab3e42 --- /dev/null +++ b/tests/ui/rust-2021/ice-unsized-fn-params-2.stderr @@ -0,0 +1,19 @@ +error[E0782]: expected a type, found a trait + --> $DIR/ice-unsized-fn-params-2.rs:7:14 + | +LL | fn guard(_s: Copy) -> bool { + | ^^^^ + | + = note: `Copy` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `Copy` + | +LL | fn guard<T: Copy>(_s: T) -> bool { + | +++++++++ ~ +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 guard(_s: impl Copy) -> bool { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/rust-2021/ice-unsized-fn-params.rs b/tests/ui/rust-2021/ice-unsized-fn-params.rs new file mode 100644 index 00000000000..6d8c1c3f152 --- /dev/null +++ b/tests/ui/rust-2021/ice-unsized-fn-params.rs @@ -0,0 +1,18 @@ +//@ edition:2021 +// Test that it doesn't trigger an ICE when using an unsized fn params. +// https://github.com/rust-lang/rust/issues/120241 +#![feature(dyn_compatible_for_dispatch)] + +trait B { + fn f(a: A) -> A; + //~^ ERROR: expected a type, found a trait + //~| ERROR: expected a type, found a trait +} + +trait A { + fn g(b: B) -> B; + //~^ ERROR: expected a type, found a trait + //~| ERROR: expected a type, found a trait +} + +fn main() {} diff --git a/tests/ui/rust-2021/ice-unsized-fn-params.stderr b/tests/ui/rust-2021/ice-unsized-fn-params.stderr new file mode 100644 index 00000000000..d56e9981a28 --- /dev/null +++ b/tests/ui/rust-2021/ice-unsized-fn-params.stderr @@ -0,0 +1,57 @@ +error[E0782]: expected a type, found a trait + --> $DIR/ice-unsized-fn-params.rs:13:13 + | +LL | fn g(b: B) -> B; + | ^ + | + = note: `B` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `B` + | +LL | fn g<T: B>(b: T) -> B; + | ++++++ ~ +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 g(b: impl B) -> B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/ice-unsized-fn-params.rs:13:19 + | +LL | fn g(b: B) -> 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(b: B) -> impl B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/ice-unsized-fn-params.rs:7:13 + | +LL | fn f(a: A) -> A; + | ^ + | + = note: `A` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `A` + | +LL | fn f<T: A>(a: T) -> A; + | ++++++ ~ +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 f(a: impl A) -> A; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/ice-unsized-fn-params.rs:7:19 + | +LL | fn f(a: A) -> A; + | ^ + | +help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(a: A) -> impl A; + | ++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2021.rs b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2021.rs new file mode 100644 index 00000000000..81080fcdce3 --- /dev/null +++ b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2021.rs @@ -0,0 +1,20 @@ +//@ force-host +//@ edition:2021 +//@ no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; +use std::str::FromStr; + +#[proc_macro] +pub fn number_of_tokens_in_a_guarded_string_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("#\"abc\"#").unwrap().into_iter().count().to_string().parse().unwrap() +} + +#[proc_macro] +pub fn number_of_tokens_in_a_guarded_unterminated_string_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("#\"abc\"").unwrap().into_iter().count().to_string().parse().unwrap() +} diff --git a/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs new file mode 100644 index 00000000000..2c3dc30f0ae --- /dev/null +++ b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs @@ -0,0 +1,21 @@ +//@ force-host +//@ compile-flags: -Zunstable-options +//@ edition:2024 +//@ no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; +use std::str::FromStr; + +#[proc_macro] +pub fn number_of_tokens_in_a_guarded_string_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("#\"abc\"#").unwrap().into_iter().count().to_string().parse().unwrap() +} + +#[proc_macro] +pub fn number_of_tokens_in_a_guarded_unterminated_string_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("#\"abc\"").unwrap().into_iter().count().to_string().parse().unwrap() +} diff --git a/tests/ui/rust-2024/reserved-guarded-strings-lexing.rs b/tests/ui/rust-2024/reserved-guarded-strings-lexing.rs new file mode 100644 index 00000000000..83e0dcbb4be --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings-lexing.rs @@ -0,0 +1,80 @@ +//@ edition:2021 +// ignore-tidy-linelength + +#![warn(rust_2024_guarded_string_incompatible_syntax)] + +macro_rules! demo2 { + ( $a:tt $b:tt ) => { println!("two tokens") }; +} + +macro_rules! demo3 { + ( $a:tt $b:tt $c:tt ) => { println!("three tokens") }; +} + +macro_rules! demo4 { + ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") }; +} + +macro_rules! demo5 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt ) => { println!("five tokens") }; +} + +macro_rules! demo7 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt $g:tt ) => { println!("seven tokens") }; +} + + +fn main() { + demo3!(## "foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!(### "foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!(## "foo"#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo7!(### "foo"###); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + + demo5!(###"foo"#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo5!(#"foo"###); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!("foo"###); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + + // Non-ascii identifiers + demo2!(Ñ"foo"); + //~^ ERROR prefix `Ñ` is unknown + demo4!(Ñ#""#); + //~^ ERROR prefix `Ñ` is unknown + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(🙃#""); + //~^ ERROR identifiers cannot contain emoji + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 +} diff --git a/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr b/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr new file mode 100644 index 00000000000..e2e1ac42f05 --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr @@ -0,0 +1,271 @@ +error: prefix `Ñ` is unknown + --> $DIR/reserved-guarded-strings-lexing.rs:70:12 + | +LL | demo2!(Ñ"foo"); + | ^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | demo2!(Ñ "foo"); + | + + +error: prefix `Ñ` is unknown + --> $DIR/reserved-guarded-strings-lexing.rs:72:12 + | +LL | demo4!(Ñ#""#); + | ^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | demo4!(Ñ #""#); + | + + +error: identifiers cannot contain emoji: `🙃` + --> $DIR/reserved-guarded-strings-lexing.rs:76:12 + | +LL | demo3!(🙃#""); + | ^^ + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:28:12 + | +LL | demo3!(## "foo"); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +note: the lint level is defined here + --> $DIR/reserved-guarded-strings-lexing.rs:4:9 + | +LL | #![warn(rust_2024_guarded_string_incompatible_syntax)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(# # "foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:31:12 + | +LL | demo4!(### "foo"); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(# ## "foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:31:13 + | +LL | demo4!(### "foo"); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(## # "foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:36:12 + | +LL | demo4!(## "foo"#); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(# # "foo"#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:39:12 + | +LL | demo7!(### "foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo7!(# ## "foo"###); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:39:13 + | +LL | demo7!(### "foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo7!(## # "foo"###); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:39:21 + | +LL | demo7!(### "foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo7!(### "foo"# ##); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:39:22 + | +LL | demo7!(### "foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo7!(### "foo"## #); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:49:12 + | +LL | demo5!(###"foo"#); + | ^^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(# ##"foo"#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:49:13 + | +LL | demo5!(###"foo"#); + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(## #"foo"#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:49:14 + | +LL | demo5!(###"foo"#); + | ^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(### "foo"#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:56:12 + | +LL | demo5!(#"foo"###); + | ^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(# "foo"###); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:56:18 + | +LL | demo5!(#"foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(#"foo"# ##); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:56:19 + | +LL | demo5!(#"foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(#"foo"## #); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:63:17 + | +LL | demo4!("foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!("foo"# ##); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:63:18 + | +LL | demo4!("foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!("foo"## #); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:72:13 + | +LL | demo4!(Ñ#""#); + | ^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(Ñ# ""#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-lexing.rs:76:13 + | +LL | demo3!(🙃#""); + | ^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(🙃# ""); + | + + +error: aborting due to 3 previous errors; 18 warnings emitted + diff --git a/tests/ui/rust-2024/reserved-guarded-strings-migration.fixed b/tests/ui/rust-2024/reserved-guarded-strings-migration.fixed new file mode 100644 index 00000000000..d92df7b5375 --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings-migration.fixed @@ -0,0 +1,99 @@ +//@ check-pass +//@ run-rustfix +//@ edition:2021 + +#![warn(rust_2024_guarded_string_incompatible_syntax)] + +macro_rules! demo1 { + ( $a:tt ) => { println!("one tokens") }; +} + +macro_rules! demo2 { + ( $a:tt $b:tt ) => { println!("two tokens") }; +} + +macro_rules! demo3 { + ( $a:tt $b:tt $c:tt ) => { println!("three tokens") }; +} + +macro_rules! demo4 { + ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") }; +} + +macro_rules! demo5 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt ) => { println!("five tokens") }; +} + +macro_rules! demo6 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt ) => { println!("six tokens") }; +} + + +fn main() { + demo1!(""); + demo2!(# ""); + demo3!(# ""#); + demo2!(# "foo"); + demo3!(# "foo"#); + demo2!("foo"#); + + demo3!(# # "foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!(# # # "foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!(# # "foo"#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo6!(# # # "foo"# #); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + + demo4!("foo"# # #); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + + demo2!(# ""); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(# ""#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(# # ""); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo2!(# "foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(# # "foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(# "foo"#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!(# # "foo"#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo5!(# # "foo"# #); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 +} diff --git a/tests/ui/rust-2024/reserved-guarded-strings-migration.rs b/tests/ui/rust-2024/reserved-guarded-strings-migration.rs new file mode 100644 index 00000000000..5905f2abe32 --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings-migration.rs @@ -0,0 +1,99 @@ +//@ check-pass +//@ run-rustfix +//@ edition:2021 + +#![warn(rust_2024_guarded_string_incompatible_syntax)] + +macro_rules! demo1 { + ( $a:tt ) => { println!("one tokens") }; +} + +macro_rules! demo2 { + ( $a:tt $b:tt ) => { println!("two tokens") }; +} + +macro_rules! demo3 { + ( $a:tt $b:tt $c:tt ) => { println!("three tokens") }; +} + +macro_rules! demo4 { + ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") }; +} + +macro_rules! demo5 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt ) => { println!("five tokens") }; +} + +macro_rules! demo6 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt ) => { println!("six tokens") }; +} + + +fn main() { + demo1!(""); + demo2!(# ""); + demo3!(# ""#); + demo2!(# "foo"); + demo3!(# "foo"#); + demo2!("foo"#); + + demo3!(## "foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!(### "foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!(## "foo"#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo6!(### "foo"##); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + + demo4!("foo"###); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + + demo2!(#""); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(#""#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(##""); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo2!(#"foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(##"foo"); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo3!(#"foo"#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo4!(##"foo"#); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + demo5!(##"foo"##); + //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 + //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax] + //~| WARNING hard error in Rust 2024 +} diff --git a/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr b/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr new file mode 100644 index 00000000000..d7f8e5c9b4b --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr @@ -0,0 +1,293 @@ +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:40:12 + | +LL | demo3!(## "foo"); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +note: the lint level is defined here + --> $DIR/reserved-guarded-strings-migration.rs:5:9 + | +LL | #![warn(rust_2024_guarded_string_incompatible_syntax)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(# # "foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:43:12 + | +LL | demo4!(### "foo"); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(# ## "foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:43:13 + | +LL | demo4!(### "foo"); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(## # "foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:48:12 + | +LL | demo4!(## "foo"#); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(# # "foo"#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:51:12 + | +LL | demo6!(### "foo"##); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo6!(# ## "foo"##); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:51:13 + | +LL | demo6!(### "foo"##); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo6!(## # "foo"##); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:51:21 + | +LL | demo6!(### "foo"##); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo6!(### "foo"# #); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:59:17 + | +LL | demo4!("foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!("foo"# ##); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:59:18 + | +LL | demo4!("foo"###); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!("foo"## #); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:65:12 + | +LL | demo2!(#""); + | ^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo2!(# ""); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:68:12 + | +LL | demo3!(#""#); + | ^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(# ""#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:71:12 + | +LL | demo3!(##""); + | ^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(# #""); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:71:13 + | +LL | demo3!(##""); + | ^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(## ""); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:76:12 + | +LL | demo2!(#"foo"); + | ^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo2!(# "foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:79:12 + | +LL | demo3!(##"foo"); + | ^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(# #"foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:79:13 + | +LL | demo3!(##"foo"); + | ^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(## "foo"); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:84:12 + | +LL | demo3!(#"foo"#); + | ^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo3!(# "foo"#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:87:12 + | +LL | demo4!(##"foo"#); + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(# #"foo"#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:87:13 + | +LL | demo4!(##"foo"#); + | ^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo4!(## "foo"#); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:92:12 + | +LL | demo5!(##"foo"##); + | ^^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(# #"foo"##); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:92:13 + | +LL | demo5!(##"foo"##); + | ^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(## "foo"##); + | + + +warning: will be parsed as a guarded string in Rust 2024 + --> $DIR/reserved-guarded-strings-migration.rs:92:19 + | +LL | demo5!(##"foo"##); + | ^^ + | + = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024! + = note: for more information, see issue #123735 <https://github.com/rust-lang/rust/issues/123735> +help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024 + | +LL | demo5!(##"foo"# #); + | + + +warning: 22 warnings emitted + diff --git a/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.rs b/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.rs new file mode 100644 index 00000000000..3f9f373ba22 --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.rs @@ -0,0 +1,18 @@ +//@ edition:2021 +//@ aux-build:reserved-guarded-strings-macro-2021.rs +//@ aux-build:reserved-guarded-strings-macro-2024.rs + +extern crate reserved_guarded_strings_macro_2021 as m2021; +extern crate reserved_guarded_strings_macro_2024 as m2024; + +fn main() { + // Ok: + m2021::number_of_tokens_in_a_guarded_string_literal!(); + m2021::number_of_tokens_in_a_guarded_unterminated_string_literal!(); + + // Error, even though *this* crate is 2021: + m2024::number_of_tokens_in_a_guarded_string_literal!(); + //~^ ERROR invalid string literal + m2024::number_of_tokens_in_a_guarded_unterminated_string_literal!(); + //~^ ERROR invalid string literal +} diff --git a/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.stderr b/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.stderr new file mode 100644 index 00000000000..1074c8a682b --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.stderr @@ -0,0 +1,20 @@ +error: invalid string literal + --> $DIR/reserved-guarded-strings-via-macro-2.rs:14:5 + | +LL | m2024::number_of_tokens_in_a_guarded_string_literal!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 + = note: this error originates in the macro `m2024::number_of_tokens_in_a_guarded_string_literal` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: invalid string literal + --> $DIR/reserved-guarded-strings-via-macro-2.rs:16:5 + | +LL | m2024::number_of_tokens_in_a_guarded_unterminated_string_literal!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 + = note: this error originates in the macro `m2024::number_of_tokens_in_a_guarded_unterminated_string_literal` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs b/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs new file mode 100644 index 00000000000..f9e3c1e3c51 --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs @@ -0,0 +1,12 @@ +//@ run-pass +//@ compile-flags: -Zunstable-options +//@ edition:2024 +//@ aux-build:reserved-guarded-strings-macro-2021.rs + +extern crate reserved_guarded_strings_macro_2021 as m2021; + +fn main() { + // Ok, even though *this* crate is 2024: + assert_eq!(m2021::number_of_tokens_in_a_guarded_string_literal!(), 3); + assert_eq!(m2021::number_of_tokens_in_a_guarded_unterminated_string_literal!(), 2); +} diff --git a/tests/ui/rust-2024/reserved-guarded-strings.rs b/tests/ui/rust-2024/reserved-guarded-strings.rs new file mode 100644 index 00000000000..dab97039be0 --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings.rs @@ -0,0 +1,74 @@ +//@ compile-flags: -Zunstable-options +//@ edition:2024 +// ignore-tidy-linelength + +macro_rules! demo1 { + ( $a:tt ) => { println!("one tokens") }; +} + +macro_rules! demo2 { + ( $a:tt $b:tt ) => { println!("two tokens") }; +} + +macro_rules! demo3 { + ( $a:tt $b:tt $c:tt ) => { println!("three tokens") }; +} + +macro_rules! demo4 { + ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") }; +} + +macro_rules! demo5 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt ) => { println!("five tokens") }; +} + +macro_rules! demo6 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt ) => { println!("six tokens") }; +} + +macro_rules! demo7 { + ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt $g:tt ) => { println!("seven tokens") }; +} + +macro_rules! demon { + ( $($n:tt)* ) => { println!("unknown number of tokens") }; +} + +fn main() { + demo1!(""); + demo2!(# ""); + demo3!(# ""#); + demo2!(# "foo"); + demo3!(# "foo"#); + demo2!("foo"#); + + demo2!(blah"xx"); //~ ERROR prefix `blah` is unknown + demo2!(blah#"xx"#); + //~^ ERROR prefix `blah` is unknown + //~| ERROR invalid string literal + + demo2!(## "foo"); //~ ERROR invalid string literal + demo3!("foo"###); //~ ERROR invalid string literal + demo3!(### "foo"); //~ ERROR invalid string literal + demo3!(## "foo"#); //~ ERROR invalid string literal + demo5!(### "foo"###); + //~^ ERROR invalid string literal + //~| ERROR invalid string literal + + demo1!(#""); //~ ERROR invalid string literal + demo1!(#""#); //~ ERROR invalid string literal + demo1!(####""); //~ ERROR invalid string literal + demo1!(#"foo"); //~ ERROR invalid string literal + demo1!(###"foo"); //~ ERROR invalid string literal + demo1!(#"foo"#); //~ ERROR invalid string literal + demo1!(###"foo"#); //~ ERROR invalid string literal + demo1!(###"foo"##); //~ ERROR invalid string literal + demo1!(###"foo"###); //~ ERROR invalid string literal + demo2!(#"foo"###); + //~^ ERROR invalid string literal + //~| ERROR invalid string literal + + // More than 255 hashes + demon!(####################################################################################################################################################################################################################################################################"foo"); + //~^ ERROR invalid string literal +} diff --git a/tests/ui/rust-2024/reserved-guarded-strings.stderr b/tests/ui/rust-2024/reserved-guarded-strings.stderr new file mode 100644 index 00000000000..f465ba7944a --- /dev/null +++ b/tests/ui/rust-2024/reserved-guarded-strings.stderr @@ -0,0 +1,254 @@ +error: prefix `blah` is unknown + --> $DIR/reserved-guarded-strings.rs:45:12 + | +LL | demo2!(blah"xx"); + | ^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | demo2!(blah "xx"); + | + + +error: prefix `blah` is unknown + --> $DIR/reserved-guarded-strings.rs:46:12 + | +LL | demo2!(blah#"xx"#); + | ^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | demo2!(blah #"xx"#); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:46:16 + | +LL | demo2!(blah#"xx"#); + | ^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo2!(blah# "xx"#); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:50:12 + | +LL | demo2!(## "foo"); + | ^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo2!(# # "foo"); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:51:17 + | +LL | demo3!("foo"###); + | ^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo3!("foo"# ##); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:52:12 + | +LL | demo3!(### "foo"); + | ^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo3!(# ## "foo"); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:53:12 + | +LL | demo3!(## "foo"#); + | ^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo3!(# # "foo"#); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:54:12 + | +LL | demo5!(### "foo"###); + | ^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo5!(# ## "foo"###); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:54:21 + | +LL | demo5!(### "foo"###); + | ^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo5!(### "foo"# ##); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:58:12 + | +LL | demo1!(#""); + | ^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# ""); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:59:12 + | +LL | demo1!(#""#); + | ^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# ""#); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:60:12 + | +LL | demo1!(####""); + | ^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# ###""); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:61:12 + | +LL | demo1!(#"foo"); + | ^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# "foo"); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:62:12 + | +LL | demo1!(###"foo"); + | ^^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# ##"foo"); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:63:12 + | +LL | demo1!(#"foo"#); + | ^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# "foo"#); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:64:12 + | +LL | demo1!(###"foo"#); + | ^^^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# ##"foo"#); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:65:12 + | +LL | demo1!(###"foo"##); + | ^^^^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# ##"foo"##); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:66:12 + | +LL | demo1!(###"foo"###); + | ^^^^^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo1!(# ##"foo"###); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:67:12 + | +LL | demo2!(#"foo"###); + | ^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo2!(# "foo"###); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:67:19 + | +LL | demo2!(#"foo"###); + | ^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demo2!(#"foo"## #); + | + + +error: invalid string literal + --> $DIR/reserved-guarded-strings.rs:72:12 + | +LL | ...n!(####################################################################################################################################################################################################################################################################"foo... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unprefixed guarded string literals are reserved for future use since Rust 2024 +help: consider inserting whitespace here + | +LL | demon!(# ###################################################################################################################################################################################################################################################################"foo"); + | + + +error: aborting due to 21 previous errors + diff --git a/tests/ui/sanitizer/cfi/async-closures.rs b/tests/ui/sanitizer/cfi/async-closures.rs index d94f2992d84..4eaa44cfa3f 100644 --- a/tests/ui/sanitizer/cfi/async-closures.rs +++ b/tests/ui/sanitizer/cfi/async-closures.rs @@ -21,7 +21,7 @@ use std::ops::AsyncFn; #[inline(never)] fn identity<T>(x: T) -> T { x } -// We can't actually create a `dyn AsyncFn()`, because it's not object-safe, but we should check +// We can't actually create a `dyn AsyncFn()`, because it's dyn-incompatible, but we should check // that we don't bug out when we encounter one. fn main() { diff --git a/tests/ui/self/arbitrary-self-opaque.stderr b/tests/ui/self/arbitrary-self-opaque.stderr index 5ccc076bfaf..5634b3d6e64 100644 --- a/tests/ui/self/arbitrary-self-opaque.stderr +++ b/tests/ui/self/arbitrary-self-opaque.stderr @@ -1,3 +1,12 @@ +error[E0307]: invalid `self` parameter type: `Bar` + --> $DIR/arbitrary-self-opaque.rs:8:18 + | +LL | fn foo(self: Bar) {} + | ^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + error: item does not constrain `Bar::{opaque#0}`, but has it in its signature --> $DIR/arbitrary-self-opaque.rs:8:8 | @@ -19,15 +28,6 @@ LL | type Bar = impl Sized; | = note: `Bar` must be used in combination with a concrete type within the same module -error[E0307]: invalid `self` parameter type: `Bar` - --> $DIR/arbitrary-self-opaque.rs:8:18 - | -LL | fn foo(self: Bar) {} - | ^^^ - | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr index e2d73fc08f6..2eb7597d5c1 100644 --- a/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/arbitrary-self-types-not-object-safe.rs:33:32 + --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:32 | LL | fn foo(self: &Rc<Self>) -> usize; | --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` @@ -8,7 +8,7 @@ LL | let x = Rc::new(5usize) as Rc<dyn Foo>; | ^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18 + --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -17,7 +17,7 @@ LL | fn foo(self: &Rc<Self>) -> usize; = help: only type `usize` implements the trait, consider using it directly instead error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/arbitrary-self-types-not-object-safe.rs:33:13 + --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:13 | LL | fn foo(self: &Rc<Self>) -> usize; | --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` @@ -26,7 +26,7 @@ LL | let x = Rc::new(5usize) as Rc<dyn Foo>; | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18 + --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr index fda07765c66..02af692c4a3 100644 --- a/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/arbitrary-self-types-not-object-safe.rs:33:13 + --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:13 | LL | fn foo(self: &Rc<Self>) -> usize; | --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` @@ -8,7 +8,7 @@ LL | let x = Rc::new(5usize) as Rc<dyn Foo>; | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18 + --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/self/arbitrary-self-types-not-object-safe.rs b/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs index 0053eb5f739..940b2f1e8e2 100644 --- a/tests/ui/self/arbitrary-self-types-not-object-safe.rs +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs @@ -1,6 +1,6 @@ -//@ revisions: curr object_safe_for_dispatch +//@ revisions: curr dyn_compatible_for_dispatch -#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] +#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))] use std::rc::Rc; @@ -33,7 +33,7 @@ fn make_foo() { let x = Rc::new(5usize) as Rc<dyn Foo>; //[curr]~^ ERROR E0038 //[curr]~| ERROR E0038 - //[object_safe_for_dispatch]~^^^ ERROR E0038 + //[dyn_compatible_for_dispatch]~^^^ ERROR E0038 } fn make_bar() { diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr index b00260fa0ef..f3393830eeb 100644 --- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr @@ -9,8 +9,8 @@ LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f } - | ++++ ++ ++ +LL | async fn a<'a>(self: Pin<&Foo>, f: &'a Foo) -> &'a Foo { f } + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:75 @@ -23,8 +23,8 @@ LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { ( | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } - | ++++ ++ ++ +LL | async fn c<'a>(self: Pin<&Self>, f: &'a Foo, g: &Foo) -> (Pin<&'a Foo>, &'a Foo) { (self, f) } + | ++++ ++ ++ ++ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64 @@ -37,8 +37,8 @@ LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } | help: consider reusing a named lifetime parameter and update trait if needed | -LL | async fn bar<'a>(self: Alias<&'a Self>, arg: &'a ()) -> &() { arg } - | ++ +LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &'a () { arg } + | ++ error: aborting due to 3 previous errors diff --git a/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs b/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs index d7149002e7b..76d7754384e 100644 --- a/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs +++ b/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs @@ -50,9 +50,9 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {} trait Trait { - // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable - // without unsized_locals), but wrappers arond `Self` currently are not. - // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented + // This method isn't dyn-compatible yet. Unsized by-value `self` is dyn-compatible (but not + // callable without unsized_locals), but wrappers arond `Self` currently are not. + // FIXME (mikeyhew) uncomment this when unsized rvalues dyn-compatibility is implemented // fn wrapper(self: Wrapper<Self>) -> i32; fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32; fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32; diff --git a/tests/ui/self/object-safety-sized-self-by-value-self.rs b/tests/ui/self/dyn-compatibility-sized-self-by-value-self.rs index d902812eb9a..658371c95e2 100644 --- a/tests/ui/self/object-safety-sized-self-by-value-self.rs +++ b/tests/ui/self/dyn-compatibility-sized-self-by-value-self.rs @@ -1,6 +1,6 @@ //@ run-pass #![allow(unused_mut)] -// Check that a trait is still object-safe (and usable) if it has +// Check that a trait is still dyn-compatible (and usable) if it has // methods with by-value self so long as they require `Self : Sized`. diff --git a/tests/ui/self/object-safety-sized-self-generic-method.rs b/tests/ui/self/dyn-compatibility-sized-self-generic-method.rs index 7a2ebd2cb79..a7b5013694f 100644 --- a/tests/ui/self/object-safety-sized-self-generic-method.rs +++ b/tests/ui/self/dyn-compatibility-sized-self-generic-method.rs @@ -1,6 +1,6 @@ //@ run-pass #![allow(unused_variables)] -// Check that a trait is still object-safe (and usable) if it has +// Check that a trait is still dyn-compatible (and usable) if it has // generic methods so long as they require `Self : Sized`. diff --git a/tests/ui/self/object-safety-sized-self-return-Self.rs b/tests/ui/self/dyn-compatibility-sized-self-return-Self.rs index 9fc3f856772..a15f4fd7813 100644 --- a/tests/ui/self/object-safety-sized-self-return-Self.rs +++ b/tests/ui/self/dyn-compatibility-sized-self-return-Self.rs @@ -1,5 +1,5 @@ //@ run-pass -// Check that a trait is still object-safe (and usable) if it has +// Check that a trait is still dyn-compatible (and usable) if it has // methods that return `Self` so long as they require `Self : Sized`. diff --git a/tests/ui/self/elision/lt-ref-self-async.fixed b/tests/ui/self/elision/lt-ref-self-async.fixed index 914511641b8..aae94f7a6cc 100644 --- a/tests/ui/self/elision/lt-ref-self-async.fixed +++ b/tests/ui/self/elision/lt-ref-self-async.fixed @@ -11,34 +11,34 @@ struct Struct<'a> { impl<'a> Struct<'a> { // Test using `&self` sugar: - async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 { + async fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } // Test using `&Self` explicitly: - async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 { + async fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 { + async fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 { + async fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 { + async fn box_box_ref_Self<'b>(self: Box<Box<&Self>>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 { + async fn box_pin_Self<'b>(self: Box<Pin<&Self>>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } diff --git a/tests/ui/self/elision/lt-ref-self-async.stderr b/tests/ui/self/elision/lt-ref-self-async.stderr index b84044f7548..c43ff49d508 100644 --- a/tests/ui/self/elision/lt-ref-self-async.stderr +++ b/tests/ui/self/elision/lt-ref-self-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:22:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:27:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:32:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:37:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'b>(self: Box<Box<&Self>>, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:42:9 @@ -85,8 +85,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_Self<'b>(self: Box<Pin<&Self>>, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: aborting due to 6 previous errors diff --git a/tests/ui/self/elision/ref-assoc-async.stderr b/tests/ui/self/elision/ref-assoc-async.stderr index cf54a86b45f..9f2768d5e69 100644 --- a/tests/ui/self/elision/ref-assoc-async.stderr +++ b/tests/ui/self/elision/ref-assoc-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_AssocType<'a>(self: &'a <Struct as Trait>::AssocType, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_AssocType<'a>(self: &<Struct as Trait>::AssocType, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-assoc-async.rs:24:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_AssocType<'a>(self: Box<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_AssocType<'a>(self: Box<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-assoc-async.rs:29:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_AssocType<'a>(self: Pin<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_AssocType<'a>(self: Pin<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-assoc-async.rs:34:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_AssocType<'a>(self: Box<Box<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_AssocType<'a>(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-assoc-async.rs:39:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_ref_AssocType<'a>(self: Box<Pin<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_AssocType<'a>(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: aborting due to 5 previous errors diff --git a/tests/ui/self/elision/ref-mut-self-async.stderr b/tests/ui/self/elision/ref-mut-self-async.stderr index 62543ba5339..945fb5e0282 100644 --- a/tests/ui/self/elision/ref-mut-self-async.stderr +++ b/tests/ui/self/elision/ref-mut-self-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_self<'a>(&mut self, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:20:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Self<'a>(self: &mut Self, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:25:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Self<'a>(self: Box<&mut Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:30:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Self<'a>(self: Pin<&mut Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:35:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'a>(self: Box<Box<&mut Self>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:40:9 @@ -85,8 +85,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Self<'a>(self: Box<Pin<&mut Self>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: aborting due to 6 previous errors diff --git a/tests/ui/self/elision/ref-mut-struct-async.stderr b/tests/ui/self/elision/ref-mut-struct-async.stderr index f8fb2e4a138..149ab01045c 100644 --- a/tests/ui/self/elision/ref-mut-struct-async.stderr +++ b/tests/ui/self/elision/ref-mut-struct-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Struct<'a>(self: &mut Struct, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:18:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Struct<'a>(self: Box<&mut Struct>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:23:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Struct<'a>(self: Pin<&mut Struct>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:28:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Struct<'a>(self: Box<Box<&mut Struct>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:33:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Struct<'a>(self: Box<Pin<&mut Struct>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: aborting due to 5 previous errors diff --git a/tests/ui/self/elision/ref-self-async.stderr b/tests/ui/self/elision/ref-self-async.stderr index 010d281b002..a75ece5f2c7 100644 --- a/tests/ui/self/elision/ref-self-async.stderr +++ b/tests/ui/self/elision/ref-self-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:30:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:35:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:40:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:45:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:50:9 @@ -85,8 +85,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:55:9 @@ -100,8 +100,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 { - | ++++ ++ ++ +LL | async fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 { + | ++++ ++ ++ error: aborting due to 7 previous errors diff --git a/tests/ui/self/elision/ref-struct-async.stderr b/tests/ui/self/elision/ref-struct-async.stderr index c9376d58f90..6bdc145223a 100644 --- a/tests/ui/self/elision/ref-struct-async.stderr +++ b/tests/ui/self/elision/ref-struct-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Struct<'a>(self: &Struct, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:18:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Struct<'a>(self: Box<&Struct>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:23:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Struct<'a>(self: Pin<&Struct>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:28:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Struct<'a>(self: Box<Box<&Struct>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:33:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_Struct<'a>(self: Box<Pin<&Struct>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: aborting due to 5 previous errors diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr index fc431eb1412..d40e9822435 100644 --- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr +++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31 | LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; - | ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html> error[E0412]: cannot find type `T` in this scope --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55 diff --git a/tests/ui/specialization/issue-44861.rs b/tests/ui/specialization/issue-44861.rs index 79d9b9490d0..9d6517e613a 100644 --- a/tests/ui/specialization/issue-44861.rs +++ b/tests/ui/specialization/issue-44861.rs @@ -12,9 +12,9 @@ pub trait Smartass { type Data2: CoerceUnsized<*const [u8]>; } -pub trait MaybeObjectSafe {} +pub trait MaybeDynCompatible {} -impl MaybeObjectSafe for () {} +impl MaybeDynCompatible for () {} impl<T> Smartass for T { type Data = <Self as Smartass>::Data2; @@ -26,7 +26,7 @@ impl Smartass for () { type Data2 = *const [u8; 1]; } -impl Smartass for dyn MaybeObjectSafe { +impl Smartass for dyn MaybeDynCompatible { type Data = *const [u8]; type Data2 = *const [u8; 0]; } @@ -35,6 +35,6 @@ impl<U: Smartass+?Sized, T: Smartass+?Sized> CoerceUnsized<SmartassPtr<T>> for S where <U as Smartass>::Data: std::ops::CoerceUnsized<<T as Smartass>::Data> {} -pub fn conv(s: SmartassPtr<()>) -> SmartassPtr<dyn MaybeObjectSafe> { +pub fn conv(s: SmartassPtr<()>) -> SmartassPtr<dyn MaybeDynCompatible> { s } diff --git a/tests/ui/suggestions/auxiliary/not-object-safe.rs b/tests/ui/suggestions/auxiliary/dyn-incompatible.rs index 7c9829b823e..7c9829b823e 100644 --- a/tests/ui/suggestions/auxiliary/not-object-safe.rs +++ b/tests/ui/suggestions/auxiliary/dyn-incompatible.rs diff --git a/tests/ui/suggestions/object-unsafe-trait-references-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs index 4b3d5faba46..4b3d5faba46 100644 --- a/tests/ui/suggestions/object-unsafe-trait-references-self.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs diff --git a/tests/ui/suggestions/object-unsafe-trait-references-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr index c00bb3efbf6..242c44abd9d 100644 --- a/tests/ui/suggestions/object-unsafe-trait-references-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/object-unsafe-trait-references-self.rs:9:12 + --> $DIR/dyn-incompatible-trait-references-self.rs:9:12 | LL | fn bar(x: &dyn Trait) {} | ^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-references-self.rs:2:22 + --> $DIR/dyn-incompatible-trait-references-self.rs:2:22 | LL | trait Trait { | ----- this trait cannot be made into an object... @@ -18,13 +18,13 @@ LL | fn bat(&self) -> Self {} = help: consider moving `bat` to another trait error[E0038]: the trait `Other` cannot be made into an object - --> $DIR/object-unsafe-trait-references-self.rs:13:12 + --> $DIR/dyn-incompatible-trait-references-self.rs:13:12 | LL | fn foo(x: &dyn Other) {} | ^^^^^^^^^ `Other` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-references-self.rs:11:14 + --> $DIR/dyn-incompatible-trait-references-self.rs:11:14 | LL | trait Other: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` @@ -32,7 +32,7 @@ LL | trait Other: Sized {} | this trait cannot be made into an object... error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/object-unsafe-trait-references-self.rs:2:22 + --> $DIR/dyn-incompatible-trait-references-self.rs:2:22 | LL | fn baz(&self, _: Self) {} | ^^^^ doesn't have a size known at compile-time @@ -48,7 +48,7 @@ LL | fn baz(&self, _: &Self) {} | + error[E0308]: mismatched types - --> $DIR/object-unsafe-trait-references-self.rs:4:27 + --> $DIR/dyn-incompatible-trait-references-self.rs:4:27 | LL | trait Trait { | ----------- expected this type parameter @@ -60,7 +60,7 @@ LL | fn bat(&self) -> Self {} found unit type `()` error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/object-unsafe-trait-references-self.rs:4:22 + --> $DIR/dyn-incompatible-trait-references-self.rs:4:22 | LL | fn bat(&self) -> Self {} | ^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs new file mode 100644 index 00000000000..10b4781eb04 --- /dev/null +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs @@ -0,0 +1,22 @@ +//@ edition:2021 +#![allow(bare_trait_objects)] +trait A: Sized { + fn f(a: A) -> A; + //~^ ERROR expected a type, found a trait + //~| ERROR expected a type, found a trait + //~| ERROR associated item referring to unboxed trait object for its own trait +} +trait B { + fn f(b: B) -> B; + //~^ ERROR expected a type, found a trait + //~| ERROR expected a type, found a trait + //~| ERROR associated item referring to unboxed trait object for its own trait +} +trait C { + fn f(&self, c: C) -> C; + //~^ ERROR expected a type, found a trait + //~| ERROR expected a type, found a trait + //~| ERROR associated item referring to unboxed trait object for its own trait +} + +fn main() {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr new file mode 100644 index 00000000000..c0cfb18955c --- /dev/null +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr @@ -0,0 +1,123 @@ +error: associated item referring to unboxed trait object for its own trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | trait A: Sized { + | - in this trait +LL | fn f(a: A) -> A; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(a: Self) -> Self; + | ~~~~ ~~~~ + +error: associated item referring to unboxed trait object for its own trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 + | +LL | trait B { + | - in this trait +LL | fn f(b: B) -> B; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(b: Self) -> Self; + | ~~~~ ~~~~ + +error: associated item referring to unboxed trait object for its own trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20 + | +LL | trait C { + | - in this trait +LL | fn f(&self, c: C) -> C; + | ^ ^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn f(&self, c: Self) -> Self; + | ~~~~ ~~~~ + +error[E0782]: expected a type, found a trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13 + | +LL | fn f(a: A) -> A; + | ^ + | + = note: `A` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `A` + | +LL | fn f<T: A>(a: T) -> A; + | ++++++ ~ +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 f(a: impl A) -> A; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:19 + | +LL | fn f(a: A) -> A; + | ^ + | +help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(a: A) -> impl A; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 + | +LL | fn f(b: B) -> B; + | ^ + | + = note: `B` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `B` + | +LL | fn f<T: B>(b: T) -> B; + | ++++++ ~ +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 f(b: impl B) -> B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:19 + | +LL | fn f(b: B) -> 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 f(b: B) -> impl B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20 + | +LL | fn f(&self, c: C) -> C; + | ^ + | + = note: `C` it is dyn-incompatible, so it can't be `dyn` +help: use a new generic type parameter, constrained by `C` + | +LL | fn f<T: C>(&self, c: T) -> C; + | ++++++ ~ +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 f(&self, c: impl C) -> C; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:26 + | +LL | fn f(&self, c: C) -> C; + | ^ + | +help: `C` is dyn-incompatible, use `impl C` to return an opaque type, as long as you return a single underlying type + | +LL | fn f(&self, c: C) -> impl C; + | ++++ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs index 4ab10f40eb6..4ab10f40eb6 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr index a7d36d9ebee..5e0d1a14452 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr @@ -1,5 +1,5 @@ error: associated item referring to unboxed trait object for its own trait - --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13 | LL | trait A: Sized { | - in this trait @@ -12,13 +12,13 @@ LL | fn f(a: Self) -> Self; | ~~~~ ~~~~ error[E0038]: the trait `A` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13 | LL | fn f(a: dyn A) -> dyn A; | ^^^^^ `A` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-should-use-self-2021.rs:3:10 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:3:10 | LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` @@ -26,7 +26,7 @@ LL | trait A: Sized { | this trait cannot be made into an object... error: associated item referring to unboxed trait object for its own trait - --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13 | LL | trait B { | - in this trait @@ -39,13 +39,13 @@ LL | fn f(a: Self) -> Self; | ~~~~ ~~~~ error[E0038]: the trait `B` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13 | LL | fn f(a: dyn B) -> dyn B; | ^^^^^ `B` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:8 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:8 | LL | trait B { | - this trait cannot be made into an object... diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs index 75f99075eb1..75f99075eb1 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr index 28952933c64..93f6ea2b12e 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr @@ -1,5 +1,5 @@ error: associated item referring to unboxed trait object for its own trait - --> $DIR/object-unsafe-trait-should-use-self.rs:3:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:3:13 | LL | trait A: Sized { | - in this trait @@ -12,13 +12,13 @@ LL | fn f(a: Self) -> Self; | ~~~~ ~~~~ error[E0038]: the trait `A` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-self.rs:3:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:3:13 | LL | fn f(a: A) -> A; | ^ `A` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-should-use-self.rs:2:10 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:10 | LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` @@ -26,7 +26,7 @@ LL | trait A: Sized { | this trait cannot be made into an object... error: associated item referring to unboxed trait object for its own trait - --> $DIR/object-unsafe-trait-should-use-self.rs:8:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13 | LL | trait B { | - in this trait @@ -39,13 +39,13 @@ LL | fn f(a: Self) -> Self; | ~~~~ ~~~~ error[E0038]: the trait `B` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-self.rs:8:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13 | LL | fn f(a: B) -> B; | ^ `B` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-should-use-self.rs:8:8 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:8 | LL | trait B { | - this trait cannot be made into an object... diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed index fd9b78934c7..fd9b78934c7 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs index e4aa0d89239..e4aa0d89239 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr index 5e3a0290d42..beafd7c2ab0 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:12 + --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:9:12 | LL | fn bar(x: &dyn Trait) {} | ^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-should-use-where-sized.rs:5:8 + --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:5:8 | LL | trait Trait { | ----- this trait cannot be made into an object... @@ -27,7 +27,7 @@ LL | fn bar(self: &Self) {} | ~~~~~ error[E0307]: invalid `self` parameter type: `()` - --> $DIR/object-unsafe-trait-should-use-where-sized.rs:6:18 + --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:6:18 | LL | fn bar(self: ()) {} | ^^ diff --git a/tests/ui/suggestions/issue-104328.rs b/tests/ui/suggestions/issue-104328.rs index c3707baf79f..2b0fbdb8d35 100644 --- a/tests/ui/suggestions/issue-104328.rs +++ b/tests/ui/suggestions/issue-104328.rs @@ -1,4 +1,4 @@ -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait Foo { fn f() {} diff --git a/tests/ui/suggestions/issue-116434-2021.rs b/tests/ui/suggestions/issue-116434-2021.rs index 6feba3dc6c1..77cdfb8b614 100644 --- a/tests/ui/suggestions/issue-116434-2021.rs +++ b/tests/ui/suggestions/issue-116434-2021.rs @@ -3,7 +3,8 @@ trait Foo { type Clone; fn foo() -> Clone; - //~^ ERROR the trait `Clone` cannot be made into an object [E0038] + //~^ ERROR expected a type, found a trait + //~| HELP `Clone` is dyn-incompatible, use `impl Clone` to return an opaque type, as long as you return a single underlying type //~| HELP there is an associated type with the same name } @@ -12,7 +13,8 @@ trait DbHandle: Sized {} trait DbInterface { type DbHandle; fn handle() -> DbHandle; - //~^ ERROR the trait `DbHandle` cannot be made into an object [E0038] + //~^ ERROR expected a type, found a trait + //~| HELP `DbHandle` is dyn-incompatible, use `impl DbHandle` to return an opaque type, as long as you return a single underlying type //~| HELP there is an associated type with the same name } diff --git a/tests/ui/suggestions/issue-116434-2021.stderr b/tests/ui/suggestions/issue-116434-2021.stderr index 7f8cc147210..3853f03f1db 100644 --- a/tests/ui/suggestions/issue-116434-2021.stderr +++ b/tests/ui/suggestions/issue-116434-2021.stderr @@ -1,29 +1,28 @@ -error[E0038]: the trait `Clone` cannot be made into an object +error[E0782]: expected a type, found a trait --> $DIR/issue-116434-2021.rs:5:17 | LL | fn foo() -> Clone; - | ^^^^^ `Clone` cannot be made into an object + | ^^^^^ | - = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> +help: `Clone` is dyn-incompatible, use `impl Clone` to return an opaque type, as long as you return a single underlying type + | +LL | fn foo() -> impl Clone; + | ++++ help: there is an associated type with the same name | LL | fn foo() -> Self::Clone; | ++++++ -error[E0038]: the trait `DbHandle` cannot be made into an object - --> $DIR/issue-116434-2021.rs:14:20 +error[E0782]: expected a type, found a trait + --> $DIR/issue-116434-2021.rs:15:20 | LL | fn handle() -> DbHandle; - | ^^^^^^^^ `DbHandle` cannot be made into an object + | ^^^^^^^^ | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/issue-116434-2021.rs:10:17 +help: `DbHandle` is dyn-incompatible, use `impl DbHandle` to return an opaque type, as long as you return a single underlying type | -LL | trait DbHandle: Sized {} - | -------- ^^^^^ ...because it requires `Self: Sized` - | | - | this trait cannot be made into an object... +LL | fn handle() -> impl DbHandle; + | ++++ help: there is an associated type with the same name | LL | fn handle() -> Self::DbHandle; @@ -31,4 +30,4 @@ LL | fn handle() -> Self::DbHandle; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0038`. +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/suggestions/issue-98500.rs b/tests/ui/suggestions/issue-98500.rs index b6fd9e7c23f..289b16abf4b 100644 --- a/tests/ui/suggestions/issue-98500.rs +++ b/tests/ui/suggestions/issue-98500.rs @@ -1,9 +1,9 @@ -//@ aux-build:not-object-safe.rs +//@ aux-build:dyn-incompatible.rs -extern crate not_object_safe; +extern crate dyn_incompatible; pub trait B where - Self: not_object_safe::A, + Self: dyn_incompatible::A, { fn f2(&self); } diff --git a/tests/ui/suggestions/issue-98500.stderr b/tests/ui/suggestions/issue-98500.stderr index c4b446763af..d7136ec1a64 100644 --- a/tests/ui/suggestions/issue-98500.stderr +++ b/tests/ui/suggestions/issue-98500.stderr @@ -5,7 +5,7 @@ LL | struct S(Box<dyn B>); | ^^^^^ `B` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/auxiliary/not-object-safe.rs:4:8 + --> $DIR/auxiliary/dyn-incompatible.rs:4:8 | LL | fn f(); | ^ ...because associated function `f` has no `self` parameter diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs deleted file mode 100644 index 37afab6b643..00000000000 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ edition:2021 -#![allow(bare_trait_objects)] -trait A: Sized { - fn f(a: A) -> A; - //~^ ERROR trait objects must include the `dyn` keyword - //~| ERROR trait objects must include the `dyn` keyword - //~| ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `A` cannot be made into an object -} -trait B { - fn f(b: B) -> B; - //~^ ERROR trait objects must include the `dyn` keyword - //~| ERROR trait objects must include the `dyn` keyword - //~| ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `B` cannot be made into an object -} -trait C { - fn f(&self, c: C) -> C; - //~^ ERROR trait objects must include the `dyn` keyword - //~| ERROR trait objects must include the `dyn` keyword - //~| ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `C` cannot be made into an object -} - -fn main() {} diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr deleted file mode 100644 index a17f821ebec..00000000000 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr +++ /dev/null @@ -1,176 +0,0 @@ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 - | -LL | trait A: Sized { - | - in this trait -LL | fn f(a: A) -> A; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL | fn f(a: Self) -> Self; - | ~~~~ ~~~~ - -error[E0038]: the trait `A` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 - | -LL | fn f(a: A) -> A; - | ^ `A` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:3:10 - | -LL | trait A: Sized { - | - ^^^^^ ...because it requires `Self: Sized` - | | - | this trait cannot be made into an object... - -error: associated item referring to unboxed trait object for its own trait - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 - | -LL | trait B { - | - in this trait -LL | fn f(b: B) -> B; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL | fn f(b: Self) -> Self; - | ~~~~ ~~~~ - -error[E0038]: the trait `B` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 - | -LL | fn f(b: B) -> B; - | ^ `B` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:8 - | -LL | trait B { - | - this trait cannot be made into an object... -LL | fn f(b: B) -> B; - | ^ ...because associated function `f` has no `self` parameter -help: consider turning `f` into a method by giving it a `&self` argument - | -LL | fn f(&self, b: B) -> B; - | ++++++ -help: alternatively, consider constraining `f` so it does not apply to trait objects - | -LL | fn f(b: B) -> B where Self: Sized; - | +++++++++++++++++ - -error: associated item referring to unboxed trait object for its own trait - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20 - | -LL | trait C { - | - in this trait -LL | fn f(&self, c: C) -> C; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL | fn f(&self, c: Self) -> Self; - | ~~~~ ~~~~ - -error[E0038]: the trait `C` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20 - | -LL | fn f(&self, c: C) -> C; - | ----- ^ `C` cannot be made into an object - | | - | help: consider changing method `f`'s `self` parameter to be `&self` (notice the capitalization): `&Self` - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:10 - | -LL | trait C { - | - this trait cannot be made into an object... -LL | fn f(&self, c: C) -> C; - | ^^^^^ ...because method `f`'s `self` parameter cannot be dispatched on - -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13 - | -LL | fn f(a: A) -> A; - | ^ - | - = note: `A` it is dyn-incompatible, so it can't be `dyn` -help: use a new generic type parameter, constrained by `A` - | -LL | fn f<T: A>(a: T) -> A; - | ++++++ ~ -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 f(a: impl A) -> A; - | ++++ - -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19 - | -LL | fn f(a: A) -> A; - | ^ - | -help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as you return a single underlying type - | -LL | fn f(a: A) -> impl A; - | ++++ - -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13 - | -LL | fn f(b: B) -> B; - | ^ - | - = note: `B` it is dyn-incompatible, so it can't be `dyn` -help: use a new generic type parameter, constrained by `B` - | -LL | fn f<T: B>(b: T) -> B; - | ++++++ ~ -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 f(b: impl B) -> B; - | ++++ - -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:19 - | -LL | fn f(b: B) -> 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 f(b: B) -> impl B; - | ++++ - -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20 - | -LL | fn f(&self, c: C) -> C; - | ^ - | - = note: `C` it is dyn-incompatible, so it can't be `dyn` -help: use a new generic type parameter, constrained by `C` - | -LL | fn f<T: C>(&self, c: T) -> C; - | ++++++ ~ -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 f(&self, c: impl C) -> C; - | ++++ - -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:26 - | -LL | fn f(&self, c: C) -> C; - | ^ - | -help: `C` is dyn-incompatible, use `impl C` to return an opaque type, as long as you return a single underlying type - | -LL | fn f(&self, c: C) -> impl C; - | ++++ - -error: aborting due to 12 previous errors - -Some errors have detailed explanations: E0038, E0782. -For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/suggest-blanket-impl-local-trait.rs b/tests/ui/suggestions/suggest-blanket-impl-local-trait.rs index 76300c6a3f4..dd7e203abd7 100644 --- a/tests/ui/suggestions/suggest-blanket-impl-local-trait.rs +++ b/tests/ui/suggestions/suggest-blanket-impl-local-trait.rs @@ -11,48 +11,48 @@ trait LocalTraitTwo { } trait GenericTrait<T> {} impl LocalTraitTwo for LocalTraitOne {} -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object //~| HELP alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne` impl fmt::Display for LocalTraitOne { -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { todo!(); } } impl fmt::Display for LocalTraitTwo + Send { -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { todo!(); } } impl LocalTraitOne for fmt::Display {} -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object //~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display` impl LocalTraitOne for fmt::Display + Send {} -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object //~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send` impl<E> GenericTrait<E> for LocalTraitOne {} -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object //~| HELP alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne` trait GenericTraitTwo<T> {} impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {} -//~^ ERROR trait objects must include the `dyn` keyword -//~| HELP add `dyn` keyword before this trait +//~^ ERROR expected a type, found a trait +//~| HELP you can add the `dyn` keyword if you want a trait object //~| HELP alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>` fn main() {} diff --git a/tests/ui/suggestions/suggest-blanket-impl-local-trait.stderr b/tests/ui/suggestions/suggest-blanket-impl-local-trait.stderr index 769f3bd64f3..102438e1ec5 100644 --- a/tests/ui/suggestions/suggest-blanket-impl-local-trait.stderr +++ b/tests/ui/suggestions/suggest-blanket-impl-local-trait.stderr @@ -1,10 +1,10 @@ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-blanket-impl-local-trait.rs:34:24 | LL | impl LocalTraitOne for fmt::Display {} | ^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl LocalTraitOne for dyn fmt::Display {} | +++ @@ -13,13 +13,13 @@ help: alternatively use a blanket implementation to implement `LocalTraitOne` fo LL | impl<T: fmt::Display> LocalTraitOne for T {} | +++++++++++++++++ ~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-blanket-impl-local-trait.rs:40:24 | LL | impl LocalTraitOne for fmt::Display + Send {} | ^^^^^^^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl LocalTraitOne for dyn fmt::Display + Send {} | +++ @@ -28,13 +28,13 @@ help: alternatively use a blanket implementation to implement `LocalTraitOne` fo LL | impl<T: fmt::Display + Send> LocalTraitOne for T {} | ++++++++++++++++++++++++ ~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-blanket-impl-local-trait.rs:13:24 | LL | impl LocalTraitTwo for LocalTraitOne {} | ^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl LocalTraitTwo for dyn LocalTraitOne {} | +++ @@ -43,13 +43,13 @@ help: alternatively use a blanket implementation to implement `LocalTraitTwo` fo LL | impl<T: LocalTraitOne> LocalTraitTwo for T {} | ++++++++++++++++++ ~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-blanket-impl-local-trait.rs:46:29 | LL | impl<E> GenericTrait<E> for LocalTraitOne {} | ^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl<E> GenericTrait<E> for dyn LocalTraitOne {} | +++ @@ -58,35 +58,35 @@ help: alternatively use a blanket implementation to implement `GenericTrait<E>` LL | impl<E, T: LocalTraitOne> GenericTrait<E> for T {} | ++++++++++++++++++ ~ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-blanket-impl-local-trait.rs:18:23 | LL | impl fmt::Display for LocalTraitOne { | ^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl fmt::Display for dyn LocalTraitOne { | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-blanket-impl-local-trait.rs:26:23 | LL | impl fmt::Display for LocalTraitTwo + Send { | ^^^^^^^^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl fmt::Display for dyn LocalTraitTwo + Send { | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-blanket-impl-local-trait.rs:53:35 | LL | impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {} | ^^^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl<T, E> GenericTraitTwo<E> for dyn GenericTrait<T> {} | +++ diff --git a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.rs b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.rs index a5ab8be7f45..fe36d093430 100644 --- a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.rs +++ b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.rs @@ -14,14 +14,14 @@ pub union Union<T> { impl<'a, T> Struct<T> for Trait<'a, T> {} //~^ ERROR expected trait, found struct `Struct` -//~| ERROR trait objects must include the `dyn` keyword +//~| ERROR expected a type, found a trait impl<'a, T> Enum<T> for Trait<'a, T> {} //~^ ERROR expected trait, found enum `Enum` -//~| ERROR trait objects must include the `dyn` keyword +//~| ERROR expected a type, found a trait impl<'a, T> Union<T> for Trait<'a, T> {} //~^ ERROR expected trait, found union `Union` -//~| ERROR trait objects must include the `dyn` keyword +//~| ERROR expected a type, found a trait fn main() {} diff --git a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr index 2893370570d..0bd601e2170 100644 --- a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr +++ b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr @@ -58,35 +58,35 @@ LL | pub union Union<T> { = 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[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:15:27 | LL | impl<'a, T> Struct<T> for Trait<'a, T> {} | ^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl<'a, T> Struct<T> for dyn Trait<'a, T> {} | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:19:25 | LL | impl<'a, T> Enum<T> for Trait<'a, T> {} | ^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl<'a, T> Enum<T> for dyn Trait<'a, T> {} | +++ -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:23:26 | LL | impl<'a, T> Union<T> for Trait<'a, T> {} | ^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl<'a, T> Union<T> for dyn Trait<'a, T> {} | +++ diff --git a/tests/ui/target-feature/tied-features-no-implication-1.paca.stderr b/tests/ui/target-feature/tied-features-no-implication-1.paca.stderr new file mode 100644 index 00000000000..bf211fbee2f --- /dev/null +++ b/tests/ui/target-feature/tied-features-no-implication-1.paca.stderr @@ -0,0 +1,4 @@ +error: the target features paca, pacg must all be either enabled or disabled together + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/tied-features-no-implication-1.pacg.stderr b/tests/ui/target-feature/tied-features-no-implication-1.pacg.stderr new file mode 100644 index 00000000000..bf211fbee2f --- /dev/null +++ b/tests/ui/target-feature/tied-features-no-implication-1.pacg.stderr @@ -0,0 +1,4 @@ +error: the target features paca, pacg must all be either enabled or disabled together + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/tied-features-no-implication-1.rs b/tests/ui/target-feature/tied-features-no-implication-1.rs new file mode 100644 index 00000000000..0473ca319b8 --- /dev/null +++ b/tests/ui/target-feature/tied-features-no-implication-1.rs @@ -0,0 +1,20 @@ +//@ revisions: paca pacg +//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@[paca] compile-flags: -Ctarget-feature=+paca +//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together +//@[pacg] compile-flags: -Ctarget-feature=+pacg +//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized {} + +// In this test, demonstrate that +paca and +pacg both result in the tied feature error if there +// isn't something causing an error. +// See tied-features-no-implication.rs + +#[cfg(target_feature = "pacg")] +pub unsafe fn foo() { +} diff --git a/tests/ui/target-feature/tied-features-no-implication.paca.stderr b/tests/ui/target-feature/tied-features-no-implication.paca.stderr new file mode 100644 index 00000000000..bf211fbee2f --- /dev/null +++ b/tests/ui/target-feature/tied-features-no-implication.paca.stderr @@ -0,0 +1,4 @@ +error: the target features paca, pacg must all be either enabled or disabled together + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/tied-features-no-implication.pacg.stderr b/tests/ui/target-feature/tied-features-no-implication.pacg.stderr new file mode 100644 index 00000000000..0e31dea24ea --- /dev/null +++ b/tests/ui/target-feature/tied-features-no-implication.pacg.stderr @@ -0,0 +1,14 @@ +error[E0428]: the name `foo` is defined multiple times + --> $DIR/tied-features-no-implication.rs:28:1 + | +LL | fn foo() {} + | -------- previous definition of the value `foo` here +... +LL | pub unsafe fn foo() { + | ^^^^^^^^^^^^^^^^^^^ `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/target-feature/tied-features-no-implication.rs b/tests/ui/target-feature/tied-features-no-implication.rs new file mode 100644 index 00000000000..157b50bb0d3 --- /dev/null +++ b/tests/ui/target-feature/tied-features-no-implication.rs @@ -0,0 +1,29 @@ +//@ revisions: paca pacg +//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@[paca] compile-flags: -Ctarget-feature=+paca +//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together +//@[pacg] compile-flags: -Ctarget-feature=+pacg +//@[pacg] error-pattern: the name `foo` is defined multiple times +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized {} + +// Can't use `compile_error!` here without `core`/`std` but requiring these makes this test only +// work if you have libcore built in the sysroot for `aarch64-unknown-linux-gnu`. Can't run this +// test on any aarch64 platform because they all have different default available features - as +// written, this test depends on `aarch64-unknown-linux-gnu` having -paca,-pacg by default. +// Cause a multiple definition error instead. +fn foo() {} + +// Enabling one of the tied features does not imply the other is enabled. +// +// With +paca, this multiple definition doesn't cause an error because +paca hasn't implied +// +pacg. With +pacg, the multiple definition error is emitted (and the tied feature error would +// be). + +#[cfg(target_feature = "pacg")] +pub unsafe fn foo() { +} diff --git a/tests/ui/target-feature/tied-features.rs b/tests/ui/target-feature/tied-features.rs index e36649d8eb1..c6cdf21a3e3 100644 --- a/tests/ui/target-feature/tied-features.rs +++ b/tests/ui/target-feature/tied-features.rs @@ -1,4 +1,3 @@ -//@ build-fail //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 #![feature(no_core, lang_items)] @@ -7,7 +6,6 @@ #[lang="sized"] trait Sized {} -// FIXME: this should not need to be public. pub fn main() { #[target_feature(enable = "pacg")] //~^ ERROR must all be either enabled or disabled together @@ -25,10 +23,15 @@ pub fn main() { //~^ ERROR must all be either enabled or disabled together unsafe fn foo() {} - #[target_feature(enable = "paca,pacg")] unsafe fn bar() {} #[target_feature(enable = "paca")] #[target_feature(enable = "pacg")] unsafe fn baz() {} + +// Confirm that functions which do not end up collected for monomorphisation will still error. + +#[target_feature(enable = "paca")] +//~^ ERROR must all be either enabled or disabled together +unsafe fn unused() {} diff --git a/tests/ui/target-feature/tied-features.stderr b/tests/ui/target-feature/tied-features.stderr index 525c9084330..8d677735e84 100644 --- a/tests/ui/target-feature/tied-features.stderr +++ b/tests/ui/target-feature/tied-features.stderr @@ -1,5 +1,5 @@ error: the target features paca, pacg must all be either enabled or disabled together - --> $DIR/tied-features.rs:12:5 + --> $DIR/tied-features.rs:10:5 | LL | #[target_feature(enable = "pacg")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,12 +7,20 @@ LL | #[target_feature(enable = "pacg")] = help: add the missing features in a `target_feature` attribute error: the target features paca, pacg must all be either enabled or disabled together - --> $DIR/tied-features.rs:24:1 + --> $DIR/tied-features.rs:22:1 | LL | #[target_feature(enable = "paca")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add the missing features in a `target_feature` attribute -error: aborting due to 2 previous errors +error: the target features paca, pacg must all be either enabled or disabled together + --> $DIR/tied-features.rs:35:1 + | +LL | #[target_feature(enable = "paca")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add the missing features in a `target_feature` attribute + +error: aborting due to 3 previous errors diff --git a/tests/ui/traits/alias/no-duplicates.rs b/tests/ui/traits/alias/no-duplicates.rs index 88feb89170d..d0829ab4cec 100644 --- a/tests/ui/traits/alias/no-duplicates.rs +++ b/tests/ui/traits/alias/no-duplicates.rs @@ -1,4 +1,4 @@ -// The purpose of this test is to demonstrate that duplicating object safe traits +// The purpose of this test is to demonstrate that duplicating dyn-compatible traits // that are not auto traits is rejected with trait aliases even though one could // reasonably accept this. @@ -6,7 +6,7 @@ use std::marker::Unpin; -// Some arbitrary object-safe trait: +// Some arbitrary dyn-compatible trait: trait Obj {} // Nest a few levels deep: diff --git a/tests/ui/traits/alias/no-extra-traits.rs b/tests/ui/traits/alias/no-extra-traits.rs index 4dad8c0f873..f3d35a8cd03 100644 --- a/tests/ui/traits/alias/no-extra-traits.rs +++ b/tests/ui/traits/alias/no-extra-traits.rs @@ -5,7 +5,7 @@ use std::marker::Unpin; -// Some arbitrary object-safe traits: +// Some arbitrary dyn-compatible traits: trait ObjA {} trait ObjB {} diff --git a/tests/ui/traits/alias/object-wf.rs b/tests/ui/traits/alias/object-wf.rs index 3abffd22d14..a14cfea3bd7 100644 --- a/tests/ui/traits/alias/object-wf.rs +++ b/tests/ui/traits/alias/object-wf.rs @@ -20,7 +20,7 @@ fn _f0() { let _: Box<dyn Unpin + _1 + Send + Sync>; } -// Include object safe traits: +// Include dyn-compatible traits: fn _f1() { let _: Box<dyn Obj + _0>; @@ -28,7 +28,7 @@ fn _f1() { let _: Box<dyn Obj + _1 + _0>; } -// And when the object safe trait is in a trait alias: +// And when the dyn-compatible trait is in a trait alias: trait _2 = Obj; diff --git a/tests/ui/traits/assoc-type-hrtb-normalization-30472.rs b/tests/ui/traits/assoc-type-hrtb-normalization-30472.rs new file mode 100644 index 00000000000..4ce3b9b3b77 --- /dev/null +++ b/tests/ui/traits/assoc-type-hrtb-normalization-30472.rs @@ -0,0 +1,32 @@ +//@ check-pass +//! Tests that associated type projections normalize properly in the presence of HRTBs. +//! Original issue: <https://github.com/rust-lang/rust/issues/30472> + + +pub trait MyFrom<T> {} +impl<T> MyFrom<T> for T {} + +pub trait MyInto<T> {} +impl<T, U> MyInto<U> for T where U: MyFrom<T> {} + + +pub trait A<'self_> { + type T; +} +pub trait B: for<'self_> A<'self_> { + // Originally caused the `type U = usize` example below to fail with a type mismatch error + type U: for<'self_> MyFrom<<Self as A<'self_>>::T>; +} + + +pub struct M; +impl<'self_> A<'self_> for M { + type T = usize; +} + +impl B for M { + type U = usize; +} + + +fn main() {} diff --git a/tests/ui/traits/bound/not-on-bare-trait-2021.rs b/tests/ui/traits/bound/not-on-bare-trait-2021.rs index 07b866cb4a6..93d2f04b54e 100644 --- a/tests/ui/traits/bound/not-on-bare-trait-2021.rs +++ b/tests/ui/traits/bound/not-on-bare-trait-2021.rs @@ -6,13 +6,11 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ ERROR trait objects must include the `dyn` keyword - //~| ERROR size for values of type + //~^ ERROR expected a type, found a trait } fn bar(x: Foo) -> Foo { - //~^ ERROR trait objects must include the `dyn` keyword - //~| ERROR trait objects must include the `dyn` keyword - //~| ERROR size for values of type + //~^ ERROR expected a type, found a trait + //~| ERROR expected a type, found a trait x } diff --git a/tests/ui/traits/bound/not-on-bare-trait-2021.stderr b/tests/ui/traits/bound/not-on-bare-trait-2021.stderr index e05ae8e5267..e50186aff7e 100644 --- a/tests/ui/traits/bound/not-on-bare-trait-2021.stderr +++ b/tests/ui/traits/bound/not-on-bare-trait-2021.stderr @@ -1,38 +1,4 @@ -error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time - --> $DIR/not-on-bare-trait-2021.rs:8:12 - | -LL | fn foo(_x: Foo + Send) { - | ^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` - = help: unsized fn params are gated as an unstable feature -help: you can use `impl Trait` as the argument type - | -LL | fn foo(_x: impl Foo + Send) { - | ++++ -help: function arguments must have a statically known size, borrowed types always have a known size - | -LL | fn foo(_x: &(dyn Foo + Send)) { - | +++++ + - -error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time - --> $DIR/not-on-bare-trait-2021.rs:12:11 - | -LL | fn bar(x: Foo) -> Foo { - | ^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` - = help: unsized fn params are gated as an unstable feature -help: you can use `impl Trait` as the argument type - | -LL | fn bar(x: impl Foo) -> Foo { - | ++++ -help: function arguments must have a statically known size, borrowed types always have a known size - | -LL | fn bar(x: &dyn Foo) -> Foo { - | ++++ - -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/not-on-bare-trait-2021.rs:8:12 | LL | fn foo(_x: Foo + Send) { @@ -51,8 +17,8 @@ help: alternatively, use a trait object to accept any type that implements `Foo LL | fn foo(_x: &(dyn Foo + Send)) { | +++++ + -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/not-on-bare-trait-2021.rs:12:11 +error[E0782]: expected a type, found a trait + --> $DIR/not-on-bare-trait-2021.rs:11:11 | LL | fn bar(x: Foo) -> Foo { | ^^^ @@ -70,8 +36,8 @@ help: alternatively, use a trait object to accept any type that implements `Foo` LL | fn bar(x: &dyn Foo) -> Foo { | ++++ -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/not-on-bare-trait-2021.rs:12:19 +error[E0782]: expected a type, found a trait + --> $DIR/not-on-bare-trait-2021.rs:11:19 | LL | fn bar(x: Foo) -> Foo { | ^^^ @@ -85,7 +51,6 @@ help: alternatively, you can return an owned trait object LL | fn bar(x: Foo) -> Box<dyn Foo> { | +++++++ + -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0782. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/traits/fn-pointer/hrtb-assoc-fn-traits-28994.rs b/tests/ui/traits/fn-pointer/hrtb-assoc-fn-traits-28994.rs new file mode 100644 index 00000000000..e2f02053f95 --- /dev/null +++ b/tests/ui/traits/fn-pointer/hrtb-assoc-fn-traits-28994.rs @@ -0,0 +1,22 @@ +//@ check-pass +//! Tests that a HRTB + FnOnce bound involving an associated type don't prevent +//! a function pointer from implementing `Fn` traits. +//! Test for <https://github.com/rust-lang/rust/issues/28994> + +trait LifetimeToType<'a> { + type Out; +} + +impl<'a> LifetimeToType<'a> for () { + type Out = &'a (); +} + +fn id<'a>(val: &'a ()) -> <() as LifetimeToType<'a>>::Out { + val +} + +fn assert_fn<F: for<'a> FnOnce(&'a ()) -> <() as LifetimeToType<'a>>::Out>(_func: F) { } + +fn main() { + assert_fn(id); +} diff --git a/tests/ui/traits/hrtb-related-type-params-30867.rs b/tests/ui/traits/hrtb-related-type-params-30867.rs new file mode 100644 index 00000000000..ec1e3355bfb --- /dev/null +++ b/tests/ui/traits/hrtb-related-type-params-30867.rs @@ -0,0 +1,14 @@ +//@ check-pass +//! Tests that HRTB impl selection covers type parameters not directly related +//! to the trait. +//! Test for <https://github.com/rust-lang/rust/issues/30867> + +#![crate_type = "lib"] + +trait Unary<T> {} +impl<T, U, F: Fn(T) -> U> Unary<T> for F {} +fn unary<F: for<'a> Unary<&'a T>, T>() {} + +pub fn test<F: for<'a> Fn(&'a i32) -> &'a i32>() { + unary::<F, i32>() +} diff --git a/tests/ui/traits/issue-106072.rs b/tests/ui/traits/issue-106072.rs index 8adbac46a5b..696bd765ebc 100644 --- a/tests/ui/traits/issue-106072.rs +++ b/tests/ui/traits/issue-106072.rs @@ -1,6 +1,4 @@ -#[derive(Clone)] //~ trait objects must include the `dyn` keyword -//~^ ERROR: the size for values of type `(dyn Foo + 'static)` cannot be known -//~| ERROR: return type cannot have an unboxed trait object +#[derive(Clone)] //~ expected a type, found a trait struct Foo; trait Foo {} //~ the name `Foo` is defined multiple times fn main() {} diff --git a/tests/ui/traits/issue-106072.stderr b/tests/ui/traits/issue-106072.stderr index 6476c8b3237..4a48e4e898d 100644 --- a/tests/ui/traits/issue-106072.stderr +++ b/tests/ui/traits/issue-106072.stderr @@ -1,5 +1,5 @@ error[E0428]: the name `Foo` is defined multiple times - --> $DIR/issue-106072.rs:5:1 + --> $DIR/issue-106072.rs:3:1 | LL | struct Foo; | ----------- previous definition of the type `Foo` here @@ -8,26 +8,7 @@ LL | trait Foo {} | = note: `Foo` must be defined only once in the type namespace of this module -error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time - --> $DIR/issue-106072.rs:1:10 - | -LL | #[derive(Clone)] - | ^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` -note: required by a bound in `Clone` - --> $SRC_DIR/core/src/clone.rs:LL:COL - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0746]: return type cannot have an unboxed trait object - --> $DIR/issue-106072.rs:1:10 - | -LL | #[derive(Clone)] - | ^^^^^ doesn't have a size known at compile-time - | - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0782]: trait objects must include the `dyn` keyword +error[E0782]: expected a type, found a trait --> $DIR/issue-106072.rs:1:10 | LL | #[derive(Clone)] @@ -35,7 +16,7 @@ LL | #[derive(Clone)] | = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0428, E0746, E0782. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0428, E0782. +For more information about an error, try `rustc --explain E0428`. diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr new file mode 100644 index 00000000000..541b49b024f --- /dev/null +++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr @@ -0,0 +1,74 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo<i64> { + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> + = note: `#[warn(bare_trait_objects)]` on by default +help: if this is a dyn-compatible trait, use `dyn` + | +LL | impl dyn Foo<i64> { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo<i64> for /* Type */ { + | ++++++++++++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo<i64> { + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: if this is a dyn-compatible trait, use `dyn` + | +LL | impl dyn Foo<i64> { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo<i64> for /* Type */ { + | ++++++++++++++ + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo<i64> { + | ^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/missing-for-type-in-impl.rs:4:8 + | +LL | trait Foo<T> { + | --- this trait cannot be made into an object... +LL | fn id(me: T) -> T; + | ^^ ...because associated function `id` has no `self` parameter +help: consider turning `id` into a method by giving it a `&self` argument + | +LL | fn id(&self, me: T) -> T; + | ++++++ +help: alternatively, consider constraining `id` so it does not apply to trait objects + | +LL | fn id(me: T) -> T where Self: Sized; + | +++++++++++++++++ + +error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied + --> $DIR/missing-for-type-in-impl.rs:19:19 + | +LL | let x: i64 = <i64 as Foo<i64>>::id(10); + | ^^^ the trait `Foo<i64>` is not implemented for `i64` + | +help: this trait has no implementations, consider adding one + --> $DIR/missing-for-type-in-impl.rs:3:1 + | +LL | trait Foo<T> { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0038, E0277. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/missing-for-type-in-impl.e2021.stderr b/tests/ui/traits/missing-for-type-in-impl.e2021.stderr new file mode 100644 index 00000000000..a49c5d9d45b --- /dev/null +++ b/tests/ui/traits/missing-for-type-in-impl.e2021.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied + --> $DIR/missing-for-type-in-impl.rs:19:19 + | +LL | let x: i64 = <i64 as Foo<i64>>::id(10); + | ^^^ the trait `Foo<i64>` is not implemented for `i64` + | +help: this trait has no implementations, consider adding one + --> $DIR/missing-for-type-in-impl.rs:3:1 + | +LL | trait Foo<T> { + | ^^^^^^^^^^^^ + +error[E0782]: expected a type, found a trait + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo<i64> { + | ^^^^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | impl dyn Foo<i64> { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo<i64> for /* Type */ { + | ++++++++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0782. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/missing-for-type-in-impl.rs b/tests/ui/traits/missing-for-type-in-impl.rs new file mode 100644 index 00000000000..e5dd3651609 --- /dev/null +++ b/tests/ui/traits/missing-for-type-in-impl.rs @@ -0,0 +1,22 @@ +//@revisions: e2021 e2015 +//@[e2021]edition: 2021 +trait Foo<T> { + fn id(me: T) -> T; +} + +/* note the "missing" for ... (in this case for i64, in order for this to compile) */ +impl Foo<i64> { +//[e2021]~^ ERROR expected a type, found a trait +//[e2015]~^^ WARNING trait objects without an explicit `dyn` are deprecated +//[e2015]~| WARNING trait objects without an explicit `dyn` are deprecated +//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//[e2015]~| ERROR the trait `Foo` cannot be made into an object + fn id(me: i64) -> i64 {me} +} + +fn main() { + let x: i64 = <i64 as Foo<i64>>::id(10); + //~^ ERROR the trait bound `i64: Foo<i64>` is not satisfied + println!("{}", x); +} diff --git a/tests/ui/traits/next-solver/object-unsafety.rs b/tests/ui/traits/next-solver/dyn-incompatibility.rs index a347984daf6..a347984daf6 100644 --- a/tests/ui/traits/next-solver/object-unsafety.rs +++ b/tests/ui/traits/next-solver/dyn-incompatibility.rs diff --git a/tests/ui/traits/next-solver/object-unsafety.stderr b/tests/ui/traits/next-solver/dyn-incompatibility.stderr index 75d0ce24413..7f2c0646ef5 100644 --- a/tests/ui/traits/next-solver/object-unsafety.stderr +++ b/tests/ui/traits/next-solver/dyn-incompatibility.stderr @@ -1,12 +1,12 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>` - --> $DIR/object-unsafety.rs:12:12 + --> $DIR/dyn-incompatibility.rs:12:12 | LL | copy::<dyn Setup<From=T>>(t) | ^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup` | = note: required because it appears within the type `dyn Setup<From = T>` note: required by a bound in `copy` - --> $DIR/object-unsafety.rs:7:12 + --> $DIR/dyn-incompatibility.rs:7:12 | LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From { | ^^^^^ required by this bound in `copy` @@ -16,7 +16,7 @@ LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T { | +++++++++++++++++++ error[E0308]: mismatched types - --> $DIR/object-unsafety.rs:12:31 + --> $DIR/dyn-incompatibility.rs:12:31 | LL | copy::<dyn Setup<From=T>>(t) | ------------------------- ^ types differ @@ -26,13 +26,13 @@ LL | copy::<dyn Setup<From=T>>(t) = note: expected reference `&<dyn Setup<From = T> as Setup>::From` found reference `&T` note: function defined here - --> $DIR/object-unsafety.rs:7:4 + --> $DIR/dyn-incompatibility.rs:7:4 | LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From { | ^^^^ -------------- error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>` - --> $DIR/object-unsafety.rs:12:5 + --> $DIR/dyn-incompatibility.rs:12:5 | LL | copy::<dyn Setup<From=T>>(t) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup` diff --git a/tests/ui/traits/next-solver/typeck/guide-ctors.rs b/tests/ui/traits/next-solver/typeck/guide-ctors.rs new file mode 100644 index 00000000000..7432ea78a56 --- /dev/null +++ b/tests/ui/traits/next-solver/typeck/guide-ctors.rs @@ -0,0 +1,32 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Makes sure we structurally normalize before trying to use expectation to guide +// coercion in adt and tuples. + +use std::any::Any; + +trait Coerce { + type Assoc; +} + +struct TupleGuidance; +impl Coerce for TupleGuidance { + type Assoc = (&'static dyn Any,); +} + +struct AdtGuidance; +impl Coerce for AdtGuidance { + type Assoc = Adt<&'static dyn Any>; +} + +struct Adt<T> { + f: T, +} + +fn foo<'a, T: Coerce>(_: T::Assoc) {} + +fn main() { + foo::<TupleGuidance>((&0u32,)); + foo::<AdtGuidance>(Adt { f: &0u32 }); +} diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs index a635edb4485..a635edb4485 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr index 0854ea28150..dd2dca74f90 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr @@ -1,5 +1,5 @@ warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/supertrait-object-safety.rs:1:12 + --> $DIR/supertrait-dyn-compatibility.rs:1:12 | LL | #![feature(non_lifetime_binders)] | ^^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | #![feature(non_lifetime_binders)] = note: `#[warn(incomplete_features)]` on by default error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/supertrait-object-safety.rs:19:23 + --> $DIR/supertrait-dyn-compatibility.rs:19:23 | LL | let x: &dyn Foo = &(); | ^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/supertrait-object-safety.rs:4:12 + --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables @@ -24,13 +24,13 @@ LL | trait Foo: for<T> Bar<T> {} = note: required for the cast from `&()` to `&dyn Foo` error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/supertrait-object-safety.rs:19:12 + --> $DIR/supertrait-dyn-compatibility.rs:19:12 | LL | let x: &dyn Foo = &(); | ^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/supertrait-object-safety.rs:4:12 + --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables @@ -39,13 +39,13 @@ LL | trait Foo: for<T> Bar<T> {} = help: only type `()` implements the trait, consider using it directly instead error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/supertrait-object-safety.rs:22:5 + --> $DIR/supertrait-dyn-compatibility.rs:22:5 | LL | needs_bar(x); | ^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/supertrait-object-safety.rs:4:12 + --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs new file mode 100644 index 00000000000..b174776c596 --- /dev/null +++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs @@ -0,0 +1,24 @@ +// Make sure that when elaborating the principal of a dyn trait for projection predicates +// we don't end up in a situation where we have an unconstrained late-bound lifetime in +// the output of a projection. + +// Fix for <https://github.com/rust-lang/rust/issues/130347>. + +trait A<T>: B<T = T> {} + +trait B { + type T; +} + +struct Erase<T: ?Sized + B>(T::T); + +fn main() { + let x = { + let x = String::from("hello"); + + Erase::<dyn for<'a> A<&'a _>>(x.as_str()) + //~^ ERROR binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types + }; + + dbg!(x.0); +} diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr new file mode 100644 index 00000000000..067eaf5e7f3 --- /dev/null +++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr @@ -0,0 +1,12 @@ +error[E0582]: binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/elaborated-predicates-unconstrained-late-bound.rs:19:21 + | +LL | trait A<T>: B<T = T> {} + | ----- due to this supertrait +... +LL | Erase::<dyn for<'a> A<&'a _>>(x.as_str()) + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0582`. diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs index 6660ff040f7..603d7af5260 100644 --- a/tests/ui/traits/object/pretty.rs +++ b/tests/ui/traits/object/pretty.rs @@ -13,7 +13,7 @@ trait SuperGeneric<'a> { } trait AnyGeneric<'a>: SuperGeneric<'a> {} trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {} -trait FixedGeneric2<'a>: Super<Assoc = &'a u8> {} +// trait FixedGeneric2<'a>: Super<Assoc = &'a u8> {} // Unsound! trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {} trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {} trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super<Assoc = u8> {} @@ -32,7 +32,7 @@ fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types -fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } //~ERROR mismatched types +// fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } // Unsound! fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } //~ERROR mismatched types diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index ca56bdbb67a..af941e69c5f 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -107,17 +107,6 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } found reference `&dyn for<'a> FixedGeneric1<'a>` error[E0308]: mismatched types - --> $DIR/pretty.rs:35:60 - | -LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } - | - ^ expected `()`, found `&dyn FixedGeneric2<'a>` - | | - | help: try adding a return type: `-> &dyn for<'a> FixedGeneric2<'a>` - | - = note: expected unit type `()` - found reference `&dyn for<'a> FixedGeneric2<'a>` - -error[E0308]: mismatched types --> $DIR/pretty.rs:36:79 | LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } @@ -172,6 +161,6 @@ LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x } = note: expected unit type `()` found reference `&dyn HasGat<u8, Assoc<bool> = ()>` -error: aborting due to 15 previous errors; 1 warning emitted +error: aborting due to 14 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/object/print_vtable_sizes.rs b/tests/ui/traits/object/print_vtable_sizes.rs index 684458d079e..2b1745da5f3 100644 --- a/tests/ui/traits/object/print_vtable_sizes.rs +++ b/tests/ui/traits/object/print_vtable_sizes.rs @@ -7,7 +7,7 @@ trait A<T: help::V>: AsRef<[T::V]> + AsMut<[T::V]> {} trait B<T>: AsRef<T> + AsRef<T> + AsRef<T> + AsRef<T> {} trait C { - fn x() {} // not object safe, shouldn't be reported + fn x() {} // not dyn-compatible, shouldn't be reported } // This does not have any upcasting cost, diff --git a/tests/ui/traits/object/safety.rs b/tests/ui/traits/object/safety.rs index f43d332d696..f4abcf8542e 100644 --- a/tests/ui/traits/object/safety.rs +++ b/tests/ui/traits/object/safety.rs @@ -1,4 +1,4 @@ -// Check that static methods are not object-safe. +// Check that static methods render the trait dyn-incompatible. trait Tr { fn foo(); diff --git a/tests/ui/traits/vtable/vtable-non-object-safe.rs b/tests/ui/traits/vtable/vtable-dyn-incompatible.rs index f98af0f23b7..64a8138bdcf 100644 --- a/tests/ui/traits/vtable/vtable-non-object-safe.rs +++ b/tests/ui/traits/vtable/vtable-dyn-incompatible.rs @@ -1,7 +1,7 @@ //@ build-fail #![feature(rustc_attrs)] -// Ensure that non-object-safe methods in Iterator does not generate +// Ensure that dyn-incompatible methods in Iterator does not generate // vtable entries. #[rustc_dump_vtable] diff --git a/tests/ui/traits/vtable/vtable-non-object-safe.stderr b/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr index 53eef5d0b13..e442c3eac00 100644 --- a/tests/ui/traits/vtable/vtable-non-object-safe.stderr +++ b/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr @@ -7,7 +7,7 @@ error: vtable entries for `<std::vec::IntoIter<u8> as A>`: [ Method(<std::vec::IntoIter<u8> as Iterator>::advance_by), Method(<std::vec::IntoIter<u8> as Iterator>::nth), ] - --> $DIR/vtable-non-object-safe.rs:8:1 + --> $DIR/vtable-dyn-incompatible.rs:8:1 | LL | trait A: Iterator {} | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/wf-object/no-duplicates.rs b/tests/ui/traits/wf-object/no-duplicates.rs index 678ede58296..83544064ce2 100644 --- a/tests/ui/traits/wf-object/no-duplicates.rs +++ b/tests/ui/traits/wf-object/no-duplicates.rs @@ -1,7 +1,7 @@ -// The purpose of this test is to demonstrate that duplicating object safe traits +// The purpose of this test is to demonstrate that duplicating dyn-compatible traits // that are not auto-traits is rejected even though one could reasonably accept this. -// Some arbitrary object-safe trait: +// Some arbitrary dyn-compatible trait: trait Obj {} // Demonstrate that recursive expansion of trait aliases doesn't affect stable behavior: diff --git a/tests/ui/traits/wf-object/reverse-order.rs b/tests/ui/traits/wf-object/reverse-order.rs index b8f2aae8966..99c727cc332 100644 --- a/tests/ui/traits/wf-object/reverse-order.rs +++ b/tests/ui/traits/wf-object/reverse-order.rs @@ -2,7 +2,7 @@ // Ensure that `dyn $($AutoTrait)+ ObjSafe` is well-formed. -// Some arbitrary object-safe trait: +// Some arbitrary dyn-compatible trait: trait Obj {} type _0 = dyn Unpin; diff --git a/tests/ui/try-trait/bad-interconversion.rs b/tests/ui/try-trait/bad-interconversion.rs index 385f5510fb4..9c45bde8898 100644 --- a/tests/ui/try-trait/bad-interconversion.rs +++ b/tests/ui/try-trait/bad-interconversion.rs @@ -1,5 +1,3 @@ -#![feature(control_flow_enum)] - use std::ops::ControlFlow; fn result_to_result() -> Result<u64, u8> { diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 9aab2cf6ab8..82877baef3e 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -1,5 +1,5 @@ error[E0277]: `?` couldn't convert the error to `u8` - --> $DIR/bad-interconversion.rs:6:20 + --> $DIR/bad-interconversion.rs:4:20 | LL | fn result_to_result() -> Result<u64, u8> { | --------------- expected `u8` because of this @@ -15,7 +15,7 @@ LL | Ok(Err(123_i32)?) = note: required for `Result<u64, u8>` to implement `FromResidual<Result<Infallible, i32>>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` - --> $DIR/bad-interconversion.rs:11:12 + --> $DIR/bad-interconversion.rs:9:12 | LL | fn option_to_result() -> Result<u64, String> { | -------------------------------------------- this function returns a `Result` @@ -26,7 +26,7 @@ LL | Some(3)?; = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>` error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` - --> $DIR/bad-interconversion.rs:17:31 + --> $DIR/bad-interconversion.rs:15:31 | LL | fn control_flow_to_result() -> Result<u64, String> { | -------------------------------------------------- this function returns a `Result` @@ -37,7 +37,7 @@ LL | Ok(ControlFlow::Break(123)?) = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` - --> $DIR/bad-interconversion.rs:22:22 + --> $DIR/bad-interconversion.rs:20:22 | LL | fn result_to_option() -> Option<u16> { | ------------------------------------ this function returns an `Option` @@ -48,7 +48,7 @@ LL | Some(Err("hello")?) = help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>` error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` - --> $DIR/bad-interconversion.rs:27:33 + --> $DIR/bad-interconversion.rs:25:33 | LL | fn control_flow_to_option() -> Option<u64> { | ------------------------------------------ this function returns an `Option` @@ -59,7 +59,7 @@ LL | Some(ControlFlow::Break(123)?) = help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>` error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` - --> $DIR/bad-interconversion.rs:32:39 + --> $DIR/bad-interconversion.rs:30:39 | LL | fn result_to_control_flow() -> ControlFlow<String> { | -------------------------------------------------- this function returns a `ControlFlow` @@ -71,7 +71,7 @@ LL | ControlFlow::Continue(Err("hello")?) = help: for that trait implementation, expected `ControlFlow<String, Infallible>`, found `Result<Infallible, &str>` error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` - --> $DIR/bad-interconversion.rs:37:12 + --> $DIR/bad-interconversion.rs:35:12 | LL | fn option_to_control_flow() -> ControlFlow<u64> { | ----------------------------------------------- this function returns a `ControlFlow` @@ -83,7 +83,7 @@ LL | Some(3)?; = help: for that trait implementation, expected `ControlFlow<u64, Infallible>`, found `Option<Infallible>` error[E0277]: the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s (with the same Break type) - --> $DIR/bad-interconversion.rs:43:29 + --> $DIR/bad-interconversion.rs:41:29 | LL | fn control_flow_to_control_flow() -> ControlFlow<i64> { | ----------------------------------------------------- this function returns a `ControlFlow` diff --git a/tests/ui/try-trait/try-operator-custom.rs b/tests/ui/try-trait/try-operator-custom.rs index 936c0b0689a..ebeb0869f98 100644 --- a/tests/ui/try-trait/try-operator-custom.rs +++ b/tests/ui/try-trait/try-operator-custom.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(control_flow_enum)] #![feature(try_trait_v2)] use std::ops::{ControlFlow, FromResidual, Try}; diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs new file mode 100644 index 00000000000..df589473a84 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs @@ -0,0 +1,18 @@ +#![feature(type_alias_impl_trait)] + +trait Captures<'a> {} +impl<T> Captures<'_> for T {} + +fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> { + //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type + loop {} +} + +pub fn main() { + //~^ ERROR item does not constrain `Opaque::{opaque#0}`, but has it in its signature + type Opaque = impl Sized; + fn define() -> Opaque { + let x: Opaque = dyn_hoops::<()>(); + x + } +} diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr new file mode 100644 index 00000000000..59d9ff86c6e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr @@ -0,0 +1,28 @@ +error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type + --> $DIR/bound-lifetime-through-dyn-trait.rs:6:71 + | +LL | fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> { + | ^^ + | +note: lifetime declared here + --> $DIR/bound-lifetime-through-dyn-trait.rs:6:37 + | +LL | fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> { + | ^^ + +error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature + --> $DIR/bound-lifetime-through-dyn-trait.rs:11:8 + | +LL | pub fn main() { + | ^^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/bound-lifetime-through-dyn-trait.rs:13:19 + | +LL | type Opaque = impl Sized; + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr index b526ab49d8d..ec8a51b0818 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr +++ b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr @@ -1,3 +1,11 @@ +error: `Bar` is forbidden as the type of a const generic parameter + --> $DIR/const_generic_type.rs:8:24 + | +LL | async fn test<const N: crate::Bar>() { + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + error: item does not constrain `Bar::{opaque#0}`, but has it in its signature --> $DIR/const_generic_type.rs:8:10 | @@ -39,13 +47,5 @@ LL | type Bar = impl std::fmt::Display; | = note: `Bar` must be used in combination with a concrete type within the same module -error: `Bar` is forbidden as the type of a const generic parameter - --> $DIR/const_generic_type.rs:8:24 - | -LL | async fn test<const N: crate::Bar>() { - | ^^^^^^^^^^ - | - = note: the only supported types are integers, `bool`, and `char` - error: aborting due to 4 previous errors diff --git a/tests/ui/type-alias-impl-trait/constrain_inputs.stderr b/tests/ui/type-alias-impl-trait/constrain_inputs.stderr index 2468fb7480b..436326e66c3 100644 --- a/tests/ui/type-alias-impl-trait/constrain_inputs.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_inputs.stderr @@ -7,19 +7,6 @@ LL | fn execute(ty: Ty<'_>) -> &str { todo!() } = note: lifetimes appearing in an associated or opaque type are not considered constrained = note: consider introducing a named lifetime parameter -error: item does not constrain `lifetime_params::Ty::{opaque#0}`, but has it in its signature - --> $DIR/constrain_inputs.rs:6:8 - | -LL | fn execute(ty: Ty<'_>) -> &str { todo!() } - | ^^^^^^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature - --> $DIR/constrain_inputs.rs:4:19 - | -LL | type Ty<'a> = impl Sized; - | ^^^^^^^^^^ - error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:10:35 | @@ -38,6 +25,19 @@ LL | type BadTraitRef = dyn Fn(Ty<'_>) -> &str; = note: lifetimes appearing in an associated or opaque type are not considered constrained = note: consider introducing a named lifetime parameter +error: item does not constrain `lifetime_params::Ty::{opaque#0}`, but has it in its signature + --> $DIR/constrain_inputs.rs:6:8 + | +LL | fn execute(ty: Ty<'_>) -> &str { todo!() } + | ^^^^^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/constrain_inputs.rs:4:19 + | +LL | type Ty<'a> = impl Sized; + | ^^^^^^^^^^ + error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:19:31 | diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr index be9b07823ae..88529b370f1 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -1,13 +1,8 @@ error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/generic_underconstrained.rs:9:51 + --> $DIR/generic_underconstrained.rs:9:31 | -LL | fn underconstrain<T>(_: T) -> Underconstrained<T> { - | ___________________________________________________^ -LL | | -LL | | -LL | | unimplemented!() -LL | | } - | |_^ the trait `Trait` is not implemented for `T` +LL | fn underconstrain<T>(_: T) -> Underconstrained<T> { + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained.rs:6:26 @@ -20,10 +15,15 @@ LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> { | +++++++ error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/generic_underconstrained.rs:9:31 + --> $DIR/generic_underconstrained.rs:9:51 | -LL | fn underconstrain<T>(_: T) -> Underconstrained<T> { - | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` +LL | fn underconstrain<T>(_: T) -> Underconstrained<T> { + | ___________________________________________________^ +LL | | +LL | | +LL | | unimplemented!() +LL | | } + | |_^ the trait `Trait` is not implemented for `T` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained.rs:6:26 diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 15d96191ba9..b3b9cbca968 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -1,13 +1,8 @@ error[E0277]: `U` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:8:53 + --> $DIR/generic_underconstrained2.rs:8:33 | -LL | fn underconstrained<U>(_: U) -> Underconstrained<U> { - | _____________________________________________________^ -LL | | -LL | | -LL | | 5u32 -LL | | } - | |_^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained<U>(_: U) -> Underconstrained<U> { + | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained2.rs:5:26 @@ -20,15 +15,10 @@ LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> { | +++++++++++++++++ error[E0277]: `V` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:17:64 + --> $DIR/generic_underconstrained2.rs:17:43 | -LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> { - | ________________________________________________________________^ -LL | | -LL | | -LL | | 5u32 -LL | | } - | |_^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> { + | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` | note: required by a bound on the type alias `Underconstrained2` --> $DIR/generic_underconstrained2.rs:14:27 @@ -41,10 +31,15 @@ LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained | +++++++++++++++++ error[E0277]: `U` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:8:33 + --> $DIR/generic_underconstrained2.rs:8:53 | -LL | fn underconstrained<U>(_: U) -> Underconstrained<U> { - | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained<U>(_: U) -> Underconstrained<U> { + | _____________________________________________________^ +LL | | +LL | | +LL | | 5u32 +LL | | } + | |_^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained2.rs:5:26 @@ -57,10 +52,15 @@ LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> { | +++++++++++++++++ error[E0277]: `V` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:17:43 + --> $DIR/generic_underconstrained2.rs:17:64 | -LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> { - | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> { + | ________________________________________________________________^ +LL | | +LL | | +LL | | 5u32 +LL | | } + | |_^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` | note: required by a bound on the type alias `Underconstrained2` --> $DIR/generic_underconstrained2.rs:14:27 diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr index 22c776e171c..eace96317dc 100644 --- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr +++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr @@ -1,3 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:41:6 + | +LL | impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<DummyT<T>> for Scope<U> { + | ^ unconstrained type parameter + error: item does not constrain `DummyT::{opaque#0}`, but has it in its signature --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:28:8 | @@ -24,12 +30,6 @@ note: this opaque type is in the signature LL | type DummyT<T> = impl F; | ^^^^^^ -error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:41:6 - | -LL | impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<DummyT<T>> for Scope<U> { - | ^ unconstrained type parameter - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0207`. 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 f1361b47c56..5ac09e20b02 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -1,14 +1,25 @@ -error[E0391]: cycle detected when computing type of `Bar::{opaque#0}` - --> $DIR/in-where-clause.rs:5:12 +error[E0283]: type annotations needed: cannot satisfy `Bar: Send` + --> $DIR/in-where-clause.rs:12:9 | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ +LL | [0; 1 + 2] + | ^^^^^ | -note: ...which requires computing type of opaque `Bar::{opaque#0}`... + = note: cannot satisfy `Bar: Send` +note: required by a bound in `foo` + --> $DIR/in-where-clause.rs:10: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 | LL | type Bar = impl Sized; | ^^^^^^^^^^ + | note: ...which requires type-checking `foo`... --> $DIR/in-where-clause.rs:8:1 | @@ -17,30 +28,15 @@ LL | | where LL | | Bar: Send, | |______________^ = note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(<Bar as core::marker::Send>, polarity:Positive), bound_vars: [] }]`... - = note: ...which again requires computing type of `Bar::{opaque#0}`, completing the cycle -note: cycle used when checking that `Bar::{opaque#0}` is well-formed +note: ...which requires computing type of `Bar::{opaque#0}`... --> $DIR/in-where-clause.rs:5:12 | LL | type Bar = impl Sized; | ^^^^^^^^^^ + = note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle + = 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[E0283]: type annotations needed: cannot satisfy `Bar: Send` - --> $DIR/in-where-clause.rs:12:9 - | -LL | [0; 1 + 2] - | ^^^^^ - | - = note: cannot satisfy `Bar: Send` -note: required by a bound in `foo` - --> $DIR/in-where-clause.rs:10:10 - | -LL | fn foo() -> Bar - | --- required by a bound in this function -LL | where -LL | Bar: Send, - | ^^^^ required by this bound in `foo` - error: aborting due to 2 previous errors Some errors have detailed explanations: E0283, E0391. diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs index 2adfad4fc5b..2383008d042 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs @@ -1,15 +1,14 @@ #![feature(type_alias_impl_trait)] #![allow(dead_code)] -type Bug<T, U> = impl Fn(T) -> U + Copy; //~ ERROR cycle detected +type Bug<T, U> = impl Fn(T) -> U + Copy; const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; -//~^ ERROR: non-defining opaque type use -//~| ERROR: item does not constrain -//~| ERROR: item does not constrain +//~^ ERROR cycle detected +//~| ERROR: non-defining opaque type use fn make_bug<T, U: From<T>>() -> Bug<T, U> { - |x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied + |x| x.into() } fn main() { diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr index 121f765e667..ac580866704 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -10,75 +10,33 @@ note: for this opaque type LL | type Bug<T, U> = impl Fn(T) -> U + Copy; | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0391]: cycle detected when computing type of `Bug::{opaque#0}` - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug<T, U> = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires computing type of opaque `Bug::{opaque#0}`... - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug<T, U> = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `CONST_BUG`... +error[E0391]: cycle detected when type-checking `CONST_BUG` --> $DIR/issue-53092-2.rs:6:1 | LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | = note: ...which requires computing layout of `Bug<u8, ()>`... = note: ...which requires normalizing `Bug<u8, ()>`... - = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle -note: cycle used when checking that `Bug::{opaque#0}` is well-formed +note: ...which requires computing type of `Bug::{opaque#0}`... --> $DIR/issue-53092-2.rs:4:18 | LL | type Bug<T, U> = impl Fn(T) -> U + Copy; | ^^^^^^^^^^^^^^^^^^^^^^ - = 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: item does not constrain `Bug::{opaque#0}`, but has it in its signature - --> $DIR/issue-53092-2.rs:6:7 - | -LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature +note: ...which requires computing type of opaque `Bug::{opaque#0}`... --> $DIR/issue-53092-2.rs:4:18 | LL | type Bug<T, U> = impl Fn(T) -> U + Copy; | ^^^^^^^^^^^^^^^^^^^^^^ - -error: item does not constrain `Bug::{opaque#0}`, but has it in its signature - --> $DIR/issue-53092-2.rs:6:61 + = note: ...which again requires type-checking `CONST_BUG`, completing the cycle +note: cycle used when checking that `CONST_BUG` is well-formed + --> $DIR/issue-53092-2.rs:6:1 | LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug<T, U> = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `U: From<T>` is not satisfied - --> $DIR/issue-53092-2.rs:12:5 - | -LL | |x| x.into() - | ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U` - | -note: required by a bound in `make_bug` - --> $DIR/issue-53092-2.rs:11:19 - | -LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> { - | ^^^^^^^ required by this bound in `make_bug` -help: consider restricting type parameter `U` - | -LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy; - | +++++++++++++++++++++++ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 5 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0391, E0792. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0391, E0792. +For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr index 2b064dcfc31..ec7b9e0e12b 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr @@ -1,3 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait<Bar, _>` + --> $DIR/issue-84660-unsoundness.rs:29:1 + | +LL | impl<In, Out> Trait<Bar, In> for Out { + | ------------------------------------ first implementation here +... +LL | impl<In, Out> Trait<(), In> for Out { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + error: item does not constrain `Bar::{opaque#0}`, but has it in its signature --> $DIR/issue-84660-unsoundness.rs:22:8 | @@ -11,15 +20,6 @@ note: this opaque type is in the signature LL | type Bar = impl Foo; | ^^^^^^^^ -error[E0119]: conflicting implementations of trait `Trait<Bar, _>` - --> $DIR/issue-84660-unsoundness.rs:29:1 - | -LL | impl<In, Out> Trait<Bar, In> for Out { - | ------------------------------------ first implementation here -... -LL | impl<In, Out> Trait<(), In> for Out { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr index 5a728a00138..e33102f687c 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr @@ -1,3 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait<Bar, _>` + --> $DIR/issue-84660-unsoundness.rs:29:1 + | +LL | impl<In, Out> Trait<Bar, In> for Out { + | ------------------------------------ first implementation here +... +LL | impl<In, Out> Trait<(), In> for Out { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + error[E0284]: type annotations needed: cannot satisfy `Bar == _` --> $DIR/issue-84660-unsoundness.rs:22:37 | @@ -9,15 +18,6 @@ LL | | unreachable!(); LL | | } | |_____^ cannot satisfy `Bar == _` -error[E0119]: conflicting implementations of trait `Trait<Bar, _>` - --> $DIR/issue-84660-unsoundness.rs:29:1 - | -LL | impl<In, Out> Trait<Bar, In> for Out { - | ------------------------------------ first implementation here -... -LL | impl<In, Out> Trait<(), In> for Out { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation - error: aborting due to 2 previous errors Some errors have detailed explanations: E0119, E0284. diff --git a/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr index d0fe920b35f..aa0c1076117 100644 --- a/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr +++ b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr @@ -1,11 +1,3 @@ -error: unconstrained opaque type - --> $DIR/nested-in-anon-const.rs:13:33 - | -LL | type B<Z> = impl Sized; - | ^^^^^^^^^^ - | - = note: `B` must be used in combination with a concrete type within the same item - error[E0308]: mismatched types --> $DIR/nested-in-anon-const.rs:12:17 | @@ -15,6 +7,14 @@ LL | | LL | | }, | |_________________^ expected `usize`, found `()` +error: unconstrained opaque type + --> $DIR/nested-in-anon-const.rs:13:33 + | +LL | type B<Z> = impl Sized; + | ^^^^^^^^^^ + | + = note: `B` must be used in combination with a concrete type within the same item + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs new file mode 100644 index 00000000000..dda42580e0f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs @@ -0,0 +1,13 @@ +#![allow(incomplete_features)] +#![feature(non_lifetime_binders)] + +trait Trait<T: ?Sized> {} + +fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> { + //~^ ERROR associated type `Assoc` not found for `Trait` + //~| ERROR associated type `Assoc` not found for `Trait` + //~| the trait bound `{integer}: Trait<()>` is not satisfied + 16 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr new file mode 100644 index 00000000000..fa3306ff11f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr @@ -0,0 +1,30 @@ +error[E0220]: associated type `Assoc` not found for `Trait` + --> $DIR/non-lifetime-binder-in-constraint.rs:6:39 + | +LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> { + | ^^^^^ associated type `Assoc` not found + +error[E0220]: associated type `Assoc` not found for `Trait` + --> $DIR/non-lifetime-binder-in-constraint.rs:6:39 + | +LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> { + | ^^^^^ associated type `Assoc` not found + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `{integer}: Trait<()>` is not satisfied + --> $DIR/non-lifetime-binder-in-constraint.rs:6:17 + | +LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<()>` is not implemented for `{integer}` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-lifetime-binder-in-constraint.rs:4:1 + | +LL | trait Trait<T: ?Sized> {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0277. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs new file mode 100644 index 00000000000..23951c34270 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs @@ -0,0 +1,10 @@ +#![allow(incomplete_features)] +#![feature(non_lifetime_binders)] + +trait Trait<T> {} + +fn f() -> impl for<T> Trait<impl Trait<T>> {} +//~^ ERROR nested `impl Trait` is not allowed +//~| ERROR the trait bound `(): Trait<impl Trait<T>>` is not satisfied + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr new file mode 100644 index 00000000000..5859d952b75 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr @@ -0,0 +1,25 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/non-lifetime-binder.rs:6:29 + | +LL | fn f() -> impl for<T> Trait<impl Trait<T>> {} + | ------------------^^^^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0277]: the trait bound `(): Trait<impl Trait<T>>` is not satisfied + --> $DIR/non-lifetime-binder.rs:6:11 + | +LL | fn f() -> impl for<T> Trait<impl Trait<T>> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<impl Trait<T>>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-lifetime-binder.rs:4:1 + | +LL | trait Trait<T> {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0666. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr index aedb78bf5e7..99646aa4d1b 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr @@ -11,18 +11,6 @@ LL | Ty: Id<Assoc = Ty>, | ^^^^^^^^^^^^^^ required by this bound error[E0275]: overflow evaluating the requirement `Ty: Id` - --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:19 - | -LL | fn define() -> Ty {} - | ^^ - | -note: required by a bound on the type alias `Ty` - --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9 - | -LL | Ty: Id<Assoc = Ty>, - | ^^^^^^^^^^^^^^ required by this bound - -error[E0275]: overflow evaluating the requirement `Ty: Id` --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:16 | LL | fn define() -> Ty {} @@ -34,6 +22,6 @@ note: required by a bound on the type alias `Ty` LL | Ty: Id<Assoc = Ty>, | ^^^^^^^^^^^^^^ required by this bound -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs index 29a21a1f45f..437a1aed403 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.rs +++ b/tests/ui/typeck/typeck_type_placeholder_item.rs @@ -160,7 +160,7 @@ impl BadTrait<_> for BadStruct<_> {} //~^ ERROR the placeholder `_` is not allowed within types on item signatures for implementations fn impl_trait() -> impl BadTrait<_> { -//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions unimplemented!() } @@ -180,7 +180,7 @@ struct Struct; trait Trait<T> {} impl Trait<usize> for Struct {} type Y = impl Trait<_>; -//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for type aliases fn foo() -> Y { Struct } diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 2c064fbb19f..8a765c21624 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -484,11 +484,16 @@ help: use type parameters instead LL | impl<T> BadTrait<T> for BadStruct<T> {} | +++ ~ ~ -error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:162:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn impl_trait<T>() -> impl BadTrait<T> { + | +++ ~ error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/typeck_type_placeholder_item.rs:167:25 @@ -518,33 +523,17 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures LL | type X = Box<_>; | ^ not allowed in type signatures -error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases --> $DIR/typeck_type_placeholder_item.rs:182:21 | LL | type Y = impl Trait<_>; | ^ not allowed in type signatures -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/typeck_type_placeholder_item.rs:44:27 - | -LL | fn test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn test10<T>(&self, _x : T) { } - | +++ ~ - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/typeck_type_placeholder_item.rs:110:34 - | -LL | fn fn_test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants + --> $DIR/typeck_type_placeholder_item.rs:206:14 | -LL | fn fn_test10<T>(&self, _x : T) { } - | +++ ~ +LL | const C: _; + | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants --> $DIR/typeck_type_placeholder_item.rs:194:14 @@ -555,6 +544,21 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants + --> $DIR/typeck_type_placeholder_item.rs:209:14 + | +LL | const D: _ = 42; + | ^ not allowed in type signatures + +error[E0046]: not all trait items implemented, missing: `F` + --> $DIR/typeck_type_placeholder_item.rs:200:1 + | +LL | type F: std::ops::Fn(_); + | ----------------------- `F` from trait +... +LL | impl Qux for Struct { + | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation + error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:217:31 | @@ -573,27 +577,6 @@ LL | const _: Option<_> = map(value); | not allowed in type signatures | help: replace with the correct type: `Option<u8>` -error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:206:14 - | -LL | const C: _; - | ^ not allowed in type signatures - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:209:14 - | -LL | const D: _ = 42; - | ^ not allowed in type signatures - -error[E0046]: not all trait items implemented, missing: `F` - --> $DIR/typeck_type_placeholder_item.rs:200:1 - | -LL | type F: std::ops::Fn(_); - | ----------------------- `F` from trait -... -LL | impl Qux for Struct { - | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation - error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:225:31 | @@ -624,6 +607,17 @@ LL | fn test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/typeck_type_placeholder_item.rs:44:27 + | +LL | fn test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn test10<T>(&self, _x : T) { } + | +++ ~ + error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:107:31 | @@ -633,6 +627,17 @@ LL | fn fn_test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/typeck_type_placeholder_item.rs:110:34 + | +LL | fn fn_test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn fn_test10<T>(&self, _x : T) { } + | +++ ~ + error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types --> $DIR/typeck_type_placeholder_item.rs:202:14 | diff --git a/tests/ui/union/unnamed-fields/anon-struct-in-enum-issue-121446.rs b/tests/ui/union/unnamed-fields/anon-struct-in-enum-issue-121446.rs deleted file mode 100644 index 00f9bfd5cdf..00000000000 --- a/tests/ui/union/unnamed-fields/anon-struct-in-enum-issue-121446.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![crate_type = "lib"] -#![feature(unnamed_fields)] -#![allow(unused, incomplete_features)] - -enum K { - M { - _ : struct { field: u8 }, - //~^ error: unnamed fields are not allowed outside of structs or unions - //~| error: anonymous structs are not allowed outside of unnamed struct or union fields - } -} diff --git a/tests/ui/union/unnamed-fields/anon-struct-in-enum-issue-121446.stderr b/tests/ui/union/unnamed-fields/anon-struct-in-enum-issue-121446.stderr deleted file mode 100644 index 43843141e2e..00000000000 --- a/tests/ui/union/unnamed-fields/anon-struct-in-enum-issue-121446.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: unnamed fields are not allowed outside of structs or unions - --> $DIR/anon-struct-in-enum-issue-121446.rs:7:9 - | -LL | _ : struct { field: u8 }, - | -^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unnamed field declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/anon-struct-in-enum-issue-121446.rs:7:13 - | -LL | _ : struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: aborting due to 2 previous errors - diff --git a/tests/ui/union/unnamed-fields/auxiliary/dep.rs b/tests/ui/union/unnamed-fields/auxiliary/dep.rs deleted file mode 100644 index a11f3e18f52..00000000000 --- a/tests/ui/union/unnamed-fields/auxiliary/dep.rs +++ /dev/null @@ -1,18 +0,0 @@ -#[repr(C)] -pub struct GoodStruct(()); - -pub struct BadStruct(()); - -pub enum BadEnum { - A, - B, -} - -#[repr(C)] -pub enum BadEnum2 { - A, - B, -} - -pub type GoodAlias = GoodStruct; -pub type BadAlias = i32; diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.rs b/tests/ui/union/unnamed-fields/field_uniqueness_check.rs deleted file mode 100644 index ddb951aa06c..00000000000 --- a/tests/ui/union/unnamed-fields/field_uniqueness_check.rs +++ /dev/null @@ -1,337 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -#[derive(Clone, Copy)] -#[repr(C)] -struct Foo { - a: u8, -} - -#[derive(Clone, Copy)] -#[repr(C)] -struct Bar { - _: union { - a: u8, - }, -} - - -// duplicated with a normal field -#[derive(Clone, Copy)] -#[repr(C)] -union A { - // referent field - a: u8, - - // normal field - a: u8, //~ ERROR field `a` is already declared [E0124] - // nested field - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - // more nested field - _: union { - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - }, - // nested field in a named adt - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt - _: struct { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, -} - -// duplicated with a nested field -#[derive(Clone, Copy)] -#[repr(C)] -struct B { - _: union { - // referent field - a: u8, - - // normal field (within the same anonymous adt) - a: u8, //~ ERROR field `a` is already declared [E0124] - // nested field (within the same anonymous adt) - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - // more nested field (within the same anonymous adt) - _: union { - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - }, - // nested field in a named adt (within the same anonymous adt) - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt (within the same anonymous adt) - _: struct { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, - }, - - // normal field - a: u8, //~ ERROR field `a` is already declared [E0124] - // nested field - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - // more nested field - _: union { - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - }, - // nested field in a named adt - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt - _: struct { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, -} - -// duplicated with a more nested field -#[derive(Clone, Copy)] -#[repr(C)] -union C { - _: struct { - _: union { - // referent field - a: u8, - - // normal field (within the same anonymous adt) - a: u8, //~ ERROR field `a` is already declared [E0124] - // nested field (within the same anonymous adt) - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - // more nested field (within the same anonymous adt) - _: union { - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - }, - // nested field in a named adt (within the same anonymous adt) - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt (within the same anonymous adt) - _: struct { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, - }, - - // normal field (within the direct outer anonymous adt) - a: u8, //~ ERROR field `a` is already declared [E0124] - // nested field (within the direct outer anonymous adt) - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - // more nested field (within the direct outer anonymous adt) - _: union { - _: struct { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - }, - // nested field in a named adt (within the direct outer anonymous adt) - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt (within the direct outer anonymous adt) - _: struct { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, - }, - // normal field - a: u8, //~ ERROR field `a` is already declared [E0124] - // nested field - _: union { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - // more nested field - _: struct { - _: union { - a: u8, //~ ERROR field `a` is already declared [E0124] - }, - }, - // nested field in a named adt - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt - _: union { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, -} - -// duplicated with a nested field in a named adt -#[derive(Clone, Copy)] -#[repr(C)] -struct D { - // referent field `a` - _: Foo, - - // normal field - a: u8, //~ ERROR field `a` is already declared - // nested field - _: union { - a: u8, //~ ERROR field `a` is already declared - }, - // more nested field - _: struct { - _: union { - a: u8, //~ ERROR field `a` is already declared - }, - }, - // nested field in another named adt - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt - _: union { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, -} - -// duplicated with a nested field in a nested field of a named adt -#[derive(Clone, Copy)] -#[repr(C)] -union D2 { - // referent field `a` - _: Bar, - - // normal field - a: u8, //~ ERROR field `a` is already declared - // nested field - _: union { - a: u8, //~ ERROR field `a` is already declared - }, - // more nested field - _: struct { - _: union { - a: u8, //~ ERROR field `a` is already declared - }, - }, - // nested field in another named adt - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt - _: union { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, -} - -// duplicated with a nested field in a named adt in an anonymous adt -#[derive(Clone, Copy)] -#[repr(C)] -struct E { - _: struct { - // referent field `a` - _: Foo, - - // normal field (within the same anonymous adt) - a: u8, //~ ERROR field `a` is already declared - // nested field (within the same anonymous adt) - _: struct { - a: u8, //~ ERROR field `a` is already declared - }, - // more nested field (within the same anonymous adt) - _: union { - _: struct { - a: u8, //~ ERROR field `a` is already declared - }, - }, - // nested field in a named adt (within the same anonymous adt) - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt (within the same anonymous adt) - _: struct { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, - }, - - // normal field - a: u8, //~ ERROR field `a` is already declared - // nested field - _: union { - a: u8, //~ ERROR field `a` is already declared - }, - // more nested field - _: struct { - _: union { - a: u8, //~ ERROR field `a` is already declared - }, - }, - // nested field in another named adt - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt - _: union { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, -} - -// duplicated with a nested field in a named adt in an anonymous adt -#[repr(C)] -#[derive(Clone, Copy)] -union E2 { - _: struct { - // referent field `a` - _: Bar, - - // normal field (within the same anonymous adt) - a: u8, //~ ERROR field `a` is already declared - // nested field (within the same anonymous adt) - _: struct { - a: u8, //~ ERROR field `a` is already declared - }, - // more nested field (within the same anonymous adt) - _: union { - _: struct { - a: u8, //~ ERROR field `a` is already declared - }, - }, - // nested field in a named adt (within the same anonymous adt) - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt (within the same anonymous adt) - _: struct { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, - }, - - // normal field - a: u8, //~ ERROR field `a` is already declared - // nested field - _: union { - a: u8, //~ ERROR field `a` is already declared - }, - // more nested field - _: struct { - _: union { - a: u8, //~ ERROR field `a` is already declared - }, - }, - // nested field in another named adt - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - // nested field in a named adt in an anoymous adt - _: union { - _: Foo, //~ ERROR field `a` is already declared - _: Bar, //~ ERROR field `a` is already declared - }, -} - -fn main() {} diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr deleted file mode 100644 index 11978386843..00000000000 --- a/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr +++ /dev/null @@ -1,1734 +0,0 @@ -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:27:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:30:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:31:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:36:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:40:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:40:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:41:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:41:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:44:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:44:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:45:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:45:9 - | -LL | _: Bar, - | ^^^^^^ - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:58:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:61:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:66:17 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:70:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:70:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:71:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:71:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:74:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:74:13 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:75:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:75:13 - | -LL | _: Bar, - | ^^^^^^ - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:80:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:83:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:88:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:92:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:92:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:93:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:93:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:96:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:96:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:97:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:97:9 - | -LL | _: Bar, - | ^^^^^^ - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:111:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:114:17 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:119:21 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:123:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:123:13 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:124:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:124:13 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:127:17 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:127:17 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:128:17 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:128:17 - | -LL | _: Bar, - | ^^^^^^ - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:133:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:136:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:141:17 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:145:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:145:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:146:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:146:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:149:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:149:13 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:150:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:150:13 - | -LL | _: Bar, - | ^^^^^^ - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:154:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:157:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:162:13 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | a: u8, - | ^^^^^ field already declared - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:166:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:166:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:167:5 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:167:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:170:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:170:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:171:9 - | -LL | a: u8, - | ----- `a` first declared here -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:171:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:183:5 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:180:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:186:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:180:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:191:13 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:180:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:195:5 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:195:5 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:180:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:196:5 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:196:5 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:180:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:199:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:199:9 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:180:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:200:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:200:9 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:180:5 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:212:5 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:209:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:215:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:209:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:220:13 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:209:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:224:5 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:224:5 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:209:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:225:5 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:225:5 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:209:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:228:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:228:9 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:209:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:229:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:229:9 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:209:5 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:242:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:245:13 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:250:17 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:254:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:254:9 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:255:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:255:9 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:258:13 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:258:13 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:259:13 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:259:13 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:264:5 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:267:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:272:13 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:276:5 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:276:5 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:277:5 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:277:5 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:280:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:280:9 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:281:9 - | -LL | _: Foo, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:281:9 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:239:9 - | -LL | _: Foo, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:294:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:297:13 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:302:17 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:306:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:306:9 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:307:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:307:9 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:310:13 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:310:13 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:311:13 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:311:13 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:316:5 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:319:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:324:13 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | a: u8, - | ^^^^^ field already declared - | -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:328:5 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:328:5 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:329:5 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:329:5 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:332:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Foo, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:7:5 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:332:9 - | -LL | _: Foo, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:333:9 - | -LL | _: Bar, - | ------ `a` first declared here in this unnamed field -... -LL | _: Bar, - | ^^^^^^ field `a` declared in this unnamed field - | -note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:333:9 - | -LL | _: Bar, - | ^^^^^^ -note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:14:9 - | -LL | a: u8, - | ^^^^^ -help: fields from the type of this unnamed field are considered fields of the outer type - --> $DIR/field_uniqueness_check.rs:291:9 - | -LL | _: Bar, - | ^^^^^^ - -error: aborting due to 85 previous errors - -For more information about this error, try `rustc --explain E0124`. diff --git a/tests/ui/union/unnamed-fields/repr_check.rs b/tests/ui/union/unnamed-fields/repr_check.rs deleted file mode 100644 index b50b54b20af..00000000000 --- a/tests/ui/union/unnamed-fields/repr_check.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -struct A { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation - //~^ NOTE struct `A` defined here - _: struct { //~ NOTE unnamed field defined here - a: i32, - }, - _: struct { //~ NOTE unnamed field defined here - _: struct { - b: i32, - }, - }, -} - -union B { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation - //~^ NOTE union `B` defined here - _: union { //~ NOTE unnamed field defined here - a: i32, - }, - _: union { //~ NOTE unnamed field defined here - _: union { - b: i32, - }, - }, -} - -#[derive(Clone, Copy)] -#[repr(C)] -struct Foo {} - -#[derive(Clone, Copy)] -struct Bar {} -//~^ `Bar` defined here -//~| `Bar` defined here -//~| `Bar` defined here -//~| `Bar` defined here - -struct C { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation - //~^ NOTE struct `C` defined here - _: Foo, //~ NOTE unnamed field defined here -} - -union D { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation - //~^ NOTE union `D` defined here - _: Foo, //~ NOTE unnamed field defined here -} - -#[repr(C)] -struct E { - _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation - //~^ NOTE unnamed field defined here - _: struct { - _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation - //~^ NOTE unnamed field defined here - }, -} - -#[repr(C)] -union F { - _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation - //~^ NOTE unnamed field defined here - _: union { - _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation - //~^ NOTE unnamed field defined here - }, -} - -fn main() {} diff --git a/tests/ui/union/unnamed-fields/repr_check.stderr b/tests/ui/union/unnamed-fields/repr_check.stderr deleted file mode 100644 index 324968b1264..00000000000 --- a/tests/ui/union/unnamed-fields/repr_check.stderr +++ /dev/null @@ -1,152 +0,0 @@ -error: struct with unnamed fields must have `#[repr(C)]` representation - --> $DIR/repr_check.rs:4:1 - | -LL | struct A { - | ^^^^^^^^ struct `A` defined here - | -note: unnamed field defined here - --> $DIR/repr_check.rs:6:5 - | -LL | / _: struct { -LL | | a: i32, -LL | | }, - | |_____^ -note: unnamed field defined here - --> $DIR/repr_check.rs:9:5 - | -LL | / _: struct { -LL | | _: struct { -LL | | b: i32, -LL | | }, -LL | | }, - | |_____^ -help: add `#[repr(C)]` to this struct - | -LL + #[repr(C)] -LL | struct A { - | - -error: union with unnamed fields must have `#[repr(C)]` representation - --> $DIR/repr_check.rs:16:1 - | -LL | union B { - | ^^^^^^^ union `B` defined here - | -note: unnamed field defined here - --> $DIR/repr_check.rs:18:5 - | -LL | / _: union { -LL | | a: i32, -LL | | }, - | |_____^ -note: unnamed field defined here - --> $DIR/repr_check.rs:21:5 - | -LL | / _: union { -LL | | _: union { -LL | | b: i32, -LL | | }, -LL | | }, - | |_____^ -help: add `#[repr(C)]` to this union - | -LL + #[repr(C)] -LL | union B { - | - -error: struct with unnamed fields must have `#[repr(C)]` representation - --> $DIR/repr_check.rs:39:1 - | -LL | struct C { - | ^^^^^^^^ struct `C` defined here - | -note: unnamed field defined here - --> $DIR/repr_check.rs:41:5 - | -LL | _: Foo, - | ^^^^^^ -help: add `#[repr(C)]` to this struct - | -LL + #[repr(C)] -LL | struct C { - | - -error: union with unnamed fields must have `#[repr(C)]` representation - --> $DIR/repr_check.rs:44:1 - | -LL | union D { - | ^^^^^^^ union `D` defined here - | -note: unnamed field defined here - --> $DIR/repr_check.rs:46:5 - | -LL | _: Foo, - | ^^^^^^ -help: add `#[repr(C)]` to this union - | -LL + #[repr(C)] -LL | union D { - | - -error: named type of unnamed field must have `#[repr(C)]` representation - --> $DIR/repr_check.rs:51:5 - | -LL | struct Bar {} - | ---------- `Bar` defined here -... -LL | _: Bar, - | ^^^^^^ unnamed field defined here - | -help: add `#[repr(C)]` to this struct - | -LL + #[repr(C)] -LL | struct Bar {} - | - -error: named type of unnamed field must have `#[repr(C)]` representation - --> $DIR/repr_check.rs:54:9 - | -LL | struct Bar {} - | ---------- `Bar` defined here -... -LL | _: Bar, - | ^^^^^^ unnamed field defined here - | -help: add `#[repr(C)]` to this struct - | -LL + #[repr(C)] -LL | struct Bar {} - | - -error: named type of unnamed field must have `#[repr(C)]` representation - --> $DIR/repr_check.rs:61:5 - | -LL | struct Bar {} - | ---------- `Bar` defined here -... -LL | _: Bar, - | ^^^^^^ unnamed field defined here - | -help: add `#[repr(C)]` to this struct - | -LL + #[repr(C)] -LL | struct Bar {} - | - -error: named type of unnamed field must have `#[repr(C)]` representation - --> $DIR/repr_check.rs:64:9 - | -LL | struct Bar {} - | ---------- `Bar` defined here -... -LL | _: Bar, - | ^^^^^^ unnamed field defined here - | -help: add `#[repr(C)]` to this struct - | -LL + #[repr(C)] -LL | struct Bar {} - | - -error: aborting due to 8 previous errors - diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs deleted file mode 100644 index 03545ed7b18..00000000000 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -struct F { - field1: struct { field2: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - _: struct { field3: u8 }, -} - -struct G { - _: (u8, u8), //~ ERROR unnamed fields can only have struct or union types -} - -union H { - field1: struct { field2: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - _: struct { field3: u8 }, -} - -union I { - _: (u8, u8), //~ ERROR unnamed fields can only have struct or union types -} - -enum K { - M { - _ : struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR unnamed fields are not allowed outside of structs or unions - }, - N { - _ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions - } -} - -fn main() {} diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr deleted file mode 100644 index 3b3890af771..00000000000 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_structs.rs:5:13 - | -LL | field1: struct { field2: u8 }, - | ^^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_anonymous_structs.rs:10:5 - | -LL | _: (u8, u8), - | ^ -------- not a struct or union - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_structs.rs:14:13 - | -LL | field1: struct { field2: u8 }, - | ^^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_anonymous_structs.rs:19:5 - | -LL | _: (u8, u8), - | ^ -------- not a struct or union - -error: unnamed fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous_structs.rs:24:9 - | -LL | _ : struct { field: u8 }, - | -^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unnamed field declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_structs.rs:24:13 - | -LL | _ : struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: unnamed fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous_structs.rs:28:9 - | -LL | _ : u8, - | -^^^^^ - | | - | unnamed field declared here - -error: aborting due to 7 previous errors - diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs deleted file mode 100644 index 9ffe71b28c2..00000000000 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -struct F { - field1: union { field2: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields - _: union { field3: u8 }, -} - -struct G { - _: (u8, u8), //~ ERROR unnamed fields can only have struct or union types -} - -union H { - field1: union { field2: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields - _: union { field3: u8 }, -} - -union I { - _: (u8, u8), //~ ERROR unnamed fields can only have struct or union types -} - -enum K { - M { - _ : union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields - //~^ ERROR unnamed fields are not allowed outside of structs or unions - }, - N { - _ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions - } -} - -fn main() {} diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr deleted file mode 100644 index f8679aad2d7..00000000000 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_unions.rs:5:13 - | -LL | field1: union { field2: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ anonymous union declared here - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_anonymous_unions.rs:10:5 - | -LL | _: (u8, u8), - | ^ -------- not a struct or union - -error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_unions.rs:14:13 - | -LL | field1: union { field2: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ anonymous union declared here - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_anonymous_unions.rs:19:5 - | -LL | _: (u8, u8), - | ^ -------- not a struct or union - -error: unnamed fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous_unions.rs:24:9 - | -LL | _ : union { field: u8 }, - | -^^^^^^^^^^^^^^^^^^^^^^ - | | - | unnamed field declared here - -error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_unions.rs:24:13 - | -LL | _ : union { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^ anonymous union declared here - -error: unnamed fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous_unions.rs:28:9 - | -LL | _ : u8, - | -^^^^^ - | | - | unnamed field declared here - -error: aborting due to 7 previous errors - diff --git a/tests/ui/union/unnamed-fields/restrict_type_hir.rs b/tests/ui/union/unnamed-fields/restrict_type_hir.rs deleted file mode 100644 index 80e4608be82..00000000000 --- a/tests/ui/union/unnamed-fields/restrict_type_hir.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@ aux-build:dep.rs - -// test for #121151 - -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -extern crate dep; - -#[repr(C)] -struct A { - a: u8, -} - -enum BadEnum { - A, - B, -} - -#[repr(C)] -enum BadEnum2 { - A, - B, -} - -type MyStruct = A; -type MyI32 = i32; - -#[repr(C)] -struct L { - _: i32, //~ ERROR unnamed fields can only have struct or union types - _: MyI32, //~ ERROR unnamed fields can only have struct or union types - _: BadEnum, //~ ERROR unnamed fields can only have struct or union types - _: BadEnum2, //~ ERROR unnamed fields can only have struct or union types - _: MyStruct, - _: dep::BadStruct, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation - _: dep::BadEnum, //~ ERROR unnamed fields can only have struct or union types - _: dep::BadEnum2, //~ ERROR unnamed fields can only have struct or union types - _: dep::BadAlias, //~ ERROR unnamed fields can only have struct or union types - _: dep::GoodAlias, - _: dep::GoodStruct, -} - -fn main() {} diff --git a/tests/ui/union/unnamed-fields/restrict_type_hir.stderr b/tests/ui/union/unnamed-fields/restrict_type_hir.stderr deleted file mode 100644 index 3e80d7fbf5c..00000000000 --- a/tests/ui/union/unnamed-fields/restrict_type_hir.stderr +++ /dev/null @@ -1,62 +0,0 @@ -error: unnamed fields can only have struct or union types - --> $DIR/restrict_type_hir.rs:31:5 - | -LL | _: i32, - | ^^^^^^ - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_type_hir.rs:32:5 - | -LL | _: MyI32, - | ^^^^^^^^ - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_type_hir.rs:33:5 - | -LL | _: BadEnum, - | ^^^^^^^^^^ - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_type_hir.rs:34:5 - | -LL | _: BadEnum2, - | ^^^^^^^^^^^ - -error: named type of unnamed field must have `#[repr(C)]` representation - --> $DIR/restrict_type_hir.rs:36:5 - | -LL | _: dep::BadStruct, - | ^^^^^^^^^^^^^^^^^ unnamed field defined here - | - ::: $DIR/auxiliary/dep.rs:4:1 - | -LL | pub struct BadStruct(()); - | -------------------- `BadStruct` defined here - | -help: add `#[repr(C)]` to this struct - --> $DIR/auxiliary/dep.rs:4:1 - | -LL + #[repr(C)] -LL | pub struct BadStruct(()); - | - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_type_hir.rs:37:5 - | -LL | _: dep::BadEnum, - | ^^^^^^^^^^^^^^^ - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_type_hir.rs:38:5 - | -LL | _: dep::BadEnum2, - | ^^^^^^^^^^^^^^^^ - -error: unnamed fields can only have struct or union types - --> $DIR/restrict_type_hir.rs:39:5 - | -LL | _: dep::BadAlias, - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 8 previous errors - diff --git a/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.rs b/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.rs deleted file mode 100644 index 5d15ec4cffd..00000000000 --- a/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.rs +++ /dev/null @@ -1,25 +0,0 @@ -type NodeId = u32; -struct Type<'a>(std::marker::PhantomData::<&'a ()>); - -type Ast<'ast> = &'ast AstStructure<'ast>; - -struct AstStructure<'ast> { -//~^ ERROR struct with unnamed fields must have `#[repr(C)]` representation - id: NodeId, - _: AstKind<'ast> -//~^ ERROR unnamed fields are not yet fully implemented [E0658] -//~^^ ERROR unnamed fields can only have struct or union types -} - -enum AstKind<'ast> { - ExprInt, - ExprLambda(Ast<'ast>), -} - -fn compute_types<'tcx,'ast>(ast: Ast<'ast>) -> Type<'tcx> -{ - match ast.kind {} -//~^ ERROR no field `kind` on type `&'ast AstStructure<'ast>` [E0609] -} - -fn main() {} diff --git a/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.stderr b/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.stderr deleted file mode 100644 index 4ea910202de..00000000000 --- a/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/unnamed-enum-field-issue-121757.rs:9:5 - | -LL | _: AstKind<'ast> - | ^ - | - = note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information - = help: add `#![feature(unnamed_fields)]` 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: struct with unnamed fields must have `#[repr(C)]` representation - --> $DIR/unnamed-enum-field-issue-121757.rs:6:1 - | -LL | struct AstStructure<'ast> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ struct `AstStructure` defined here - | -note: unnamed field defined here - --> $DIR/unnamed-enum-field-issue-121757.rs:9:5 - | -LL | _: AstKind<'ast> - | ^^^^^^^^^^^^^^^^ -help: add `#[repr(C)]` to this struct - | -LL + #[repr(C)] -LL | struct AstStructure<'ast> { - | - -error: unnamed fields can only have struct or union types - --> $DIR/unnamed-enum-field-issue-121757.rs:9:5 - | -LL | _: AstKind<'ast> - | ^^^^^^^^^^^^^^^^ - -error[E0609]: no field `kind` on type `&'ast AstStructure<'ast>` - --> $DIR/unnamed-enum-field-issue-121757.rs:21:15 - | -LL | match ast.kind {} - | ^^^^ unknown field - | - = note: available fields are: `id`, `_` - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0609, E0658. -For more information about an error, try `rustc --explain E0609`. diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index 279d723a26c..799e8071d02 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -23,7 +23,6 @@ #![feature(trace_macros)] #![feature(trait_alias)] #![feature(try_blocks)] -#![feature(unnamed_fields)] #![feature(yeet_expr)] #![allow(incomplete_features)] @@ -786,20 +785,6 @@ mod types { let _: (T, T); } - /// TyKind::AnonStruct - fn ty_anon_struct() { - struct Struct { - _: struct { t: T }, - } - } - - /// TyKind::AnonUnion - fn ty_anon_union() { - struct Struct { - _: union { t: T }, - } - } - /// TyKind::Path fn ty_path() { let _: T; diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 149659693ae..d8384951e12 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -24,7 +24,6 @@ #![feature(trace_macros)] #![feature(trait_alias)] #![feature(try_blocks)] -#![feature(unnamed_fields)] #![feature(yeet_expr)] #![allow(incomplete_features)] #[prelude_import] @@ -364,8 +363,6 @@ mod expressions { - - { builtin # offset_of(T, field) }; } /// ExprKind::MacCall @@ -636,22 +633,6 @@ mod types { fn ty_never() { let _: !; } /// TyKind::Tup fn ty_tup() { let _: (); let _: (T,); let _: (T, T); } - /// TyKind::AnonStruct - fn ty_anon_struct() { - struct Struct { - _: struct { - t: T, - }, - } - } - /// TyKind::AnonUnion - fn ty_anon_union() { - struct Struct { - _: union { - t: T, - }, - } - } /// TyKind::Path fn ty_path() { let _: T; diff --git a/tests/ui/unsized-locals/by-value-trait-object-safety-rpass.rs b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.rs index 7ccea43d182..7ccea43d182 100644 --- a/tests/ui/unsized-locals/by-value-trait-object-safety-rpass.rs +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-rpass.rs diff --git a/tests/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.rs index 1f9b5f11fb5..1f9b5f11fb5 100644 --- a/tests/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility-with-default.rs diff --git a/tests/ui/unsized-locals/by-value-trait-object-safety.rs b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.rs index d0ba6944a1e..d0ba6944a1e 100644 --- a/tests/ui/unsized-locals/by-value-trait-object-safety.rs +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.rs diff --git a/tests/ui/unsized-locals/by-value-trait-object-safety.stderr b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.stderr index 6a93464febb..223624cfca4 100644 --- a/tests/ui/unsized-locals/by-value-trait-object-safety.stderr +++ b/tests/ui/unsized-locals/by-value-trait-dyn-compatibility.stderr @@ -1,5 +1,5 @@ warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/by-value-trait-object-safety.rs:1:12 + --> $DIR/by-value-trait-dyn-compatibility.rs:1:12 | LL | #![feature(unsized_locals)] | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(unsized_locals)] = note: `#[warn(incomplete_features)]` on by default error: the `foo` method cannot be invoked on a trait object - --> $DIR/by-value-trait-object-safety.rs:20:7 + --> $DIR/by-value-trait-dyn-compatibility.rs:20:7 | LL | Self: Sized; | ----- this has a `Sized` requirement diff --git a/tests/ui/utf8-bom.rs b/tests/ui/utf8-bom.rs index e2e4ccd63c1..5b9e27fb7b9 100644 --- a/tests/ui/utf8-bom.rs +++ b/tests/ui/utf8-bom.rs @@ -1,6 +1,4 @@ +// This file has utf-8 BOM, it should be compiled normally without error. //@ run-pass -// - -// This file has utf-8 BOM, it should be compiled normally without error. pub fn main() {} diff --git a/tests/ui/wf/wf-convert-unsafe-trait-obj-box.rs b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.rs index ffdb49a3be5..26292a1d218 100644 --- a/tests/ui/wf/wf-convert-unsafe-trait-obj-box.rs +++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.rs @@ -1,7 +1,7 @@ // Check that we do not allow casts or coercions -// to object unsafe trait objects inside a Box +// to dyn-incompatible trait objects inside a Box -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait Trait: Sized {} diff --git a/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr index 2565e25a242..38426545bc8 100644 --- a/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr +++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-convert-unsafe-trait-obj-box.rs:16:33 + --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:16:33 | LL | let t_box: Box<dyn Trait> = Box::new(S); | ^^^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14 + --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` @@ -15,13 +15,13 @@ LL | trait Trait: Sized {} = note: required for the cast from `Box<S>` to `Box<dyn Trait>` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15 + --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:17:15 | LL | takes_box(Box::new(S)); | ^^^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14 + --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` @@ -31,13 +31,13 @@ LL | trait Trait: Sized {} = note: required for the cast from `Box<S>` to `Box<(dyn Trait + 'static)>` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5 + --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:15:5 | LL | Box::new(S) as Box<dyn Trait>; | ^^^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14 + --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` diff --git a/tests/ui/wf/wf-convert-unsafe-trait-obj.rs b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.rs index 143b854ed6b..ec4bb2897f9 100644 --- a/tests/ui/wf/wf-convert-unsafe-trait-obj.rs +++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.rs @@ -1,7 +1,7 @@ // Check that we do not allow casts or coercions -// to object unsafe trait objects by ref +// to dyn-incompatible trait objects by ref -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait Trait: Sized {} diff --git a/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr index 97f6bcd0428..94259aa5b0a 100644 --- a/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr +++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-convert-unsafe-trait-obj.rs:16:25 + --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:16:25 | LL | let t: &dyn Trait = &S; | ^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14 + --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` @@ -15,13 +15,13 @@ LL | trait Trait: Sized {} = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-convert-unsafe-trait-obj.rs:17:17 + --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:17:17 | LL | takes_trait(&S); | ^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14 + --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` @@ -31,13 +31,13 @@ LL | trait Trait: Sized {} = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-convert-unsafe-trait-obj.rs:15:5 + --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:15:5 | LL | &S as &dyn Trait; | ^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14 + --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.rs b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs index c8731a8ecaf..07e90538b85 100644 --- a/tests/ui/wf/wf-unsafe-trait-obj-match.rs +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs @@ -1,7 +1,7 @@ // Check that we do not allow coercions to object // unsafe trait objects in match arms -#![feature(object_safe_for_dispatch)] +#![feature(dyn_compatible_for_dispatch)] trait Trait: Sized {} diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr index edbdec6a5ef..d7366e12256 100644 --- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr @@ -1,5 +1,5 @@ error[E0308]: `match` arms have incompatible types - --> $DIR/wf-unsafe-trait-obj-match.rs:23:17 + --> $DIR/wf-dyn-incompat-trait-obj-match.rs:23:17 | LL | / match opt() { LL | | Some(()) => &S, @@ -13,13 +13,13 @@ LL | | } found reference `&R` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-unsafe-trait-obj-match.rs:26:21 + --> $DIR/wf-dyn-incompat-trait-obj-match.rs:26:21 | LL | Some(()) => &S, | ^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-unsafe-trait-obj-match.rs:6:14 + --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` @@ -31,7 +31,7 @@ LL | trait Trait: Sized {} = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-unsafe-trait-obj-match.rs:25:25 + --> $DIR/wf-dyn-incompat-trait-obj-match.rs:25:25 | LL | let t: &dyn Trait = match opt() { | _________________________^ @@ -41,7 +41,7 @@ LL | | }; | |_____^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-unsafe-trait-obj-match.rs:6:14 + --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` diff --git a/tests/ui/wf/wf-object-safe.rs b/tests/ui/wf/wf-dyn-incompatible.rs index 42e6917551f..16e7ca1cbc6 100644 --- a/tests/ui/wf/wf-object-safe.rs +++ b/tests/ui/wf/wf-dyn-incompatible.rs @@ -1,4 +1,4 @@ -// Check that object-safe traits are not WF when used as object types. +// Check that dyn-incompatible traits are not WF when used as trait object types. // Issue #21953. trait A { diff --git a/tests/ui/wf/wf-object-safe.stderr b/tests/ui/wf/wf-dyn-incompatible.stderr index 7c14f3d2f8b..cf016b63c74 100644 --- a/tests/ui/wf/wf-object-safe.stderr +++ b/tests/ui/wf/wf-dyn-incompatible.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `A` cannot be made into an object - --> $DIR/wf-object-safe.rs:9:13 + --> $DIR/wf-dyn-incompatible.rs:9:13 | LL | let _x: &dyn A; | ^^^^^^ `A` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/wf-object-safe.rs:5:23 + --> $DIR/wf-dyn-incompatible.rs:5:23 | LL | trait A { | - this trait cannot be made into an object... diff --git a/triagebot.toml b/triagebot.toml index aba36692828..60ec1043aad 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -921,8 +921,8 @@ cc = ["@kobzol"] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ + "BoxyUwU", "fmease", - "jhpratt", "jyn514", "oli-obk", ] @@ -938,7 +938,6 @@ compiler-team = [ "@oli-obk", "@pnkfelix", "@wesleywiser", - "@michaelwoerister", ] compiler-team-contributors = [ "@TaKO8Ki", @@ -971,6 +970,7 @@ bootstrap = [ "@albertlarsan68", "@onur-ozkan", "@kobzol", + "@jieyouxu", ] infra-ci = [ "@Mark-Simulacrum", @@ -989,7 +989,6 @@ query-system = [ "@cjgillot", ] incremental = [ - "@michaelwoerister", "@wesleywiser", ] diagnostics = [ @@ -1048,7 +1047,6 @@ ast_lowering = [ "@spastorino", ] debuginfo = [ - "@michaelwoerister", "@davidtwco" ] fallback = [ |
