diff --git a/.github/ISSUE_TEMPLATE/blank_issue.md b/.github/ISSUE_TEMPLATE/blank_issue.md deleted file mode 100644 index 9aef3ebe637a1..0000000000000 --- 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 b6dc27f123465..003c1e5d7ebbe 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 9ac7f1a9b494c..dc5bfe6d5fc76 100644 --- a/.mailmap +++ b/.mailmap @@ -74,6 +74,7 @@ Ben Striegel Benjamin Jackman Benoît Cortier Bheesham Persaud Bheesham Persaud +bjorn3 <17426603+bjorn3@users.noreply.github.com> Björn Steinbrink blake2-ppc blyxyas Alejandra González @@ -311,6 +312,7 @@ Josh Driver Josh Holmer Josh Stone Josh Stone +Julia Ryan Julian Knodt jumbatm <30644300+jumbatm@users.noreply.github.com> Junyoung Cho diff --git a/Cargo.lock b/Cargo.lock index 502920350d5c5..b50b44bd077b4 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]] @@ -5640,6 +5646,12 @@ version = "0.1.14" 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" @@ -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 ded0b59fc6cd3..74fcc58348b43 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=` + 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= + ``` + + or set `prefix` and `sysconfdir` in the `[install]` section to your custom + directory path: + + ```sh + ./configure --set install.prefix= --set install.sysconfdir= + ``` + + 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 0000000000000..2ecac8a9df1c6 --- /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(&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 { + 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 { + 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(&self, cx: &C) -> Result + 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 620a051eeb7dd..6e1299944a09d 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 similarity index 96% rename from compiler/rustc_target/src/abi/mod.rs rename to compiler/rustc_abi/src/layout/ty.rs index 3eaff65261869..c6812c4d4c075 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 fa7c98a7fa0cc..84d756b6d517c 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 37f429cce44d7..937031324f57f 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), + List(ThinVec), /// 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>), - /// An anonymous struct type i.e. `struct { foo: Type }`. - AnonStruct(NodeId, ThinVec), - /// An anonymous union type i.e. `union { bar: Type }`. - AnonUnion(NodeId, ThinVec), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g., ` 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 124d0acfa4912..b73412a4b1de9 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> { + pub fn meta_item_list(&self) -> Option> { 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> { + fn meta_item_list(&self) -> Option> { 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> { + fn list_from_tokens(tokens: TokenStream) -> Option> { 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) -> Option + fn from_tokens<'a, I>(tokens: &mut iter::Peekable) -> Option where I: Iterator, { 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 104f84f26e0af..1a7da46913d7e 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(vis: &mut T, ty: &mut P) { 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(vis: &mut T, macro_def: &mut MacroDef) { visit_delim_args(vis, body); } -fn walk_meta_list_item(vis: &mut T, li: &mut NestedMetaItem) { +fn walk_meta_list_item(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 1a80a9ccdbf54..a517f17c82c34 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 9f9c3d8c39239..4dcadb8517eb4 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 e77c0fb3a3ed3..6289966561f58 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 9275308cccbce..365924ef782e8 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 c361c35b723d8..7cfbd6c6c6cb5 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 5bdd9b6eda80f..87e3a6871b9e1 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 5cce47ce7bd21..c60925b30495a 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -814,33 +814,6 @@ pub(crate) struct NegativeBoundWithParentheticalNotation { pub span: Span, } -#[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 { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 83931a8c1a960..82de83f8da4ab 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 726ceebe3c524..97cb6e52d5625 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 7e07ccf28a0cb..44a5a2d0baf28 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 5d9ac23ec490e..adabf18ca85d6 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 28d73fbe9f374..c1db4d07dfc86 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 { /// 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> { 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 959a5a4bba752..626840aa6a3cd 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 c994c4dc1e484..7ace38c3e85ff 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>, /// The set of borrows occurring in `body` with data about them. - pub borrow_set: Rc>, + 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>, + 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>, /// Polonius output facts. Populated when using /// [`ConsumerOptions::PoloniusOutputFacts`]. - pub output_facts: Option>, + pub output_facts: Option>, } /// 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 60ea0d1edbf4e..c687be69b1a65 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, + 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 = 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 d8fa5506a9919..26a090f5579ce 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>, + 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>, + 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 98417e8c7a3f4..3871816777c7f 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 d4598a1f582b6..1a5f9bdb154c0 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 a11eca0b9c746..cbf8aa313c517 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>, + regioncx: &'a RegionInferenceContext<'tcx>, /// The set of borrows extracted from the MIR - borrow_set: Rc>, + 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, /// Results of Polonius analysis. - polonius_output: Option>, + polonius_output: Option>, diags: diags::BorrowckDiags<'infcx, 'tcx>, move_errors: Vec>, @@ -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 d85af52b01e36..3674053409b8d 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>, pub polonius_input: Option>, - pub polonius_output: Option>, + pub polonius_output: Option>, pub opt_closure_req: Option>, 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 519ba0b9e0c9f..679e111caa984 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 afd811a0efb43..d1b65943199c4 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 c62ea870acfe9..e85f529bf0ee1 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>, type_tests: Vec>, liveness_constraints: LivenessValues, - elements: &Rc, + elements: Rc, ) -> 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>, + polonius_output: Option>, ) -> (Option>, 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>>, errors_buffer: &mut RegionErrors<'tcx>, - polonius_output: Rc, + 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 2f90e91628141..a16c1931a552b 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, 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 b95fe5b50282e..662e6fa46b5c9 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -275,15 +275,16 @@ impl RegionValues { /// 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, + elements: Rc, num_universal_regions: usize, - placeholder_indices: &Rc, + placeholder_indices: Rc, ) -> 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 0a375c7fae8e2..b7aef71eb54a0 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>, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index fc1600ea4a611..6c86968389aa0 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 6977fed59ed9d..cded9935f971a 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>, + universal_regions: Rc>, 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 d4900d21f8f5a..b8e35f882ec14 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, + 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 8cbe3ac67016b..a5175e653d8fe 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, + elements: &DenseLocationMap, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6b17879de262d..82aeca6669359 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>, - universal_regions: &Rc>, + universal_regions: Rc>, location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, - elements: &Rc, + elements: Rc, 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 bf079e813f16b..cfc14d146bd2c 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> 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> 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> 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 9695df9c87e8a..77cb8dc63c484 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 75dbb3d8e6abb..9ae48024f445b 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, ()> { 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 cf1d5c68eadd0..15993dbf5ecc3 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 4be2d209ae785..60450d085f6c0 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 dde696fca610b..f79227d52a813 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; 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 d5ee5e430d5d0..e884c0ec71897 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;`. 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 78028df2aa0ee..e3878d90e4143 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 4fffffb91c8b4..639c2aa231cb1 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, } -#[derive(Diagnostic)] -#[diag(builtin_macros_global_asm_clobber_abi)] -pub(crate) struct GlobalAsmClobberAbi { - #[primary_span] - pub(crate) spans: Vec, -} - pub(crate) struct AsmClobberNoReg { pub(crate) spans: Vec, pub(crate) clobbers: Vec, @@ -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, + 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 5e535ff62e173..9fc0318df5dc0 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 ccbd5a78485d7..e47431e0f873a 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 ebaa9c69c810a..3078288c28615 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 1ce0aacab4998..a681e6d9f3cd1 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 e78ba5a341531..69a32cc3d43c9 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 a710701e72c4b..714742aeaffe0 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 e7ac084558a5a..d462dcd63a925 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -3,7 +3,8 @@ //! Adapted from //! () -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 19e5adc253854..35f0ccff3f99e 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 f6b7981395a5f..b6f9ce8fc2988 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 0235384445e71..bbae59ea7a55a 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 5fdf2680aac88..d20e13e15b944 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::>(); - - 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 acd5358883166..b611f9ba8bcb3 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 726b126e727dd..0d3e7083d56ad 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 6bada3d334ce4..dc1895f437b52 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] @@ -45,15 +42,6 @@ pub(crate) struct InvalidMinimumAlignment { pub err: String, } -#[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 { @@ -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, - pub missing_features: Option, -} - -#[derive(Subdiagnostic)] -#[help(codegen_gcc_missing_features)] -pub(crate) struct MissingFeatures; - -impl 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 01dd1a8856aab..3104088e0d5e9 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 945eedf555667..972d66321403d 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 eeab2a5f15597..4e1b99fdebfdf 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 a7a32e285d8fa..7486eefeb85a7 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 cb45bbde2c27d..183e9ddf8bf98 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 a93baf88413a1..03a871297c481 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 df2198df14b6a..0950e4bb26bac 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 3d75393bf06fd..2fe5ed32daa31 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 82ca3f519f740..298cac2fd6e77 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 489259da85646..2c5ec9dad59f1 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::>(); - 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 4e0c62c8bf8c9..dbf5298d64ba3 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 31d59905446f3..0ced37b53a841 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 2b8912d1db2ab..c836dd5473f3c 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 77821ca89bc14..90f7dd733ca18 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 for BranchParameters { fn from(value: ConditionInfo) -> Self { + let to_llvm_cond_id = |cond_id: Option| { + 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 267a22449167d..c2c261da79b68 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 3a80d216f47ee..d7d29eebf8593 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 b7a6f80956dd3..15d441a986d88 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`. + // a (wide) pointer. Make sure it is not called for e.g. `Box`. 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 acb15449ce323..960487ada16ad 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 { +) -> Option { 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 7be44dd51b577..33258cb46fad2 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 bb481d2a30856..0d436e1891ece 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -80,30 +80,6 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { } } -pub(crate) struct TargetFeatureDisableOrEnable<'a> { - pub features: &'a [&'a str], - pub span: Option, - pub missing_features: Option, -} - -#[derive(Subdiagnostic)] -#[help(codegen_llvm_missing_features)] -pub(crate) struct MissingFeatures; - -impl 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 c66c80da9fcca..bfe623e7fc354 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 d3950df91fbd0..661debbb9f126 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 bd847cd0068e5..57936215ff130 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 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, -) -> 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 { @@ -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 6e429a1674ade..1af666f818bba 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 58baf40b5812b..dffb7a7271e09 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 9091602d75b71..d07274920feaf 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 e7b1c63a82251..34dc599e4fddd 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. + // + 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 3f3d305da0142..c4bb82d0dd7b1 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 4d81ff933dded..e3d11cfaf4fe3 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> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } @@ -1924,7 +1923,7 @@ impl Emitter for SharedEmitter { ); } - fn source_map(&self) -> Option<&Lrc> { + 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 e99c3a462711c..d536419ab3c20 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::>(); 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 08b326e3ac3c6..d67cf0e3a6d5f 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, + pub missing_features: Option, +} + +#[derive(Subdiagnostic)] +#[help(codegen_ssa_missing_features)] +pub struct MissingFeatures; + +impl 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 162d14272a555..cbd95146294f5 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, - pub cfg: Option, + pub cfg: Option, pub verbatim: bool, pub dll_imports: Vec, } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 125d3b908c733..be9a6d9a90eed 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 c4fb24aa625d9..8bd172a9ce6d3 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 17f66c12a0332..88ceff327d0aa 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 { /// 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 0b764ae7747d8..a7d5541481a6c 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 f9c0f3ce94146..a132ca6954050 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 c4f8841d71c63..41136019a88df 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 73a9a1569f64e..24dbe688f363b 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 2cbf242fcf28d..463a66d4e2e46 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 6eb33c29e1d89..5c4a899f28a14 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 4aec74595bc86..2db43a0f787eb 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 interpret::AllocMap for FxIndexMap { #[inline(always)] fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { - 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 c60bacb85067f..c943236affc56 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 565a7d1624249..30b5a8d70bc33 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 0f796c3122210..89d49ba046e7d 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 e6ab8ca12a886..7700eb792effb 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, Allocation)> { // 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 291664d556af4..cd5e2aeca855e 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 Immediate { } /// 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, 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 49656e10f2a21..81b926a1b65fa 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 cc49d7cebf450..e636090a324ce 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>( &self, layout: TyAndLayout<'tcx>, diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 7ff1339c5ab34..3d6d000348324 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 48e21a9dab1b6..0617ef83aad9c 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 = HashMap>; pub type UnhashSet = HashSet>; +pub type UnindexMap = indexmap::IndexMap>; /// 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 6d7fba36fb3d0..9fa4242de3c82 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 76b7270d4b815..a59dea557bb96 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 0545246929f48..8ebc227114d95 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::(); 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 cee5082927026..f5c5faa066b6b 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 b2e51e24e141f..ccd1b43bd194a 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 f468fbf4497e0..335432c9cfec3 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> { - 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> { - 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 1dc52c4d0a423..1adb6b9dcfee3 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>; + 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> { - 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> { - 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> { + 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> { + fn source_map(&self) -> Option<&SourceMap> { None } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 1972a522e394a..1534e25652077 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> { - 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> { + 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 39acacfbe59c8..94365a89adc7e 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> { + 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> { + 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 17a1635bd1143..70179237e5d41 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> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index e0b64b276ebc6..156f5e5d26e64 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>; + 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 766d96e268f04..57bac9d09d5ec 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 d0552a754feb0..f0cfe133a4955 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 { 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 3208837427736..ea06415801f1a 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 { + fn feature_list(attr: &Attribute) -> ThinVec { 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 0fdccb0891899..5682c574552b4 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -467,6 +467,20 @@ pub(crate) struct GlobDelegationOutsideImpls { pub span: Span, } +#[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 { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 079dcee99d3f4..a872b12e744c4 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 0cd0963d4e328..cba4535156b8a 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 c5530097e9606..c0398db9c101f 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()]`. + (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` 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() {`. (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 80813af386472..4e9d21c900df6 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, Q: AsRef>(p: P, q: Q) -> io::Result
  • 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 f58ec22aea971..2ef6fa53f4edd 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`. 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 {C, D}`. Enum(EnumDef<'hir>, &'hir Generics<'hir>), /// A struct definition, e.g., `struct Foo {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 d0a8aaa85bb29..58916d0586593 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 c1a4a4497c7a9..381062b142971 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 155270ca6a7c2..6ff57396b4a19 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 c73826c489f96..da814cd2d6900 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 312212232bcdc..4429f6346e88a 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::>(); - 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; 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 35c2b7e7ce2fb..2d6b9813271e2 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 25e219ef3f23a..06317a3b3049c 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 d3d88919d8795..004540b264308 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 02d23b95d46e6..3a9d2640eee93 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 bea8d28a9f756..76c75d976ee0f 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 69d3642644709..eea5a16ac6fd3 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 93b021be24584..f63e2d40e3906 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 d76d9213129fa..8648a7d1e3220 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 8ff9640a87489..14b6b17ed18a7 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 2418037ae962f..4346504450d0b 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 `::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 33f6623edfdf3..6d30f7c7b9d07 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 a15621bf28b9b..c8852a3a3695a 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, + defs: ItemLocalMap, // 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>, + late_bound_vars: ItemLocalMap>, } 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); } @@ -486,6 +485,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 { @@ -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) { - 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 3af4d1f5edad5..470bcaeded167 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>, 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 4edb68e61999e..9099703e81290 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -734,13 +734,6 @@ pub(crate) struct InvalidUnionField { pub note: (), } -#[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> { @@ -1598,41 +1591,6 @@ pub(crate) struct UnconstrainedGenericParameter { pub const_param_note2: bool, } -#[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, - #[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 { diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs index b6cffb90805b3..8a83866b7fa46 100644 --- a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs +++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs @@ -34,6 +34,15 @@ pub(crate) struct LifetimeNotCaptured { pub opaque_span: Span, } +#[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 { 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 5150db7f51b19..a562759da1112 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 e7b8e6e69b0c6..394a263fbb595 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> ::Item = &'a str // <-- 'a is bad + // for<'a> >::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 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>>( 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 a70f881f5fedc..11c0450bfe211 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 { 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 95f83836d7573..d760acf53bdd8 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 7d40a7746b97c..71ee77f8f6172 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 dbaf9c2c6f075..a0fdf95a83173 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 12bb9a3f9e0f3..02cfb57b836f6 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 1c52283d537d3..9fe6a8ee3425a 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 73a775690d66b..894402a8c2e88 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 39d430cf73b76..3669100ed9167 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 2dbadf8198b3f..0d9d1910ae0c1 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 fcd2940b83ae3..407191661a4b3 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 3e7ce2955fc05..fcaa5751152b6 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 fb462eec1b9aa..bd0b98702983a 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 { + pub(crate) fn deref_steps_for_suggestion( + &self, + expr_ty: Ty<'tcx>, + target: Ty<'tcx>, + ) -> Option { 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 cfa8fc4bbf2e6..777248ff873de 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 a692642ccfcc2..cceaabaff65b6 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 67f4dbee3cb4a..4653458b5ddcc 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 b34ed4640db12..b310398a0f1ba 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 62107877283a0..eccb18ad6c443 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>) { + pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec>) { 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>, @@ -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 550c58b5a17c6..fa471647d02d0 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 487cc7e55cd9e..1df4d32f3cbac 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>, call_ident: Option, 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 a4121adf628af..8a7005ac32893 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 f8352d9d44a97..6b0a897faba94 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 72842075fec0a..1d7b3433fe5cb 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 3e9cb0ac2c80c..cb8b1df2c6e47 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 a8b5b6165db06..b20592c85d285 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 3bb7070d61dfa..ba6bfd3a5e940 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` 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> { + 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 a37e9744293c3..4f726f3ed3866 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 49c5a7d8a652d..fb78da0a86c66 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 3254dddaee9a2..b193b81f6de48 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 9dc5cbaafce19..d25fe4219b587 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 52f354b8ecaff..cae55230b0679 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 similarity index 100% rename from compiler/rustc_infer/src/errors/mod.rs rename to 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 6ce47db8b9bd2..8c943a961e76a 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>, { - 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( - 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( @@ -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( - self, - expected: T, - variance: ty::Variance, - actual: T, - ) -> Result>>, NoSolution> - where - T: Relate>, - { - 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( - self, - expected: T, - actual: T, - ) -> Result>>, NoSolution> - where - T: Relate>, - { - 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( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'tcx, T> + pub fn lub(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( - 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>>, + ) -> 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 c06836edcfb55..57007752cade3 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>>( + 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>( &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result>>, 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>>( + fn instantiate_const_var_raw>( &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, 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(&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 5fa1bf51634a3..bc813305ba480 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>`, 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, TypeError<'tcx>>; -pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" -pub type FixupResult = Result; // "fixup result" +pub(crate) type FixupResult = Result; // "fixup result" pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< ut::InPlace, &'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)>>, /// 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>, - /// 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>), ExistentialTraitRef(ExpectedFound>), ExistentialProjection(ExpectedFound>), - 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, - ) -> 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( - self, + mut self, span: Span, canonical: &Canonical<'tcx, T>, ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>) where T: TypeFoldable>, { - 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>>, + in_regions: Lrc>>, ) { 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::>::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 `::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() { let _ = [0; bar::()]; }` the repeat count - /// constant `bar::()` 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() { let _ = [0; bar::()]; }` the repeat count + /// constant `bar::()` 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 55c51bc856f8e..365ddaba138ff 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, OpaqueTypeDecl<'tcx>>; -pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; - -use super::DefineOpaqueTypes; +pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap, 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 { 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 { 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> 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 4aa2ccab0e7bb..047d8edad3de7 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 a071b84a1a00f..9300fc574dc29 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_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>>; 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>, ) -> 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(&mut self, outlives_bounds: I) - where - I: IntoIterator>, - { // 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 f5c873b037552..e23bb1aaa5631 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::>::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 634cda86bc338..e0e03a2922010 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> >::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> >::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 74a80a1b9aa7c..247fbc259652e 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>, @@ -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> { @@ -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> { 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 7913f0e340e09..3cfc58dea05bd 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>, } -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 82f7668b2d2ec..270217e26b78c 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, + pub(super) var_infos: IndexVec, - 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; /// 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::>::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>>, + choice_regions: Lrc>>, ) { 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, Vec) { - 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> 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 4a8c7387ddc6c..0000000000000 --- 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`. 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>>, -} - -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> { - 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( - &self, - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - R: PredicateEmittingRelation>, - { - debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::(), 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( - &self, - relation: &mut R, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> - where - R: PredicateEmittingRelation>, - { - debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::(), 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>>, - ) { - self.goals.extend(obligations); - } - - pub fn register_predicates( - &mut self, - obligations: impl IntoIterator, 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 a6d10aa5968c7..7049444db9b5f 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>>( + pub(crate) fn instantiate_const_var>>( &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 9564baa6ab287..7eb61abfbc124 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>, } -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> { + self.obligations } } -impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { +impl<'tcx> TypeRelation> for LatticeOp<'_, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() + self.infcx.tcx } fn relate_with_variance>>( @@ -70,7 +83,15 @@ impl<'tcx> TypeRelation> 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> 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> 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> 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> 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> 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> 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( @@ -202,7 +221,7 @@ impl<'tcx> TypeRelation> 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> for LatticeOp<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation> 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> 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, ty::Predicate<'tcx>>>, + preds: impl IntoIterator, 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>>, - ) { - self.fields.register_obligations(obligations); + fn register_goals(&mut self, goals: impl IntoIterator>>) { + 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 edc0c4f078ab2..e6d1003cab61e 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 7acfea643dd1e..35103c070c27d 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>, /// 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> { + self.obligations + } } -impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> TypeRelation> 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> 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> 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> 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> 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> 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> 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> 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( @@ -271,8 +275,8 @@ impl<'tcx> TypeRelation> 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> for TypeRelating<'_, '_, 'tcx> { } } -impl<'tcx> PredicateEmittingRelation> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation> 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, ty::Predicate<'tcx>>>, + preds: impl IntoIterator, 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>>, - ) { - self.fields.register_obligations(obligations); + fn register_goals(&mut self, goals: impl IntoIterator>>) { + 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 671a66d504f9d..64cc76f827eb8 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> 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> 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> 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 964fb1f681955..07a482c2f9ac3 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 7eb2c20e0d8e7..779ce976becc0 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>>> for TypeVariabl } } -#[derive(Clone)] -pub struct TypeVariableStorage<'tcx> { +#[derive(Clone, Default)] +pub(crate) struct TypeVariableStorage<'tcx> { /// The origins of each type variable. values: IndexVec, /// Two variables are unified in `eq_relations` when we have a @@ -29,7 +29,7 @@ pub struct TypeVariableStorage<'tcx> { eq_relations: ut::UnificationTableStorage>, } -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> { + pub(crate) fn known(&self) -> Option> { 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, Vec) { @@ -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 { + pub(crate) fn unresolved_variables(&mut self) -> Vec { (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 051bba5851869..a04b2bb2b08b5 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 fa813d0f90ca0..64b72de398622 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, }, } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 204ae437a3e9a..fd850d2f39a5f 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 60aab668cbaa6..b0ab50dd77388 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 }, - /// "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 }, /// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal. RawCStr { n_hashes: Option }, } +/// `#"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 { + 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 { // 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 8acb986bfc9d0..c4d709aa1f985 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 - 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 d904020730019..63a8a949e9699 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 168e3a8e92c5f..565c3c0425256 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 5aeaad420699e..d029ad934079b 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 de40139715076..6d5903ac46740 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 007e86ae0d2b2..89a67fc0d8988 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 c74cb866f21fa..81352af3d48fa 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)] @@ -570,6 +569,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see RFC #3535 \ for more information", ); + store.register_removed( + "deprecated_cfg_attr_crate_type_name", + "converted into hard error, see issue #91632 \ + for more information", + ); store.register_removed( "pointer_structural_match", "converted into hard error, see RFC #3535 \ diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0045cfcaa56ad..16cfae17d4020 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, + suggestion: InvalidNanComparisonsSuggestion, }, #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)] LtLeGtGe, @@ -2441,14 +2438,6 @@ pub(crate) struct DuplicateMacroAttribute; #[diag(lint_cfg_attr_no_attributes)] 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 56f930ea7f62e..3c31b879bd6aa 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, + outermost_impl_parent: Option, ) -> 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, + outermost_impl_parent: Option, ) -> 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 { + 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 342ebfa0b06cc..ffbcf7f808ebe 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 15fe18adbfb10..db4413149a49f 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 12d5b5cf97938..1a00725096148 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 549dc64a562b2..23dc5214fe2ea 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!(""); } /// } /// ``` /// @@ -3143,42 +3145,6 @@ declare_lint! { "detects large moves or copies", } -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 ", - }; -} - declare_lint! { /// The `unexpected_cfgs` lint detects unexpected conditional compilation conditions. /// @@ -3874,6 +3840,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 + /// = 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 ", + }; +} + 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 ", }; } + +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 ", + }; + crate_level_only +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 734e7069c9026..c01fa5c54d65e 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 4532fd8d48d07..cda81d4a9b5b2 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(Params.DecisionParameters.BitmapIdx), - parameter.NumConditions = - static_cast(Params.DecisionParameters.NumConditions); - return parameter; - case LLVMRustMCDCParametersTag::Branch: - parameter.ID = static_cast( - Params.BranchParameters.ConditionID), - parameter.FalseID = - static_cast( - Params.BranchParameters.ConditionIDs[0]), - parameter.TrueID = - static_cast( - 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 Expressions; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f9fc2bd6da3b0..72b03fa0560e6 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 f206dba6cf4bc..b817b4cb7b83c 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 82b907d2501fe..c7953d50406ac 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 f02fd2ab6fe3d..4b406496337a7 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 610c682d3a461..afe03531861c9 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 b23589afb5874..8cb602d9ea841 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 72e6c96e6f646..8fd5ff1f369d4 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, foreign_items: Vec, body_owners: Vec, + opaques: Vec, } 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 7a07ef80dedb4..ad0d70152e1ad 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 + '_ { + self.opaques.iter().copied() + } + pub fn definitions(&self) -> impl Iterator + '_ { 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 70e61df1ab4d1..e9b73d25ba208 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 32e2f3b4b1685..13e35cd090983 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>, + pub defs: SortedMap, - pub late_bound_vars: FxIndexMap>>, + pub late_bound_vars: SortedMap>, } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index bfe2a2c2cb3db..4a876dc1228e5 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, pub mappings: Vec, /// 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, - pub mcdc_branch_spans: Vec, - pub mcdc_decision_spans: Vec, + /// 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, + pub mcdc_spans: Vec<(MCDCDecisionSpan, Vec)>, } #[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, + pub false_next_id: Option, } #[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, + 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, 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 431043b043192..fcb87e1943505 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>, guard: Guard, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 4878956521831..2a3a070a6e715 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 ae75f2d4187ba..c610fac80f68f 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 { 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 783952fb9cb8a..b919f5726db58 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 64898a8495e26..9f9ee8497b60b 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 989fbd711c3c8..f0be70e00dfca 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> { - desc { "looking up a named region" } + query named_variable_map(owner_id: hir::OwnerId) -> &'tcx SortedMap { + desc { |tcx| "looking up a named region inside `{}`", tcx.def_path_str(owner_id) } } - query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet> { - desc { "testing if a region is late bound" } + query is_late_bound_map(owner_id: hir::OwnerId) -> Option<&'tcx FxIndexSet> { + 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>> { - desc { "looking up late bound vars" } + query late_bound_vars_map(owner_id: hir::OwnerId) + -> &'tcx SortedMap> { + 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 e614d41899a0e..fe865b8a51508 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 58e2ebaeaf8df..36f0e3d890cfd 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 41a20e89cbf78..71833eea5c000 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 8f89f5c25afb4..3322a2643d7d3 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, 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 2ffb273cb6fc9..1bdcae4dfb479 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> for &'tcx rustc_featu } } +impl<'tcx> rustc_type_ir::inherent::Span> for Span { + fn dummy() -> Self { + DUMMY_SP + } +} + type InternedSet<'tcx, T> = ShardedHashMap, ()>; pub struct CtxtInterners<'tcx> { @@ -1419,16 +1429,8 @@ impl<'tcx> TyCtxt<'tcx> { kind: AdtKind, variants: IndexVec, 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 { 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 { 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 d98e18c1b0c2e..354ca746b466a 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 cf0c29e0c8c39..6c12b691c26c0 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(cx: &C, ity: ty::IntTy) -> Integer { + fn from_int_ty(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(cx: &C, ity: ty::UintTy) -> Integer { + fn from_uint_ty(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 f32daee7c44f2..ed24fcc7eb88a 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, 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 fd4e8f1cd4e71..d20cb368278b3 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> 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 61c03922ac05f..4c7bcb1bf2e88 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -212,15 +212,7 @@ impl<'tcx> Relate> 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 db9978a7f5334..3f00458d195c4 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 17280c3d0476f..c01d212011163 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, - /// 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, 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 204ee45bfa2d7..52a4a4b4b510d 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 6019a93e7876a..343d400004315 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, processing_decision: Option, + conditions: Vec, } 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, Option) { + degraded_branches: &mut Vec, + ) -> Option<(MCDCDecisionSpan, Vec)> { 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, - decision_spans: Vec, + degraded_spans: Vec, + mcdc_spans: Vec<(MCDCDecisionSpan, Vec)>, 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, Vec) { - (self.decision_spans, self.branch_spans) + pub(crate) fn into_done( + self, + ) -> (Vec<(MCDCDecisionSpan, Vec)>, Vec) { + (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 86fe447f39973..dc317feb20c4c 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 2ffad0b4834a0..5995d60e7e073 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 61317925d09e5..dae13df4054a4 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 f2541c37167f0..a3b117a3f1966 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 faf5c610a0c47..9d50e57d66868 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( field: &mut Option, tcx: TyCtxt<'_>, - attr: &ast::NestedMetaItem, + attr: &ast::MetaItemInner, mapper: impl FnOnce(Symbol) -> Result, ) -> 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 3c8be2f73e14a..162245cb95060 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 f9b79d72b0504..c8992b8b83430 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 0000000000000..8ba14a1158ef9 --- /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 ef4031c5c034f..9408815675692 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, ) -> 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 { - self.bcb_counters[bcb] + pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option { + 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, } impl<'a> MakeBcbCounters<'a> { fn new( - coverage_counters: &'a mut CoverageCounters, basic_coverage_blocks: &'a CoverageGraph, + bcb_needs_counter: &'a BitSet, ) -> 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 ec5ba354805f1..bc86ae22a0dbd 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, - 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, - 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, pub(super) branch_pairs: Vec, - pub(super) mcdc_bitmap_bytes: u32, - pub(super) mcdc_branches: Vec, - pub(super) mcdc_decisions: Vec, + pub(super) mcdc_bitmap_bits: usize, + pub(super) mcdc_degraded_branches: Vec, + pub(super) mcdc_mappings: Vec<(MCDCDecision, Vec)>, } /// 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, - mcdc_decisions: &mut impl Extend, + mcdc_bitmap_bits: &mut usize, + mcdc_degraded_branches: &mut impl Extend, + mcdc_mappings: &mut impl Extend<(MCDCDecision, Vec)>, ) { 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::>()?; - - // 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 { + 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::>()?; + 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) -> usize { + let mut indegree_stats = IndexVec::::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::::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::>(); + + 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 104f340c8d63f..d0f30314e79a9 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::>(); + + 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 84d44c2ab4c41..8b309147c64cd 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 50c9702cb9b02..daf868559bcae 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 1844b97887ab9..9b9b0b705bfec 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 ccc029b1e281e..8f490094d6030 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 4c090665992bd..d184328748f84 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> { &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 05b3859e554ea..b4d084d4dffc4 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` 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 ca140500e2cd3..de74ac3280411 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 db819961bbd75..0000000000000 --- 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 96968327d8ee3..0000000000000 --- 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::Interner>: - TypeRelation -where - Infcx: InferCtxtLike, - 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>); - - /// 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>, - ); - - /// 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 252a9ed1a2e79..fdefec33eeb5d 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 ffa800348f2ce..daacc6691182d 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 { /// 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::Predicate>, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option>); + ) -> ( + Result<(HasChanged, Certainty), NoSolution>, + Option>, + ); + + /// 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::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::Predicate>, generate_proof_tree: GenerateProofTree, ) -> ( - Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution>, Option>, ); } @@ -149,31 +170,41 @@ where D: SolverDelegate, 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, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option>) { - EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + ) -> (Result<(HasChanged, Certainty), NoSolution>, Option>) { + 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::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, generate_proof_tree: GenerateProofTree, ) -> ( - Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution>, Option>, ) { - 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( delegate: &D, + root_depth: usize, generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option>) { - 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, - ) -> 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, - ) -> Result<(NestedNormalizationGoals, bool, Certainty), NoSolution> { + ) -> Result<(NestedNormalizationGoals, 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>, 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 + 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, - ty: I::Ty, - ) -> Vec> { - // 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::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 309ab7f28d154..8fe39bb4ee163 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( 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 fc9c634942b70..005b293621afc 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 6a0703c531323..f8d51f304f332 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 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 e47cc03f5adf9..0e3f179b0c846 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 2074bdec48531..5828b2ecf34d5 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, 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 c59ae48a07d03..2360914a0aba1 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 5d1c300b45357..1af7fb9b86a7c 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: 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 40502158469f0..fdd500e90f807 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1755,6 +1755,14 @@ pub(crate) struct MissingFnParams { pub span: Span, } +#[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 { @@ -2110,6 +2118,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, +} +#[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 { @@ -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 3e46fc93fa49d..d627ef3d2cbe3 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 f7a8b8780edc4..2792050a0b39d 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 \ "; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index c65cf3f40f658..b6fa209958831 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> { + pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec> { // 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 b9256daa72525..5aebe716b0a10 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::() {}` + 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 9fc82d84225cc..36733726564fb 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 a8ed8b5df9c00..625a4cabdf273 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> { - 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> { - 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 b15d1edf79cda..f3174e7dea2d8 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 5369f54afb908..c11c38500345a 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 a24259a1e358f..44a62383e6eed 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, @@ -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 100f3e80603e5..af17fbf7e4df3 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 29a087bf75975..f9186d3089ab3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1187,27 +1187,11 @@ impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { } #[derive(Diagnostic)] -#[diag(passes_naked_functions_operands, code = E0787)] -pub(crate) struct NakedFunctionsOperands { - #[primary_span] - pub unsupported_operands: Vec, -} - -#[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)] @@ -1496,6 +1480,17 @@ pub(crate) struct CannotStabilizeDeprecated { pub item_sp: Span, } +#[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> { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 903fb1147440c..b5dccf85041e7 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 8d3f7e0231f78..b2f8d7dadff37 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 = 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::>() - .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 925ee26202283..056318fbcb793 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 46b67e930d5e9..751c87a9fe519 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 d00e7eff75212..f67c4cb922cee 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 a9ea268e51a9d..0145ffd3a4b7c 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 98662385434c3..0047f2c4b51e9 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 582db97e1ce87..5437ca65935f8 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 35d166e8b4ab3..fce5ec36c661b 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, + 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: "); + } + 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 fcbbb523cfc9f..24a0c252e55ad 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 21924437a4a46..fa2be8216c73f 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 d1c1b6c882eaa..02e255d7726d1 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, String> { - let mut res = FxHashMap::default(); +) -> FxIndexMap, 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 320d66163848f..53834198f6328 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, /// 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, 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 5f7184a42407c..83dcceeaa84fc 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 b7977a848ce00..47f72298e22ce 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 c7c561156e35b..27e9f817894f3 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -437,10 +437,10 @@ impl IntEncodedWithFixedSize { impl Encodable 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 2d37f5bdab800..bae5f259fccf4 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -325,7 +325,7 @@ impl Decodable for [u8; N] { } } -impl<'a, S: Encoder, T: Encodable> Encodable for Cow<'a, [T]> +impl> Encodable for Cow<'_, [T]> where [T]: ToOwned>, { @@ -345,14 +345,14 @@ where } } -impl<'a, S: Encoder> Encodable for Cow<'a, str> { +impl Encodable for Cow<'_, str> { fn encode(&self, s: &mut S) { let val: &str = self; val.encode(s) } } -impl<'a, D: Decoder> Decodable for Cow<'a, str> { +impl Decodable 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 66ad70d8d18be..041a10475eaad 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, - pub cfg: Option, + pub cfg: Option, pub foreign_module: Option, pub verbatim: Option, pub dll_imports: Vec, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 9781c74652081..3d44810e7dd36 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>, + pub symbols: Lock>, } impl SymbolGallery { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index d67e69fe0fb72..27879d817b208 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 37528a4425f58..9182789cf0269 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, 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 0dbbc338e738b..dbae4b7e71919 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 c52d1fcc07fe2..781fe6a11fe8d 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 b55465ddef7f1..5b1be5bca0593 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> { + 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 360baec273d9a..5b39706f3ade1 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 e8aa129c6cdbe..cc3bda99a117b 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 df13d24cb9e21..73ae1ae96ae23 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/aarch64.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/amdgpu.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/arm.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/avr.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/bpf.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/csky.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/hexagon.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/loongarch.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/m68k.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/mips.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/mips64.rs rename to 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 similarity index 74% rename from compiler/rustc_target/src/abi/call/mod.rs rename to compiler/rustc_target/src/callconv/mod.rs index f4469467249f4..832246495bc99 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(&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 { - 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 { - 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(&self, cx: &C) -> Result - 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/msp430.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/nvptx64.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/powerpc.rs rename to 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 similarity index 85% rename from compiler/rustc_target/src/abi/call/powerpc64.rs rename to compiler/rustc_target/src/callconv/powerpc64.rs index b9767bf906bd0..71e533b8cc519 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/riscv.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/s390x.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/sparc.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/sparc64.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/wasm.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/x86.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/x86_64.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/x86_win64.rs rename to 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 similarity index 100% rename from compiler/rustc_target/src/abi/call/xtensa.rs rename to compiler/rustc_target/src/callconv/xtensa.rs diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 2c367defe7ba3..b09d8d724efd4 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 2121c4110dde6..50679ab8cc81c 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 fb97738618b28..4f348af21ad99 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 c557091242e98..82e11a3afce32 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 de8d99977b438..e869314d4d8b9 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 a5088bcd5c257..70e8bf633a9a6 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 32a856be66907..90bcd9a45cf42 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 0000000000000..b1f52973c107f --- /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 0000000000000..feeaa48778d43 --- /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 0000000000000..45d73c1323371 --- /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 0cd4faefd6bb1..0157d03f854b7 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 0000000000000..a6af06b03db9f --- /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 51960dbec4af4..254ae54db21f7 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 21330615a874d..34d8383a60476 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 fca47b4bdb121..023a67f28719f 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 0a98b363b1a6e..e92366d5c5c3f 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 c7b3f704330bd..bd78a6ee3aff7 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 31256bca55e93..a6ecd1cc9871b 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 7802d5bf7a6b9..cf0ab630f2e21 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 a2d717817db14..94610a9e0e653 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 6c3f3afce11b9..709b6eb18e35f 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 1889ecc7670ee..824c25db07d2e 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 2c7ca50f9549c..c3100c48b0aa2 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, + pub condition: Option, pub subcommands: Vec, pub message: Option, pub label: Option, @@ -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 6df7fac949c2f..87834c329e19f 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 a17c007debd8b..11d72106b221f 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 e47f5389cd180..d425ab50ae0fd 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 5c344930314a6..df9ac2b80fded 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 c6e3ba3c95735..081d7a6a769a1 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 27d2a3c15b9ac..b29e41beab551 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 d5d7681a8d608..45e7de942fb61 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 ). /// Instead, we fudge a little by introducing a new type parameter `U` such that /// `Self: Unsize` 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> 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 084b61115dbcf..20adda6f0de29 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 7e140ecfee08b..a849cdfe1257a 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> 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 1e5da4ec49d09..9dabcea706f46 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< as QueryContext>::Ref> { + pub(crate) fn answer(self) -> Answer< 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 01d5251bfa0cc..40356e0c97855 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 f23c2cf2c07a7..deda16b76b587 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`, 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` @@ -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 e41f2c8ce4869..a057caa932952 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, - 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 34c9f1b63c066..afdfa2e80c1f6 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 7c4b4887b2d75..5e2232ff47d73 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 61736633cfa28..dac45ff2aba3f 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -44,6 +44,46 @@ pub trait Elaboratable { ) -> Self; } +pub struct ClauseWithSupertraitSpan { + 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 ClauseWithSupertraitSpan { + pub fn new(pred: I::Predicate, span: I::Span) -> Self { + ClauseWithSupertraitSpan { pred, original_span: span, supertrait_span: span } + } +} +impl Elaboratable for ClauseWithSupertraitSpan { + fn predicate(&self) -> ::Predicate { + self.pred + } + + fn child(&self, clause: ::Clause) -> Self { + ClauseWithSupertraitSpan { + pred: clause.as_predicate(), + original_span: self.original_span, + supertrait_span: self.supertrait_span, + } + } + + fn child_with_derived_cause( + &self, + clause: ::Clause, + supertrait_span: ::Span, + _parent_trait_pred: crate::Binder>, + _index: usize, + ) -> Self { + ClauseWithSupertraitSpan { + pred: clause.as_predicate(), + original_span: self.original_span, + supertrait_span: supertrait_span, + } + } +} + pub fn elaborate>( cx: I, obligations: impl IntoIterator, diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 1d0b2345b805f..b9f5cde653eaa 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>( - &self, - param_env: ::ParamEnv, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result::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>( + fn instantiate_ty_var_raw>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: ty::TyVid, + instantiation_variance: ty::Variance, + source_ty: ::Ty, + ) -> RelateResult; + 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: ::Const, + ); + fn instantiate_const_var_raw>( &self, - param_env: ::ParamEnv, - lhs: T, - rhs: T, - ) -> Result::Predicate>>, NoSolution>; + relation: &mut R, + target_is_expected: bool, + target_vid: ty::ConstVid, + source_ct: ::Const, + ) -> RelateResult; + + fn set_tainted_by_errors(&self, e: ::ErrorGuaranteed); fn shallow_resolve( &self, ty: ::Ty, ) -> ::Ty; + fn shallow_resolve_const( + &self, + ty: ::Const, + ) -> ::Const; fn resolve_vars_if_possible(&self, value: T) -> T where @@ -90,6 +119,12 @@ pub trait InferCtxtLike: Sized { sup: ::Region, ); + fn equate_regions( + &self, + a: ::Region, + b: ::Region, + ); + fn register_ty_outlives( &self, ty: ::Ty, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 59a83ea5412d5..f7875bb515270 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -460,6 +460,8 @@ pub trait Clause>: + IntoKind>> + Elaboratable { + fn as_predicate(self) -> I::Predicate; + fn as_trait_clause(self) -> Option>> { self.kind() .map_bound(|clause| if let ty::ClauseKind::Trait(t) = clause { Some(t) } else { None }) @@ -563,6 +565,10 @@ pub trait BoundExistentialPredicates: ) -> impl IntoIterator>>; } +pub trait Span: Copy + Debug + Hash + Eq + TypeFoldable { + fn dummy() -> Self; +} + pub trait SliceLike: Sized + Copy { type Item: Copy; type IntoIter: Iterator; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b2ac67efef611..f06017d7e5c35 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; type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; - type Span: Copy + Debug + Hash + Eq + TypeFoldable; + type Span: Span; type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike; @@ -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 02a9ad1e35fab..51c887fc4daa1 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( } } -#[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 <: T 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 9c725f34d8e5b..e1f3e493e36e3 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 = Result>; +/// 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 Relate for ty::AliasTy { 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 0000000000000..60a953801a479 --- /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::Interner>: + TypeRelation +where + Infcx: InferCtxtLike, + 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>); + + /// 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>, + ); + + /// 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: &Infcx, + relation: &mut R, + a: I::Ty, + b: I::Ty, +) -> RelateResult +where + Infcx: InferCtxtLike, + I: Interner, + R: PredicateEmittingRelation, +{ + debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::(), 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: &Infcx, + relation: &mut R, + a: I::Const, + b: I::Const, +) -> RelateResult +where + Infcx: InferCtxtLike, + I: Interner, + R: PredicateEmittingRelation, +{ + debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::(), 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 0000000000000..ad10ad5af9caf --- /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>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result< + Vec::Predicate>>, + TypeError, + >; + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result< + Vec::Predicate>>, + TypeError, + >; +} + +impl RelateExt for Infcx { + fn relate>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result< + Vec::Predicate>>, + TypeError, + > { + let mut relate = + SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env); + relate.relate(lhs, rhs)?; + Ok(relate.goals) + } + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result< + Vec::Predicate>>, + TypeError, + > { + 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>, + /// 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 sub Vec + /// ?0 eq u32 + /// Vec sub Vec + /// ``` + /// Without a cache, the second `Vec sub Vec` 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, + 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 TypeRelation for SolverRelating<'_, Infcx, I> +where + Infcx: InferCtxtLike, + 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 { + 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>( + &mut self, + variance: ty::Variance, + _info: VarianceDiagInfo, + a: T, + b: T, + ) -> RelateResult { + 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 { + 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 { + 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 { + super_combine_consts(self.infcx, self, a, b) + } + + fn binders( + &mut self, + a: ty::Binder, + b: ty::Binder, + ) -> RelateResult> + where + T: Relate, + { + // 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 PredicateEmittingRelation for SolverRelating<'_, Infcx, I> +where + Infcx: InferCtxtLike, + 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>, + ) { + 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>) { + 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 ac4d0795a92e8..f4fb03562de9c 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( - cx: D::Cx, + root_depth: AvailableDepth, stack: &IndexVec>, ) -> Option { 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 { pub struct SearchGraph, X: Cx = ::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, X: Cx = ::Cx> { } impl, X: Cx> SearchGraph { - pub fn new(mode: SolverMode) -> SearchGraph { + pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph { Self { mode, + root_depth: AvailableDepth(root_depth), stack: Default::default(), provisional_cache: Default::default(), _marker: PhantomData, @@ -460,7 +461,8 @@ impl, X: Cx> SearchGraph { 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::(cx, &self.stack) + let Some(available_depth) = + AvailableDepth::allowed_depth_for_nested::(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 ab9fc218d19fb..742469a1c9325 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 aeae866e9d344..e2d1ff7fdd3a4 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 47ebb20d8fa82..4b591b949b36d 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 209e30b304027..59b76d8d4427d 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 11db50a0fdf3c..259a3ed2bebde 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 f86face3f90cb..dbfd2e74abee6 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -225,7 +225,6 @@ impl 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 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 b1759a486ac64..54739c50d1d84 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 Clone for VecDeque { + #[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 Clone for VecDeque { /// /// 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 VecDeque { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] + #[track_caller] pub fn with_capacity(capacity: usize) -> VecDeque { Self::with_capacity_in(capacity, Global) } @@ -625,6 +628,7 @@ impl VecDeque { /// let deque: VecDeque = VecDeque::with_capacity(10); /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[track_caller] pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque { VecDeque { head: 0, len: 0, buf: RawVec::with_capacity_in(capacity, alloc) } } @@ -789,6 +793,7 @@ impl VecDeque { /// /// [`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 VecDeque { /// 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 VecDeque { /// 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 VecDeque { /// 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 VecDeque { /// 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 VecDeque { /// ``` #[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 VecDeque { /// 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 VecDeque { #[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 VecDeque { /// ``` #[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 VecDeque { // 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 VecDeque { /// 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 VecDeque { /// 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 IndexMut for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for VecDeque { + #[track_caller] fn from_iter>(iter: I) -> VecDeque { SpecFromIter::spec_from_iter(iter.into_iter()) } @@ -2909,16 +2926,19 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Extend for VecDeque { + #[track_caller] fn extend>(&mut self, iter: I) { >::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 Extend for VecDeque { #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque { + #[track_caller] fn extend>(&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 From<[T; N]> for VecDeque { /// 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 a9b0fd073b548..d246385ca8419 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 { + #[track_caller] fn spec_extend(&mut self, iter: I); } @@ -14,6 +15,7 @@ impl SpecExtend for VecDeque where I: Iterator, { + #[track_caller] default fn spec_extend(&mut self, mut iter: I) { // This function should be the moral equivalent of: // @@ -44,6 +46,7 @@ impl SpecExtend for VecDeque where I: TrustedLen, { + #[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 SpecExtend> for VecDeque { + #[track_caller] fn spec_extend(&mut self, mut iterator: vec::IntoIter) { let slice = iterator.as_slice(); self.reserve(slice.len()); @@ -93,6 +97,7 @@ where I: Iterator, 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 2708c7fe10259..1efe84d6d7d7d 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 SpecFromIter for VecDeque where I: Iterator, { + #[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 ff5ddd16e07e3..50bf385d671e3 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 436e0596e3d5e..45de0617f3342 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 RawVec { #[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 RawVec { #[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 { #[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 RawVec { /// 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 RawVec { /// 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 RawVec { /// `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 RawVec { /// /// 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::()) } @@ -324,6 +330,7 @@ impl RawVec { /// 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 RawVec { /// 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 RawVec { /// /// 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 RawVec { /// /// 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 RawVecInner { #[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 RawVecInner { #[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 RawVecInner { } #[inline] - fn ptr(&self) -> *mut T { + const fn ptr(&self) -> *mut T { self.non_null::().as_ptr() } #[inline] - fn non_null(&self) -> NonNull { - self.ptr.cast().into() + const fn non_null(&self) -> NonNull { + 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 RawVecInner { #[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 RawVecInner { #[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 RawVecInner { } #[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 RawVecInner { #[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 a92d22b1c309e..e3c7835f1d10b 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 786704caeb0ad..0000000000000 --- 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, -} - -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 { - 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 = 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::>(); - - if has_runs { - for c in &mut input { - c.x = c.id as u32; - } - - for _ in 0..5 { - let a = rng.gen::() % len; - let b = rng.gen::() % 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::(&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::() % len; - let b = rng.gen::() % 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::() % 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 ee878e879e98a..82dbf0306083c 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 { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn into_bytes(self) -> Vec { 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 { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec { &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 c18091705a636..4deb35efffc14 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -58,6 +58,7 @@ impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone, { + #[track_caller] fn from_iter>(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 fd94bbbdeb17c..a7dba16944e7d 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 + InPlaceCollect, ::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 = const { @@ -246,6 +247,7 @@ where } } +#[track_caller] fn from_iter_in_place(mut iterator: I) -> Vec where I: Iterator + InPlaceCollect, diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1984cfeefc14b..07a1bd4932138 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -478,6 +478,7 @@ impl Vec { #[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 Vec { #[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 Vec { /// ``` #[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 Vec { /// ``` #[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 Vec { /// ``` #[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 Vec { /// ``` #[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 Vec { /// ``` #[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 Vec { /// ``` #[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 Vec { #[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::` <= `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 Vec { #[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::` <= + // `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 Vec { /// [`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 Vec { /// [`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 Vec { /// 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 Vec { #[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 Vec { #[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 Vec { /// 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 Vec { /// ``` #[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 Vec { /// ``` #[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 Vec { #[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 Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_resize_with", since = "1.33.0")] + #[track_caller] pub fn resize_with(&mut self, new_len: usize, f: F) where F: FnMut() -> T, @@ -2940,6 +2986,7 @@ impl Vec { /// ``` #[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 Vec { /// [`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 Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_extend_from_within", since = "1.53.0")] + #[track_caller] pub fn extend_from_within(&mut self, src: R) where R: RangeBounds, @@ -3058,6 +3107,7 @@ impl Vec<[T; N], A> { impl Vec { #[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 Vec { #[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(elem: T, n: usize) -> Vec { ::from_elem(elem, n, Global) } @@ -3125,6 +3176,7 @@ pub fn from_elem(elem: T, n: usize) -> Vec { #[doc(hidden)] #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] +#[track_caller] pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { ::from_elem(elem, n, alloc) } @@ -3197,7 +3249,7 @@ impl ops::Deref for Vec { #[inline] fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + self.as_slice() } } @@ -3205,7 +3257,7 @@ impl ops::Deref for Vec { impl ops::DerefMut for Vec { #[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 ops::DerefPure for Vec {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { #[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 Clone for Vec { /// // 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, A: Allocator> IndexMut for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for Vec { #[inline] + #[track_caller] fn from_iter>(iter: I) -> Vec { >::from_iter(iter.into_iter()) } @@ -3419,16 +3474,19 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Extend for Vec { #[inline] + #[track_caller] fn extend>(&mut self, iter: I) { >::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 Vec { // 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>(&mut self, mut iterator: I) { // This is the case for a general iterator. // @@ -3475,6 +3534,7 @@ impl Vec { // 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) { let (low, high) = iterator.size_hint(); if let Some(additional) = high { @@ -3625,16 +3685,19 @@ impl Vec { #[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 { + #[track_caller] fn extend>(&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 From<&[T]> for Vec { /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); /// ``` #[cfg(not(test))] + #[track_caller] fn from(s: &[T]) -> Vec { s.to_vec() } @@ -3765,6 +3829,7 @@ impl From<&mut [T]> for Vec { /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); /// ``` #[cfg(not(test))] + #[track_caller] fn from(s: &mut [T]) -> Vec { s.to_vec() } @@ -3784,6 +3849,7 @@ impl From<&[T; N]> for Vec { /// ``` /// assert_eq!(Vec::from(&[1, 2, 3]), vec![1, 2, 3]); /// ``` + #[track_caller] fn from(s: &[T; N]) -> Vec { Self::from(s.as_slice()) } @@ -3799,6 +3865,7 @@ impl From<&mut [T; N]> for Vec { /// ``` /// assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]); /// ``` + #[track_caller] fn from(s: &mut [T; N]) -> Vec { Self::from(s.as_mut_slice()) } @@ -3815,6 +3882,7 @@ impl From<[T; N]> for Vec { /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); /// ``` #[cfg(not(test))] + #[track_caller] fn from(s: [T; N]) -> Vec { <[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 { s.into_owned() } @@ -3892,6 +3961,7 @@ impl From> for Box<[T], A> { /// /// assert_eq!(Box::from(vec), vec![1, 2, 3].into_boxed_slice()); /// ``` + #[track_caller] fn from(v: Vec) -> Self { v.into_boxed_slice() } @@ -3907,6 +3977,7 @@ impl From<&str> for Vec { /// ``` /// assert_eq!(Vec::from("123"), vec![b'1', b'2', b'3']); /// ``` + #[track_caller] fn from(s: &str) -> Vec { From::from(s.as_bytes()) } diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 7085bceef5baa..b98db669059f9 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 { + #[track_caller] fn spec_extend(&mut self, iter: I); } @@ -13,6 +14,7 @@ impl SpecExtend for Vec where I: Iterator, { + #[track_caller] default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter) } @@ -22,12 +24,14 @@ impl SpecExtend for Vec where I: TrustedLen, { + #[track_caller] default fn spec_extend(&mut self, iterator: I) { self.extend_trusted(iterator) } } impl SpecExtend> for Vec { + #[track_caller] fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); @@ -41,6 +45,7 @@ where I: Iterator, 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) { 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 96d701e15d487..6c7b4d89f2da7 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 SpecFromElem for T { + #[track_caller] default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { let mut v = Vec::with_capacity_in(n, alloc); v.extend_with(n, elem); @@ -19,6 +20,7 @@ impl SpecFromElem for T { impl SpecFromElem for T { #[inline] + #[track_caller] default fn from_elem(elem: T, n: usize, alloc: A) -> Vec { if elem.is_zero() { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; @@ -31,6 +33,7 @@ impl SpecFromElem for T { impl SpecFromElem for i8 { #[inline] + #[track_caller] fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { 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(elem: u8, n: usize, alloc: A) -> Vec { 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 e1f0b639bdfd6..ad7688e1c59f0 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -29,12 +29,14 @@ impl SpecFromIter for Vec where I: Iterator, { + #[track_caller] default fn from_iter(iterator: I) -> Self { SpecFromIterNested::from_iter(iterator) } } impl SpecFromIter> for Vec { + #[track_caller] fn from_iter(iterator: IntoIter) -> 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 77f7761d22f95..22eed238798cf 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 SpecFromIterNested for Vec where I: Iterator, { + #[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 SpecFromIterNested for Vec where I: TrustedLen, { + #[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 9e36377c148d2..ca5cb17f8bfda 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -52,6 +52,7 @@ impl ExactSizeIterator for Splice<'_, I, A> {} #[stable(feature = "vec_splice", since = "1.21.0")] impl 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 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 1d07a7690da43..3ec4332c71b32 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 0000000000000..11515ea476971 --- /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 { + 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 { + 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 0000000000000..f8615435fc2a7 --- /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(v: &mut [T]) { + stable_sort(v, |a, b| a.lt(b)) +} + +#[inline(always)] +fn stable_sort bool>(v: &mut [T], mut is_less: F) { + if mem::size_of::() == 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 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 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(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(opt_val: Option) -> 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 { + buf_ptr: ptr::NonNull, + capacity: usize, +} + +impl BufGuard { + // 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::() > 0); + + // SAFETY: See function safety description. + let layout = unsafe { unwrap_unchecked(Layout::array::(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 Drop for BufGuard { + 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::(self.capacity).unwrap()); + } + } +} diff --git a/library/alloc/tests/sort/mod.rs b/library/alloc/tests/sort/mod.rs new file mode 100644 index 0000000000000..0e2494ca9d34e --- /dev/null +++ b/library/alloc/tests/sort/mod.rs @@ -0,0 +1,17 @@ +pub trait Sort { + fn name() -> String; + + fn sort(v: &mut [T]) + where + T: Ord; + + fn sort_by(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 0000000000000..e5d31d868b251 --- /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 { + // . + // : . : : + // :.:::.:: + + random_vec(len) +} + +pub fn random_uniform(len: usize, range: R) -> Vec +where + R: Into> + 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 = range.into(); + (0..len).map(|_| dist.sample(&mut rng)).collect() +} + +pub fn random_zipf(len: usize, exponent: f64) -> Vec { + // 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 { + // .: + // .:::. : + // .::::::.:: + // [----][--] + // ^ ^ + // | | + // 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 { + // ...... + // :::::: + + (0..len).map(|_| 66).collect::>() +} + +pub fn ascending(len: usize) -> Vec { + // .: + // .::: + // .::::: + + (0..len as i32).collect::>() +} + +pub fn descending(len: usize) -> Vec { + // :. + // :::. + // :::::. + + (0..len as i32).rev().collect::>() +} + +pub fn saw_mixed(len: usize, saw_count: usize) -> Vec { + // :. :. .::. .: + // :::.:::..::::::..::: + + 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) -> Vec { + // :. + // :. :::. .::. .: + // :::.:::::..::::::..:.::: + + // 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 { + // .:. + // .:::::. + + 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 = 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 { + let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + (0..len).map(|_| rng.gen::()).collect() +} diff --git a/library/alloc/tests/sort/tests.rs b/library/alloc/tests/sort/tests.rs new file mode 100644 index 0000000000000..14e6013f965d8 --- /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(v: &mut [T]) { + let seed = patterns::get_or_init_rand_seed(); + + let is_small_test = v.len() <= 100; + let v_orig = v.to_vec(); + + ::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( + test_len: usize, + map_fn: impl Fn(i32) -> T, + pattern_fn: impl Fn(usize) -> Vec, +) { + let mut test_data: Vec = pattern_fn(test_len).into_iter().map(map_fn).collect(); + check_is_sorted::(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 { + 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 { + 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::().unwrap()) +} + +fn cell_i32_from_i32(val: i32) -> Cell { + Cell::new(val) +} + +fn i32_from_cell_i32(val: &Cell) -> i32 { + val.get() +} + +fn calc_comps_required(v: &mut [T], mut cmp_fn: impl FnMut(&T, &T) -> Ordering) -> u32 { + let mut comp_counter = 0u32; + + ::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, +} + +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)}() { + 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::(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::, 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::(len, string_from_i32, i32_from_string, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 3], + [$(($pattern_name, $pattern_fn),)*], + ); + }; +} + +// --- TESTS --- + +pub fn basic_impl() { + check_is_sorted::(&mut []); + check_is_sorted::<(), S>(&mut []); + check_is_sorted::<(), S>(&mut [()]); + check_is_sorted::<(), S>(&mut [(), ()]); + check_is_sorted::<(), S>(&mut [(), (), ()]); + check_is_sorted::(&mut []); + check_is_sorted::(&mut [77]); + check_is_sorted::(&mut [2, 3]); + check_is_sorted::(&mut [2, 3, 6]); + check_is_sorted::(&mut [2, 3, 99, 6]); + check_is_sorted::(&mut [2, 7709, 400, 90932]); + check_is_sorted::(&mut [15, -1, 3, -1, -3, -1, 7]); +} + +fn fixed_seed_impl() { + 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() { + 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() { + // Ensure that the sort can handle integer edge cases. + check_is_sorted::(&mut [i32::MIN, i32::MAX]); + check_is_sorted::(&mut [i32::MAX, i32::MIN]); + check_is_sorted::(&mut [i32::MIN, 3]); + check_is_sorted::(&mut [i32::MIN, -3]); + check_is_sorted::(&mut [i32::MIN, -3, i32::MAX]); + check_is_sorted::(&mut [i32::MIN, -3, i32::MAX, i32::MIN, 5]); + check_is_sorted::(&mut [i32::MAX, 3, i32::MIN, 5, i32::MIN, -3, 60, 200, 50, 7, 10]); + + check_is_sorted::(&mut [u64::MIN, u64::MAX]); + check_is_sorted::(&mut [u64::MAX, u64::MIN]); + check_is_sorted::(&mut [u64::MIN, 3]); + check_is_sorted::(&mut [u64::MIN, u64::MAX - 3]); + check_is_sorted::(&mut [u64::MIN, u64::MAX - 3, u64::MAX]); + check_is_sorted::(&mut [u64::MIN, u64::MAX - 3, u64::MAX, u64::MIN, 5]); + check_is_sorted::(&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::(&mut large); +} + +fn sort_vs_sort_by_impl() { + // 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(); + + ::sort(&mut input_normal); + ::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::(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::(len, extend_i32_to_u64, pattern_fn), + TEST_LENGTHS, + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_u128, + |len, pattern_fn| test_is_sorted::(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::, 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::( + 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::(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::(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::, S>(len, dyn_trait_from_i32, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn stability_legacy_impl() { + // 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 ::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. + ::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( + len: usize, + type_into_fn: impl Fn(i32) -> T, + _type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + if ::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. + ::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(len: usize, pattern_fn: fn(usize) -> Vec) { + // 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>> 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::>(); + + let mut comp_count_global = 0; + + ::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::, + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn panic_retain_orig_set( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + let mut test_data: Vec = 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::(&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(|| { + ::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(len: usize, pattern_fn: fn(usize) -> Vec) { + // 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>> 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::>(); + + 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::(&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(|| { + ::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::, + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn deterministic( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + // 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::>(); + + 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) + }; + + ::sort_by(&mut test_input, comparison_fn); + ::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( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + _type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + // 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::>(); + + let comparison_fn = |a: &T, b: &T| { + assert_ne!(a as *const T as usize, b as *const T as usize); + a.cmp(b) + }; + + ::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( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + // 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 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 = 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(|| { + ::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() { + ${concat($test_fn_name, _impl)}::(); + })* + + + 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(v: &mut [T]) + where + T: Ord, + { + v.sort_unstable(); + } + + fn sort_by(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(v: &mut [T]) + where + T: Ord, + { + v.sort(); + } + + fn sort_by(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 0000000000000..cc774ee5c43bf --- /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 { + 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(&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::() * (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 for ZipfDistribution { + fn sample(&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 107d82267e576..fca32b9d3c59d 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 05797b042ee4a..e2faef855bc2c 100644 --- a/library/core/src/array/ascii.rs +++ b/library/core/src/array/ascii.rs @@ -9,7 +9,6 @@ impl [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 24c42bc85dd91..a95046162d284 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -146,7 +146,8 @@ pub const fn from_ref(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(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 de212581e825e..8ccd1a44ff163 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -494,8 +494,9 @@ impl Cell { /// ``` #[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 Cell { /// ``` #[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 Cell { /// ``` #[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 Cell { /// ``` #[inline] #[stable(feature = "as_cell", since = "1.37.0")] - pub fn from_mut(t: &mut T) -> &Cell { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn from_mut(t: &mut T) -> &Cell { // SAFETY: `&mut` ensures unique access. unsafe { &*(t as *mut T as *const Cell) } } @@ -662,7 +666,7 @@ impl Cell { impl, U> CoerceUnsized> for Cell {} // 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 Cell<[T]> { /// assert_eq!(slice_cell.len(), 3); /// ``` #[stable(feature = "as_cell", since = "1.37.0")] - pub fn as_slice_of_cells(&self) -> &[Cell] { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn as_slice_of_cells(&self) -> &[Cell] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T]> as *const [Cell]) } } @@ -706,7 +711,8 @@ impl Cell<[T; N]> { /// let array_cell: &[Cell; 3] = cell_array.as_array_of_cells(); /// ``` #[unstable(feature = "as_array_of_cells", issue = "88248")] - pub fn as_array_of_cells(&self) -> &[Cell; N] { + #[rustc_const_unstable(feature = "as_array_of_cells", issue = "88248")] + pub const fn as_array_of_cells(&self) -> &[Cell; N] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T; N]> as *const [Cell; N]) } } @@ -2175,7 +2181,8 @@ impl UnsafeCell { /// ``` #[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 From for UnsafeCell { impl, U> CoerceUnsized> for UnsafeCell {} // 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 From for SyncUnsafeCell { impl, U> CoerceUnsized> for SyncUnsafeCell {} // 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 7f3c998aaa5bc..6bedb0d0dc4e5 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 cac00b37d1fa7..95a39cc3aed38 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 b213cc2b9167c..0685f525dca83 100644 --- a/library/core/src/escape.rs +++ b/library/core/src/escape.rs @@ -18,38 +18,106 @@ const fn backslash(a: ascii::Char) -> ([ascii::Char; N], Range(byte: u8) -> ([ascii::Char; N], Range) { + 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(a: ascii::Char) -> ([ascii::Char; N], Range) { + 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(byte: u8) -> ([ascii::Char; N], Range) { 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 c7c462a4df1f5..3d0c9f7c96414 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); @@ -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); @@ -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 d7a2f1909cabe..e3b4628e1846a 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); @@ -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(ptr: *mut T, value: T); @@ -3472,13 +3525,13 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] -#[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(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(dst: *mut T, val: u8, count: usize); } diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index fb0aa5398a55b..a2ab39caade53 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 7963459bfb5d9..302720eddef22 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) {} +fn _assert_is_dyn_compatible(_: &dyn Iterator) {} /// A trait for dealing with iterators. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 817d9e3b962e3..08c0d6e34cd02 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 fd41b80cdbd0a..aed6be4c6277b 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` 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>` @@ -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 c67796ad3db83..f992785c43bb7 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -913,7 +913,11 @@ impl MaybeUninit { /// }; /// ``` #[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 MaybeUninit { /// /// [`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 414262fcf5ab1..9bf2aa594c047 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -857,7 +857,8 @@ pub fn take(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(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 919f681f911f9..d3360c1820719 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 100271fa54c1f..764df4fe4b058 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 6bdc569df28bd..897fc8c105d46 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::(mem::transmute::(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 d0eb6bb3f2879..a9a2595c25c29 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::(mem::transmute::(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 4bc275ad14786..aa7a54ca65080 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::(mem::transmute::(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 ab73dc19fcc73..7a8158b823185 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -171,14 +171,13 @@ impl ControlFlow { /// # Examples /// /// ``` - /// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// assert_eq!(ControlFlow::::Break(3).break_value(), Some(3)); /// assert_eq!(ControlFlow::::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 { match self { ControlFlow::Continue(..) => None, @@ -189,11 +188,8 @@ impl ControlFlow { /// Maps `ControlFlow` to `ControlFlow` 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(self, f: F) -> ControlFlow - where - F: FnOnce(B) -> T, - { + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] + pub fn map_break(self, f: impl FnOnce(B) -> T) -> ControlFlow { match self { ControlFlow::Continue(x) => ControlFlow::Continue(x), ControlFlow::Break(x) => ControlFlow::Break(f(x)), @@ -206,14 +202,13 @@ impl ControlFlow { /// # Examples /// /// ``` - /// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// assert_eq!(ControlFlow::::Break(3).continue_value(), None); /// assert_eq!(ControlFlow::::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 { match self { ControlFlow::Continue(x) => Some(x), @@ -224,11 +219,8 @@ impl ControlFlow { /// Maps `ControlFlow` to `ControlFlow` 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(self, f: F) -> ControlFlow - where - F: FnOnce(C) -> T, - { + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] + pub fn map_continue(self, f: impl FnOnce(C) -> T) -> ControlFlow { 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 25c4b87f4e76b..5464bf645d978 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 b51f12580ea4f..d2a07197f6f6a 100644 --- a/library/core/src/ops/unsize.rs +++ b/library/core/src/ops/unsize.rs @@ -68,8 +68,8 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} #[unstable(feature = "coerce_unsized", issue = "18598")] impl, 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, 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, U: ?Sized> CoerceUnsized<*const U> for *const T {} /// T: Unsize, /// {} /// ``` +/// +/// [^1]: Formerly known as *object safety*. #[unstable(feature = "dispatch_from_dyn", issue = "none")] #[lang = "dispatch_from_dyn"] pub trait DispatchFromDyn { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 154e52e288bc1..84ccb7a1f6680 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -723,7 +723,8 @@ impl Option { /// ``` #[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 Option { #[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 Option { #[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 Option { #[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 Option { /// ``` #[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 { // FIXME(const-hack) replace `mem::replace` by `mem::take` when the latter is const ready mem::replace(self, None) @@ -1769,8 +1774,9 @@ impl Option { /// 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 { mem::replace(self, Some(value)) } @@ -1878,7 +1884,7 @@ impl 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 where T: Copy, @@ -1931,7 +1937,8 @@ impl 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 where T: Copy, @@ -1986,7 +1993,8 @@ impl Option> { /// ``` #[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, 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 Option> { /// ``` #[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 { // 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 962da6643ddb1..89936dc12ac36 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 332c5e904d7e0..c9af7f13e46c4 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -395,6 +395,36 @@ impl *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::(), + ) => 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 *const T { true } - #[allow(unused_unsafe)] intrinsics::const_eval_select((this, origin), comptime, runtime) } @@ -858,6 +887,36 @@ impl *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::(), + ) => 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 *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::(), + ) => 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 *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 b6df780fe2f4a..6b07449292417 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(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(data: *mut T, len: usize) -> *mut [T] { from_raw_parts_mut(data, len) @@ -1263,7 +1263,8 @@ const unsafe fn swap_nonoverlapping_simple_untyped(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(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(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(dst: *mut T, src: T) { @@ -1719,7 +1720,8 @@ pub const unsafe fn write(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(dst: *mut T, src: T) { @@ -1909,6 +1911,7 @@ pub unsafe fn write_volatile(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(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 287073497f825..ced6cb7d520de 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -393,6 +393,37 @@ impl *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::(), + ) => 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 *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::(), + ) => 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 *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::(), + ) => 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 *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 *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 *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 *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 e7a265f7e2b7d..980d4a3cf6ceb 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -394,7 +394,8 @@ impl NonNull { /// /// [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 NonNull { #[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 NonNull { #[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 NonNull { #[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 NonNull { /// /// ``` /// #![feature(const_nonnull_new)] - /// #![feature(const_option)] /// #![feature(const_pointer_is_aligned)] /// use std::ptr::NonNull; /// @@ -1263,7 +1263,6 @@ impl NonNull { /// /// ``` /// #![feature(const_pointer_is_aligned)] - /// #![feature(const_option)] /// #![feature(const_nonnull_new)] /// use std::ptr::NonNull; /// @@ -1433,7 +1432,10 @@ impl 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, len: usize) -> Self { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 610edae48d36b..95faacbf96db7 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -734,7 +734,8 @@ impl Result { /// ``` #[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 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 where T: Copy, @@ -1586,7 +1588,9 @@ impl 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 where T: Copy, @@ -1639,7 +1643,8 @@ impl Result, 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> { 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 922168b9e8ef0..90ddc9c1d85d6 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -171,7 +171,8 @@ impl [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] { /// 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] { /// 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] { /// 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] { /// ``` #[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(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -417,7 +422,8 @@ impl [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( &mut self, ) -> Option<(&mut [T; N], &mut [T])> { @@ -487,7 +493,8 @@ impl [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( &mut self, ) -> Option<(&mut [T], &mut [T; N])> { @@ -556,7 +563,8 @@ impl [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(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -1899,7 +1907,8 @@ impl [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] { /// 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] { /// 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 2cf3fecb47542..998f9360332ff 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(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(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 d6459607221ae..194db56fdafda 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 3d535214637f6..e93c52f27999e 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 65560dfcf9d2d..f7ea7e06e9cdb 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 db2e3ddd754f5..cba53bf5054e6 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 3d3f8ac10c603..ce09ee507f11f 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 03826fc4c92cd..bf91e9e5df0e2 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 = &RandomState::new(); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4f2190f78bf59..37e7db1157c89 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 a10b51c550d5b..707f9a160e127 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 7197f3812e542..9ae2bcc852649 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1800,57 +1800,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::() % 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 diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 5522d556a5975..72b597a8083ba 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 63c65b8ef3994..358bd25ff1bc6 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 7d37d4e9d7d83..032326556bd5b 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 ("arm64ec", _) => false, // MinGW ABI bugs - ("x86_64", "windows") if target_env == "gnu" => false, + ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion ("csky", _) => false, ("hexagon", _) => false, @@ -129,7 +130,7 @@ fn main() { // ABI unsupported ("sparc", _) => false, // MinGW ABI bugs - ("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 124ef121b186c..675140ff18f5f 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 dd6458c38c6e9..8fedcb241d095 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 { skip_until(self, byte) } diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index bf242e715bd94..35b38ed783ff2 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 9f4d244b5479e..453b2708daab9 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 65a9aa66c7cc6..057a57f799772 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 33b50c9e53b8f..2ee6aa4660094 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 0a841f07e3be7..80e7c3c026bd7 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 44913ffe3a9ff..c966886d16344 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 { } } -fn addr_to_sockaddr(addr: &Option) -> io::Result { - addr.as_ref() - .ok_or(io::ErrorKind::AddrNotAvailable)? +fn addr_to_sockaddr(addr: Option<&str>) -> io::Result { + 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 { - addr_to_sockaddr(&self.peer_addr) + addr_to_sockaddr(self.peer_addr.as_deref()) } pub fn socket_addr(&self) -> io::Result { - 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 { - 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 39aabf0b2d679..567577b2b4d23 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 { 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 { let info = Box::::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 d9c41d4348756..13290fed762ae 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 { - &self.cwd + pub fn get_cwd(&self) -> Option<&CStr> { + self.cwd.as_deref() } #[allow(dead_code)] pub fn get_uid(&self) -> Option { 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 5d30f388da18e..4551d49e841f7 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 2d9a304c49512..38daf6af91808 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 2f2d6e6add396..040246618360f 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 c40eb229ba9a4..06e623df8438e 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 { @@ -327,53 +328,90 @@ impl Socket { } } -impl AsInner for Socket { +impl AsInner for WasiSocket { #[inline] - fn as_inner(&self) -> &WasiFd { + fn as_inner(&self) -> &OwnedFd { &self.0 } } -impl IntoInner for Socket { - fn into_inner(self) -> WasiFd { +impl IntoInner for WasiSocket { + fn into_inner(self) -> OwnedFd { self.0 } } -impl FromInner for Socket { - fn from_inner(inner: WasiFd) -> Socket { - Socket(inner) +impl FromInner 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 for TcpListener { +impl AsInner for Socket { + #[inline] + fn as_inner(&self) -> &WasiSocket { + &self.0 + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> WasiSocket { + self.0 + } +} + +impl FromInner 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 b65ad7dbe8c5a..9ce3e912caf1b 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 c8e25dd0c94ba..42999da166451 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 { - // 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 1ea253e5e5263..a9886012e8ee9 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 6849cacf88e76..d0c998a559737 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 5b5e7770b0627..986cd0cb7d188 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); pub struct Condvar { - inner: LazyBox, + inner: OnceBox, mutex: AtomicPtr, } -#[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 { +impl AllocatedCondvar { + fn new() -> Box { 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 ecb5872f60d90..e60715e4b592e 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>); - pub struct Condvar { - inner: LazyBox, -} - -impl LazyInit for AllocatedCondvar { - fn init() -> Box { - Box::new(AllocatedCondvar(SpinMutex::new(WaitVariable::new(())))) - } + // FIXME: `UnsafeList` is not movable. + inner: OnceBox>>, } impl Condvar { pub const fn new() -> Condvar { - Condvar { inner: LazyBox::new() } + Condvar { inner: OnceBox::new() } + } + + fn get(&self) -> &SpinMutex> { + 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 943867cd76169..0000000000000 --- 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); - -pub struct Condvar { - inner: LazyBox, - mutex: AtomicPtr, -} - -#[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 { - 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 52fac5902a296..0691e96785198 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 73d9bd273de17..360df3fc4b55d 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 1c407bc253776..87c95f45f964e 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); pub struct Mutex { - inner: LazyBox, -} - -#[inline] -pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { - m.inner.0.get() + inner: OnceBox, } unsafe impl Send for AllocatedMutex {} unsafe impl Sync for AllocatedMutex {} -impl LazyInit for AllocatedMutex { - fn init() -> Box { +impl AllocatedMutex { + fn new() -> Box { 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) { - // 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) { - // 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 65d1e880f7baf..8529e85797043 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>); +use crate::sys::sync::OnceBox; pub struct Mutex { - inner: LazyBox, -} - -impl LazyInit for AllocatedMutex { - fn init() -> Box { - Box::new(AllocatedMutex(SpinMutex::new(WaitVariable::new(false)))) - } + // FIXME: `UnsafeList` is not movable. + inner: OnceBox>>, } // 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> { + 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 0000000000000..1422b5a172162 --- /dev/null +++ b/library/std/src/sys/sync/once_box.rs @@ -0,0 +1,82 @@ +//! A racily-initialized alternative to `OnceLock>`. +//! +//! 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 { + ptr: AtomicPtr, +} + +impl OnceBox { + #[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 { + 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> { + 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 { + 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 Send for OnceBox {} +unsafe impl Sync for OnceBox {} + +impl Drop for OnceBox { + 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 ef9b1ab51546c..763430223834b 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 0ebc5e093ee2a..f4d8fa0a58c11 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 . 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 b45b05f63baaa..0000000000000 --- 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 { - ptr: AtomicPtr, - _phantom: PhantomData, -} - -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; - - /// 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::destroy(x); - } - - /// This is called to destroy a used box. - /// - /// The default implementation just drops it. - fn destroy(_: Box) {} -} - -impl LazyBox { - #[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 Deref for LazyBox { - type Target = T; - #[inline] - fn deref(&self) -> &T { - unsafe { &*self.get_pointer() } - } -} - -impl DerefMut for LazyBox { - #[inline] - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.get_pointer() } - } -} - -impl Drop for LazyBox { - 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 aa27886ff6f9c..4f7a131f6bb90 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 b38149a0da740..e6eb90c4c30a5 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 d1d4eabb9bd45..3975388850998 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); 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 = Mutex::new(1); + static COUNTER: Mutex = 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 dcd5cd7f6b9c7..dd14c0266aa4d 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 index ace72223a0e32..c881fe3231b39 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit ace72223a0e321c1b0a37b5862aa756fe8ab5111 +Subproject commit c881fe3231b3947a4766aa15a26a93022fbb8723 diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 4b2c65cfdf548..30ccfe2af8dbd 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 c5f4b03bfc96c..79fe07bc1ac5c 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, - exec_time: &Option, + 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, - exec_time: &Option, + 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 46026324d2f82..5a476d5843b2f 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 f4ffac1ba16da..2d36a8be00469 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::(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 0ac58645d2dfc..f036603ee707b 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 b9df7336cca0b..e9ec79e417b20 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::>(); @@ -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 d04e2fbeb7853..18f5a1a58db93 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 7671fc7e013b7..f419bebdc1263 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 eaa982d4e2bbd..27bbc8bd8ff22 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 for details. + // + // Also see the discussion for properly handling I/O errors related to broken pipes, i.e. safe + // variants of `println!` in + // . 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 3d504c3771fb2..ca2b874264788 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 952d8d73328fb..5ca4321d85555 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>, 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 3021358415790..a2d40f6fbd891 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 0ee2cb451f39c..519649779336c 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> { + 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 { - 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 { + 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 { } } 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 { } }; 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 { // 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 3552224f33b56..f3d4b6aa4db6e 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 7283b0e9574c5..e25b571acbac5 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 64dfe054d9c77..a01497c2bb98a 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 + // . + // + // For the rustc discussion, see + // + // 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 c35384ce3c0be..9ac0b0a01f7ee 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::>(); + 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 bd81dc930be05..695a66834d45d 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!(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 07460b81412ac..f768470c4ff0e 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, pub rust_lto: RustcLto, pub rust_validate_mir_opts: Option, + pub rust_std_features: BTreeSet, pub llvm_profile_use: Option, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option, @@ -1152,6 +1155,7 @@ define_config! { download_rustc: Option = "download-rustc", lto: Option = "lto", validate_mir_opts: Option = "validate-mir-opts", + std_features: Option> = "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) -> Option { + fn download_ci_rustc_commit( + &self, + download_rustc: Option, + llvm_assertions: bool, + ) -> Option { + 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 87db5f93fb03c..3aefe517a5be6 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 = "|hook|vscode|link")] + #[arg(value_name = "|hook|editor|link")] profile: Option, }, /// 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 e38d4eac051d8..2611b6cf51bbe 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 = + ["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 = 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 444b75876f248..db1f5b0833826 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 888ba8e2a3f75..6fbdd76ed5b6c 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 75659f46431af..3924a6d714e3b 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::>().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 e6f7f105fa27a..b37786496cb56 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 7150c84313c55..6d3c276cc056d 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 865a9e32fa92b..71eb72686b06a 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 62dbfaaa67315..5081f25e56743 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 571378774be01..0f8ebb987c3aa 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 ba3e8bdb68754..0cae83a85b3a4 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 6a09ab3065ffa..17fc1a5749299 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 fad4b5af0953f..28487bce48280 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 3f5e2c6ff1dca..8b2b39ee1629e 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 8011e07e92e60..27dbfc6040ce0 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 98290f5a72cd8..dea38b6fd2a4a 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 6379f1ade1ce8..8f49f623afaa4 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 c8201d9bcfd27..3962c354c10e5 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 0000000000000..52b4c98a89016 --- /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 2b0a10e4d08d9..1e6a008a5de81 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 index 99cf75a5414fa..f38ce8baef98c 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 99cf75a5414fa8adbe3974bd0836661ca901708f +Subproject commit f38ce8baef98cb20229e56f1be2d50e345f11792 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index dbae36bf3f841..f40a8b420ec4b 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit dbae36bf3f8410aa4313b3bad42e374735d48a9d +Subproject commit f40a8b420ec4b4505d9489965e261f1d5c28ba23 diff --git a/src/doc/nomicon b/src/doc/nomicon index 14649f15d232d..456b904f79175 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 14649f15d232d509478206ee9ed5105641aa60d0 +Subproject commit 456b904f791751892b01282fd2757904993c4c26 diff --git a/src/doc/reference b/src/doc/reference index 24fb2687cdbc5..c64e52a3d306e 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 24fb2687cdbc54fa18ae4acf5d879cfceca77b2c +Subproject commit c64e52a3d306eac0129f3ad6c6d8806ab99ae2e9 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index c79ec345f08a1..8bede1b919a81 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit c79ec345f08a1e94494cdc8c999709a90203fd88 +Subproject commit 8bede1b919a81ab7d0c961f6bbf68d3efa297bd2 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 555f3de2fa0d6..07bc9ca9eb1cd 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 555f3de2fa0d61c4294b74d245f1cbad6fcbf589 +Subproject commit 07bc9ca9eb1cd6d9fbbf758c2753b748804a134f diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 207eb5d6d4f76..0ef95ba64a1f5 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 e72bfb8bae767..32e4f85531375 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 9a27a568b5703..38742143c4ba2 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 0000000000000..69f08774f8381 --- /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, , [@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 0000000000000..ad795ff9d9b26 --- /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 2aa0d9f69cc87..ba7f2c9fb5d66 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 [|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 [|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 e55d80d98dec3..7b4309f8e188f 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 267392190858c..9255242611afc 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, ) -> Result, 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 { - Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) + pub(crate) fn parse(cfg: &MetaItemInner) -> Result { + 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 0ab655103e293..2c62e12c96dc1 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 b79458eaa7890..fa73733360ca1 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 a3277e8ca921e..bc5bf4c05838a 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 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>, + pub(crate) external_traits: Box>, } impl Crate { @@ -952,7 +953,7 @@ pub(crate) struct Module { } pub(crate) trait AttributesExt { - type AttributeIterator<'a>: Iterator + type AttributeIterator<'a>: Iterator where Self: 'a; type Attributes<'a>: Iterator @@ -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 + 'a; + type AttributeIterator<'a> = impl Iterator + 'a; type Attributes<'a> = impl Iterator + 'a; fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { @@ -1071,7 +1072,7 @@ impl AttributesExt for [ast::Attribute] { impl AttributesExt for [(Cow<'_, ast::Attribute>, Option)] { type AttributeIterator<'a> - = impl Iterator + 'a + = impl Iterator + '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; + fn get_word_attr(self, word: Symbol) -> Option; } -impl> NestedAttributesExt for I { - fn get_word_attr(mut self, word: Symbol) -> Option { +impl> NestedAttributesExt for I { + fn get_word_attr(mut self, word: Symbol) -> Option { 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 + '_ { + pub(crate) fn lists(&self, name: Symbol) -> impl Iterator + '_ { 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>; +type SimplifiedTypes = FxIndexMap>; 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 { - static PRIMITIVE_LOCATIONS: OnceCell> = OnceCell::new(); + pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap { + static PRIMITIVE_LOCATIONS: OnceCell> = 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 { + pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet { self.trait_ .as_ref() .map(|t| t.def_id()) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 7a37f5c70a592..2cd69474b1cf0 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, + pub(crate) default_settings: FxIndexMap, /// 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 4c48c075a944d..aaf4c80f99763 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, + pub(crate) external_traits: FxIndexMap, /// 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 4e7571a480380..d5bc2a93fa807 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::>(); + let extern_names = + externs.iter().map(|(name, _)| name).collect::>(); let mut unused_extern_names = unused_extern_reports .iter() - .map(|uexts| uexts.unused_extern_names.iter().collect::>()) + .map(|uexts| uexts.unused_extern_names.iter().collect::>()) .fold(extern_names, |uextsa, uextsb| { - uextsa.intersection(&uextsb).copied().collect::>() + uextsa.intersection(&uextsb).copied().collect::>() }) .iter() .map(|v| (*v).clone()) @@ -253,7 +254,7 @@ pub(crate) fn run_tests( rustdoc_options: &Arc, unused_extern_reports: &Arc>>, mut standalone_tests: Vec, - mergeable_tests: FxHashMap>, + mergeable_tests: FxIndexMap>, ) { 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, - mergeable_tests: FxHashMap>, + mergeable_tests: FxIndexMap>, rustdoc_options: Arc, 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 326ca4ee1e68f..942ec8d9936cf 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, + crate_attrs: FxIndexSet, 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 db1a0bd0af938..ff0d537b19f75 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, ItemType)>, + pub(crate) paths: FxIndexMap, 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, + pub(crate) traits: FxIndexMap, /// 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>, + pub(crate) implementors: FxIndexMap>, /// Cache of where external crate documentation can be found. - pub(crate) extern_locations: FxHashMap, + pub(crate) extern_locations: FxIndexMap, /// Cache of where documentation for primitives can be found. - pub(crate) primitive_locations: FxHashMap, + pub(crate) primitive_locations: FxIndexMap, // 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, Impl)>, + orphan_trait_impls: Vec<(DefId, FxIndexSet, 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 691f86847b56d..31a2701f06a54 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 FmRadio, which is technically + // correct, but needlessly bloated. + // + // is_uppercase && !next_is_uppercase checks for camelCase. HTTPSProxy, + // for example, should become HTTPSProxy. + // + // !next_is_underscore avoids turning TEST_RUN into TEST_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("")?; last = i; diff --git a/src/librustdoc/html/escape/tests.rs b/src/librustdoc/html/escape/tests.rs index a09649e9e18dc..de702e1606353 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:second"); assert_eq!(&E("first::second").to_string(), "first::second"); assert_eq!(&E("MY_CONSTANT").to_string(), "MY_CONSTANT"); + assert_eq!( + &E("_SIDD_MASKED_NEGATIVE_POLARITY").to_string(), + "_SIDD_MASKED_NEGATIVE_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 69b3421f8881f..b68b729509635 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 75328e724fea8..fd5275189d661 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 3684dc42ac73c..31ccfeb38738c 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, + pub(crate) default_settings: FxIndexMap, 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 8ae5484feda7a..5dacabd031e06 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>> Iterator for SummaryLine<'a, I> { /// references. struct Footnotes<'a, I> { inner: I, - footnotes: FxHashMap>, u16)>, + footnotes: FxIndexMap>, 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>, u16) { @@ -694,7 +693,7 @@ impl<'a, I: Iterator>> 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("

      "); 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, 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 { - let mut display_text: Option = 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 bce3f21890857..dc4d45e592eb7 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, + pub(crate) types_with_notable_traits: FxIndexSet, /// 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, + pub(crate) local_sources: FxIndexMap, /// 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 227df0c5f3930..399730a01c82f 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, - enums: FxHashSet, - unions: FxHashSet, - primitives: FxHashSet, - traits: FxHashSet, - macros: FxHashSet, - functions: FxHashSet, - type_aliases: FxHashSet, - statics: FxHashSet, - constants: FxHashSet, - attribute_macros: FxHashSet, - derive_macros: FxHashSet, - trait_aliases: FxHashSet, + structs: FxIndexSet, + enums: FxIndexSet, + unions: FxIndexSet, + primitives: FxIndexSet, + traits: FxIndexSet, + macros: FxIndexSet, + functions: FxIndexSet, + type_aliases: FxIndexSet, + statics: FxIndexSet, + constants: FxIndexSet, + attribute_macros: FxIndexSet, + derive_macros: FxIndexSet, + trait_aliases: FxIndexSet, } 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, kind: ItemSection) { + fn print_entries(f: &mut Buffer, e: &FxIndexSet, 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), + GotoSource(ItemId, &'a FxIndexSet), } 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("
      "); - 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(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 38276e4d20c26..3c96f8736814e 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 660ca3b2594cc..c958458b662c2 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, - rgen: &mut FxHashMap)>, + rgen: &mut FxIndexMap)>, ) -> 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)>, + rgen: &mut FxIndexMap)>, ) -> Option { 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, - rgen: &mut FxHashMap)>, + rgen: &mut FxIndexMap)>, 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)>, - rgen: &mut FxHashMap)>, + rgen: &mut FxIndexMap)>, is_return: bool, cache: &Cache, ) { @@ -1285,7 +1285,7 @@ fn get_fn_inputs_and_outputs<'tcx>( ) -> (Vec, Vec, Vec>) { let decl = &func.decl; - let mut rgen: FxHashMap)> = Default::default(); + let mut rgen: FxIndexMap)> = 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 2143f1ff23650..b314b060368aa 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, FxHashMap) { +) -> (FxIndexMap, FxHashMap) { 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 af94b1042c05c..12b6346005697 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, elem: OsString, - children: RefCell>>, - elems: RefCell>, + children: RefCell>>, + elems: RefCell>, } impl Hierarchy { @@ -961,8 +961,8 @@ impl Serialize for AliasSerializableImpl { fn get_path_parts( dst: &Path, crates_info: &[CrateInfo], -) -> FxHashMap> { - let mut templates: FxHashMap> = FxHashMap::default(); +) -> FxIndexMap> { + let mut templates: FxIndexMap> = 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 7be9cc0b8858e..f4a0ef01c253b 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 { - let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root }; +) -> FxIndexMap { + 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, + local_sources: FxIndexMap, src_root: &'a Path, } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index beac7e73c62d2..df9776ff5f88c 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 b411f9a1a52d0..b8791c9918b12 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, + extra: Option, + ) -> Id { + let make_part = |def_id: DefId, name: Option, extra: Option| { + 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) -> Vec { + 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, + ) -> Vec> { + items + .into_iter() + .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(&i))) + .collect() + } } -pub(crate) trait FromWithTcx { - fn from_tcx(f: T, tcx: TyCtxt<'_>) -> Self; +pub(crate) trait FromClean { + fn from_clean(f: T, renderer: &JsonRenderer<'_>) -> Self; } -pub(crate) trait IntoWithTcx { - fn into_tcx(self, tcx: TyCtxt<'_>) -> T; +pub(crate) trait IntoJson { + fn into_json(self, renderer: &JsonRenderer<'_>) -> T; } -impl IntoWithTcx for T +impl IntoJson for T where - U: FromWithTcx, + U: FromClean, { - 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 FromWithTcx for Vec +impl FromClean for Vec where I: IntoIterator, - U: FromWithTcx, + U: FromClean, { - fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec { - f.into_iter().map(|x| x.into_tcx(tcx)).collect() + fn from_clean(f: I, renderer: &JsonRenderer<'_>) -> Vec { + 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 for GenericArgs { - fn from_tcx(args: clean::GenericArgs, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for GenericArg { - fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Constant { +impl FromClean 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 for Constant { } } -impl FromWithTcx for Constant { +impl FromClean 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 for Constant { } } -impl FromWithTcx for AssocItemConstraint { - fn from_tcx(constraint: clean::AssocItemConstraint, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for AssocItemConstraintKind { - fn from_tcx(kind: clean::AssocItemConstraintKind, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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, - extra: Option<&Id>, -) -> Id { - struct DisplayDefId<'a, 'b>(DefId, TyCtxt<'a>, Option<&'b Id>, Option); - - 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 for Struct { - fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Union { - fn from_tcx(union_: clean::Union, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Generics { - fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for GenericParamDef { - fn from_tcx(generic_param: clean::GenericParamDef, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for GenericParamDefKind { - fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for WherePredicate { - fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 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 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 for GenericBound { - fn from_tcx(bound: clean::GenericBound, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Type { - fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Path { - fn from_tcx(path: clean::Path, tcx: TyCtxt<'_>) -> Path { +impl FromClean 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 for Term { - fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term { +impl FromClean 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 for FunctionPointer { - fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 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 for FunctionSignature { - fn from_tcx(decl: clean::FnDecl, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Trait { - fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 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 for PolyTrait { - fn from_tcx( +impl FromClean 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 for Impl { - fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self { - let provided_trait_methods = impl_.provided_trait_methods(tcx); +impl FromClean 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 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, 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 for Enum { - fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Variant { - fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Variant { } } -impl FromWithTcx for Discriminant { - fn from_tcx(disr: clean::Discriminant, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Discriminant { } } -impl FromWithTcx for Use { - fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 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 for ProcMacro { - fn from_tcx(mac: clean::ProcMacro, _tcx: TyCtxt<'_>) -> Self { +impl FromClean 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> for TypeAlias { - fn from_tcx(type_alias: Box, tcx: TyCtxt<'_>) -> Self { +impl FromClean> for TypeAlias { + fn from_clean(type_alias: Box, 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 for Static { - fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self { +impl FromClean 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 for Static { } } -impl FromWithTcx 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 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 for ItemKind { - fn from_tcx(kind: ItemType, _tcx: TyCtxt<'_>) -> Self { +impl FromClean for ItemKind { + fn from_clean(kind: ItemType, _renderer: &JsonRenderer<'_>) -> Self { use ItemType::*; match kind { Module => ItemKind::Module, @@ -878,25 +886,3 @@ impl FromWithTcx for ItemKind { } } } - -fn ids(items: impl IntoIterator, tcx: TyCtxt<'_>) -> Vec { - 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, - tcx: TyCtxt<'_>, -) -> Vec> { - 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 b7a683eed1c2f..df97c5ea2634a 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, + /// Used to distinguish imports of different items with the same name + extra: Option, +} + #[derive(Clone)] pub(crate) struct JsonRenderer<'tcx> { tcx: TyCtxt<'tcx>, @@ -46,6 +55,7 @@ pub(crate) struct JsonRenderer<'tcx> { out_dir: Option, cache: Rc, imported_items: DefIdSet, + id_interner: Rc), 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 2be415e2e0ef3..10fc0ea999015 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 0dba16cbaf32f..db235786cf49a 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, - 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, - 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 b307e84e42ec2..d1a1f0df3e7ed 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 848e70a7bdbab..e0dc5b4c51333 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> { + fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { None } @@ -169,7 +169,7 @@ impl Emitter for BufferEmitter { } } - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { None } } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 9d4d203562cb4..a59c43bfbf904 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; -pub(crate) type AllCallLocations = FxHashMap; +pub(crate) type FnCallLocations = FxIndexMap; +pub(crate) type AllCallLocations = FxIndexMap; /// 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, 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 409728a8e867c..2c00bb7e13295 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, - pub(crate) children: FxHashMap, + pub(crate) rules: FxIndexMap, + pub(crate) children: FxIndexMap, } /// 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>, - paths: &mut FxHashMap, + paths: &mut FxIndexMap, ) -> 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>, - paths: &mut FxHashMap, + paths: &mut FxIndexMap, ) -> 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, String> { +pub(crate) fn load_css_paths(content: &str) -> Result, 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, - against: &FxHashMap, + origin: &FxIndexMap, + against: &FxIndexMap, v: &mut Vec, ) { for (selector, entry) in origin.iter() { @@ -235,7 +234,7 @@ pub(crate) fn get_differences( pub(crate) fn test_theme_against>( f: &P, - origin: &FxHashMap, + origin: &FxIndexMap, dcx: DiagCtxtHandle<'_>, ) -> (bool, Vec) { let against = match fs::read_to_string(f) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c44e5ecaba81c..f789aca73784d 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 index 56997739365e8..3a17f74904a74 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 56997739365e8132cc817e00899480746c09d7d9 +Subproject commit 3a17f74904a74565c54cfac0d67026362d038698 diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index b3707cf615714..fc64bc98bb981 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 10c5476cd8f3b..2aad5650fa898 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> { - 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 { - 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 index 80d82ca22abbe..15fbd2f607d4d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 80d82ca22abbee5fb7b51fa1abeb1ae34e99e88a +Subproject commit 15fbd2f607d4defc87053b8b76bf5038f2483cf4 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 40959eccd3a9f..5d4e864b9b0b5 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 508963a20ea71..0baf889faa076 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 888f28fa2258c..1a34ca99fc2b9 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 877025cce4c2b..7eff5eccfa138 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 12668c616c13e..72e6ce59d5980 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 91ae19acbf7f6..9b10ae8365149 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 { +pub(super) fn extract_clippy_lint(lint: &MetaItemInner) -> Option { 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 884d15cabffcb..84136a2e6c28f 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 796af851bac0a..6ad879b9fe7ae 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 6794c6cabfeef..5f349d780537b 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 73ebe6aec15a0..96550c4d1cb95 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::>(); + .collect::>(); 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 45346cd18a61b..311bbce14bd7e 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 2eb6d99b761f7..6ee064a6124b9 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 5c37e73544577..ec28671a061e4 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 { +fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet { 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>, + map: FxIndexMap>, where_predicate_depth: usize, generic_args_depth: usize, phantom: std::marker::PhantomData, @@ -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>, + map: &FxIndexMap>, ) { 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 745f070a577d5..214b8b0f37922 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>, /// 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, Ty<'tcx>)>, + indexed_directly: FxIndexMap, 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, 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 7097c85156c34..81115cffdca88 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)> { - 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 7372f52e1e5bd..2ce6a8a85a5eb 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, + found_sig_drop_spans: FxIndexSet, } 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::::default(), + found_sig_drop_spans: FxIndexSet::::default(), } } } -fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxHashSet { +fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxIndexSet { 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 b40d7eba15e5e..c56a4014b3494 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 { } /// 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>>) { +fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnindexMap>>) { 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>>) { +fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnindexMap>>) { 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>>) { +fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap>>) { 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> 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 64fc1a8a1a580..007bcebdff650 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 d342be4545cea..f95a0f63fab7a 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 e9c5f64a2550d..676d608eb318c 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 c2facb2fcf68c..5c631a176c4af 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, - closures: FxHashSet, + closures: FxIndexSet, ) { 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 = FxHashSet::default(); + let mut closures: FxIndexSet = 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, - async_closures: FxHashSet, + async_closures: FxIndexSet, tcx: TyCtxt<'tcx>, } diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 1f223048ce5ce..662745e4b5d67 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 a3145c4647cab..6cba560393d0d 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 00277593622aa..3c3973857e796 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 08449de79b364..f5cf4a586fd29 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 9143d292f670f..bfb3a76ad251c 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 514ec70a40bf7..10e258444a676 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 4ad7575e7201f..eecbfb3936ac4 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 baf939af24efb..cdb8fa0454cd4 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 e300ba18c3309..e53d53db5f7a4 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 320578bfabce0..b58ce9b8af3e4 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 8d1dbface8eba..0000000000000 --- 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 e352519142332..bda9221a5e1e9 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 80606c2db054a..8244254026be7 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 edfffe8fcfe36..355f2bc773611 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 3c0f6913e3289..9ced267762210 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 62beb195939c6..2dd3c30a4e29b 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 1e09ff5c67e51..94226564cacb5 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 0f8b279da1e7a..8eacb249c60c6 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 ca422e605d666..aa2a274525bce 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) -> Option { diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index aad6e13136f1a..bf67cfd3698a1 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) -> Option { diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index da0fa220d8c4a..d3c2a6badc0f4 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 83814ca43b96d..075a198918a0d 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 64d6e9172039d..12541b2f7cf32 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 e95054a7ccb0e..617d32d1fa793 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

      (ptr: *const P) { - unsafe { transmute::<*const i32, usize>(&42i32) }; - unsafe { transmute::(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::(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 e5fcdef7a1c39..d68db3c2deb9f 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

      (ptr: *const P) { - unsafe { transmute::<*const i32, usize>(&42i32) }; - unsafe { transmute::(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::(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 a4cedbf66e2ad..4d57907f26f92 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 adc89cad72f89..a5418ad838488 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, - /// The valgrind path. - pub valgrind_path: Option, - - /// 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, @@ -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 0000000000000..b605bc813f195 --- /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> { + config.cdb.as_ref()?; + + Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) +} + +pub(crate) fn configure_gdb(config: &Config) -> Option> { + 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> { + 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 { + 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, + target: &str, +) -> (Option, 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, + target: &str, + android_cross_path: &PathBuf, +) -> (Option, Option) { + #[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 { + 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 { + // 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 83a10c5620864..099e620ffe035 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, - pub aux_bin: Vec, - 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, } @@ -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, - // 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, - // Auxiliary crates that should be compiled as `#![crate_type = "bin"]`. - pub aux_bins: Vec, - // 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, + /// 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, 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 = 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) { + fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec) { 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( 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( }; } - 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 0000000000000..6f6538ce196d4 --- /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, + /// Auxiliary crates that should be compiled as `#![crate_type = "bin"]`. + pub(crate) bins: Vec, + /// 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, +} + +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 { + 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 948568e63c2dc..b9314f0abbbc8 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 f5dd722ed3711..a744fb61b9cfc 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 108ca432e1308..0000000000000 --- 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 ae661200c6cfa..c3c9496c4d2d9 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, 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] @@ -621,17 +617,6 @@ fn test_unknown_directive_check() { assert!(poisoned); } -#[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; diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a8355ee9590d6..18000e5602cb7 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) { 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) { } } -fn configure_cdb(config: &Config) -> Option> { - config.cdb.as_ref()?; - - Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) -} - -fn configure_gdb(config: &Config) -> Option> { - 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> { - 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 { - 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, target: &str) -> (Option, 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, - target: &str, - android_cross_path: &PathBuf, -) -> (Option, Option) { - #[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 { - 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 { - // 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) { 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 7b85e6f80b32a..b0f87593f9532 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 74d86d2b521dc..29f9925de16a2 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) { - if self.should_compile_successfully(pm) { + fn check_if_test_should_compile( + &self, + fail_mode: Option, + pass_mode: Option, + 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> = 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 36127414ab147..bd0845b45241e 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 81b006292e492..591aff0defeb0 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 bd8ef952a863b..bb747c6802926 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 8d72c4be9ff29..0000000000000 --- 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 7c2e7b0f023cc..680579c59aec5 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 c779dd0583c4e..33fac3edccd11 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 b04919bdd3edc..f7c752033c59e 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 d15aa7db31571..e842e1318db92 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 eb4dfcf57cf00..8b9e7efdff908 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 5b1bad28c07c7..475139a3b5192 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, 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 75dce211dd4f7..9f93f151668a9 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 665dd7c441a55..13eac60f9113e 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 330147c8f1cf8..f089d1e1bcc36 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 0d28a4ed3e494..af0ca00a0c03b 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, @@ -338,6 +338,14 @@ pub struct AllocExtra<'tcx> { pub backtrace: Option>>, } +// 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 6ab18a5345ea2..853d3e80517da 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 0000000000000..b46cf1ddf65df --- /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 f0afe5589546e..f59bb9f5c82d5 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::(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::(); 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::(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::(); 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 . +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 82c393d34a679..e401554640c49 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 286548bef618f..6096560ca52a0 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::().unwrap(), expected_output); - } + assert_eq!(output.downcast_ref::().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 f7fe4f5422399..cc3d1281d0ab2 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>(&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>(&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>(&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(&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 e11d6e15d1058..39ac652de0f86 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 dc820fcb28d20..7891edc2447a9 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" @@ -1852,6 +1855,12 @@ dependencies = [ "lazy_static", ] +[[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" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index b4587a3796181..0b3d6e2a1efbe 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 e9daaf7de3c3b..c2d4008605618 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 85fb90fdfb69f..d568f6faa7299 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 e09ef4f205d3c..7f1d19719dab7 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 b9afc666f7528..2a8691b461c05 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 { @@ -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 { + 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 584f9631e3445..484a8662eb174 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 cc02332207d6c..5e1448f7950d6 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, Transparency); fn outer_mark(self, db: &dyn ExpandDatabase) -> (Option, 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 95380979492a2..56cb5fd375cbf 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 + '_>> { - let tokens = self - .exp_map - .ranges_with_span_exact(span) - .flat_map(move |range| self.expanded.value.covering_element(range).into_token()); + ) -> Option + '_>> { + 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 + '_>> { - let tokens = self - .exp_map - .ranges_with_span(span) - .flat_map(move |range| self.expanded.value.covering_element(range).into_token()); + ) -> Option + '_>> { + 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 e74e3d789883e..f7bacbd49b335 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 for ChalkContext<'_> { } fn is_object_safe(&self, trait_id: chalk_ir::TraitId) -> 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 ce5a821ea2bc4..5620d80adb537 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 { #[salsa::invoke(crate::layout::target_data_layout_query)] fn target_data_layout(&self, krate: CrateId) -> Result, Arc>; - #[salsa::invoke(crate::object_safety::object_safety_of_trait_query)] - fn object_safety_of_trait(&self, trait_: TraitId) -> Option; + #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] + fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option; #[salsa::invoke(crate::lower::ty_query)] #[salsa::cycle(crate::lower::ty_recover)] @@ -280,8 +280,8 @@ pub trait HirDatabase: DefDatabase + Upcast { } #[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 82517e6991752..7f6b7e392b308 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 cbe1af1570375..aa0c9e30be10d 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 similarity index 92% rename from src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs rename to src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index a4c6626855523..e0d1758210ecc 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 { +pub fn dyn_compatibility( + db: &dyn HirDatabase, + trait_: TraitId, +) -> Option { 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( +pub fn dyn_compatibility_with_callback( 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( +pub fn dyn_compatibility_of_trait_with_callback( 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 { +) -> Option { 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.visit_with(visitor.as_dyn(), outer_binder).is_break() } -fn object_safety_violation_for_assoc_item( +fn dyn_compatibility_violation_for_assoc_item( 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 similarity index 78% rename from src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs rename to src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index c2a9117c5be4f..3f3e68eeb1c28 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)>, + expected: impl IntoIterator)>, ) { 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: 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 { @@ -251,7 +253,7 @@ trait Baz : Bar { #[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 + 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 5ed41b99ba3e7..ef570a2055661 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 878d584a4efa0..9830fa1ca7b73 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, result: &mut ArenaMap>, ) { - 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 8f5db32f9576e..30e023e1a4720 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 { - // 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, 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 { - hir_ty::object_safety::object_safety(db, self.id) + pub fn dyn_compatibility(&self, db: &dyn HirDatabase) -> Option { + hir_ty::dyn_compatibility::dyn_compatibility(db, self.id) } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index fa14b53dbc3d7..b27f1fbb5db13 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), + mut cb: impl FnMut(InFile, 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( &self, token: InRealFile, - mut cb: impl FnMut(InFile) -> ControlFlow, + mut cb: impl FnMut(InFile, SyntaxContextId) -> ControlFlow, ) -> Option { 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( &self, InRealFile { value: token, file_id }: InRealFile, - f: &mut dyn FnMut(InFile) -> ControlFlow, + f: &mut dyn FnMut(InFile, SyntaxContextId) -> ControlFlow, ) -> Option { 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

      (P); +pub struct Bind(P, F); +impl Trait for Bind { type Assoc = (); } +impl Trait for BlockWrapper { type Assoc = (); } +impl Trait for IfWrapper { type Assoc = (); } + +pub fn block() -> Parser { + loop {} +} +pub fn option(arg: Parser

      ) -> Parser { + bind(arg, |_| block()) +} +fn bind Parser>(_: Parser

      ` (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: Rc`, `self: Arc`, or `self: Pin

      ` (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 702e0b375e577..c95ae1147df36 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: Rc`, `self: Arc`, or `self: Pin

      ` (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 b60b6982bb879..ee617617da069 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 fce6210b2f436..d47a8e085fd3a 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 94e9628f0f0f6..41be378424543 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 0000000000000..3b0a71007a0e6 --- /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 a7261ebe9365e..bafb7e2b20cc7 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 fbf273b1f1dbf..e52de93a92646 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 18e7b68ff3c22..2b0bceebf15ca 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 similarity index 63% rename from tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs rename to tests/ui/cfg/crate-attributes-using-cfg_attr.rs index 3ced3a630e334..f99fad881f284 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 0000000000000..1dfca2b88d0e5 --- /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 82b2d7d1b1da6..0000000000000 --- 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 - = 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 - -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 - = 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 - = 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 0000000000000..4cb8bb71c924b --- /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 0000000000000..03d96fbafecbe --- /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 7726c2d52f571..c21016e929093 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 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 3c99fdd3821c5..da790bbd52859 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 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 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 f8ed792e3c675..e0d900a1eb564 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 e05dbf3bbc4bc..2d0ed5d2a3074 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:: 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 64e9b7cc63959..120d5cc5293b4 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:: 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 similarity index 54% rename from tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs rename to tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.rs index bce3b0fd729fe..f41d3a783abca 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 0000000000000..542be2dbc305c --- /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 + --> $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 ce65e079ab45a..0000000000000 --- 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 - --> $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 9859a226efd00..16baf0958a674 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 95c16bce6e8b8..23269e4123182 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 similarity index 100% rename from tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs rename to 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 similarity index 93% rename from tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr rename to tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr index 831b40887ac42..84281eb53c946 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 similarity index 100% rename from tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.rs rename to 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 similarity index 91% rename from tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr rename to tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr index fb57da42bb297..d2017615e67db 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 - --> $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::()]; = 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 - --> $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 similarity index 100% rename from tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs rename to 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 similarity index 88% rename from tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr rename to tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr index 831bda7129542..26ca2d4df5ffc 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 - --> $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::()]: 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 - --> $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 similarity index 100% rename from tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs rename to 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 similarity index 85% rename from tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr rename to tests/ui/const-generics/generic_const_exprs/dyn-compatibility-ok-infer-err.stderr index d1e1c976da664..a124fbc60920d 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(v: &dyn Foo) where [u8; N + 1]: Sized { | ^^^^^^^^^^^^^^ required by this const generic parameter in `use_dyn` @@ -15,7 +15,7 @@ LL | use_dyn::(&()); | +++++ 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 Foo 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 similarity index 100% rename from tests/ui/const-generics/generic_const_exprs/object-safety-ok.rs rename to 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 4bea3ad87f5ed..c1d3321f84077 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( 1 }], ) -> impl Iterator { -//~^ 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 416a938112424..5c4d643a28e97 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( | +++ -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 { - | ^^^^^^^^^ - --> $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> { - | +++++ - -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 { - | ^^^^^^^^^ - --> $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> { - | +++++ - 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 { | = 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 { | ^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | ) -> impl Iterator { | +++ @@ -70,7 +39,7 @@ help: you might have meant to write a bound here LL | ) -> impl Iterator { | ~ -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 eb672194340e8..b454562ad497a 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 { +trait Trait { //~^ 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 ade40550c7389..2500409e82858 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 { - | ^^^ not found in this scope +LL | trait Trait { + | ^^^ 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 { - | ^^^^^ +LL | trait Trait { + | ^^^^^ | = 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 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Trait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/not_wf_param_in_rpitit.rs:3:22 | -LL | trait Trait { - | ^^^^^ `Trait` cannot be made into an object +LL | trait 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 - --> $DIR/not_wf_param_in_rpitit.rs:10:14 + --> $DIR/not_wf_param_in_rpitit.rs:9:14 | -LL | trait Trait { +LL | trait Trait { | ----- 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 { - | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object +LL | trait 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 - --> $DIR/not_wf_param_in_rpitit.rs:10:14 + --> $DIR/not_wf_param_in_rpitit.rs:9:14 | -LL | trait Trait { +LL | trait Trait { | ----- 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 { - | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object +LL | trait 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 - --> $DIR/not_wf_param_in_rpitit.rs:10:14 + --> $DIR/not_wf_param_in_rpitit.rs:9:14 | -LL | trait Trait { +LL | trait Trait { | ----- 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 { - | ^^^^^ - | -help: add `dyn` keyword before this trait - | -LL | trait Trait { - | +++ - -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 847f1da16f612..a060488b3287e 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() {} + | ^^^ + | + = 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() {} - | ^^^ - | - = 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 0000000000000..19c78f019aab7 --- /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); + +impl Type { + 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 0000000000000..ca6ad9408ab91 --- /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 bc79c7db2fc80..ea0a15af1be77 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::::None.unwrap(); -//~^ERROR: evaluation of constant value failed +//~^ ERROR: evaluation of constant value failed +//~| NOTE: the evaluated program panicked + +const BAZ: i32 = Option::::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 fee22a1d070b8..aa5dd9a5c36c8 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::::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::::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 56c4b6ea36f6a..2e30eebb07b2e 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, diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index ebfa09b2e5d5d..a85c5e10374f8 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::::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 similarity index 53% rename from tests/ui/consts/issue-77062-large-zst-array.rs rename to tests/ui/consts/large-zst-array-77062.rs index ef5178fba9515..089353d0885da 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 d97e9cb3d9df6..2a8adbd5e1665 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 3b861d784d8b8..19e7a723a22fa 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 ae4d27d65ebd6..55c86d260d4b3 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 03ded300bb446..6a627be3b64e7 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 - = 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::::{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 + = 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::::{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 f02fb56130fa7..41d3039236f71 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 e7c2afc8b00c7..9ab117698c7a0 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 similarity index 95% rename from tests/ui/object-safety/almost-supertrait-associated-type.rs rename to tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs index 963cdff526ee6..83076f7d5fc3b 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 similarity index 100% rename from tests/ui/object-safety/almost-supertrait-associated-type.stderr rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_const_bounds.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_const_bounds_sized.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds.stderr rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds2.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds2.stderr rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_sized.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_sized_others.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_sized_others.stderr rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_sized_used.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/assoc_type_bounds_sized_used.stderr rename to 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 similarity index 86% rename from tests/ui/object-safety/object-safety-associated-consts.curr.stderr rename to tests/ui/dyn-compatibility/associated-consts.curr.stderr index 3c070f17c82ad..17d184942c701 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: &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 - --> $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 - --> $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 similarity index 87% rename from tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr rename to tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr index 5b98cc35505c6..cc5120232c244 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 - --> $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 similarity index 66% rename from tests/ui/object-safety/object-safety-associated-consts.rs rename to tests/ui/dyn-compatibility/associated-consts.rs index a090214bbb404..fc7b372b782a4 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 0000000000000..83795f3128ec7 --- /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: 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) -> 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: 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 similarity index 98% rename from tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr rename to tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr index 180cd679dea11..54daefea31c10 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: 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 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: 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 similarity index 65% rename from tests/ui/object-safety/avoid-ice-on-warning-2.rs rename to tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs index db2f4aea05b58..3c2da667b3924 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: 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 0000000000000..813b5863738f8 --- /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(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(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 similarity index 96% rename from tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr rename to tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr index bd362abb35501..6bc2d73a0d0e4 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 - --> $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 similarity index 74% rename from tests/ui/object-safety/avoid-ice-on-warning-3.rs rename to tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs index 38bee8142bb9a..00d47225e92fa 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 0000000000000..e9eb1cdd0c233 --- /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) : Fn(&str) + call_that {} + | ^ + | +help: use `->` instead + | +LL | fn call_this(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) : 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) : 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) : 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 similarity index 100% rename from tests/ui/object-safety/avoid-ice-on-warning.old.stderr rename to 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 similarity index 89% rename from tests/ui/object-safety/avoid-ice-on-warning.rs rename to tests/ui/dyn-compatibility/avoid-ice-on-warning.rs index b90d8911d500b..ef82321df0e3b 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) : 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 similarity index 77% rename from tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed rename to tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed index 4f5310082e18d..a54892afd3e4b 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 0000000000000..52168261a64ea --- /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 similarity index 100% rename from tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr rename to 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 similarity index 76% rename from tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs rename to tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs index cb5a305eab087..cf9be612d2e7e 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 similarity index 72% rename from tests/ui/object-safety/object-safety-bounds.rs rename to tests/ui/dyn-compatibility/bounds.rs index 44bd369324a4b..1e04d11c516cb 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; diff --git a/tests/ui/object-safety/object-safety-bounds.stderr b/tests/ui/dyn-compatibility/bounds.stderr similarity index 89% rename from tests/ui/object-safety/object-safety-bounds.stderr rename to tests/ui/dyn-compatibility/bounds.stderr index 96a81a69639bd..9231d524fd173 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> { | ^^^^^^^^^^^^^^ `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 - --> $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 similarity index 79% rename from tests/ui/object-safety/object-safety-by-value-self-use.rs rename to tests/ui/dyn-compatibility/by-value-self-use.rs index 8e93c538217bb..3c04ec0cd888c 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 similarity index 83% rename from tests/ui/object-safety/object-safety-by-value-self-use.stderr rename to tests/ui/dyn-compatibility/by-value-self-use.stderr index 1701f6059a8ee..14785b982a39e 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 similarity index 90% rename from tests/ui/object-safety/object-safety-by-value-self.rs rename to tests/ui/dyn-compatibility/by-value-self.rs index 0d20032327cae..a057a7ff0b57a 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 similarity index 100% rename from tests/ui/object-safety/call-when-assoc-ty-is-sized.rs rename to 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 similarity index 93% rename from tests/ui/object-safety/issue-102933.rs rename to tests/ui/dyn-compatibility/elaborated-predicates-ordering.rs index aa678fea17620..d3c3963a673d5 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 similarity index 100% rename from tests/ui/object-safety/erroneous_signature.rs rename to 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 similarity index 100% rename from tests/ui/object-safety/erroneous_signature.stderr rename to 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 similarity index 88% rename from tests/ui/object-safety/object-safety-generics.curr.stderr rename to tests/ui/dyn-compatibility/generics.curr.stderr index 7528785d90b47..c63db38a080b4 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: &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 - --> $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(&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: &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 - --> $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(&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 - --> $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(&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 - --> $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(&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 - --> $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 similarity index 89% rename from tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr rename to tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr index 4686b994b33ed..ba2546ef2dc5c 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 - --> $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(&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 - --> $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 similarity index 74% rename from tests/ui/object-safety/object-safety-generics.rs rename to tests/ui/dyn-compatibility/generics.rs index f005a689ac45c..b51555aa500c5 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: &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: &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 similarity index 73% rename from tests/ui/object-safety/issue-106247.rs rename to tests/ui/dyn-compatibility/impossible-predicates-multiple_supertrait_upcastable-check.rs index 20a451a59a164..c2b8ecc141d7d 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 similarity index 100% rename from tests/ui/object-safety/item-bounds-can-reference-self.rs rename to 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 similarity index 90% rename from tests/ui/object-safety/issue-19538.rs rename to tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.rs index 7054ef41b1c82..1289d2d7874aa 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(&self, val: T); } diff --git a/tests/ui/object-safety/issue-19538.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr similarity index 87% rename from tests/ui/object-safety/issue-19538.stderr rename to tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr index 3dbe389686a44..7378ec023c926 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 - --> $DIR/issue-19538.rs:2:8 + --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 | LL | fn foo(&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 - --> $DIR/issue-19538.rs:2:8 + --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 | LL | fn foo(&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 similarity index 100% rename from tests/ui/object-safety/object-safety-issue-22040.rs rename to 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 similarity index 87% rename from tests/ui/object-safety/object-safety-issue-22040.stderr rename to tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr index e5723f12258fe..7578edce7d19e 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>, | ^^^^^^^^^^^^^ `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 - --> $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 = 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 - --> $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 = 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 - --> $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 similarity index 88% rename from tests/ui/object-safety/object-safety-mentions-Self.curr.stderr rename to tests/ui/dyn-compatibility/mentions-Self.curr.stderr index 7efb6ec3542d0..434e41cf2182d 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: &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 - --> $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: &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 - --> $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 - --> $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 - --> $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 similarity index 88% rename from tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr rename to tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr index d0efb9c587e4e..dc2d1f87eb737 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 - --> $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 - --> $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 similarity index 84% rename from tests/ui/object-safety/object-safety-mentions-Self.rs rename to tests/ui/dyn-compatibility/mentions-Self.rs index 1311faf97bc36..84c229e252d30 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 similarity index 100% rename from tests/ui/traits/object/object-unsafe-missing-assoc-type.rs rename to 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 similarity index 86% rename from tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr rename to tests/ui/dyn-compatibility/missing-assoc-type.stderr index 9258b38f26c3a..f8450ba212d03 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 - --> $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; = 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 - --> $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; = 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 - --> $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; = 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 - --> $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 similarity index 92% rename from tests/ui/object-safety/object-safety-no-static.curr.stderr rename to tests/ui/dyn-compatibility/no-static.curr.stderr index 91c3d89602e86..584db77985566 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 { | ^^^^^^^ `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 - --> $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 = 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 - --> $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 = 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 - --> $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 similarity index 93% rename from tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr rename to tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr index 52f6865b6f3cb..f2deb3b8d84b9 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 = 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 - --> $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 similarity index 73% rename from tests/ui/object-safety/object-safety-no-static.rs rename to tests/ui/dyn-compatibility/no-static.rs index 4f4e03d734e8e..54af16fe18eb6 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 similarity index 92% rename from tests/ui/object-safety/object-safety-phantom-fn.rs rename to tests/ui/dyn-compatibility/phantom-fn.rs index 1019c24859fba..9e410da82eed5 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 similarity index 50% rename from tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs rename to tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs index dabaa309c16a1..7bc2af463cb9f 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 similarity index 87% rename from tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr rename to tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr index 8bdfea7766e38..4c6d84f05341f 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; | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 { | ~~~~~~~~~~~~~~ -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 similarity index 88% rename from tests/ui/object-safety/object-safety-sized-2.curr.stderr rename to tests/ui/dyn-compatibility/sized-2.curr.stderr index 4ce7ac5704e42..1017fde53d313 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: &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 - --> $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 - --> $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 similarity index 89% rename from tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr rename to tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr index 99066c104b7cb..534cf0f1b033f 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 - --> $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 similarity index 69% rename from tests/ui/object-safety/object-safety-sized-2.rs rename to tests/ui/dyn-compatibility/sized-2.rs index cfb5d588d70df..f5edd287f24d8 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 similarity index 88% rename from tests/ui/object-safety/object-safety-sized.curr.stderr rename to tests/ui/dyn-compatibility/sized.curr.stderr index b61f968d90210..613833aad12ee 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: &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 - --> $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 - --> $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 similarity index 89% rename from tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr rename to tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr index 5ce713375a49a..cf847bc157785 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 - --> $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 similarity index 67% rename from tests/ui/object-safety/object-safety-sized.rs rename to tests/ui/dyn-compatibility/sized.rs index f4d6c945b33d5..4c4fe3f8f2593 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(&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 similarity index 100% rename from tests/ui/object-safety/object-safety-supertrait-mentions-GAT.rs rename to 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 similarity index 86% rename from tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr rename to tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr index 4d44627e77926..ac5a5b28d94d4 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: for<'a> GatTrait = 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; | ^^^^^^^^^^^^^^^^^ `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 - --> $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 similarity index 100% rename from tests/ui/object-safety/object-safety-supertrait-mentions-Self.rs rename to 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 similarity index 86% rename from tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr rename to tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr index b1a70fb859d7f..6474b115c4628 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 { | ^^^^^^^^^ 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 { | ^ required by the implicit `Sized` requirement on this type parameter in `Bar` @@ -19,13 +19,13 @@ LL | trait Bar { | ++++++++ 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: &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 - --> $DIR/object-safety-supertrait-mentions-Self.rs:8:13 + --> $DIR/supertrait-mentions-Self.rs:8:13 | LL | trait Baz : Bar { | --- ^^^^^^^^^ ...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 similarity index 79% rename from tests/ui/object-safety/issue-102762.rs rename to tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs index 576f73e08bcf9..5c71bd7769ce1 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 similarity index 87% rename from tests/ui/object-safety/issue-102762.stderr rename to tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr index 05451eb8399cf..8d62ac9d923f9 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) -> Pin> + 'a>> | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` @@ -8,7 +8,7 @@ LL | fn fetcher() -> Box { | ^^^^^^^^^^^ `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 - --> $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) -> Pin> | ^^^^^^^^^^^^^ ...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) -> Pin> + '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 - --> $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) -> Pin> | ^^^^^^^^^^^^^ ...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) -> Pin> + '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 - --> $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 f98bf4ef5d177..5d607d82ea1ac 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) { - //~^ 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 52ee6c81ab794..6d1a1618ac033 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) { @@ -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) { | +++ -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) { | ^^^^^^^^^ | -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) { | +++ -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 19b5edb620f6b..bee15788da925 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 4446a89b63b15..6a2bb3ec09adf 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 | ::CONST => {} | ++++ + diff --git a/tests/ui/editions/dyn-trait-sugg-2021.rs b/tests/ui/editions/dyn-trait-sugg-2021.rs index d702bfb2f88db..a536466260016 100644 --- a/tests/ui/editions/dyn-trait-sugg-2021.rs +++ b/tests/ui/editions/dyn-trait-sugg-2021.rs @@ -8,5 +8,5 @@ impl dyn Foo { 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 8a65fea11c95c..3aea8ac491d40 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 | ::hi(123); | ++++ + diff --git a/tests/ui/error-codes/E0010-teach.stderr b/tests/ui/error-codes/E0010-teach.stderr index 7634970f36e2e..37a9892ccbf49 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 = 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::::into_vec::` in constants diff --git a/tests/ui/error-codes/E0607.stderr b/tests/ui/error-codes/E0607.stderr index 835ababf44953..3fa134c20283a 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 9d75671c4e6b4..26393352b2b65 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 0000000000000..6784b4450490b --- /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 0000000000000..64491464f1d43 --- /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 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(true)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:4:12 + | +LL | #[cfg_attr(true, cfg(false))] + | ^^^^ + | + = note: see issue #131204 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(false)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:4:22 + | +LL | #[cfg_attr(true, cfg(false))] + | ^^^^^ + | + = note: see issue #131204 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(false)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:9:10 + | +LL | cfg!(false); + | ^^^^^ + | + = note: see issue #131204 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs index 23857cbaca85e..3c9e903d4ba00 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 0000000000000..e38ab66dbe549 --- /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(&self); +} + +trait DynIncompatible4 { + fn foo(&self, s: &Self); +} + +fn takes_dyn_incompatible_ref(obj: &dyn DynIncompatible1) { + //~^ ERROR E0038 +} + +fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 { + //~^ ERROR E0038 + loop {} +} + +fn takes_dyn_incompatible_box(obj: Box) { + //~^ ERROR E0038 +} + +fn return_dyn_incompatible_rc() -> std::rc::Rc { + //~^ 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 0000000000000..ed021c154a5b8 --- /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(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 + --> $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 + --> $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) { + | ^^^^^^^^^^^^^^^^^^^^ `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 + --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:11:8 + | +LL | trait DynIncompatible3 { + | ---------------- this trait cannot be made into an object... +LL | fn foo(&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 { + | ^^^^^^^^^^^^^^^^^^^^ `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 + --> $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 + --> $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 d8a85c8838d4d..7dfd79c728641 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 | @@ -36,6 +28,14 @@ LL | type Bop = impl std::fmt::Debug; = help: add `#![feature(inherent_associated_types)]` 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: unconstrained opaque type --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:16 | diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs index 36980fd74c264..5fe0bbdc77435 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 ffdf31e147aed..709234eb02372 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 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 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 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 37348e476d408..0000000000000 --- 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(&self); -} - -trait NonObjectSafe4 { - fn foo(&self, s: &Self); -} - -fn takes_non_object_safe_ref(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) { - //~^ ERROR E0038 -} - -fn return_non_object_safe_rc() -> std::rc::Rc { - //~^ 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 fd5ed9c40f7ab..0000000000000 --- 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(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 - --> $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 - --> $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) { - | ^^^^^^^^^^^^^^^^^^ `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 - --> $DIR/feature-gate-object_safe_for_dispatch.rs:11:8 - | -LL | trait NonObjectSafe3 { - | -------------- this trait cannot be made into an object... -LL | fn foo(&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 { - | ^^^^^^^^^^^^^^^^^^ `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 - --> $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 - --> $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 d694531d53abe..3382504af9d61 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 6c9029d817674..430b78662414a 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 0000000000000..308b41dfc68ab --- /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; + //~^ 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 0000000000000..b2c6bf61124d9 --- /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; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + = note: see issue #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 302a9bbeb4518..0000000000000 --- 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 bc9e95bab989a..0000000000000 --- 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 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 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 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 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 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 0000000000000..9e697aaa0dcef --- /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 0000000000000..319056a9c8898 --- /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 b19e67d5284d0..ca852ea2468bc 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 e85a889d2c240..3046728fe66ff 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 277ffcc1f0dd3..743a3df0acc81 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); - // 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 9831348de7569..e2916725fbd90 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: 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 1b5e875cccb68..f54e07c3a6370 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: 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 7b20f1683a976..580a8bcff05fa 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::::with_capacity(!0); } diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index bfed4cd665030..b9086ecef8141 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 similarity index 59% rename from tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs rename to tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs index 068f7d3eea6da..76dbb05f53d66 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 { //~ ERROR the trait `NotObjectSafe` cannot be made into an +fn cat() -> Box { //~ 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 similarity index 62% rename from tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr rename to tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr index 2a36824e29254..576bd909cbc7d 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 - --> $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 { - | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object +LL | fn cat() -> Box { + | ^^^^^^^^^^^^^^^^^^^ `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 - --> $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 { +LL ~ fn car() -> Box { 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 - --> $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` to `Box<(dyn NotObjectSafe + 'static)>` + = note: required for the cast from `Box` 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 - --> $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` to `Box<(dyn NotObjectSafe + 'static)>` + = note: required for the cast from `Box` 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 similarity index 61% rename from tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs rename to tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.rs index 503515013b9ab..25a901e4ff350 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 similarity index 54% rename from tests/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr rename to tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.stderr index e5147bcea1662..6a485881bfccb 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 7917fa991ee32..1e268bc7f49b9 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 { - | ^^^^^^^^^^^^^^^^^^^ 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 { | ^^^^^^^ | -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 { | +++ -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 582386aa7596a..c71f794d5d125 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 { //[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 50a9f3ebeabb8..91550f0e284c1 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 similarity index 100% rename from tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.rs rename to 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 similarity index 82% rename from tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr rename to tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr index af624e2a75871..a975b6204aa5a 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 - --> $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 - --> $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 - --> $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 similarity index 100% rename from tests/ui/impl-trait/in-trait/object-safety-sized.rs rename to 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 similarity index 100% rename from tests/ui/impl-trait/in-trait/object-safety.rs rename to 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 similarity index 91% rename from tests/ui/impl-trait/in-trait/object-safety.stderr rename to tests/ui/impl-trait/in-trait/dyn-compatibility.stderr index e2f23bca621c6..115cb014b8c34 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; | ^^^^^^^^^^^^ `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 - --> $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 - --> $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 - --> $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; | ^^^^^^^^^^^^^^^^ `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 - --> $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 d71c1768a6a3b..058517f0014e9 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 + MyFn, | +++++++++++ -error[E0277]: the trait bound `F: Callback` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:43:12 - | -LL | F: Callback, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn` is not implemented for `F`, which is required by `F: Callback` - | -note: required for `F` to implement `Callback` - --> $DIR/false-positive-predicate-entailment-error.rs:14:21 - | -LL | impl> Callback for F { - | ------- ^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here -note: the requirement `F: Callback` 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(self) -> impl Trait - | ^^^^^^^^^ this trait's method doesn't have the requirement `F: Callback` -help: consider further restricting this bound - | -LL | F: Callback + MyFn, - | +++++++++++ - error[E0277]: the trait bound `F: MyFn` 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 + MyFn, | +++++++++++ -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 59fdeab9e0a9f..2987d183e0401 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` is not satisfied where F: Callback, - //[current]~^ ERROR the trait bound `F: Callback` is not satisfied - //[current]~| ERROR the trait bound `F: MyFn` is not satisfied + //[current]~^ ERROR the trait bound `F: MyFn` 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 84bc39d926307..ee47de2c73283 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 for Bar { fn foo>(self) -> impl Foo { //~^ ERROR: the trait bound `impl Foo: Foo` is not satisfied [E0277] //~| ERROR: the trait bound `Bar: Foo` is not satisfied [E0277] - //~| ERROR: impl has stricter requirements than trait //~| ERROR: the trait bound `F2: Foo` 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 ae4490999878f..768224e4c515c 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 `>::foo` LL | fn foo>(self) -> impl Foo { | ^^^^^^^ required by this bound in `>::foo` -error[E0276]: impl has stricter requirements than trait - --> $DIR/return-dont-satisfy-bounds.rs:8:16 - | -LL | fn foo(self) -> impl Foo; - | -------------------------------- definition of `foo` from trait -... -LL | fn foo>(self) -> impl Foo { - | ^^^^^^^ impl has extra requirement `F2: Foo` - error[E0277]: the trait bound `Bar: Foo` is not satisfied --> $DIR/return-dont-satisfy-bounds.rs:8:34 | @@ -44,7 +35,6 @@ LL | self = help: the trait `Foo` 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 0ac44bf7546c2..19905c608e3b5 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 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 54e0afbaa950d..f65174e1c358c 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 dc5579c1c829e..2cf6b94dd9d9b 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 9d68819f657db..6c2477c9744ab 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() -> 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 d9be9d543e450..93b44a0c18c27 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() -> impl Sized + use<> {} | - ^^^^^^^^^^^^^^^^^^ @@ -17,7 +9,7 @@ LL | fn type_param() -> 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 d1bcbaa33ae2b..0000000000000 --- 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 213888356e572..0000000000000 --- 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 4a08ffb61be03..e19d935f5b0d4 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 0000000000000..274d9d2375f7d --- /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 71a91fe319e8d..b39c1408c0509 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; - //~^ 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 339e2e6335e2d..45f755d3cc1be 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; - | ^^^^^^^^^ - | - = 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; | ^^^^^^^^^^^^^^^^^^^^^^ - = 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; - | ---------------------- 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 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 0000000000000..b16b0522d6e11 --- /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; +} + +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 0000000000000..e1856b929106e --- /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; + | ^^^^^^^^^^^^^^^^^^^^^^ + = 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 feeeb1461e827..3f887e8e47f1c 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; +#![feature(precise_capturing_in_traits)] + +fn eq_types(_: T, _: T) {} + +trait TraitLt<'a: 'a> { + fn hello() -> impl Sized + use; + //~^ 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 + >::hello(), + >::hello(), + ); } -fn test<'a, 'b, T: for<'r> Foo<'r>>() { - PartialEq::eq( - &>::hello(), - &>::hello(), +trait MethodLt { + fn hello<'a: 'a>() -> impl Sized + use; +} +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 5a120df9f047a..498eae54a1c68 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; - | ^^^^^^^^^ - | - = 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; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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; + | ^^^^^^^^^^^^^^^^^^^^^^ 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 | | &>::hello(), -LL | | &>::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 | | >::hello(), +LL | | >::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 | | &>::hello(), -LL | | &>::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 | | >::hello(), +LL | | >::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 a61a7f06edc1d..15985da50b55e 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; - //~^ 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 c1974600f30c5..0000000000000 --- 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; - | ^^^^^^^^^ - | - = 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 3692cc77b0fb4..6485aa207103c 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 2770a6cc40e59..13f50fcea7b3f 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) {} + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted 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 + = 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 {} + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted 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 + 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 Fn for Box where Args: Tuple, F: Fn, 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 {} - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted 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 - = 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 {} | = 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) {} - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted 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 - 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 {} - | ^^^^^^^^^^^^^^ +LL | fn in_method_generic_param_default(_: 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 @@ -436,10 +436,10 @@ LL | impl 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) {} - | ^^^^^^^^^^^^^^ +LL | impl 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 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 b8b7d6e1a5e93..0000000000000 --- 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 91ff6381df766..118ae482fc6ce 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 0000000000000..d03297884f791 --- /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 53fecb0166351..6c8df1157c6c8 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 177b78754cc3c..2048bd7ec1666 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 c838fde5d73b6..9b630666baf85 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 7fe7a4aa579fb..72538081ccb3a 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 similarity index 100% rename from tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr rename to 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 c785736f42e4b..dda95229ddf00 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(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 0000000000000..356f1e777c7d0 --- /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(fut: impl Future) -> 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(&mut self, iterator: T) + where + T: IntoIterator; +} + +impl Blah for () { + async fn iter(&mut self, iterator: T) + //~^ ERROR recursion in an async fn requires boxing + where + T: IntoIterator, + { + Blah::iter(self, iterator).await + } +} + +struct Wrap { + t: T, +} + +impl Wrap +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 0000000000000..ad01c2694faf5 --- /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(&mut self, iterator: T) +LL | | +LL | | where +LL | | T: IntoIterator, + | |___________________________________^ +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 0000000000000..8d136190c0052 --- /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 { + _x: ::Assoc, +} + +fn abi(_: Option>) {} +//~^ ERROR a cycle occurred during layout computation + +fn indirect() { + abi::(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 0000000000000..47f7f30b1cb4c --- /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>` + = 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(_: Option>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 f2d55c107ba08..054c06d38b30b 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 77ee28b48cc7f..d579fa391fc28 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 = 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 d8a497e43e502..5b9dab3cfd369 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 7f76056c0210c..20fb4a6432e4e 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 = 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 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 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 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 `` 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 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 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 `` 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 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 `` 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 -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 0000000000000..72fd056d461ad --- /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 0000000000000..8e738544a718f --- /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 c58ec12aaacaa..83e46df185de2 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 = 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 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 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 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 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 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 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 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 dd41b2206d842..1e6fc910621f6 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 = 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 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 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 Trait for Vec { } | `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 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 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 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 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 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 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 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 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 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 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 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 6839ebd2c8a3e..f173c054e786f 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 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 = 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 aefe8921fe2c7..66769cc1e0b8a 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 Global for Vec { } | `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 = 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 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 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 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 faab6aea2b318..b6fe1a921d756 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 = 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 166ee88c0210c..f7ecd68f59e90 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 4e86fc7b987e6..28779a7806641 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 = 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 = 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 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 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 f6ce063929e8f..ec3517140ef2e 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 `` | = 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 = 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 `` | = 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 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 `` 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 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 `` 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 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 `` 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 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 `` 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 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 0000000000000..37bcf04651352 --- /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 0000000000000..647a84a55fda5 --- /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 0000000000000..8287b3d3ac785 --- /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 0000000000000..0b6edae30e70d --- /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 0000000000000..65513553f7e81 --- /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 2aac50a9d011a..50998572274ec 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 2633d5f720d70..5332691486562 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 c5193b19d9e4a..0af5624ff9c59 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 3d12ba9899bc5..2e5cbb900364a 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 0000000000000..b9bc29a218c4a --- /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 0000000000000..74e1bfa0a6b64 --- /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 4e3d2ebebade0..0000000000000 --- 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: 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 - -error[E0618]: expected function, found `(dyn Copy + 'static)` - --> $DIR/avoid-ice-on-warning-2.rs:11:5 - | -LL | fn id(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: 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: impl Copy) -> usize { - | ++++ -help: function arguments must have a statically known size, borrowed types always have a known size - | -LL | fn id(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 fdd3e8ab5072a..0000000000000 --- 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 - --> $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 - --> $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 4ff45d7a84858..0000000000000 --- 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) : Fn(&str) + call_that {} - | ^ - | -help: use `->` instead - | -LL | fn call_this(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) : 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 bb2bf6ddcda8e..0000000000000 --- 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 - --> $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 9ed387fc8d1f4..605567acdb58b 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 3fc416dd5311f..5ca248380ee5b 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::.z foo; - | ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: 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 0000000000000..2c6fddccb7315 --- /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() {} +//~^ 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 0000000000000..5f69061504385 --- /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::() {} +//~^ 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 0000000000000..3ad05050da0db --- /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::() {} + | ^^ + | +help: remove invalid path separator + | +LL - fn invalid_path_separator::() {} +LL + fn invalid_path_separator() {} + | + +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 7ebbf4ac370d7..c92e165b23b65 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: 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 a25c277d78a5b..fef3fcde7b799 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: 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 18cf2df028216..a2a972652d188 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: 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 892883c4aedca..14ae602fedfa1 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: 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 5e1f35d1b6f9a..ef080368e19ca 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: 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: 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 63956f35c079f..6cb3753de8d17 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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 596bff2139525..17cb7b4aead80 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: 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: 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: 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:: {} - | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: 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: 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: 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 e54586b092483..b481813b24621 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: 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: 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: 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: 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: 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 088f83b0ccbac..0a9b54474689a 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: 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: 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: 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: 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: 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: 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 30307726a973b..8d4212ed389dd 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: 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 2e8be28d76ebf..9eadd09867d41 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 = ::X; //~ ERROR type `Priv` is private trait Tr2 {} impl Tr2 for u8 {} fn g() -> impl Tr2 { 0 } //~ ERROR type `Priv` is private - //~| ERROR type `Priv` is private fn g_ext() -> impl Tr2 { 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 091cae42dea3c..03225d84fdb34 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 { 0 } | ^^^^^^^^^^^^^^^^^^ private type -error: type `Priv` is private - --> $DIR/private-type-in-interface.rs:28:11 - | -LL | fn g() -> impl Tr2 { 0 } - | ^^^^^^^^^^^^^^^^^^ private type - -error: type `ext::Priv` is private - --> $DIR/private-type-in-interface.rs:30:15 - | -LL | fn g_ext() -> impl Tr2 { 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 { 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 8fe041d61b81e..439297d87ca5d 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 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 0000000000000..80d441729f746 --- /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 { + 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() -> *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 0000000000000..af9e788982179 --- /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 { + | - 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() -> *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 c51156b3f40cf..cfbbe04db769d 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 fe36a7e00bff3..d529536b95256 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 7b218694b269e..172d016c6e6c4 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: error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-111312.rs b/tests/ui/resolve/issue-111312.rs index 79c6f67dadd39..574e9870cd2f7 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 431802ead30c4..a1f8d6bc46c59 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 | ::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 fcab924b80977..a5c2c0ca8c6aa 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 1ef5a1a1d5efb..71ea989ac349f 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 | ::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 similarity index 77% rename from tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs rename to tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/downcast-unsafe-trait-objects.rs index d4337dcb16543..b1b2dcf3eb9fd 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 similarity index 100% rename from tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr rename to 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 similarity index 100% rename from tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr rename to 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 similarity index 90% rename from tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs rename to tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.rs index a020d91fb1407..425dc130d4587 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 similarity index 94% rename from tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs rename to tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/static-dispatch-unsafe-object.rs index cbf76a6830b8f..c38928a9f44e9 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 0c73b9abf351d..0e85515fd104a 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 b59c6d1eed8da..1040af7541c08 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 + ~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 + ~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 0000000000000..26c734d3e9eed --- /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 0000000000000..d7a3a4389eca4 --- /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 0000000000000..e57e9ce4844a4 --- /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 0000000000000..b8a9a5c81297a --- /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(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(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 0000000000000..055b11b4424a1 --- /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 0000000000000..c0969570e920d --- /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(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 0000000000000..2b4f7bd088fbe --- /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 0000000000000..d35c8ab3e4254 --- /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(_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 0000000000000..6d8c1c3f152f1 --- /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 0000000000000..d56e9981a2886 --- /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(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(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 0000000000000..81080fcdce307 --- /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 0000000000000..2c3dc30f0ae9b --- /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 0000000000000..83e0dcbb4bebc --- /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 0000000000000..e2e1ac42f05c2 --- /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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 0000000000000..d92df7b5375a7 --- /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 0000000000000..5905f2abe3232 --- /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 0000000000000..d7f8e5c9b4b24 --- /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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 0000000000000..3f9f373ba227b --- /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 0000000000000..1074c8a682bfb --- /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 0000000000000..f9e3c1e3c51b4 --- /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 0000000000000..dab97039be03f --- /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 0000000000000..f465ba7944a08 --- /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 d94f2992d8428..4eaa44cfa3f47 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(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 5ccc076bfaf6c..5634b3d6e64a3 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: Rc`, `self: Arc`, or `self: Pin

      ` (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: Rc`, `self: Arc`, or `self: Pin

      ` (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 similarity index 89% rename from tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr rename to tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr index e2d73fc08f6d7..2eb7597d5c105 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) -> 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; | ^^^^^^^^^^^ `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 - --> $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) -> 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) -> 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; | ^^^^^^^^^^^^^^^ `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 - --> $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 similarity index 90% rename from tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr rename to tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr index fda07765c6620..02af692c4a352 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) -> 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; | ^^^^^^^^^^^^^^^ `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 - --> $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 similarity index 77% rename from tests/ui/self/arbitrary-self-types-not-object-safe.rs rename to tests/ui/self/arbitrary-self-types-dyn-incompatible.rs index 0053eb5f73948..940b2f1e8e2fa 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; //[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 b00260fa0efa4..f3393830eebb3 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 d7149002e7bca..76d7754384ebe 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, U> DispatchFromDyn> for Wrapper {} 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) -> i32; fn ptr_wrapper(self: Ptr>) -> i32; fn wrapper_ptr(self: Wrapper>) -> 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 similarity index 90% rename from tests/ui/self/object-safety-sized-self-by-value-self.rs rename to tests/ui/self/dyn-compatibility-sized-self-by-value-self.rs index d902812eb9a67..658371c95e2f5 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 similarity index 90% rename from tests/ui/self/object-safety-sized-self-generic-method.rs rename to tests/ui/self/dyn-compatibility-sized-self-generic-method.rs index 7a2ebd2cb7935..a7b5013694ff2 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 similarity index 90% rename from tests/ui/self/object-safety-sized-self-return-Self.rs rename to tests/ui/self/dyn-compatibility-sized-self-return-Self.rs index 9fc3f85677223..a15f4fd781360 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 914511641b894..aae94f7a6ccce 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>, f: &'b u32) -> &u32 { + async fn box_box_ref_Self<'b>(self: Box>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn box_pin_Self<'b>(self: Box>, f: &'b u32) -> &u32 { + async fn box_pin_Self<'b>(self: Box>, 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 b84044f754887..c43ff49d5080c 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>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'b>(self: Box>, 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>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_Self<'b>(self: Box>, 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 cf54a86b45f06..9f2768d5e695d 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 ::AssocType, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_AssocType<'a>(self: &::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 ::AssocType>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_AssocType<'a>(self: Box<&::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 ::AssocType>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_AssocType<'a>(self: Pin<&::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::AssocType>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_AssocType<'a>(self: Box::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::AssocType>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_AssocType<'a>(self: Box::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 62543ba533955..945fb5e028216 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>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'a>(self: Box>, 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>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Self<'a>(self: Box>, 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 f8fb2e4a1383b..149ab01045c1f 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>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Struct<'a>(self: Box>, 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>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Struct<'a>(self: Box>, 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 010d281b00224..a75ece5f2c768 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>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'a>(self: Box>, 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>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Self<'a>(self: Box>, 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 c9376d58f9096..6bdc145223a68 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>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Struct<'a>(self: Box>, 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>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_Struct<'a>(self: Box>, 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 fc431eb14127f..d40e98224355b 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: 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 79d9b9490d09d..9d6517e613a22 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 Smartass for T { type Data = ::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 CoerceUnsized> for S where ::Data: std::ops::CoerceUnsized<::Data> {} -pub fn conv(s: SmartassPtr<()>) -> SmartassPtr { +pub fn conv(s: SmartassPtr<()>) -> SmartassPtr { s } diff --git a/tests/ui/suggestions/auxiliary/not-object-safe.rs b/tests/ui/suggestions/auxiliary/dyn-incompatible.rs similarity index 100% rename from tests/ui/suggestions/auxiliary/not-object-safe.rs rename to 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 similarity index 100% rename from tests/ui/suggestions/object-unsafe-trait-references-self.rs rename to 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 similarity index 87% rename from tests/ui/suggestions/object-unsafe-trait-references-self.stderr rename to tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr index c00bb3efbf640..242c44abd9d66 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 - --> $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 - --> $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 0000000000000..10b4781eb0494 --- /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 0000000000000..c0cfb18955cec --- /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(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(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(&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 similarity index 100% rename from tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.rs rename to 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 similarity index 85% rename from tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr rename to tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr index a7d36d9ebee5d..5e0d1a1445230 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 - --> $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 - --> $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 similarity index 100% rename from tests/ui/suggestions/object-unsafe-trait-should-use-self.rs rename to 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 similarity index 86% rename from tests/ui/suggestions/object-unsafe-trait-should-use-self.stderr rename to tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr index 28952933c644f..93f6ea2b12e67 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 - --> $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 - --> $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 similarity index 100% rename from tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed rename to 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 similarity index 100% rename from tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.rs rename to 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 similarity index 89% rename from tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr rename to tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr index 5e3a0290d42c0..beafd7c2ab00f 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 - --> $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 c3707baf79fc3..2b0fbdb8d35bb 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 6feba3dc6c16d..77cdfb8b614aa 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 7f8cc147210ea..3853f03f1db67 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 +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 - --> $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 b6fd9e7c23fe3..289b16abf4b37 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 c4b446763afe5..d7136ec1a649f 100644 --- a/tests/ui/suggestions/issue-98500.stderr +++ b/tests/ui/suggestions/issue-98500.stderr @@ -5,7 +5,7 @@ LL | struct S(Box); | ^^^^^ `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 - --> $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 37afab6b643ca..0000000000000 --- 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 a17f821ebec48..0000000000000 --- 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 - --> $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 - --> $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 - --> $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(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(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(&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 76300c6a3f424..dd7e203abd7a8 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 {} 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 GenericTrait 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` for all types that also implement `LocalTraitOne` trait GenericTraitTwo {} impl GenericTraitTwo for GenericTrait {} -//~^ 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` for all types that also implement `GenericTrait` 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 769f3bd64f320..102438e1ec506 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 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 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 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 GenericTrait for LocalTraitOne {} | ^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl GenericTrait for dyn LocalTraitOne {} | +++ @@ -58,35 +58,35 @@ help: alternatively use a blanket implementation to implement `GenericTrait` LL | impl GenericTrait 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 GenericTraitTwo for GenericTrait {} | ^^^^^^^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: you can add the `dyn` keyword if you want a trait object | LL | impl GenericTraitTwo for dyn GenericTrait {} | +++ 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 a5ab8be7f45a7..fe36d09343005 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 { impl<'a, T> Struct 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 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 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 2893370570d24..0bd601e217034 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 { = 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 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 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 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 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 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 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 0000000000000..bf211fbee2f3a --- /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 0000000000000..bf211fbee2f3a --- /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 0000000000000..0473ca319b8f0 --- /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 0000000000000..bf211fbee2f3a --- /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 0000000000000..0e31dea24ea4d --- /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 0000000000000..157b50bb0d329 --- /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 e36649d8eb1a9..c6cdf21a3e3f7 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 525c9084330d4..8d677735e8460 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 88feb89170dd3..d0829ab4cecbf 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 4dad8c0f87349..f3d35a8cd034d 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 3abffd22d142f..a14cfea3bd7ad 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; } -// Include object safe traits: +// Include dyn-compatible traits: fn _f1() { let _: Box; @@ -28,7 +28,7 @@ fn _f1() { let _: Box; } -// 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 0000000000000..4ce3b9b3b7764 --- /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: + + +pub trait MyFrom {} +impl MyFrom for T {} + +pub trait MyInto {} +impl MyInto for T where U: MyFrom {} + + +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<>::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 07b866cb4a65b..93d2f04b54e56 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 e05ae8e526713..e50186aff7e67 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 { | +++++++ + -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 0000000000000..e2f02053f959f --- /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 + +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 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 0000000000000..ec1e3355bfba7 --- /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 + +#![crate_type = "lib"] + +trait Unary {} +impl U> Unary for F {} +fn unary Unary<&'a T>, T>() {} + +pub fn test Fn(&'a i32) -> &'a i32>() { + unary::() +} diff --git a/tests/ui/traits/issue-106072.rs b/tests/ui/traits/issue-106072.rs index 8adbac46a5bd8..696bd765ebc5c 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 6476c8b3237ac..4a48e4e898d31 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 0000000000000..541b49b024fda --- /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 { + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` on by default +help: if this is a dyn-compatible trait, use `dyn` + | +LL | impl dyn Foo { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo for /* Type */ { + | ++++++++++++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo { + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: if this is a dyn-compatible trait, use `dyn` + | +LL | impl dyn Foo { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo 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 { + | ^^^^^^^^ `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 + --> $DIR/missing-for-type-in-impl.rs:4:8 + | +LL | trait Foo { + | --- 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` is not satisfied + --> $DIR/missing-for-type-in-impl.rs:19:19 + | +LL | let x: i64 = >::id(10); + | ^^^ the trait `Foo` 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 { + | ^^^^^^^^^^^^ + +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 0000000000000..a49c5d9d45b7b --- /dev/null +++ b/tests/ui/traits/missing-for-type-in-impl.e2021.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `i64: Foo` is not satisfied + --> $DIR/missing-for-type-in-impl.rs:19:19 + | +LL | let x: i64 = >::id(10); + | ^^^ the trait `Foo` 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 { + | ^^^^^^^^^^^^ + +error[E0782]: expected a type, found a trait + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo { + | ^^^^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | impl dyn Foo { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo 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 0000000000000..e5dd365160984 --- /dev/null +++ b/tests/ui/traits/missing-for-type-in-impl.rs @@ -0,0 +1,22 @@ +//@revisions: e2021 e2015 +//@[e2021]edition: 2021 +trait Foo { + fn id(me: T) -> T; +} + +/* note the "missing" for ... (in this case for i64, in order for this to compile) */ +impl Foo { +//[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 = >::id(10); + //~^ ERROR the trait bound `i64: Foo` 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 similarity index 100% rename from tests/ui/traits/next-solver/object-unsafety.rs rename to 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 similarity index 90% rename from tests/ui/traits/next-solver/object-unsafety.stderr rename to tests/ui/traits/next-solver/dyn-incompatibility.stderr index 75d0ce244132e..7f2c0646ef501 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` - --> $DIR/object-unsafety.rs:12:12 + --> $DIR/dyn-incompatibility.rs:12:12 | LL | copy::>(t) | ^^^^^^^^^^^^^^^^^ within `dyn Setup`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup: Setup` | = note: required because it appears within the type `dyn Setup` note: required by a bound in `copy` - --> $DIR/object-unsafety.rs:7:12 + --> $DIR/dyn-incompatibility.rs:7:12 | LL | fn copy(from: &U::From) -> U::From { | ^^^^^ required by this bound in `copy` @@ -16,7 +16,7 @@ LL | pub fn copy_any(t: &T) -> T { | +++++++++++++++++++ error[E0308]: mismatched types - --> $DIR/object-unsafety.rs:12:31 + --> $DIR/dyn-incompatibility.rs:12:31 | LL | copy::>(t) | ------------------------- ^ types differ @@ -26,13 +26,13 @@ LL | copy::>(t) = note: expected reference `& 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(from: &U::From) -> U::From { | ^^^^ -------------- error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup` - --> $DIR/object-unsafety.rs:12:5 + --> $DIR/dyn-incompatibility.rs:12:5 | LL | copy::>(t) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup: 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 0000000000000..7432ea78a56a0 --- /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 { + f: T, +} + +fn foo<'a, T: Coerce>(_: T::Assoc) {} + +fn main() { + foo::((&0u32,)); + foo::(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 similarity index 100% rename from tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs rename to 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 similarity index 88% rename from tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr rename to tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr index 0854ea28150fb..dd2dca74f9087 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 - --> $DIR/supertrait-object-safety.rs:4:12 + --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for Bar {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables @@ -24,13 +24,13 @@ LL | trait Foo: for Bar {} = 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 - --> $DIR/supertrait-object-safety.rs:4:12 + --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for Bar {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables @@ -39,13 +39,13 @@ LL | trait Foo: for Bar {} = 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 - --> $DIR/supertrait-object-safety.rs:4:12 + --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for Bar {} | --- ^^^^^^^^^^^^^ ...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 0000000000000..b174776c596ee --- /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 . + +trait A: B {} + +trait B { + type T; +} + +struct Erase(T::T); + +fn main() { + let x = { + let x = String::from("hello"); + + Erase:: 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 0000000000000..067eaf5e7f30f --- /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: B {} + | ----- due to this supertrait +... +LL | Erase:: 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 6660ff040f753..603d7af526002 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 {} +// trait FixedGeneric2<'a>: Super {} // 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 {} @@ -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) { x } //~ERROR mismatched types diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index ca56bdbb67a56..af941e69c5f84 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -106,17 +106,6 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } = note: expected unit type `()` 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 | @@ -172,6 +161,6 @@ LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x } = note: expected unit type `()` found reference `&dyn HasGat = ()>` -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 684458d079e5e..2b1745da5f308 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: AsRef<[T::V]> + AsMut<[T::V]> {} trait B: AsRef + AsRef + AsRef + AsRef {} 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 f43d332d69637..f4abcf8542e5f 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 similarity index 78% rename from tests/ui/traits/vtable/vtable-non-object-safe.rs rename to tests/ui/traits/vtable/vtable-dyn-incompatible.rs index f98af0f23b732..64a8138bdcfb3 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 similarity index 92% rename from tests/ui/traits/vtable/vtable-non-object-safe.stderr rename to tests/ui/traits/vtable/vtable-dyn-incompatible.stderr index 53eef5d0b13ca..e442c3eac00ea 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 ` as A>`: [ Method( as Iterator>::advance_by), Method( 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 678ede58296a4..83544064ce210 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 b8f2aae89663b..99c727cc332b2 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 385f5510fb414..9c45bde88987a 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 { diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 9aab2cf6ab848..82877baef3e3c 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 { | --------------- expected `u8` because of this @@ -15,7 +15,7 @@ LL | Ok(Err(123_i32)?) = note: required for `Result` to implement `FromResidual>` 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 { | -------------------------------------------- this function returns a `Result` @@ -26,7 +26,7 @@ LL | Some(3)?; = help: the trait `FromResidual>` is implemented for `Result` 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 { | -------------------------------------------------- this function returns a `Result` @@ -37,7 +37,7 @@ LL | Ok(ControlFlow::Break(123)?) = help: the trait `FromResidual>` is implemented for `Result` 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 { | ------------------------------------ this function returns an `Option` @@ -48,7 +48,7 @@ LL | Some(Err("hello")?) = help: the trait `FromResidual>` is implemented for `Option` 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 { | ------------------------------------------ this function returns an `Option` @@ -59,7 +59,7 @@ LL | Some(ControlFlow::Break(123)?) = help: the trait `FromResidual>` is implemented for `Option` 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 { | -------------------------------------------------- this function returns a `ControlFlow` @@ -71,7 +71,7 @@ LL | ControlFlow::Continue(Err("hello")?) = help: for that trait implementation, expected `ControlFlow`, found `Result` 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 { | ----------------------------------------------- this function returns a `ControlFlow` @@ -83,7 +83,7 @@ LL | Some(3)?; = help: for that trait implementation, expected `ControlFlow`, found `Option` error[E0277]: the `?` operator in a function that returns `ControlFlow` can only be used on other `ControlFlow`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 { | ----------------------------------------------------- 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 936c0b0689add..ebeb0869f9882 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 0000000000000..df589473a8460 --- /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 Captures<'_> for T {} + +fn dyn_hoops() -> dyn for<'a> Iterator> { + //~^ 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 0000000000000..59d9ff86c6e09 --- /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() -> dyn for<'a> Iterator> { + | ^^ + | +note: lifetime declared here + --> $DIR/bound-lifetime-through-dyn-trait.rs:6:37 + | +LL | fn dyn_hoops() -> dyn for<'a> Iterator> { + | ^^ + +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 b526ab49d8d4a..ec8a51b08188a 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() { + | ^^^^^^^^^^ + | + = 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() { - | ^^^^^^^^^^ - | - = 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 2468fb7480b07..436326e66c386 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 be9b07823ae0a..88529b370f133 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) -> Underconstrained { - | ___________________________________________________^ -LL | | -LL | | -LL | | unimplemented!() -LL | | } - | |_^ the trait `Trait` is not implemented for `T` +LL | fn underconstrain(_: T) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ 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) -> Underconstrained { | +++++++ 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) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` +LL | fn underconstrain(_: T) -> Underconstrained { + | ___________________________________________________^ +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 15d96191ba9e2..b3b9cbca96854 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) -> Underconstrained { - | _____________________________________________________^ -LL | | -LL | | -LL | | 5u32 -LL | | } - | |_^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained(_: U) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ `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) -> Underconstrained { | +++++++++++++++++ error[E0277]: `V` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:17:64 + --> $DIR/generic_underconstrained2.rs:17:43 | -LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ________________________________________________________________^ -LL | | -LL | | -LL | | 5u32 -LL | | } - | |_^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ^^^^^^^^^^^^^^^^^^^^ `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) -> Underconstrained | +++++++++++++++++ error[E0277]: `U` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:8:33 + --> $DIR/generic_underconstrained2.rs:8:53 | -LL | fn underconstrained(_: U) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained(_: U) -> Underconstrained { + | _____________________________________________________^ +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) -> Underconstrained { | +++++++++++++++++ error[E0277]: `V` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:17:43 + --> $DIR/generic_underconstrained2.rs:17:64 | -LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ________________________________________________________________^ +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 22c776e171c2f..eace96317dc1d 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>>, U> MyIndex> for Scope { + | ^ 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 = 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>>, U> MyIndex> for Scope { - | ^ 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 f1361b47c56e6..5ac09e20b02c2 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(, 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 2adfad4fc5b80..2383008d042f7 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 = impl Fn(T) -> U + Copy; //~ ERROR cycle detected +type Bug = impl Fn(T) -> U + Copy; const CONST_BUG: Bug = 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>() -> Bug { - |x| x.into() //~ ERROR the trait bound `U: From` 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 121f765e66726..ac580866704d7 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 = 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 = 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 = 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 = unsafe { std::mem::transmute(|_: u8| ()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | = note: ...which requires computing layout of `Bug`... = note: ...which requires normalizing `Bug`... - = 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 = 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 = 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 = 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 = 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 = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `U: From` is not satisfied - --> $DIR/issue-53092-2.rs:12:5 - | -LL | |x| x.into() - | ^^^^^^^^^^^^ the trait `From` is not implemented for `U` - | -note: required by a bound in `make_bug` - --> $DIR/issue-53092-2.rs:11:19 - | -LL | fn make_bug>() -> Bug { - | ^^^^^^^ required by this bound in `make_bug` -help: consider restricting type parameter `U` - | -LL | type Bug> = 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 2b064dcfc31a5..ec7b9e0e12b3f 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` + --> $DIR/issue-84660-unsoundness.rs:29:1 + | +LL | impl Trait for Out { + | ------------------------------------ first implementation here +... +LL | impl 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` - --> $DIR/issue-84660-unsoundness.rs:29:1 - | -LL | impl Trait for Out { - | ------------------------------------ first implementation here -... -LL | impl 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 5a728a00138c8..e33102f687c53 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` + --> $DIR/issue-84660-unsoundness.rs:29:1 + | +LL | impl Trait for Out { + | ------------------------------------ first implementation here +... +LL | impl 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` - --> $DIR/issue-84660-unsoundness.rs:29:1 - | -LL | impl Trait for Out { - | ------------------------------------ first implementation here -... -LL | impl 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 d0fe920b35f4a..aa0c1076117cc 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 = 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 = 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 0000000000000..dda42580e0f3a --- /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 {} + +fn produce() -> impl for Trait<(), Assoc = impl Trait> { + //~^ ERROR associated type `Assoc` not found for `Trait` + //~| ERROR associated type `Assoc` not found for `Trait` + //~| the trait bound `{integer}: Trait<()>` is not satisfied + 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 0000000000000..fa3306ff11fa0 --- /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 Trait<(), Assoc = impl Trait> { + | ^^^^^ 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 Trait<(), Assoc = impl Trait> { + | ^^^^^ 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 Trait<(), Assoc = impl Trait> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +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 0000000000000..23951c3427006 --- /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 {} + +fn f() -> impl for Trait> {} +//~^ ERROR nested `impl Trait` is not allowed +//~| ERROR the trait bound `(): Trait>` 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 0000000000000..5859d952b75c7 --- /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 Trait> {} + | ------------------^^^^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0277]: the trait bound `(): Trait>` is not satisfied + --> $DIR/non-lifetime-binder.rs:6:11 + | +LL | fn f() -> impl for Trait> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-lifetime-binder.rs:4:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^^^^ + +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 aedb78bf5e7a1..99646aa4d1b2c 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 @@ -10,18 +10,6 @@ note: required by a bound on the type alias `Ty` LL | Ty: Id, | ^^^^^^^^^^^^^^ 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, - | ^^^^^^^^^^^^^^ required by this bound - error[E0275]: overflow evaluating the requirement `Ty: Id` --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:16 | @@ -34,6 +22,6 @@ note: required by a bound on the type alias `Ty` LL | Ty: Id, | ^^^^^^^^^^^^^^ 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 29a21a1f45f56..437a1aed40307 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 {} impl Trait 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 2c064fbb19f71..8a765c21624e6 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 BadTrait for BadStruct {} | +++ ~ ~ -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() -> impl BadTrait { + | +++ ~ 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(&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(&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` -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(&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(&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 00f9bfd5cdff9..0000000000000 --- 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 43843141e2e7a..0000000000000 --- 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 a11f3e18f52a9..0000000000000 --- 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 ddb951aa06cac..0000000000000 --- 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 11978386843a4..0000000000000 --- 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 b50b54b20afe6..0000000000000 --- 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 324968b126413..0000000000000 --- 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 03545ed7b18e2..0000000000000 --- 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 3b3890af771db..0000000000000 --- 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 9ffe71b28c292..0000000000000 --- 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 f8679aad2d7e6..0000000000000 --- 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 80e4608be82e6..0000000000000 --- 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 3e80d7fbf5c0e..0000000000000 --- 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 5d15ec4cffdb9..0000000000000 --- 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 4ea910202de98..0000000000000 --- 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 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 279d723a26c51..799e8071d028a 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 149659693ae67..d8384951e12f0 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] @@ -361,8 +360,6 @@ mod expressions { - - @@ -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 similarity index 100% rename from tests/ui/unsized-locals/by-value-trait-object-safety-rpass.rs rename to 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 similarity index 100% rename from tests/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs rename to 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 similarity index 100% rename from tests/ui/unsized-locals/by-value-trait-object-safety.rs rename to 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 similarity index 84% rename from tests/ui/unsized-locals/by-value-trait-object-safety.stderr rename to tests/ui/unsized-locals/by-value-trait-dyn-compatibility.stderr index 6a93464febb10..223624cfca4dd 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 e2e4ccd63c164..5b9e27fb7b942 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 similarity index 77% rename from tests/ui/wf/wf-convert-unsafe-trait-obj-box.rs rename to tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.rs index ffdb49a3be5c7..26292a1d218c9 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 similarity index 86% rename from tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr rename to tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr index 2565e25a24297..38426545bc8cb 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 = 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 - --> $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` to `Box` 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 - --> $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` 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; | ^^^^^^^^^^^ `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 - --> $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 similarity index 76% rename from tests/ui/wf/wf-convert-unsafe-trait-obj.rs rename to tests/ui/wf/wf-convert-dyn-incompat-trait-obj.rs index 143b854ed6b2d..ec4bb2897f9dc 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 similarity index 87% rename from tests/ui/wf/wf-convert-unsafe-trait-obj.stderr rename to tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr index 97f6bcd0428b6..94259aa5b0aa8 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 - --> $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 - --> $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 - --> $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 similarity index 91% rename from tests/ui/wf/wf-unsafe-trait-obj-match.rs rename to tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs index c8731a8ecafa4..07e90538b85dd 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 similarity index 89% rename from tests/ui/wf/wf-unsafe-trait-obj-match.stderr rename to tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr index edbdec6a5efc6..d7366e12256a2 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 - --> $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 - --> $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 similarity index 57% rename from tests/ui/wf/wf-object-safe.rs rename to tests/ui/wf/wf-dyn-incompatible.rs index 42e6917551fd9..16e7ca1cbc618 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 similarity index 90% rename from tests/ui/wf/wf-object-safe.stderr rename to tests/ui/wf/wf-dyn-incompatible.stderr index 7c14f3d2f8bf6..cf016b63c7405 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 - --> $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 aba3669282806..60ec1043aadb3 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 = [

      , _: F) -> Parser> + { loop {} } + +fn main() { + if_impl().0; +} diff --git a/tests/crashes/130967.rs b/tests/crashes/130967.rs new file mode 100644 index 0000000000000..8a3aae72c20c5 --- /dev/null +++ b/tests/crashes/130967.rs @@ -0,0 +1,13 @@ +//@ known-bug: #130967 + +trait Producer { + type Produced; + fn make_one() -> Self::Produced; +} + +impl Producer for () { + type Produced = Option; + fn make_one() -> Self::Produced { + loop {} + } +} diff --git a/tests/crashes/131046.rs b/tests/crashes/131046.rs new file mode 100644 index 0000000000000..2638705ae18b2 --- /dev/null +++ b/tests/crashes/131046.rs @@ -0,0 +1,15 @@ +//@ known-bug: #131046 + +trait Owner { + const C: u32; +} + +impl Owner for () { + const C: u32 = N; +} + +fn take0(_: impl Owner = { N }>) {} + +fn main() { + take0::<128>(()); +} diff --git a/tests/crashes/131048.rs b/tests/crashes/131048.rs new file mode 100644 index 0000000000000..d57e9921a8ab5 --- /dev/null +++ b/tests/crashes/131048.rs @@ -0,0 +1,7 @@ +//@ known-bug: #131048 + +impl std::ops::CoerceUnsized 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 0000000000000..07f8662d016f7 --- /dev/null +++ b/tests/crashes/131050.rs @@ -0,0 +1,27 @@ +//@ known-bug: #131050 +//@ compile-flags: --edition=2021 + +fn query_as() {} + +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); + +impl Filter for AndThen +where + F: Fn() -> R, + R: Send, +{ +} diff --git a/tests/crashes/131052.rs b/tests/crashes/131052.rs new file mode 100644 index 0000000000000..7ae3ec08f3ed7 --- /dev/null +++ b/tests/crashes/131052.rs @@ -0,0 +1,8 @@ +//@ known-bug: #131052 +#![feature(adt_const_params)] + +struct ConstBytes; + +pub fn main() { + let _: ConstBytes = ConstBytes::; +} diff --git a/tests/crashes/131101.rs b/tests/crashes/131101.rs new file mode 100644 index 0000000000000..3ec441101b7d9 --- /dev/null +++ b/tests/crashes/131101.rs @@ -0,0 +1,12 @@ +//@ known-bug: #131101 +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +impl Foo 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 0000000000000..12b35f8d1b2ac --- /dev/null +++ b/tests/crashes/131102.rs @@ -0,0 +1,4 @@ +//@ known-bug: #131102 +pub struct Blorb([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 0000000000000..70193e8b3bd38 --- /dev/null +++ b/tests/crashes/131103.rs @@ -0,0 +1,6 @@ +//@ known-bug: #131103 +struct Struct(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 0000000000000..3a0e64c69d5b5 --- /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(fut: impl Future) -> 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 0000000000000..f46185b5b4a66 --- /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 0000000000000..01e0eca0bd6d6 --- /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 0000000000000..130a8b10fb78e --- /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 { + 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 0000000000000..ec6c95674677e --- /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 { + 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 0000000000000..f31d6bc324a26 --- /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 0000000000000..833f1b04ffab9 --- /dev/null +++ b/tests/crashes/131298.rs @@ -0,0 +1,12 @@ +//@ known-bug: #131298 + +fn dyn_hoops() -> *const dyn Iterator { + loop {} +} + +mod typeck { + type Opaque = impl Sized; + fn define() -> Opaque { + let _: Opaque = super::dyn_hoops::(); + } +} diff --git a/tests/crashes/131342-2.rs b/tests/crashes/131342-2.rs new file mode 100644 index 0000000000000..79b6a837a49fb --- /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 + where + Self: Sized, + { + loop {} + } +} + +struct Peekable { + _peeked: I::Item, +} + +impl Iterator for Peekable { + type Item = I::Item; +} + +impl Iterator for &I { + type Item = I::Item; +} diff --git a/tests/crashes/131342.rs b/tests/crashes/131342.rs new file mode 100644 index 0000000000000..7f7ee9c9ac110 --- /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) { + 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 0000000000000..15f367d79e208 --- /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 0000000000000..661fecd7620b8 --- /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, +{ + 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 0000000000000..ea642f949280d --- /dev/null +++ b/tests/crashes/131406.rs @@ -0,0 +1,12 @@ +//@ known-bug: #131406 + +trait Owner { + const C: u32 = N; +} + +impl Owner for () {} +fn take0(_: impl Owner = { N }>) {} + +fn main() { + take0::<128>(()); +} diff --git a/tests/crashes/131507.rs b/tests/crashes/131507.rs new file mode 100644 index 0000000000000..d402fb8afc322 --- /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: Copy, +{ + || format_args!(""); +} diff --git a/tests/crashes/131534.rs b/tests/crashes/131534.rs new file mode 100644 index 0000000000000..545b3e68fe8d5 --- /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 0000000000000..47ccdf87f2de7 --- /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 v0<'_, v2 = impl v0 + '_>) {} diff --git a/tests/crashes/131538.rs b/tests/crashes/131538.rs new file mode 100644 index 0000000000000..f971d8b7791e4 --- /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(); +} + +fn do_health_check_par() +where + HealthCheck: HealthCheck, +{ +} diff --git a/tests/debuginfo/type-names.rs b/tests/debuginfo/type-names.rs index 6831786c228d4..4caaf3fc97f78 100644 --- a/tests/debuginfo/type-names.rs +++ b/tests/debuginfo/type-names.rs @@ -17,7 +17,7 @@ // gdb-check:type = type_names::GenericStruct // gdb-command:whatis generic_struct2 -// gdb-check:type = type_names::GenericStruct usize> +// gdb-check:type = type_names::GenericStruct 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 = GenericStruct(PhantomData); - let generic_struct2: GenericStruct usize> = + let generic_struct2: GenericStruct 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 ab4d578458d40..016a1813babd7 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 0000000000000..047441e609913 --- /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 0000000000000..047441e609913 --- /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 9487a4e7e5ffe..743ee8e728bbe 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 3f89ab0e6f330..fee4214982d59 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 0ad7f5910a0b3..4d964b0afb78c 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] { let mut _0: &[u8]; scope 1 (inlined as Deref>::deref) { debug self => _1; - let mut _6: usize; - scope 2 (inlined Vec::::as_ptr) { + scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec; - scope 3 (inlined alloc::raw_vec::RawVec::::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; - scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::) { - debug self => _3; - scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _6: usize; + scope 3 (inlined Vec::::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + debug self => _2; + let mut _3: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { debug self => _3; - let mut _4: std::ptr::NonNull; - scope 6 (inlined Unique::::cast::) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 7 (inlined NonNull::::cast::) { - debug self => _4; - scope 8 (inlined NonNull::::as_ptr) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { + debug self => _3; + let mut _4: std::ptr::NonNull; + scope 7 (inlined Unique::::cast::) { + debug ((self: Unique).0: std::ptr::NonNull) => _4; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; + scope 8 (inlined NonNull::::cast::) { debug self => _4; - let mut _5: *const u8; + scope 9 (inlined NonNull::::as_ptr) { + debug self => _4; + let mut _5: *const u8; + } } } - } - scope 9 (inlined #[track_caller] as Into>>::into) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 10 (inlined as From>>::from) { - debug ((unique: Unique).0: std::ptr::NonNull) => _4; - debug ((unique: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 11 (inlined Unique::::as_non_null_ptr) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - } + scope 10 (inlined Unique::::as_non_null_ptr) { + debug ((self: Unique).0: std::ptr::NonNull) => _4; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; } } + scope 11 (inlined NonNull::::as_ptr) { + debug self => _4; + } } - scope 12 (inlined NonNull::::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::) { - } - scope 17 (inlined align_of::) { - } - scope 18 (inlined slice_from_raw_parts::) { + 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::) { + } + scope 16 (inlined align_of::) { + } + scope 17 (inlined slice_from_raw_parts::) { + 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 0ad7f5910a0b3..4d964b0afb78c 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] { let mut _0: &[u8]; scope 1 (inlined as Deref>::deref) { debug self => _1; - let mut _6: usize; - scope 2 (inlined Vec::::as_ptr) { + scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec; - scope 3 (inlined alloc::raw_vec::RawVec::::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; - scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::) { - debug self => _3; - scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _6: usize; + scope 3 (inlined Vec::::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + debug self => _2; + let mut _3: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { debug self => _3; - let mut _4: std::ptr::NonNull; - scope 6 (inlined Unique::::cast::) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 7 (inlined NonNull::::cast::) { - debug self => _4; - scope 8 (inlined NonNull::::as_ptr) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { + debug self => _3; + let mut _4: std::ptr::NonNull; + scope 7 (inlined Unique::::cast::) { + debug ((self: Unique).0: std::ptr::NonNull) => _4; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; + scope 8 (inlined NonNull::::cast::) { debug self => _4; - let mut _5: *const u8; + scope 9 (inlined NonNull::::as_ptr) { + debug self => _4; + let mut _5: *const u8; + } } } - } - scope 9 (inlined #[track_caller] as Into>>::into) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 10 (inlined as From>>::from) { - debug ((unique: Unique).0: std::ptr::NonNull) => _4; - debug ((unique: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 11 (inlined Unique::::as_non_null_ptr) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - } + scope 10 (inlined Unique::::as_non_null_ptr) { + debug ((self: Unique).0: std::ptr::NonNull) => _4; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; } } + scope 11 (inlined NonNull::::as_ptr) { + debug self => _4; + } } - scope 12 (inlined NonNull::::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::) { - } - scope 17 (inlined align_of::) { - } - scope 18 (inlined slice_from_raw_parts::) { + 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::) { + } + scope 16 (inlined align_of::) { + } + scope 17 (inlined slice_from_raw_parts::) { + 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 5e8371b3e490d..0583594298026 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 240f409817d77..02e1f4be15e2e 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 51514ba5e5d90..64711755f7394 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 859535852cf0d..90b5353f29143 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 0000000000000..6bf4be652bef3 --- /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 0000000000000..15769cdd75b3f --- /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 f1904e5d0f44e..0000000000000 --- 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::(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::(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::(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 c279f59001210..0000000000000 --- 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::(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::(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::(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 cc0ac9a342740..0000000000000 --- 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) {} - -// CHECK-LABEL: fn foo( -fn foo(foo: Foo) { - // CHECK [[a:_.*]] = (_1.0: u8); - // CHECK _.* = access::(move [[a]]) -> [return: bb1, unwind: bb5]; - access(foo.a); - // CHECK [[b:_.*]] = ((_1.1: Foo::{anon_adt#0}).0: i8); - // CHECK _.* = access::(move [[b]]) -> [return: bb2, unwind: bb5]; - access(foo.b); - // CHECK [[c:_.*]] = ((_1.1: Foo::{anon_adt#0}).1: bool); - // CHECK _.* = access::(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::(move [[a]]) -> [return: bb1, unwind: bb5]; - access(bar.a); - // CHECK [[b:_.*]] = ((_1.1: Bar::{anon_adt#0}).0: i8); - // CHECK _.* = access::(move [[b]]) -> [return: bb2, unwind: bb5]; - access(bar.b); - // CHECK [[c:_.*]] = ((_1.1: Bar::{anon_adt#0}).1: bool); - // CHECK _.* = access::(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 0000000000000..378c3289cb7bc --- /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 . + +//@ 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 03c9af4bb8982..50790e18cec10 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 80e9b6a4ded67..0000000000000 --- 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 0000000000000..a9a3796731b4b --- /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 . + +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 0000000000000..afb0dc42f443a --- /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 0000000000000..2d2d2e6812582 --- /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 0000000000000..3db1ae3452d6a --- /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 f00123f006b24..8dd19e613bff8 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() -> u32 { @@ -48,7 +48,7 @@ pub extern "C" fn public_vanilla_generic() -> u32 { #[naked] pub extern "C" fn public_naked_generic() -> 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 228c43cc5f18a..471ce89f188b7 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 105c2fafc5a10..1893248e3077a 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 53d1623bf580e..4f7ae9fb24c91 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 ad2f6388e8fff..5cd5a4583edaf 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 28232eb256621..ce9754f13b931 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 276af9ea263a7..c09a82353b9be 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 4287ab0a93150..58a1b53c0406e 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 84f4e0bd383e8..5869dbf9c2419 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 a57dc3734789e..0000000000000 --- 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 e4ce80b330593..0000000000000 --- a/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs +++ /dev/null @@ -1,28 +0,0 @@ -// This would previously leak the Box 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); - } - 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 cf8f81cf5aa7c..0000000000000 --- 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 8c7375610dd76..0000000000000 --- 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 95f16a8cc896e..0000000000000 --- 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 0d3745bba5ba9..0000000000000 --- 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 47065151a037b..0000000000000 --- 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 { - f: T, -} - -pub fn main() { - { - let _x: Box> = Box::>::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 d8abebfb4473c..0000000000000 --- 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 { - f: T, -} - -pub fn main() { - { - let _x: Box> = Box::>::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 09adaca21c714..0000000000000 --- 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 a66ac8e3cfca6..0000000000000 --- 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 4e25ef76d39af..0000000000000 --- 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 f76657ca75207..0000000000000 --- 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 5d3f558a63a97..0000000000000 --- 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 { - 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); - -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>); - assert_eq!(x.call_once(()), format!("hello")); - let x = *(Box::new(B(42)) as Box>); - assert_eq!(x.call_once(()), format!("42")); - let x = *(Box::new(C(format!("jumping fox"))) as Box>); - assert_eq!(x.call_once(()), format!("jumping fox")); - let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box>); - 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 9b6648f2e27a5..0000000000000 --- 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 { - type Output; - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -struct A; - -impl FnOnce<(String, Box)> for A { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - format!("hello") - } -} - -struct B(i32); - -impl FnOnce<(String, Box)> for B { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - format!("{}", self.0) - } -} - -struct C(String); - -impl FnOnce<(String, Box)> for C { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - self.0 - } -} - -struct D(Box); - -impl FnOnce<(String, Box)> for D { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> 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), 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), 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), 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), 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 3f6b6d262b5dc..0000000000000 --- 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); - -impl Foo for D { - fn foo(self) -> String { - *self.0 - } -} - -fn main() { - let x = *(Box::new(A) as Box); - assert_eq!(x.foo(), format!("hello")); - let x = *(Box::new(B(42)) as Box); - assert_eq!(x.foo(), format!("42")); - let x = *(Box::new(C(format!("jumping fox"))) as Box); - assert_eq!(x.foo(), format!("jumping fox")); - let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box); - 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 a7b9052617f0c..0000000000000 --- 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 { - 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 1126a72ab67ea..efd513715d495 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 0000000000000..c83f5898e8e46 --- /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 . + +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 0000000000000..1003cec33f952 --- /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 b8fa26b17f6b6..e02974e60829a 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 7397992c0ab0f..352995c49030b 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 0000000000000..a4a2d2c7f8c1e --- /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 0000000000000..4d4e599bfeef2 --- /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 f39d2c2608b88..c1f750017e703 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 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 2b47e6b5bc4d5..e39dc4d5ee048 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 = 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 8142bd83877c3..f63a9e87497d0 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 488120304fde0..ef7fec77b1e0d 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 f37f49c24ccc5..e885a3b35f6c7 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 a982bba009591..07d328f99a308 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 6c834fd0a1b61..a347044bfe979 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 0000000000000..6f57b7c6f1082 --- /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 0000000000000..8d2a6649f4c01 --- /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 f50feb57fccf2..17bcbc783fd9e 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 7518ea902ecf5..5b7da7bb12995 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 7752ff51ac811..1e2f640f39f5f 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 be52853a47950..131fd99ebaa97 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 9f45b62d34345..ec3cf1753e2cd 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 5bb1053f18798..3402b345818c7 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 06d2af4ac8a34..4acbabbb6be1d 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 68eb3c54593ea..7d63e202fa6ca 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 1d5b19304c1fb..91baa074c1085 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 5098547c2c8db..8721f243587b4 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 1d3e4c6845ba8..40217b9aa95a6 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 0b8cfcf27fd9b..0715e0cfc52d0 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 4c9a8a665b848..6b458c5d923de 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 d68e7d37950fa..a8bf4c1d39974 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 07f404fd471cb..6f5478c08bf9b 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 957d840f7a241..7dbf892f9e4b1 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 ac428c80e0f12..f1bc03781b94e 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 0000000000000..e3894431eb44d --- /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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 0000000000000..e3894431eb44d --- /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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 0000000000000..e3894431eb44d --- /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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 + --> :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 0000000000000..714b0ee4633c9 --- /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 123e76632574a..00a5b4b2ee142 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 + = 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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + = 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 + +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 + +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 - = 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 7376bb17d6b95..dfb5ceb0c3370 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 + = 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 + +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 + +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 + +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 + +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 + +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 + +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 + = 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 + +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 + +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 - = 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 23b0e581887f4..6537ce6605770 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 + = 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 + +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 + +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 + +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 + +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 + +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 + +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 708fd2c92a998..a53f85f28bcee 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 + = 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 + +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 + +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 + +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 + +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 + +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 + +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 + = 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 + +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 + +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 - = 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 708fd2c92a998..a53f85f28bcee 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 + = 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 + +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 + +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 + +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 + +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 + +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 + +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 + = 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 + +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 + +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 - = 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 c12883e3fce21..0eb039269a3ee 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 7b918a948d3ba..45ba9a6649c51 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 + = 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 + +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 + +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 + +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 + +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 + +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 + +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 + = 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 + +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 + +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 - = 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 0000000000000..9d8235e58d929 --- /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 1c1f4fe0bf6ce..0000000000000 --- 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 93d23885b1353..b78d1e6a0d1c6 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 b81b65cff74fc..37c7b52c191cd 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 12943ac0378b7..7e373270e9fc6 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 8d3c300e0586c..ea63ced1aab04 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 745d30e6a84a9..c27037819a44f 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 8d3c300e0586c..ea63ced1aab04 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 116a84506c570..5c58f1498cc97 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 { 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 93c02e2fbef82..0898f3620f24f 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>, | ^^^^^^^^^^^^^^ 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 57edd57de998e..4053c58fb5136 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 e8ddccc854abe..640f9d9510d15 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 687fe1ad73db1..18b9c1014c3fa 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 3740f17a9dc32..8248a8c165791 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 043aab9029d7d..77831e679ed42 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 e5e177fb8b83e..44ce358c62bdb 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 `:` should be used in inline asm = note: see the asm section of Rust By Example 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 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 `:` should be used in inline asm = note: see the asm section of Rust By Example 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 `:` should be used in inline asm = note: see the asm section of Rust By Example for more information diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr index cf4809991c370..0dabcbdce1bbf 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 { | = 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::() - | +++++ - 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 { | = 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::() - | +++++ - 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 { | = 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::() - | +++++ - 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; | = 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::() + | +++++ + +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::() + | +++++ + +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::() + | +++++ + 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 similarity index 67% rename from tests/ui/associated-type-bounds/entails-sized-object-safety.rs rename to tests/ui/associated-type-bounds/entails-sized-dyn-compatibility.rs index ad2cbe4820981..943df68493fb1 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; } -fn _assert_obj_safe_1(_: Box) {} +fn _assert_dyn_compat_1(_: Box) {} trait ObjTr2 { fn foo() -> Self where Self: Tr1; } -fn _assert_obj_safe_2(_: Box) {} +fn _assert_dyn_compat_2(_: Box) {} trait ObjTr3 { fn foo() -> Self where Self: Tr1 + 'static + Copy>; } -fn _assert_obj_safe_3(_: Box) {} +fn _assert_dyn_compat_3(_: Box) {} trait ObjTr4 { fn foo() -> Self where Self: Tr1 Tr2<'a>>; } -fn _assert_obj_safe_4(_: Box) {} +fn _assert_dyn_compat_4(_: Box) {} trait ObjTr5 { fn foo() -> Self where for<'a> Self: Tr1>; } -fn _assert_obj_safe_5(_: Box) {} +fn _assert_dyn_compat_5(_: Box) {} trait ObjTr6 { fn foo() -> Self where Self: for<'a> Tr1 Tr2<'b>>>; } -fn _assert_obj_safe_6(_: Box) {} +fn _assert_dyn_compat_6(_: Box) {} 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 7df042d5f88e6..c8bb0ebd5744b 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) {} -//~^ 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) {} -//~^ 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 = '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; -//~^ 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 bec60187e4253..dbe285c531078 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) {} - | ^^^^^^^^ `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 - -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) {} - | --------------- ^^ 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 - -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) {} - | ^^^^^^^^^^^^^^^^^^^^ `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 - --> $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) {} | ^^^^ | -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) {} | +++ @@ -44,13 +13,13 @@ help: you might have meant to write a bound here LL | fn f(_: impl Trait) {} | ~ -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) {} | ^^^^^^^^^^^^^^^^^^^^ | -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) {} | +++ @@ -59,13 +28,13 @@ help: you might have meant to write a bound here LL | fn g(_: impl Trait) {} | ~ -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 = '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 = 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: '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; | ^^^^^ | -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; | +++ -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 6083cc7d96dca..b4df58b3c25a8 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 7f3cd2a590053..e6379954776df 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(&mut self, _func: F) -> () LL | F: FnMut() + Send, | ^^^^ required by this bound in `::bar` -error[E0276]: impl has stricter requirements than trait - --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22 - | -LL | / fn bar(&mut self, func: F) -> impl std::future::Future + 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 23ffee0d0a6b2..358bb3e112ed4 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 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 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 similarity index 100% rename from tests/ui/async-await/in-trait/object-safety.rs rename to 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 similarity index 90% rename from tests/ui/async-await/in-trait/object-safety.stderr rename to tests/ui/async-await/in-trait/dyn-compatibility.stderr index 8e73abab9335f..5cc3b6800ddbc 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 - --> $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 7bfa9be66dd37..7b7b3dbc757f1 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: Rc`, `self: Arc`, or `self: Pin